web-dev-qa-db-ja.com

initスクリプトから任意のプログラムをデーモンとして実行する

Red Hatでプログラムをサービスとしてインストールする必要があります。自身の背景、PIDファイルの管理、独自のログの管理は行いません。実行され、STDOUTおよびSTDERRに出力されます。

ガイドとして標準のinitスクリプトを使用して、以下を開発しました。

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

/etc/init.dにある既存のスクリプトの一部をコピーして貼り付け、修正するのが私の間違いだったのかもしれません。いずれにしても、結果のサービスは奇妙な動作をします:

  • service someprog startで開始すると、プログラムがターミナルに出力され、コマンドが完了しません。
  • cTRL-Cを押すと、「セッションが終了し、シェルを強制終了しています... ...強制終了しました。失敗しました」と出力されます。シェルプロンプトを再び表示するには、これを行う必要があります。
  • service someprog statusを実行すると、実行中と表示され、そのPIDが一覧表示されます。 psで確認できるので、実行中です。
  • service someprog stopを実行すると停止しません。 psを使用して、まだ実行中であることを確認できます。

someprogがバックグラウンドに送信され、サービスとして管理されるようにするには、何を変更する必要がありますか?

編集:私は今、いくつかの関連する質問を見つけましたが、どちらも「他のことをする」以外の実際の答えはありません:

編集:ダブルフォークに関するこの答えは私の問題を解決したかもしれませんが、今私のプログラム自体はダブルフォークであり、それは機能します: https://stackoverflow.com/a/9646251/898699

10
Baron Schwartz

daemon関数はアプリケーションをバックグラウンドで実行しないため、コマンドは「完了しません」。次のように、daemonコマンドの最後に&を追加する必要があります。

daemon --user someproguser $exec &

someprogSIGHUPを処理しない場合は、Nohupを指定してコマンドを実行し、プロセスがSIGHUPを受信しないようにする必要があります。親シェルが終了すると終了します。これは次のようになります。

daemon --user someproguser "Nohup $exec" &

stop関数では、killproc "exec"はプログラムを停止するために何も実行していません。それはそう読むべきです:

killproc $exec

killprocを正しく停止するには、アプリケーションへのフルパスが必要です。過去にkillprocで問題が発生したため、someprogのPIDを書き込むPIDFILEのPIDを次のように削除することもできます。

cat $pidfile | xargs kill

次のようにPIDFILEを書き込むことができます。

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

ここで、$pidfile/var/run/someprog.pidを指します。

stop関数で[OK]または[FAILED]が必要な場合は、/etc/rc.d/init.d/functionssuccessおよびfailure関数を使用する必要があります。 startは適切なものを呼び出すため、daemon関数ではこれらは必要ありません。

スペースを含む文字列を囲む引用符も必要です。それはスタイルの選択ですが、それはあなた次第です。

これらの変更はすべて次のようになります。

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