Ejecutar un programa arbitrario como demonio desde el script de inicio

10

Necesito instalar un programa como servicio en Red Hat. No se ejecuta en segundo plano, no administra su archivo PID ni administra sus propios registros. Simplemente se ejecuta e imprime en STDOUT y STDERR.

Utilizando los scripts de inicio estándar como guías, he desarrollado lo siguiente:

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

Puede ser que mi error fue copiar y pegar y modificar algunos de los scripts existentes en /etc/init.d. En cualquier caso, el servicio resultante se comporta de manera extraña:

  • cuando lo inicio con service someprog startel programa se imprime en la terminal y el comando no se completa.
  • si CTRL-C, imprime "Sesión terminada, matando shell ... ... matado. FALLIDO". Tengo que hacer esto para recuperar mi indicador de shell nuevamente.
  • ahora cuando ejecuto service someprog statusdice que se está ejecutando y enumera su PID. Puedo verlo psasí que se está ejecutando.
  • ahora cuando corro service someprog stopno se detiene. Puedo verificar que todavía se está ejecutando ps.

¿Qué necesito cambiar para que someprogse envíe en segundo plano y se administre como un servicio?

Editar: ahora he encontrado un par de preguntas relacionadas, ninguna de las cuales tiene una respuesta real que no sea "hacer otra cosa":

Editar: esta respuesta sobre doble bifurcación podría haber resuelto mi problema, pero ahora mi programa en sí mismo se bifurca y funciona: /programming//a/9646251/898699

Baron Schwartz
fuente
¿Estás iniciando el programa con la utilidad "daemon" proporcionada por libslack. libslack.org/daemon/#documentation En este caso, el programa se puede detener como daemon -n name --stop. Además, intente redirigir la salida (al iniciar el programa) a un archivo o / dev / null y verifique.
Ankit
2
Dependiendo de su versión de redhat, puede hacer un simple envoltorio para él en el arranque y llamarlo directamente en el arranque. Luego, upstart gestionará el servicio por usted. Sin embargo, esto es una cosa EL6.
Matthew Ife

Respuestas:

1

El comando "no se completa" porque la daemonfunción no ejecuta su aplicación en segundo plano por usted. Deberá agregar un &al final de su daemoncomando de la siguiente manera:

daemon --user someproguser $exec &

Si someprogno se maneja SIGHUP, debe ejecutar el comando nohuppara asegurarse de que su proceso no reciba, lo SIGHUPque le indica a su proceso que salga cuando salga el shell principal. Eso se vería así:

daemon --user someproguser "nohup $exec" &

En su stopfunción, killproc "exec"no está haciendo nada para detener su programa. Debería leer así:

killproc $exec

killprocrequiere la ruta completa a su aplicación para detenerla correctamente. He tenido algunos problemas killprocen el pasado, por lo que también puede matar el PID en el PIDFILE en el que debería escribir someprogel PID con algo como esto:

cat $pidfile | xargs kill

Puede escribir el PIDFILE de esta manera:

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

donde $pidfileapunta a /var/run/someprog.pid.

Si desea [OK] o [FAILED] en su stopfunción, debe usar las funciones successy failurede /etc/rc.d/init.d/functions. No necesita estos en la startfunción porque daemonllama al apropiado para usted.

También solo necesita comillas alrededor de cadenas con espacios. Sin embargo, es una elección de estilo, así que depende de usted.

Todos estos cambios se ven así:

#!/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
fuente
Lo sentimos, tardó casi 4,5 años en obtener una respuesta adecuada.
Stuporman
-1

Si este es su programa, escríbalo como un demonio apropiado. Especialmente si es por redistribución. :)

Puedes probar monit . O tal vez algo como runit o daemontools. Esos poderosos no tienen paquetes fácilmente disponibles. Daemontools es de DJB, si eso influye en su decisión (en cualquier dirección).

carro derribado
fuente
-1

He investigado un poco más y parece que la respuesta es "no puedes hacer eso". El programa que se debe ejecutar debe demonizarse correctamente: bifurca y separa sus controladores de archivo estándar, se desconecta del terminal y comienza una nueva sesión.

Editar: aparentemente estoy equivocado: doble bifurcación funcionaría. /programming//a/9646251/898699

Baron Schwartz
fuente
Puede hacerlo utilizando el sistema de arranque como se indica en los comentarios.