読者です 読者をやめる 読者になる 読者になる

起動スクリプト(httpd)を読んでみた

サーバ Linux Apache

シェルスクリプトの勉強がてら/etc/init.d/httpdを読んでみました。

. /etc/rc.d/init.d/functions

if [ -f /etc/sysconfig/httpd ]; then
        . /etc/sysconfig/httpd
fi

この部分で別の関数などを定義したファイルをインクルードしています。
正確には.コマンドは実行中のシェルと同じシェルで実行するというコマンドなので実行された段階で読み込まれ、他の言語で言うところのインクルードされたようにみえています。
読み込んでいる/etc/rc.d/init.d/functionsはinit.dでつかう汎用的な関数をまとめたものです。
また、/etc/sysconfig/httpdhttpdを制御するための定数を定義したファイルとなっています。(デフォルトではすべてコメントアウトされていました。)
if文ではこのファイルがあるかどうかを-f演算子でチェックし、存在すれば読み込むという処理をしています。

HTTPD_LANG=${HTTPD_LANG-"C"}

ここでは言語の設定をしています。${HTTPD_LANG-"C"}の部分はHTTPD_LANGが定義されていればその値を
されていなければ"C"を返します。
それをHTTPD_LANGに代入することでデフォルトで"C"で設定ファイルで設定されていればそっちを優先するということをしています。

INITLOG_ARGS=""

これはコメントによるとmod_sslを使う際にパスフレーズが要求されたのがlogに残るのを防ぐために設定するようです(英語自信ない...)
ただinitlogが非推奨になっていて使われていないようなのであまり関係ない部分な気がしました。

apachectl=/usr/sbin/apachectl
httpd=${HTTPD-/usr/sbin/httpd}
prog=httpd
pidfile=${PIDFILE-/var/run/httpd/httpd.pid}
lockfile=${LOCKFILE-/var/lock/subsys/httpd}
RETVAL=0
STOP_TIMEOUT=${STOP_TIMEOUT-10}

先ほどと同じようにディレクトリやファイル、タイムアウト時間などデフォルトの設定を設定しています。
これも設定ファイルで設定されていればそちらを優先します。

次にstart,stop,reroadという起動スクリプトの根幹部分の関数定義が来ます。

start() {
        echo -n $"Starting $prog: "
        LANG=$HTTPD_LANG daemon --pidfile=${pidfile} $httpd $OPTIONS
        RETVAL=$?
        echo
        [ $RETVAL = 0 ] && touch ${lockfile}
        return $RETVAL
}

start関数は名前の通り起動処理をします。

echo -n $"Starting $prog: "

echoの-nオプションは最後の改行を出力しないというオプションです。
また$""という形式になっていますがこれはこの部分が翻訳対象であることを明示しています。
翻訳データ自体は/etc/rc.d/init.d/functionのTEXTDOMAINでよみこみ先が指定されています。

LANG=$HTTPD_LANG daemon --pidfile=${pidfile} $httpd $OPTIONS
RETVAL=$?

ではhttpd本体をdaemon関数(/etc/rc.d/init.d/function)を用いてデーモンとして起動しています。
また、--pidfileオプションでPIDファイルの出力先を決めています。また最初のLANGの部分でhttpdを起動する言語を指定しています。
またRETVALはreturn valueの略語のようでそのとおり$?で前のコマンドの終了コードを代入しています。

echo
[ $RETVAL = 0 ] && touch ${lockfile}

つぎにechoで改行を入れ、そのあとの部分でRETVALが0ならばロックファイルを生成する(orタイムスタンプを更新)という処理をしています。
ロックファイルは起動スクリプト内のどこにも存在をチェックしている部分がないのでおそらくhttpd内部で処理をしている気がします。

stop() {
        echo -n $"Stopping $prog: "
        killproc -p ${pidfile} -d ${STOP_TIMEOUT} $httpd
        RETVAL=$?
        echo
        [ $RETVAL = 0 ] && rm -f ${lockfile} ${pidfile}
}

次はhttpdを停止するstop関数です。
基本的な流れとしてはstopしていることを表示し、killprocによってプロセスを殺します。
そして正常に殺せた場合はlockfileとpidfileを削除します。

reload() {
    echo -n $"Reloading $prog: "
    if ! LANG=$HTTPD_LANG $httpd $OPTIONS -t >&/dev/null; then
        RETVAL=6
        echo $"not reloading due to configuration syntax error"
        failure $"not reloading $httpd due to configuration syntax error"
    else
        # Force LSB behaviour from killproc
        LSB=1 killproc -p ${pidfile} $httpd -HUP
        RETVAL=$?
        if [ $RETVAL -eq 7 ]; then
            failure $"httpd shutdown"
        fi
    fi
    echo
}

つぎは設定ファイルを読み込むreload関数です。

if ! LANG=$HTTPD_LANG $httpd $OPTIONS -t >&/dev/null; then

の部分ではhttpdを-tオプションをつけ実行して結果を捨てています。

  • tオプションをつけると文法チェックをしてくれるのでこのif文では

文法エラーがあったらthenの部分を実行します(!で結果を反転させているため)

RETVAL=6
echo $"not reloading due to configuration syntax error"
failure $"not reloading $httpd due to configuration syntax error"

の部分を実行します。この部分では返り値を6とし文法エラーがある旨を出力します。
文法エラーがなかった場合

LSB=1 killproc -p ${pidfile} $httpd -HUP
RETVAL=$?
if [ $RETVAL -eq 7 ]; then
    failure $"httpd shutdown"

の部分でkillprocによりhttpdにHUPシグナル(子プロセスは殺すが、親プロセスは殺さない)が送られます。
そしてその結果を見て成功かどうかを表示します。

関数の定義が終わると引数によるパターンマッチを行なって適切な関数へのディスパッチをおこなう処理に入ります。

case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  status)
        status -p ${pidfile} $httpd
        RETVAL=$?
        ;;
  restart)
        stop
        start
        ;;
  condrestart|try-restart)
        if status -p ${pidfile} $httpd >&/dev/null; then
                stop
                start
        fi
        ;;
  force-reload|reload)
        reload
        ;;
  graceful|help|configtest|fullstatus)
        $apachectl $@
        RETVAL=$?
        ;;
  *)
        echo $"Usage: $prog {start|stop|restart|condrestart|try-restart|force-reload|reload|status|fullstatus|graceful|help|configtest}"
        RETVAL=2
esac

第一引数でパターンマッチを行なっています。start,restart,reload(force-reload)は基本的に先ほど定義した関数を組み合わせているだけです。
condrestartはプログラムが実行中であるかどうかを判定して実行中である場合のみ再起動、gracefulはapachectlに丸投げしています。
また、それ以外の場合はマッチするものがなかった旨を表示します。

最後に

exit $RETVAL

として終了します。

bashはすごく奥が深そうです...