Мне нужно установить программу как службу в 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
программа выводит на терминал, и команда не завершается.service someprog status
он говорит, что работает, и перечисляет его PID. Я вижу это в ps
так что он работает.service someprog stop
это не может остановиться. Я могу убедиться, что он все еще работает с ps
.Что мне нужно изменить, чтобы 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, который вы должны написать 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
.
Если вы хотите [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, если это повлияет на ваше решение (в любом направлении).