我有一个非常简单的 SysVinit 服务/etc/rc.d
:
#!/bin/bash
PIDFILE="/var/run/test.pid"
status() {
if [ -f "$PIDFILE" ]; then
echo 'Service running'
return 1
fi
return 0
}
start() {
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")"; then
echo 'Service already running'
return 1
fi
echo 'Starting...'
test & echo $! > "$PIDFILE"
return 0
}
stop() {
if [ ! -f "$PIDFILE" ] || ! kill -0 "$(cat "$PIDFILE")"; then
echo 'Service not running'
return 1
fi
echo 'Stopping...'
kill -15 "$(cat "$PIDFILE")" && rm -f "$PIDFILE"
return 0
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
当系统启动时,它会启动该服务。
但当系统停止时,它永远不会调用停止命令。我能想到的唯一原因是系统认为服务没有运行或没有正确启动。
但这样做有什么要求呢?
- 您需要为启动命令返回特殊的退出代码吗?
- 我是否需要创建一个文件
/var/lock/subsys
来表明它处于活动状态? - 还有什么可能导致系统认为服务没有启动吗?
答案1
看起来 Synology 从经典的 SysVinit 转移到了upstart
DSM 6 左右,然后转移到了systemd
DSM 7。这两个 init 系统都为经典的 SysVinit 风格的启动/停止脚本提供了向后兼容性,但有一些怪癖您应该注意。
如果您有 DSM 7.0 或更高版本,那么在安装脚本后您可能应该运行systemctl daemon-reload
,因此应该自动为其systemd-sysv-generator
创建一个文件(可能在 中)。然后您可以使用 - 启动脚本,事实上应该这样做,而不是仅仅手动运行脚本。仅当以下情况时才会意识到需要运行作业.service
/run/systemd
systemctl start <script name>
systemd
<your script> stop
它实际上已经执行了相应的启动作业。
这是因为systemd
将每个服务设置为单独的控制组启动进程时的进程数(管理员手动运行启动脚本不会执行此操作)。
这对服务本身来说是完全不可见的(除非他们专门去寻找它),并且服务的任何子进程都将继承此控制组成员身份。如果控制组中没有剩余进程,它将自动停止存在。
关闭时,systemd
将仅遍历现有控制组,并对找到的任何非默认控制组运行停止命令。任何未使用而启动的服务systemctl start
都将成为“管理员的交互式会话”控制组的一部分,而不是“服务 X”控制组的一部分,并且本质上将被终止而不运行相应的停止脚本。
如果您需要诸如在服务由于某种原因终止时自动重新启动之类的功能,您应该考虑为适用的 init 系统使用适当的“本机”配置方法:
/etc/init/*
Synology DSM 6.x 系列中 Upstart 的文件/etc/systemd/system/*.service
Synology DSM 7.x 系列及更高版本中的 systemd 文件。这些初始化系统具有内置的自动重启功能,您只需进行一点配置即可使用,而不必编写包装器脚本来自己观察服务进程。