RedHat のプロセスの停止処理がおかしいというので init
スクリプト周りを眺めていたら、どういうわけか /var/lock/subsys/
ディレクトリ以下を操作していた。
/var/lock/subsys/
以下のファイルを何に使っているのかわからなかったので、ちょっと調べてみた。
結果的に言えば↓の RedHat Magazine の記事にかいてあることを確認しただけ。
RedHat Magazines Issue #8 June 2005
Why do init scripts require lock files?
by Bradford Hinson
http://www.redhat.com/magazine/008jun05/departments/tips_tricks/
/var/lock/subsys/ が作成されるタイミング
CentOS(RedHat) の /etc/init.d/crond
を例に取るとだいたい以下のようになっており、プロセスの起動が成功すると /var/lock/subsys/crond
を作成し、プロセスの終了が成功すると /var/lock/subsys/crond
を削除し、一種のロックファイルとして存在している。
# excerpt from /etc/init.d/crond start() { echo -n $"Starting $prog: " if [ -e /var/lock/subsys/crond ]; then if [ -e /var/run/crond.pid ] && [ -e /proc/`cat /var/run/crond.pid` ]; then echo -n $"cannot start crond: crond is already running."; failure $"cannot start crond: crond already running."; echo return 1 fi fi daemon crond $CRONDARGS RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/crond; return $RETVAL } stop() { echo -n $"Stopping $prog: " if [ ! -e /var/lock/subsys/crond ]; then echo -n $"cannot stop crond: crond is not running." failure $"cannot stop crond: crond is not running." echo return 1; fi killproc crond RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/crond; return $RETVAL } rhstatus() { status crond } ... case "$1" in start) start ;; stop) stop ;; ... status) rhstatus ;; condrestart) [ -f /var/lock/subsys/crond ] && restart || : ;; *) echo $"Usage: $0 {start|stop|status|reload|restart|condrestart}" exit 1 esac
/var/lock/subsys/ の用途
気になるのは作成された /var/lock/subsys/
以下のファイルがいつ何のために使われるのか?
ざっと、以下の様な用途で使われている
- プログラムのステータスチェック
- ランレベル変更時のプログラム再起動
- サーバ再起動/シャットダウン時のプログラム終了
順に確認
#1:プログラムのステータスチェック
$ sudo /sbin/service initスクリプト名 status
で、プログラムのステータスを確認できる。
この時、以下の順でプログラムのステータスを確認している。
1 プログラム名から PID を取得し、成功すれば running 扱い
$ sudo /sbin/service crond status crond (pid 11672) is running...
PID の取得には
pid=`pidof -o $$ -o $PPID -o %PPID -x $1 || \ pidof -o $$ -o $PPID -o %PPID -x ${base}`
というようなことをやっている
2 pid ファイルが存在すれば、異常終了扱い
$ sudo /sbin/service crond status crond dead but pid file exists
3 subsys ファイルが存在すれば、異常終了扱い
$ sudo /sbin/service crond status crond dead but subsys locked
4 #1-#3 いずれも見たなされけば、停止状態
$ sudo /etc/init.d/crond status crond is stopped
#3 で subsys 以下のファイルを利用している。
#2:ランレベル変更時のプログラム再起動
ランレベルを変更した時、新しいランレベルに合わせてプログラムを停止/起動する。この動処理は "/etc/rc.d/rc"
で行なっている。
起動されるのは /etc/rc{変更後のランレベル}/S で始まるファイルのうち、subsys ディレクトリにファイルが存在しないプログラム。停止されるのは /etc/rc{変更後のランレベル}/K で始まるファイルのうち、 subsys ディレクトリにファイルが存在するプログラム。
実際にコードを見てみると
# excerpt from /etc/rc.d/rc ... # First, run the KILL scripts. for i in /etc/rc$runlevel.d/K* ; do check_runlevel "$i" || continue # Check if the subsystem is already up. subsys=${i#/etc/rc$runlevel.d/K??} [ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] \ || continue # Bring the subsystem down. if egrep -q "(killproc |action )" $i ; then $i stop else action $"Stopping $subsys: " $i stop fi done # Now run the START scripts. for i in /etc/rc$runlevel.d/S* ; do check_runlevel "$i" || continue # Check if the subsystem is already up. subsys=${i#/etc/rc$runlevel.d/S??} [ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] \ && continue # If we're in confirmation mode, get user confirmation if [ -f /var/run/confirm ]; then confirm $subsys test $? = 1 && continue fi update_boot_stage "$subsys" # Bring the subsystem up. if [ "$subsys" = "halt" -o "$subsys" = "reboot" ]; then export LC_ALL=C exec $i start fi if egrep -q "(daemon |action |success |failure )" $i 2>/dev/null \ || [ "$subsys" = "single" -o "$subsys" = "local" ]; then $i start else action $"Starting $subsys: " $i start fi done ...
■実際の動作を確認
・kill/start対象のプログラムを確認
ランレベル5で kill/start 対象のプログラムを確認
$ ls /etc/rc.d/rc5.d/ | egrep '(cron|ntp)' K74ntpd S90crond S95anacron
ntpd は kill 対象、crond は start 対象。
ランレベルを 5 に変更した時、ntpd に subsys ファイルがあれば kill され、subsys ファイルがなければ crond が start されるはず。
・プログラムの起動を確認
$ sudo /etc/init.d/ntpd status ntpd (pid 26633) is running... $ sudo /etc/init.d/crond status crond is stopped
・subsys ファイルを操作
subsys ファイルを操作して /etc/rc の管理対象外にする
$ sudo rm /var/lock/subsys/ntpd $ sudo touch /var/lock/subsys/crond
・ランレベルを変更
$ sudo /sbin/init 5 $ who -r # /sbin/runlevel でも OK run-level 5 May 29 22:26 last=3
ランレベルが3から5に変わっている。
・プロセスを確認
$ ps aux | egrep '(cron|ntp)' ntp 26633 0.0 0.2 5764 5760 ? SLs 13:42 0:00 ntpd -u ntp:ntp -p /var/run/ntpd.pid -g abcd 26935 0.0 0.0 4740 636 pts/2 R+ 13:45 0:00 egrep (cron|ntp)
ntpd は起動したままで、crond も起動していない。
・subsys ファイルを操作
subsys ファイルを再度操作して、 /etc/rc の管理対象にする
$ sudo touch /var/lock/subsys/ntpd $ sudo unlink /var/lock/subsys/crond
・ランレベルを変更
$ sudo /sbin/init 3
ランレベルが5から3に変更。
・プロセスを確認
$ ps aux | egrep '(cron|ntp)' root 27431 0.0 0.0 5660 1036 ? Ss 13:48 0:00 crond abcd 27951 0.0 0.0 4212 636 pts/2 R+ 13:49 0:00 egrep (cron|ntp) $ tail /var/log/messages May 29 22:52:20 hogehoge init: Switching to runlevel: 5 ... May 29 22:52:20 hogehoge ntpd[26633 ]: ntpd exiting on signal 15 May 29 22:52:20 hogehoge ntpd: ntpd shutdown succeeded ... May 29 22:52:20 hogehoge crond: crond startup succeeded
ntpd は終了し、crond は起動している
#3:サーバ再起動・シャットダウン時のプログラム終了
シャットダウンがかかると、次の順で成功するまでエスカレートしてプログラムを終了させる(参照)
- 各サービスに対して
service stop
を実行 kill -SIGTERM
を実行- 5秒まつ
kill -SIGKILL
を実行
#1 の箇所では killall が呼ばれる。このプログラムは /var/lock/subsys
以下にあるファイルをチェックし、対応する init
スクリプトの stop
を呼び出す(プログラムの先頭コメントにあるように、各 daemon プログラムを終了させる sanity check として実行)
# excerpt from /etc/init.d/killall #! /bin/bash # Bring down all unneeded services that are still running (there shouldn't # be any, so this is just a sanity check) case "$1" in *start) ;; *) echo $"Usage: $0 {start}" exit 1 ;; esac for i in /var/lock/subsys/* ; do # Check if the script is there. [ -f "$i" ] || continue # Get the subsystem name. subsys=${i#/var/lock/subsys/} # Networking could be needed for NFS root. [ $subsys = network ] && continue # Bring the subsystem down. if [ -f /etc/init.d/$subsys.init ]; then /etc/init.d/$subsys.init stop elif [ -f /etc/init.d/$subsys ]; then /etc/init.d/$subsys stop else rm -f "$i" fi done
References
- RedHat Magazines Issue #8 June 2005 Why do init scripts require lock files?
http://www.redhat.com/magazine/008jun05/departments/tips_tricks/
- DeveloperWorks : Learn Linux, 101: Runlevels, shutdown, and reboot “Clean Shutdown”
http://www.ibm.com/developerworks/library/l-lpic1-v3-101-3/