Executando programa arbitrário como daemon a partir do script de inicialização

9

Eu preciso instalar um programa como um serviço na Red Hat. Ele não faz o plano em si, gerencia seu arquivo PID ou gerencia seus próprios logs. Apenas corre e imprime para STDOUT e STDERR.

Usando os scripts init padrão como guias, desenvolvi o seguinte:

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

Pode ser que meu erro tenha sido copiar, colar e modificar alguns dos scripts existentes em /etc/init.d. Em qualquer caso, o serviço resultante se comporta de forma estranha:

  • quando eu inicio com service someprog start , o programa imprime no terminal e o comando não é concluído.
  • se eu CTRL-C, ele imprime "Session terminated, killing shell ... ... kill. FAILED". Eu tenho que fazer isso para obter o meu prompt de volta.
  • agora, quando executo o service someprog status , ele diz que está em execução e lista seu PID. Eu posso ver em ps , então está em execução.
  • agora, quando executo service someprog stop , ele não consegue parar. Posso verificar se ainda está em execução com ps .

O que preciso alterar para que someprog seja enviado para o segundo plano e gerenciado como um serviço?

Editar: agora encontrei algumas perguntas relacionadas, nenhuma delas com uma resposta real diferente de "fazer outra coisa":

Edit: esta resposta em double-forking pode ter resolvido o meu problema, mas agora o meu próprio programa double-forks e isso funciona: link

    
por Baron Schwartz 28.03.2013 / 03:13

3 respostas

-1

Eu fiz mais pesquisas e parece que a resposta é "você não pode fazer isso". O programa a ser executado deve realmente se daemonizar apropriadamente: bifurque e desconecte seus filehandles padrão, desconecte-se do terminal e inicie uma nova sessão.

Edit: aparentemente eu estou errado - double forking iria funcionar. link

    
por 30.03.2013 / 21:46
1

O comando "não é concluído" porque a função daemon não executa seu aplicativo em segundo plano para você. Você precisará adicionar um & ao final do seu comando daemon da seguinte forma:

daemon --user someproguser $exec &

Se someprog não manipular SIGHUP , você deverá executar o comando com nohup para garantir que o processo não receba SIGHUP , o que instrui o processo a sair quando o shell pai sair. Isso ficaria assim:

daemon --user someproguser "nohup $exec" &

Na sua função stop , killproc "exec" não está fazendo nada para interromper seu programa. Deve ser assim:

killproc $exec

killproc requer o caminho completo para seu aplicativo para pará-lo corretamente. Eu tive alguns problemas com killproc no passado, então você também pode simplesmente matar o PID no PIDFILE você deve estar escrevendo someprog 's PID para algo como isto:

cat $pidfile | xargs kill

Você pode escrever o PIDFILE assim:

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

em que $pidfile aponta para /var/run/someprog.pid .

Se você quiser [OK] ou [FAILED] na sua função stop , use as funções success e failure de /etc/rc.d/init.d/functions . Você não precisa disso na função start porque daemon chama o nome adequado para você.

Você também precisa apenas de aspas ao redor de strings com espaços. É uma escolha de estilo, então cabe a você.

Todas essas alterações são assim:

#!/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
    
por 26.08.2017 / 13:06
-1

Se este é o seu programa, por favor, escreva-o como um daemon apropriado. Especialmente se for para redistribuição. :)

Você pode tentar monit . Ou talvez algo como runit ou daemontools. Aqueles poderosos não têm pacotes prontamente disponíveis. Daemontools é de DJB, se isso influencia sua decisão (em qualquer direção).

    
por 28.03.2013 / 06:39