Exécution d'un programme arbitraire en tant que démon à partir du script init

10

J'ai besoin d'installer un programme en tant que service dans Red Hat. Il ne se déroule pas en arrière-plan, ne gère pas son fichier PID ou ne gère pas ses propres journaux. Il s'exécute et s'imprime simplement sur STDOUT et STDERR.

En utilisant les scripts init standard comme guides, j'ai développé ce qui suit:

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

Il se peut que mon erreur ait été de copier-coller et de modifier certains des scripts existants dans /etc/init.d. Dans tous les cas, le service résultant se comporte étrangement:

  • quand je le démarre avec service someprog startle programme imprime sur le terminal et la commande ne se termine pas.
  • si je CTRL-C, il affiche "Session terminée, tuant shell ... ... tué. ÉCHEC". Je dois le faire pour récupérer à nouveau mon invite shell.
  • maintenant, quand je lance, service someprog statusil dit qu'il fonctionne et répertorie son PID. Je peux le voir psdonc il fonctionne.
  • maintenant, quand je cours, service someprog stopil n'arrête pas. Je peux vérifier qu'il fonctionne toujours avec ps.

Que dois-je changer pour qu'il someprogsoit envoyé en arrière-plan et géré en tant que service?

Edit: J'ai maintenant trouvé quelques questions connexes, aucune d'entre elles avec une réponse réelle autre que "faire autre chose":

Edit: cette réponse sur le double forking a peut-être résolu mon problème, mais maintenant mon programme lui-même double-forks et cela fonctionne: /programming//a/9646251/898699

Baron Schwartz
la source
Démarrez-vous le programme avec l'utilitaire "démon" fourni par libslack. libslack.org/daemon/#documentation Dans ce cas, le programme peut être arrêté en tant que démon -n nom --stop. Essayez également de rediriger la sortie (au démarrage du programme) vers un fichier ou / dev / null et vérifiez.
Ankit
2
En fonction de votre version de redhat, vous pouvez simplement créer un wrapper simple pour elle dans upstart et l'appeler directement dans upstart. Par la suite, upstart gérera le service pour vous. C'est une chose EL6 cependant.
Matthew Ife

Réponses:

1

La commande "ne se termine pas" car la daemonfonction n'exécute pas votre application en arrière-plan pour vous. Vous devrez ajouter un &à la fin de votre daemoncommande comme ceci:

daemon --user someproguser $exec &

Si someprogne gère pas SIGHUP, vous devez exécuter la commande avec nohuppour vous assurer que votre processus ne recevra pas, SIGHUPce qui indique à votre processus de se terminer à la fermeture du shell parent. Cela ressemblerait à ceci:

daemon --user someproguser "nohup $exec" &

Dans votre stopfonction, killproc "exec"ne fait rien pour arrêter votre programme. Il devrait se lire comme suit:

killproc $exec

killprocnécessite le chemin d'accès complet à votre application pour l'arrêter correctement. J'ai eu quelques problèmes avec killprocle passé, vous pouvez donc aussi simplement tuer le PID dans le PIDFILE auquel vous devriez écrire someprogle PID avec quelque chose comme ceci:

cat $pidfile | xargs kill

Vous pouvez écrire le PIDFILE comme ceci:

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

$pidfilepointe /var/run/someprog.pid.

Si vous voulez [OK] ou [ÉCHEC] sur votre stopfonction, vous devez utiliser les fonctions successet à failurepartir de /etc/rc.d/init.d/functions. Vous n'en avez pas besoin dans la startfonction, car elle daemonappelle celle qui vous convient.

Vous n'avez également besoin que de guillemets autour des chaînes avec des espaces. C'est un choix de style, donc c'est à vous de décider.

Tous ces changements ressemblent à ceci:

#!/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
la source
Désolé, il vous a fallu près de 4,5 ans pour obtenir une réponse correcte.
Stuporman
-1

S'il s'agit de votre programme, veuillez l'écrire en tant que démon approprié. Surtout si c'est pour la redistribution. :)

Vous pourriez essayer monit . Ou peut-être quelque chose comme runit ou daemontools. Ces puissants n'ont pas de packages facilement disponibles. Daemontools est de DJB, si cela influence votre décision (dans les deux sens.)

chariot renversé
la source
-1

J'ai fait quelques recherches supplémentaires et il semble que la réponse soit «vous ne pouvez pas faire ça». Le programme à exécuter doit en fait se démonifier correctement: bifurquer et détacher ses descripteurs de fichiers standard, se détacher du terminal et démarrer une nouvelle session.

Edit: apparemment je me trompe - une double fourche fonctionnerait. /programming//a/9646251/898699

Baron Schwartz
la source
Vous pouvez le faire en utilisant upstart comme indiqué dans les commentaires.