いつもそれっぽく適当に書いていたinitスクリプト。
いい加減ちゃんと書いてみようと思い Linux Standard Base の VIII. System Initialization あたりを見ながら書いてみた。
でもAmazon Linuxでしか確認していない。
initスクリプト例
全体はこんな感じ。
20.8. Init Script Functions というのもあって、ある程度それに沿って実装されたのが /etc/init.d/functions
かと思われるのでそれを使っている
#! /bin/sh
### BEGIN INIT INFO
# Provides: myapp
# Required-Start: $local_fs $network $remote_fs
# Should-Start: $time
# Required-Stop: $local_fs $network $remote_fs
# Should-Stop:
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Short-Description: start and stop MyApp
# Description: MyApp is a very fast and reliable application
# used for illustrating init scripts
### END INIT INFO
. /etc/rc.d/init.d/functions
prog="myapp"
user="myusr"
cmd="/opt/$prog/ctrl.sh"
pid_file="/var/run/$prog/$prog.pid"
lock_file="/var/lock/subsys/$prog"
kill_delay=5
function start() {
daemon --check $prog --pidfile $pid_file --user $user $cmd start
RETVAL=$?
[ $RETVAL -eq 0 ] && touch $lock_file
}
function stop() {
killproc -p $pid_file -d $kill_delay $prog
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f $lock_file
}
function call() {
$cmd $1
RETVAL=$?
}
function p_status() {
status $prog
return $?
}
RETVAL=0
case "$1" in
start)
echo -n $"Starting $prog: "
start
echo
;;
stop)
echo -n $"Stopping $prog: "
stop
echo
;;
restart|try-restart)
echo -n $"Restarting $prog: "
p_status > /dev/null 2>&1
if [ $? -eq 0 ]; then
call restart
elif [ "$1" = "restart" ]; then
call start
else
[ -z $LSB ] && RETVAL=0 || RETVAL=7 # Program is not running
fi
[ $RETVAL -eq 0 ] && success || failure
echo
;;
reload|force-reload)
echo -n $"Reloading $prog: "
call reload
[ $RETVAL -eq 0 ] && success || failure
echo
;;
status)
p_status
RETVAL=$?
;;
*)
RETVAL=2 # Invalid or excess argument(s)
;;
esac
exit $RETVAL
冒頭のコメント
### BEGIN INIT INFO
# Provides: myapp
# Required-Start: $local_fs $network $remote_fs
# Should-Start: $time
# Required-Stop: $local_fs $network $remote_fs
# Should-Stop:
# Default-Start: 3 4 5
# Default-Stop: 0 1 2 6
# Short-Description: start and stop MyApp
# Description: MyApp is a very fast and reliable application
# used for illustrating init scripts
### END INIT INFO
-
20.3. Comment Conventions for Init Scripts を見ながら設定した。
-
20.5. Run Levels や 20.6. Facility Names (
$local_fs
,$network
など)の説明も書いてあるので読んでみるといいかも。 -
chkconfig 専用の書き方があるけど、このLSB形式のコメントも理解してくれる。
-
プライオリティは指定できない。代わりにRequired-Start|Stopに他のファシリティを書く。
例えば ntpd が S58 の場合 Required-Start に ntpd を指定すれば S59 に起動するようになる。
指定するファシリティ名はそのサービスの Provides によって決まる。
Required-Start: $local_fs $network $remote_fs ntpd
$LSB変数
LSB=1
-
Amazon Linuxの
/etc/rc.d/init.d/functions
を見ていると $LSB によって多少動きが変わるようだ。
[OK] [FAILED] などが表示されなくなったり killproc が 7 (Program is not running)を返す場合があったり。 -
まぁいいかな、と思ったのでここでは指定しないことにした。
メッセージ
echo -n $"Starting $prog: " # $prog を起動中:
echo -n $"Stopping $prog: " # $prog を停止中:
echo -n $"Restarting $prog: " # $prog を再起動中:
echo -n $"Reloading $prog: " # $prog を再読み込み中:
- 上記のようにしとくとロケールごとのメッセージで表示される。コメント部分は日本語の場合。
起動処理
daemon --check $prog --pidfile $pid_file --user $user $cmd start
-
daemon 関数で起動する。
-
--checkオプションを使うとPIDのチェックや表示でその値が使われる。
指定しないと $cmd から取得する。 -
--userオプション付きだと
runuser
コマンドで起動する。
自動起動でも limits.conf あたりの設定が効く。
/etc/pam.d/runuser
を見ると pam_limits.so を実行するようになっているからかな。 -
デフォルトで
/var/run/$prog.pid
をPIDファイルとして使う。
また、PIDファイルを使ってプロセスの起動チェックをしているので二重起動を防止してくれる。
停止処理
killproc -p $pid_file -d $kill_delay $prog
-
killproc 関数で停止する。
-
killレベルを指定しないので TERM → (待機) → KILL の順にシグナルが発行される。
-d オプションを指定することで待機時間を秒数で指定できる。 -
daemon 関数と同じくデフォルトで
/var/run/$prog.pid
をPIDファイルとして使う。 -
killレベルを指定しないとPIDファイルを消してくれる。
指定すると消してくれない。なぜ。
再起動処理
p_status > /dev/null 2>&1
if [ $? -eq 0 ]; then
call restart
elif [ "$1" = "restart" ]; then
call start
else
[ -z $LSB ] && RETVAL=0 || RETVAL=7 # Program is not running
fi
-
restart と try-restart の違いは、起動していなかった場合の挙動。
restart は起動してたら再起動、起動してなかったら起動する。
try-restart は起動してたら再起動、起動してなかったら何もしない。 -
try-restart で起動してなかった場合 $LSB がセットしてあったら 20.2. Init Script Actions にあるように 7 を返すようにした。
再読み込み処理
-
ここでは再読み込み処理が実装済みという前提。
-
reload と force-reload の違いは、再読み込み処理が未実装の場合の挙動。
reload は実装してあれば reload 、未実装ならエラー。
force-reload は実装してあれば reload 、未実装かつ起動していれば restart する。 -
reload が未実装の場合はこんな感じ?
reload)
echo -n $"Reloading $prog: "
RETVAL=3 # Unimplemented feature
failure
echo
;;
force-reload)
echo -n $"Reloading $prog: "
p_status > /dev/null 2>&1
if [ $? -eq 0 ]; then
call restart
elif [ -z $LSB ]
RETVAL=0
else
RETVAL=7 # Program is not running
fi
[ $RETVAL -eq 0 ] && success || failure
echo
;;