从init脚本运行任意程序作为守护进程

我需要在Red Hat上安装一个程序作为服务。 它不会后台自己,pipe理其PID文件,或pipe理自己的日志。 它只是运行并打印到STDOUT和STDERR。

使用标准的初始化脚本作为指南,我开发了以下内容:

#!/bin/bash # # /etc/rc.d/init.d/someprog # # Starts the someprog daemon # # chkconfig: 345 80 20 # description: the someprog daemon # processname: someprog # config: /etc/someprog.conf # Source function library. . /etc/rc.d/init.d/functions prog="someprog" exec="/usr/local/bin/$prog" [ -e "/etc/sysconfig/$prog" ] && . "/etc/sysconfig/$prog" lockfile="/var/lock/subsys/$prog" RETVAL=0 check() { [ `id -u` = 0 ] || exit 4 test -x "$exec" || exit 5 } start() { check if [ ! -f "$lockfile" ]; then echo -n $"Starting $prog: " daemon --user someproguser "$exec" RETVAL=$? [ $RETVAL -eq 0 ] && touch "$lockfile" echo fi return $RETVAL } stop() { check echo -n $"Stopping $prog: " killproc "exec" RETVAL=$? [ $RETVAL -eq 0 ] && rm -f "$lockfile" echo return $RETVAL } restart() { stop start } case "$1" in start) start ;; stop) stop ;; restart) restart ;; status) status "$prog" RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|status}" RETVAL=2 esac exit $RETVAL 

这可能是我的错误是复制粘贴和修改/etc/init.d中的一些现有的脚本。 无论如何,由此产生的服务行为奇怪:

  • 当我用service someprog start启动时, service someprog start程序打印到terminal,命令没有完成。
  • 如果我CTRL-C,它打印“会话终止,杀死shell……死亡。失败”。 我必须这样做,让我的shell提示符重新回来。
  • 现在当我运行service someprog status它说它正在运行并列出其PID。 我可以看到它在ps所以它正在运行。
  • 现在当我运行service someprog stop它无法停止。 我可以validation它仍然运行与ps

我需要改变什么,以便将someprog程序发送到后台并作为服务进行pipe理?

编辑:我现在发现了一些相关的问题,除了“做别的事情”之外,他们都没有真正的答案:

  • 在/etc/init.d脚本中调用守护进程是阻塞的,而不是在后台运行
  • 让shell脚本在CentOS上作为守护进程运行?

编辑:这个双分叉的答案可能已经解决了我的问题,但现在我的程序本身双叉和工程: https : //stackoverflow.com/a/9646251/898699

该命令“不完整”,因为daemonfunction不会在daemon运行您的应用程序。 你需要在你的daemon命令的末尾添加一个& ,如下所示:

daemon --user someproguser $exec &

如果someprog不能处理SIGHUP ,则应该使用nohup运行该命令,以确保您的进程不会收到SIGHUP ,这会告诉您的进程在父shell退出时退出。 这看起来像这样:

daemon --user someproguser "nohup $exec" &

在你的stop函数中, killproc "exec"没有做任何事情来停止你的程序。 它应该这样读:

killproc $exec

killproc需要您的应用程序的完整path来正确地停止它。 我在过去使用killproc时遇到了一些麻烦,所以你也可以在PIDFILE中杀掉PID,你应该用下面这样的东西来写someprog PID:

cat $pidfile | xargs kill

你可以这样写PIDFILE:

ps aux | grep $exec | grep -v grep | tr -s " " | cut -d " " -f2 > $pidfile

$pidfile指向/var/run/someprog.pid

如果你想在stop函数中使用[OK]或者[FAILED],你应该使用/etc/rc.d/init.d/functionssuccessfailure函数。 你不需要这些在start函数,因为daemon为你调用适当的。

你也只需要用空格的string引号。 不过这是一种风格select,所以取决于你。

所有这些变化看起来像这样:

 #!/bin/bash # # /etc/rc.d/init.d/someprog # # Starts the someprog daemon # # chkconfig: 345 80 20 # description: the someprog daemon # processname: someprog # config: /etc/someprog.conf # Source function library. . /etc/rc.d/init.d/functions prog=someprog exec=/usr/local/bin/$prog [ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog lockfile=/var/lock/subsys/$prog pidfile=/var/run/$prog RETVAL=0 check() { [ `id -u` = 0 ] || exit 4 test -x $exec || exit 5 } start() { check if [ ! -f $lockfile ]; then echo -n $"Starting $prog: " daemon --user someproguser "nohup $exec" & RETVAL=$? if [ $RETVAL -eq 0 ]; then touch $lockfile ps aux | grep $exec | grep -v grep | tr -s " " | cut -d " " -f2 > $pidfile fi echo fi return $RETVAL } stop() { check echo -n $"Stopping $prog: " killproc $exec && cat $pidfile | kill RETVAL=$? if [ $RETVAL -eq 0 ]; then rm -f $lockfile rm -f $pidfile success; echo else failure; echo fi echo return $RETVAL } restart() { stop start } case "$1" in start) start ;; stop) stop ;; restart) restart ;; status) status $prog RETVAL=$? ;; *) echo $"Usage: $0 {start|stop|restart|status}" RETVAL=2 esac exit $RETVAL 

如果这是你的程序,请把它写成适当的守护进程。 特别是如果它的重新分配。 🙂

你可以尝试monit 。 或者,也许像runit或daemontools。 那些可能没有现成的软件包。 Daemontools来自DJB,如果这影响你的决定(在任何方向)。

我已经做了更多的研究,看来答案是“你不能这样做”。 要运行的程序必须正确地进行自身的守护程序:fork和分离它的标准文件句柄,从terminal分离,并开始一个新的会话。

编辑:显然我错了 – 双分叉将工作。 https://stackoverflow.com/a/9646251/898699