以守护进程运行程序返回错误的PID

我有这个专有的程序叫lightid,我想运行它作为守护进程。 lightid的开发人员在命令行选项中添加了“-d”开关,以便能够将其作为后台进程运行。 使用示例服务脚本 ,我创build了一个合适的启动/停止bash脚本,并将其作为服务安装,以便能够使用服务lightid启动服务lightid停止服务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和守护进程可以使用kill -15 $(cat“$ PIDFILE”)来杀死

问题是,上面的行su -c "$CMD" $RUNAS > "$PIDFILE"写入$PIDFILE一个pid,它与在后台运行的进程不一样。 例如,它将返回9933,而在后台运行的进程将有pid = 9935。 实际的PID始终是返回值+2。 我问灯开发者,它的“-d”开关实际上是做了什么,如果这可能是某种原因,实际的pid与su返回的不同。 实际上,我怀疑返回的pid是父进程在父进程“自动守护”后立即终止的。 他回答我

我之所以创build守护进程的原因是因为Michael Kerrisk所着的“The Linux Programming Interface”(Linux编程接口)中记载了这一点,他给出的理由是:

1.)通过分支和终止父进程,孩子成为init进程的subprocess。

2.)孩子需要调用setsid来启动一个新的会话,并从控制terminal中解脱出来。

3.)第二个分支确保过程不是会议的领导者,因此不能重新获得控制terminal(系统V要求)。

我从来没有遇到过创build一个守护进程的方法,而不是像现在这样按照你想要的方式获得进程PID的问题,恐怕不是我之前处理过的。

有什么办法可以得到正确的PID吗? 我应该通过将stdin,stdout和stderrredirect到/ dev / null来在非守护模式下运行lightid吗?

就像你已经正确地推断出的那样,问题是你的脚本会守护那个守护lightid服务的lightid启动器。

既然你是守护进程守护进程而不是实际的服务,你最终会得到错误的pid。

你应该确保只涉及一个守护进程。 如果lightid支持本地写pidfile,只需使用它的功能。

如果没有,你应该使用一个工具来daemon ,比如daemon ,并且运行一个 daemon lightid。 这些工具重定向fds,创建会话,重置信号处理程序以及偶然的守护进程脚本会忘记的所有其他事情。