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

10

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

  • когда я запускаю его, service someprog startпрограмма печатает на терминал, и команда не завершается.
  • если я нажимаю CTRL-C, выводится сообщение «Сеанс завершен, оболочка уничтожена ... ... убита. Сбой». Я должен сделать это, чтобы снова получить приглашение оболочки.
  • теперь, когда я запускаю, service someprog statusон говорит, что он работает и перечисляет его PID. Я вижу это psтак, что он работает.
  • теперь, когда я бегу, service someprog stopон не может остановиться. Я могу убедиться, что он все еще работает с ps.

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

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

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

Барон шварц
источник
Вы запускаете программу с помощью утилиты "daemon", предоставляемой libslack. libslack.org/daemon/#documentation В этом случае программу можно остановить как демон -n name --stop. Также попробуйте перенаправить вывод (при запуске программы) в файл или / dev / null и проверьте.
Анкит,
2
В зависимости от вашей версии redhat, вы можете просто сделать для него простую обертку в upstart и напрямую вызвать ее в upstart. Тогда выскочка будет управлять сервисом для вас. Это вещь EL6, хотя.
Мэтью Ифе

Ответы:

1

Команда «не завершена», потому что 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
Stuporman
источник
Извините, что вам понадобилось почти 4,5 года, чтобы получить правильный ответ.
Ступорман
-1

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

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

toppledwagon
источник
-1

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

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

Барон шварц
источник
Вы можете сделать это, используя выскочку, как указано в комментариях.