【发布时间】:2014-08-29 20:50:42
【问题描述】:
我有一个名为 lightid 的专有程序,我想将它作为守护程序运行。 lightid 的开发人员在命令行选项中添加了一个“-d”开关,以便能够将其作为守护程序运行。 使用sample-service-script,我创建了一个正确的启动/停止 bash 脚本并将其作为服务安装,以便能够使用 服务 lightid 启动 服务灯停止 服务指示灯状态 等等... 最重要的是这样我可以使用 monit 检查它的状态。 bash 脚本的启动函数(要放在 /etc/init.d/lightid 中)看起来像这样
SCRIPT="/home/foo/lightid -d"
RUNAS=giulio
NAME=lightid
PIDFILE=/var/run/$NAME.pid
LOGFILE="/dev/null"
CMD="$SCRIPT &> \"$LOGFILE\" & echo \$!"
su -c "$CMD" $RUNAS > "$PIDFILE"
如您所见,su 命令应该返回守护进程的 pid,以便可以将其写入 $PIDFILE, 并且可以使用检查其状态 PID=$(cat $PIDFILE) ps axf | grep ${PID} | grep -v grep 并且可以使用杀死守护进程 杀死 -15 $(cat "$PIDFILE")
问题在于su -c "$CMD" $RUNAS > "$PIDFILE" 上面的行写入$PIDFILE 的pid 与后台运行的进程不同。例如,它将返回 9933 而在后台运行的进程将具有 pid=9935 。实际的 pid 始终是返回值 +2。
我询问了 lightid 的开发者,它的“-d”开关实际上做了什么,这是否可能是实际 pid 与 su 返回的 pid 不同的原因。事实上,我怀疑返回的 pid 是父进程之一,它在分叉后“守护”自己时立即终止。他回复我了
“我以这种方式创建守护进程的原因是因为这就是 Michael Kerrisk 的《Linux 编程接口》一书中所记录的内容。他给出的原因是:
1.) 通过分叉和终止父进程,子进程成为 init 进程的子进程。
2.) 孩子需要调用 setsid 来开始一个新的会话并从控制终端中解放出来。
3.) 第二个分叉确保进程不是会话领导者,因此无法重新获取控制终端(系统 V 要求)。
我从来没有遇到过无需分叉就可以创建守护进程的方法,因此以您想要的方式获取进程 PID 的问题恐怕不是我以前处理过的问题。”
有什么方法可以得到正确的 pid 吗? 我是否应该通过将 stdin、stdout 和 stderr 适当地重定向到 /dev/null 来在非守护程序模式下运行 lightid ?
【问题讨论】:
-
对
CMD的分配似乎充满了问题的机会。如果您只在单独的行上运行su -c $SCRIPT &> $LOGFILE &后跟echo $! > $PIDFILE会发生什么?祝你好运。
标签: linux shell fork daemon pid