名前

init, telinit - プロセス制御の初期化

書式

/sbin/init [ -a ] [ -s ] [ -b ] [ -z xxx ] [ 0123456Ss ]
 
/sbin/telinit [ -t sec ] [ 0123456sSQqabcUu ]

説明

init は全てのプロセスの親である。 その主な役割は、 /etc/inittab ( inittab(5) 参照) ファイルに書かれたスクリプトに従ってプロセスを作り出すことにある。 通常このファイルには、ユーザがログイン可能な各接続ラインごとに getty を生成させるためのエントリが記されている。 また、特定のシステムが必要とする、自律的なプロセスの制御も行う。

ランレベル

ランレベル とはシステムのソフトウェア的な設定で、 指定したプロセス群のみを存在させるようにするものである。 それぞれのランレベルで init が作り出すプロセスは /etc/inittab ファイルで定められている。 init0–6, S, s という 8 つのランレベルのうちの一つを取ることができる。 ランレベルは特権ユーザが telinit を実行することによって変更される。 telinitinit に適切なシグナルを送り、 どのランレベルに変更すべきかを指示する。
ランレベル 0, 1, 6 は予約されている。 ランレベル 0 はシステムを停止するために、 ランレベル 6 はシステムをリブートするために、 ランレベル 1 はシステムをシングルユーザモードにするために用いられる。 ランレベル S は直接用いるためのものではなく、 ランレベル 1 になった時に実行されるスクリプトのために存在する。 この詳細は shutdown(8) および inittab(5) 各 man ページを参照のこと。
文書には書かれてはいないが、ランレベル 7-9 も使用できる。 文書に書かれていないのは、「伝統的な」 Unix の派生種はランレベル 7-9 を使用していないからである。 参考のために言っておくと、実はランレベル Ss も同様である。 内部的には、この 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 baudCLOCAL という設定 (訳注: ローカルに直接接続されている状態) に初期化する。 シングルユーザモードを抜ける際には、 次回のシングルユーザモードセッションでも同じ設定を利用できるよう、 コンソールの ioctl の状態を /etc/ioctl.save ファイルに保存する。
初めてマルチユーザモードに入るとき、 initboot エントリと 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 が彼らのために生成したものと同じであると仮定している。 あるプロセスが自分のプロセスグループ属性を変えてしまった場合は、 上記のシグナルを受け取らない。 したがって、そのようなプロセスは別の方法で終了させる必要がある。

telinit

/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)

Recommended readings

Pages related to telinit you should read also: