Назад | Перейти на главную страницу

Запуск произвольной программы как демона из сценария инициализации

Мне нужно установить программу как службу в Red Hat. Он не работает в фоновом режиме, не управляет своим PID-файлом или собственными журналами. Он просто запускается и печатает в 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. В любом случае получившийся сервис ведет себя странно:

Что мне нужно изменить, чтобы someprog отправляется в фоновый режим и управляется как услуга?

Изменить: теперь я нашел несколько связанных вопросов, ни один из которых не имеет фактического ответа, кроме «сделать что-то еще»:

Изменить: этот ответ о двойном разветвлении мог бы решить мою проблему, но теперь моя программа сама разветвляется, и это работает: https://stackoverflow.com/a/9646251/898699

Команда "не завершена", потому что daemon функция не запускает ваше приложение в фоновом режиме. Вам нужно будет добавить & до конца твоего daemon команда так:

daemon --user someproguser $exec &

Если someprog не справляется SIGHUP, вы должны запустить команду с nohup чтобы гарантировать, что ваш процесс не получит SIGHUP который сообщает вашему процессу, что нужно выйти, когда родительская оболочка завершится. Это выглядело бы так:

daemon --user someproguser "nohup $exec" &

В твоем stop функция killproc "exec" ничего не делает, чтобы остановить вашу программу. Он должен выглядеть так:

killproc $exec

killproc для правильной остановки требуется полный путь к вашему приложению. У меня были проблемы с killproc в прошлом, поэтому вы также можете просто убить PID в PIDFILE, который вы должны написать someprogPID на что-то вроде этого:

cat $pidfile | xargs kill

Вы можете написать PIDFILE так:

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

где $pidfile указывает на /var/run/someprog.pid.

Если вы хотите [OK] или [FAILED] на вашем stop функцию, вы должны использовать success и failure функции от /etc/rc.d/init.d/functions. Вам это не нужно в start функция, потому что daemon называет подходящий для вас.

Вам также нужны кавычки вокруг строк с пробелами. Однако это выбор стиля, так что решать вам.

Все эти изменения выглядят так:

#!/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

Я провел еще несколько исследований, и, похоже, ответ - «вы не можете этого сделать». Программа, которая должна быть запущена, должна фактически демонстрировать себя должным образом: разветвлять и отсоединять стандартные дескрипторы файлов, отсоединяться от терминала и начинать новый сеанс.

Изменить: видимо, я ошибаюсь - двойное разветвление будет работать. https://stackoverflow.com/a/9646251/898699

Если это ваша программа, напишите ее как полноценный демон. Особенно если это для распространения. :)

Вы можете попробовать контролировать. Или, может быть, что-то вроде runit или daemontools. У этих могучих нет готовых пакетов. Daemontools от DJB, если это повлияет на ваше решение (в любом направлении).