Executando um programa arbitrário como daemon a partir do script init

10

Preciso instalar um programa como serviço no Red Hat. Ele não se destaca, gerencia seu arquivo PID ou gerencia seus próprios logs. Apenas executa e imprime em 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 e colar e modificar alguns dos scripts existentes no /etc/init.d. De qualquer forma, o serviço resultante se comporta de maneira estranha:

  • quando inicio, service someprog starto programa é impresso no terminal e o comando não é concluído.
  • se eu CTRL-C, ele imprime "Sessão terminada, matando shell ... ... morto. FAILED". Eu tenho que fazer isso para obter meu prompt de shell novamente.
  • Agora, quando corro, service someprog statusele diz que está sendo executado e lista seu PID. Eu posso vê-lo, psentão ele está sendo executado.
  • Agora, quando eu corro, service someprog stopele não para. Posso verificar se ele ainda está sendo executado ps.

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

Edit: Agora encontrei algumas perguntas relacionadas, nenhuma delas com uma resposta real que não seja "faça outra coisa":

Edit: esta resposta sobre a bifurcação dupla pode ter resolvido o meu problema, mas agora o meu próprio programa bifurca-se e funciona: /programming//a/9646251/898699

Barão Schwartz
fonte
Você está iniciando o programa com o utilitário "daemon" fornecido pelo libslack. libslack.org/daemon/#documentation Nesse caso, o programa pode ser parado como daemon -n name --stop. Além disso, tente redirecionar a saída (ao iniciar o programa) para um arquivo ou / dev / null e verifique.
Ankit
2
Dependendo da sua versão do redhat, você pode criar um invólucro simples para ele no inicio e chamá-lo diretamente no iniciante. Em seguida, o iniciante gerenciará o serviço para você. Isso é uma coisa do EL6.
Matthew Ife

Respostas:

1

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

daemon --user someproguser $exec &

Se someprognão funcionar SIGHUP, você deve executar o comando nohuppara garantir que seu processo não seja recebido, o SIGHUPque instrui o processo a sair quando o shell pai sair. Isso seria assim:

daemon --user someproguser "nohup $exec" &

Na sua stopfunção, killproc "exec"não está fazendo nada para interromper o seu programa. Deve ler-se assim:

killproc $exec

killprocrequer o caminho completo para o seu aplicativo para pará-lo corretamente. Eu tive alguns problemas killprocno passado, então você também pode matar o PID no PIDFILE no qual você deve escrever someprogo PID com algo assim:

cat $pidfile | xargs kill

Você pode escrever o PIDFILE assim:

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

para onde $pidfileaponta /var/run/someprog.pid.

Se você deseja [OK] ou [FAILED] em sua stopfunção, use as funções successe failurede /etc/rc.d/init.d/functions. Você não precisa disso na startfunção porque daemonchama o apropriado para você.

Você também só precisa de aspas em torno de strings com espaços. É uma escolha de estilo, porém, é com você.

Todas essas mudanças 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
Stuporman
fonte
Desculpe, demorou quase 4,5 anos para você obter uma resposta adequada.
Stuporman
-1

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

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

vagão
fonte
-1

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

Edit: aparentemente eu estou errado - bifurcação dupla iria funcionar. /programming//a/9646251/898699

Barão Schwartz
fonte
Você pode fazer isso usando o upstart, conforme indicado nos comentários.