Linuxでシャットダウン時に想定した処理が実行されない

シャットダウン時にhogeというスクリプトを実行したくて

+ /etc/init.d/hoge
+ /etc/rc0.d/K99hoge
+ /etc/rc1.d/K99hoge
+ /etc/rc6.d/K99hoge

と配置したのに実行されてなかったので調査した時のメモ

# 結論

`/var/lock/subdys/`配下に

+ hoge
+ hoge.init

がなかったので。

# 参考

+ [/var/lock/subsys/について](http://blog.kenjiskywalker.org/blog/2014/02/24/var-lock-subsys/)
+ [（今さら）Linuxでサービスを登録する](http://d.hatena.ne.jp/higher_tomorrow/20110421/1303337554)

# そもそも/etc/rc0.d/とかって何か？

/etc/rc0.d/とかの数字の部分はランレベルを示します。
それぞれのランレベルは以下のとおり。

| ランレベル | 概要 | 
|:-----------:|:------------|
| 0      | システムの停止 |
| 1     | シングルユーザーモード |
| 2       |マルチユーザーモード（NFSなし）|
| 3         |マルチユーザーモード（テキストログイン）|
| 4       |未使用|
| 5    |マルチユーザーモード（グラフィカルログイン）|
| 6    |システムの再起動|

上記より、終了したいスクリプトはランレベル0とランレベル6の時に実行されるように設定がきればOKです。あとランレベル1の時のシングルユーザーモードでは必要最小限のサービスだけにする必要があるので、マルチユーザーモードで動いているサービスを明示的に止めるため場合にはランレベル1の時に明示的に停止させるように設定する必要があります。

# スクリプトの前のKとかSって何か？

```lang:/etc/rc.d/rc
#! /bin/bash
#
# rc            This file is responsible for starting/stopping
#               services when the runlevel changes.
#
# Original Author:
#               Miquel van Smoorenburg, <miquels@drinkel.nl.mugnet.org>
#
... 

# First, run the KILL scripts.
for i in /etc/rc$runlevel.d/K* ; do

        # 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
        check_runlevel "$i" || continue

        # Bring the subsystem down.
        [ -n "$UPSTART" ] && initctl emit --quiet stopping JOB=$subsys
        $i stop
        [ -n "$UPSTART" ] && initctl emit --quiet stopped JOB=$subsys
done

# Now run the START scripts.
for i in /etc/rc$runlevel.d/S* ; do

        # Check if the subsystem is already up.
        subsys=${i#/etc/rc$runlevel.d/S??}
        [ -f /var/lock/subsys/$subsys ] && continue
        [ -f /var/lock/subsys/$subsys.init ] && continue
        check_runlevel "$i" || continue

        # If we're in confirmation mode, get user confirmation
        if [ "$do_confirm" = "yes" ]; then
                confirm $subsys
                rc=$?
                if [ "$rc" = "1" ]; then
                        continue
                elif [ "$rc" = "2" ]; then
                        do_confirm="no"
                fi
        fi

        update_boot_stage "$subsys"
        # Bring the subsystem up.
        [ -n "$UPSTART" ] && initctl emit --quiet starting JOB=$subsys
        if [ "$subsys" = "halt" -o "$subsys" = "reboot" ]; then
                export LC_ALL=C
                exec $i start
        fi
        $i start
        [ -n "$UPSTART" ] && initctl emit --quiet started JOB=$subsys
done
[ "$do_confirm" = "yes" ] && rm -f /var/run/confirm
exit 0
```

ということでランレベルが変わる時に

+ /etc/rcランレベル/K数字となっているスクリプトが数字が若い順に第一引数`stop`で実行される
+ 次に/etc/rcランレベル/K数字となっているスクリプトが数字が若い順に第一引数`start`で実行される

ということが分かります。なので、例えばランレベル3とかにK01hogeとS01fugaというスクリプトを置くことも出来て、その場合、K01hogeの方が先に実行される

# /var/lock/subdys/?

上記スクリプトの中で` [ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] || continue`という部分があり、ファイルがないとそもそもKスクリプトは実行されないことになっています

なので終了したいスクリプトの引数がstartで呼び出された時にはtouchコマンドを作って`/var/lock/subdys/hoge`か`/var/lock/subdys/hoge.init`というファイルを作成する必要があります

```lang:hoge
!/bin/sh

lock_file="/var/lock/subsys/hoge"

start()
{
    touch ${lock_file}

    # 何か

}

stop()
{
    rm -r ${lock_file}

    # 何か
}

case "$1" in
    start)
        start
    ;;
    stop)
        stop
    ;;
    *)
        echo "Usage: $0 {start|stop}"
    ;;
esac

exit 0
```