Esecuzione di un programma arbitrario come demone dallo script init


10

Devo installare un programma come servizio in Red Hat. Non si basa su se stesso, non gestisce il suo file PID o gestisce i propri log. Funziona e stampa su STDOUT e STDERR.

Usando gli script init standard come guide, ho sviluppato quanto segue:

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

È possibile che il mio errore sia stato copiare e incollare e modificare alcuni degli script esistenti in /etc/init.d. In ogni caso, il servizio risultante si comporta in modo strano:

  • quando lo avvio con service someprog startil programma stampa sul terminale e il comando non viene completato.
  • se I CTRL-C, stampa "Sessione terminata, uccisione shell ... ... ucciso. NON RIUSCITO". Devo farlo per riavere il mio prompt della shell.
  • ora quando corro service someprog statusdice che è in esecuzione ed elenca il suo PID. Posso vederlo in psmodo che sia in esecuzione.
  • ora quando corro service someprog stopnon riesce a fermarsi. Posso verificare che sia ancora in esecuzione con ps.

Cosa devo modificare in modo che someprogvenga inviato in background e gestito come servizio?

Modifica: ora ho trovato un paio di domande correlate, nessuna delle quali con una risposta effettiva diversa da "fai qualcos'altro":

Modifica: questa risposta sul doppio fork potrebbe aver risolto il mio problema, ma ora il mio programma stesso double-fork e funziona: https://stackoverflow.com/a/9646251/898699


Stai avviando il programma con l'utility "daemon" fornita da libslack. libslack.org/daemon/#documentation In questo caso il programma può essere fermato come demone -n ​​nome --stop. Inoltre, prova a reindirizzare l'output (all'avvio del programma) su un file o / dev / null e controlla.
Ankit,

2
A seconda della versione di Redhat, puoi semplicemente creare un semplice wrapper per l'avvio e chiamarlo direttamente all'avvio. Quindi upstart gestirà il servizio per te. Questa è una cosa EL6 però.
Matthew Ife,

Risposte:


1

Il comando "non viene completato" perché la daemonfunzione non esegue l'applicazione in background per te. Dovrai aggiungere un &alla fine del tuo daemoncomando in questo modo:

daemon --user someproguser $exec &

In caso someprogcontrario SIGHUP, è necessario eseguire il comando nohupper assicurarsi che il processo non venga ricevuto, il SIGHUPche indica che il processo verrà chiuso alla chiusura della shell padre. Sarebbe così:

daemon --user someproguser "nohup $exec" &

Nella tua stopfunzione, killproc "exec"non stai facendo nulla per fermare il tuo programma. Dovrebbe essere così:

killproc $exec

killprocrichiede il percorso completo dell'applicazione per arrestarlo correttamente. Ho avuto qualche problema con killprocin passato, quindi puoi anche uccidere il PID nel PIDFILE con cui dovresti scrivere someprogil PID con qualcosa del genere:

cat $pidfile | xargs kill

Puoi scrivere il PIDFILE in questo modo:

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

dove $pidfileindica /var/run/someprog.pid.

Se si desidera [OK] o [FALLITO] sulla propria stopfunzione, è necessario utilizzare le funzioni successe failureda /etc/rc.d/init.d/functions. Non hai bisogno di questi nella startfunzione perché daemonchiama quello appropriato per te.

Sono inoltre necessarie solo virgolette attorno alle stringhe con spazi. È una scelta di stile, però, quindi dipende da te.

Tutti questi cambiamenti si presentano così:

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

Mi dispiace, ci sono voluti quasi 4,5 anni per ottenere una risposta adeguata.
Stuporman,

-1

Se questo è il tuo programma, scrivilo come un demone corretto. Soprattutto se si tratta di ridistribuzione. :)

Potresti provare a monit . O forse qualcosa come runit o daemontools. Quei potenti non hanno pacchetti prontamente disponibili. Daemontools proviene da DJB, se ciò influenza la tua decisione (in entrambe le direzioni).


-1

Ho fatto qualche ricerca in più e sembra che la risposta sia "non puoi farlo". Il programma da eseguire deve effettivamente demonizzare se stesso correttamente: fork e staccare i suoi filehandle standard, staccare dal terminale e avviare una nuova sessione.

Modifica: apparentemente mi sbaglio - il doppio fork avrebbe funzionato. https://stackoverflow.com/a/9646251/898699


Puoi farlo usando upstart come indicato nei commenti.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.