init, telinit -
プロセス制御の初期化
/sbin/init [
-a ] [
-s ] [
-b ] [
-z xxx ]
[
0123456Ss ]
/sbin/telinit [
-t sec ] [
0123456sSQqabcUu ]
init
は全てのプロセスの親である。
その主な役割は、
/etc/inittab (
inittab(5) 参照)
ファイルに書かれたスクリプトに従ってプロセスを作り出すことにある。
通常このファイルには、ユーザがログイン可能な各接続ラインごとに
getty
を生成させるためのエントリが記されている。
また、特定のシステムが必要とする、自律的なプロセスの制御も行う。
ランレベル
とはシステムのソフトウェア的な設定で、
指定したプロセス群のみを存在させるようにするものである。
それぞれのランレベルで
init
が作り出すプロセスは
/etc/inittab
ファイルで定められている。
init は
0–6,
S,
s
という 8
つのランレベルのうちの一つを取ることができる。
ランレベルは特権ユーザが
telinit
を実行することによって変更される。
telinit は
init
に適切なシグナルを送り、
どのランレベルに変更すべきかを指示する。
ランレベル
0,
1,
6
は予約されている。
ランレベル 0
はシステムを停止するために、
ランレベル 6
はシステムをリブートするために、
ランレベル 1
はシステムをシングルユーザモードにするために用いられる。
ランレベル
S
は直接用いるためのものではなく、
ランレベル
1
になった時に実行されるスクリプトのために存在する。
この詳細は
shutdown(8)
および
inittab(5) 各 man
ページを参照のこと。
文書には書かれてはいないが、ランレベル
7-9 も使用できる。
文書に書かれていないのは、「伝統的な」
Unix
の派生種はランレベル
7-9
を使用していないからである。
参考のために言っておくと、実はランレベル
S と
s
も同様である。
内部的には、この 2
つは同一のランレベルのエイリアスになっている。
カーネルブートの最後のステップとして
init が起動されると、
init は
/etc/inittab
ファイルを検索し、
initdefault
というエントリが存在するか調べる
(
inittab(5) 参照)。
initdefault
はシステムが最初に取るべきランレベルを定義する。
/etc/inittab
ファイル中にそのようなエントリがない場合、
あるいは
/etc/inittab
ファイル自体が存在しない場合は、
システムコンソールからランレベルを入力しなければならない。
ランレベルを
S
または
s にすると、
システムはシングルユーザモードに入る。
この場合は
/etc/inittab
ファイルを必要としない。
シングルユーザモードでは、
/dev/console で
/sbin/sulogin
が起動される。
シングルユーザモードに入るとき、
init は
/etc/ioctl.save
からコンソールの
ioctl(2)
の状態を読み込む。
このファイルが存在しない場合は、
init
はコンソールの接続ラインを
9600 baud で
CLOCAL
という設定 (訳注:
ローカルに直接接続されている状態)
に初期化する。
シングルユーザモードを抜ける際には、
次回のシングルユーザモードセッションでも同じ設定を利用できるよう、
コンソールの
ioctl
の状態を
/etc/ioctl.save
ファイルに保存する。
初めてマルチユーザモードに入るとき、
init は
boot エントリと
bootwait
エントリを実行し、
ユーザがログイン可能となる前にファイルシステムをマウントできるようにする。
そして、ランレベルにマッチする全てのエントリを処理する。
新たなプロセスを起動するとき、
init はまず
/etc/initscript
ファイルが存在するかを調べ、
存在する場合はそのスクリプトを用いてプロセスを起動する。
子プロセスが終了するごとに、
init
はその旨と終了した理由とを、
/var/run/utmp と
/var/log/wtmp
とに記録する
(ただしこれらのファイルが存在する場合)。
指示された全てのプロセスを生成すると、
init は
子孫のプロセスが死ぬか、powerfail
シグナルが発せられるか、
telinit
からランレベルを変更せよとのシグナルが送られるまで待機する。
この 3
つのいずれかが起きた場合は、
init は
/etc/inittab
ファイルを再度調べる。
このファイルには、いつでも新たなエントリを追加できる。
しかし、上の 3
条件のどれかが起きるまでは、
init
は待機状態を続ける。
新たなエントリを即座に反映させるには、
telinit Q または
q
コマンドを用いて
init
を目覚めさせ、
/etc/inittab
ファイルを再度調べさせればよい。
シングルユーザモードにない時に
init が powerfail シグナル (SIGPWR)
を受け取ると、
init は
/etc/powerstatus
ファイルを読み込む。
そしてこのファイルの内容に基づいてコマンドを実行する。
- F(AIL)
- 電源供給が途絶え、UPS
が電源を供給している。
powerwait エントリと powerfail
エントリを実行する。
- O(K)
- 電源供給が回復している。powerokwait
エントリを実行する。
- L(OW)
- 電源供給が途絶え、UPS
のバッテリー容量が少なくなっている。
powerfailnow
エントリを実行する。
/etc/powerstatus
が存在しないか、その内容が
F,
O,
L
のいずれでもない場合、
init は
F
を読み込んだものとして動作する。
SIGPWR と
/etc/powerstatus
の利用は推奨されない。
init
と通信したい場合は、
制御チャネル
/dev/initctl
を使うべきである。
これに関する詳しい記述は、
sysvinit
パッケージのソースコードを参照すること。
init
は、ランレベルを変更するよう要請を受けると、
まず新たなランレベルでは定義されていない全てのプロセスに対して
警告シグナル
SIGTERM
を送る。 その後 5
秒間待機してから
SIGKILL
シグナルを送り、それらのプロセスを強制的に終了させる。
init は、
これら全てのプロセス
(およびそれらの子孫)
の属するプロセスグループが、
もともと
init
が彼らのために生成したものと同じであると仮定している。
あるプロセスが自分のプロセスグループ属性を変えてしまった場合は、
上記のシグナルを受け取らない。
したがって、そのようなプロセスは別の方法で終了させる必要がある。
/sbin/telinit は
/sbin/init
にリンクされている。
/sbin/telinit
は一文字の引数を受け取り、
init
にシグナルを送って適切な動作を行なわせる。
telinit への指示には、
以下に示すような引数が利用できる。
-
0,1,2,3,4,5,6
- 指定されたランレベルに変更するよう
init に伝える。
-
a,b,c
-
/etc/inittab
中で、ランレベル a,
b, c
のいずれかを含むエントリだけを実行するよう
init に伝える。
-
Q または q
-
/etc/inittab
ファイルを調べ直すよう
init に伝える。
-
S または s
- シングルユーザモードに切り替えるよう
init に伝える。
-
U または u
- (状態はそのままで)
自分自身を再実行するよう
init に伝える。 /etc/inittab
は調べ直さない。
ランレベルは Ss12345
のいずれかでなければならない。
それ以外の場合は、この要求は黙って無視される。
init がプロセスに TERM
シグナルを送ってから
KILL
シグナルを送るまでの時間を、
telinit
から指示することもできる。
デフォルトでは 5
秒に設定されているが、
-t sec
オプションで変更できる。
telinit
は適切な特権を持ったユーザのみが実行できる。
init
のバイナリは、自分の
プロセスID を見て、
自分が
init なのか
telinit
なのかを判断する。
本物の
init のプロセス
ID は常に
1 である。
よって、
telinit
を起動するかわりに
init
を起動しても構わない。
init
は子プロセスに以下のような環境変数を設定する:
- PATH
- /usr/local/sbin:/sbin:/bin:/usr/sbin:/usr/bin
- INIT_VERSION
- 名前の通り。
あるスクリプトが
init
により直接実行されたのかどうかを見分けるのに便利。
- RUNLEVEL
- システムの現在のランレベル。
- PREVLEVEL
- 直前のランレベル
(ランレベルを変更した場合に便利)。
- CONSOLE
- システムコンソール。これは実際はカーネルから継承したものである。
しかしこれが設定されていなかった場合は、
init はデフォルトで
/dev/console を設定する。
ブートモニタ (例えば LILO)
から
init
に様々なフラグを渡すことが可能である。
init
は以下のようなフラグを受け付ける:
- -s, S, single
- シングルユーザモードでブートする。
このモードでは
/etc/inittab を参照する。
またシングルユーザモードのシェルが起動される前に
ブートアップ rc
スクリプトが実行される。
- 1-5
- ブート時に入るべきランレベル。
- -b, emergency
- 他の起動用スクリプトは実行せず、
直接シングルユーザシェルへとブートする。
- -a, auto
- LILO
ブートローダは、
デフォルトのコマンドラインで
(ユーザの介入なしに)
カーネルを起動すると、
コマンドラインに単語
"auto" を追加する。
init
はこの単語を見つけると、"AUTOBOOT"
環境変数を "yes"
に設定する。
ただしこの機能をセキュリティの判断には使えない。
あたりまえだが、
ユーザーは "auto" や -a
を手動でコマンドラインに追加することもできる。
- -z xxx
- -z
の引数は無視される。
これを使うとコマンドラインが少し長くなるので、
そのためにスタックを若干余分に使用するようになる。
すると init
にコマンドラインを操作し、
ps(1)
に現在のランレベルを表示させるようにできる。
init
はメッセージのやりとりのために、
/dev にある FIFO である
/dev/initctl を listen している。
telinit はこれを用いて init
と通信する。
このインターフェースは十分に文書化されていない。
興味を持った人は、
init のソース tar
アーカイブの
src/
サブディレクトリにある
initreq.h
を調べてほしい。
init
はいくつかのシグナルに反応する。
- SIGHUP
- init は /etc/initrunlvl と
/var/log/initrunlvl を探す。
もしこれらのどちらかのファイルがあり、
ランレベルが ASCII
コードで書かれていたら、
init
はそのランレベルに切り替わる。
これは過去との互換性のためだけに存在する!
通常の場合
(これらのファイルがない場合)、
init は telinit q
が実行されたときと同じ動作をする。
- SIGUSR1
- このシグナルを受け取ると、init
は制御用 FIFO である
/dev/initctl
を一旦クローズして再オープンする。
ブートスクリプトが
/dev
を再マウントした時に便利である。
- SIGINT
- 通常、カーネルは
CTRL-ALT-DEL
が押されるとこのシグナルを
init に送る。
これにより ctrlaltdel
アクションが実行される。
- SIGWINCH
- カーネルは
KeyboardSignal
キーが押されるとこのシグナルを送る。
これにより kbrequest
アクションが実行される。
init は System V の init
と互換である。
init は
/etc/init.d ディレクトリや
/etc/rc{runlevel}.d
ディレクトリのスクリプトと密接に連係しながら動作する。
あなたのシステムがこの規則に従っているなら、
/etc/init.d ディレクトリに
README があり、
スクリプトがどのように動作するかが説明されているはずである。
/etc/inittab
/etc/initscript
/dev/console
/etc/ioctl.save
/var/run/utmp
/var/log/wtmp
/dev/initctl
init は、
生成したプロセスとその子孫とが、
それらのために作ったプロセスグループに留まっていると仮定している。
プロセスグループが元々のものと変わっている場合は、
init はそのプロセスを
kill できないので、
異なる二つのプロセスが同一の端末ラインから入力を読み込む、
といった現象が起きてしまう可能性がある。
init
は、あるエントリが 2
分間に 10
回以上繰り返して再生成されるのを発見すると、
コマンド文字列に誤りがあるとみなし、
システムコンソールにエラーメッセージを表示し、
5
分以上経過するかシグナルを受け取るまで、
それ以上そのエントリの再生成を拒否する。
こうすることによって、
/etc/inittab
中に書き間違いがあったり、
そのエントリで使用するプログラムが削除されている場合に、
システム資源を使い尽くしてしまうことを防いでいる。
Miquel van Smoorenburg (
[email protected])。 もとの man
ページは Michael Haardt
(
[email protected]) による。
getty(1),
login(1),
sh(1),
runlevel(8),
shutdown(8),
kill(1),
inittab(5),
initscript(5),
utmp(5)