カーネルが呼び出されてからログインプロンプトが表示されるまでの間に、一体どのような処理が行われているのか。これを理解するには、この部分の全般をつかさどるinitとその設定ファイルであるinittabがカギとなる。
Linuxが起動するまでの流れや、起動に際して使用されるファイルについて知っておくことは有益でしょう。そこで、今回と次回の2回に分けて、Linuxの起動の仕組みを紹介します。説明の都合上、用語の説明が多少前後するところもありますがご了承ください。
まず、Linuxが起動するまでの大まかな流れを概観しておきましょう。
マシンの電源をオンにすると、BIOSが起動して制御をハードディスクのMBRなどに移管します。Linuxの場合、MBRに書き込まれているブートローダ(LILOやGRUB)を起動し、このブートローダからカーネルを呼び出すのが一般的です。今回、BIOSからカーネルの起動までには深入りしません。とにかく、何らかの方法でカーネルが動き出した後からを追うことにします。
カーネルが起動された後の流れを挙げると、
といった処理が行われています。
これは、カーネルに組み込まれた、あるいはモジュールとしてロードしたデバイスドライバを使って行います。各種デバイスの中には、電源投入直後の動作が不定と決まっているものがあります。いずれにしても、実際に利用する方法に合うように設定を変えなければなりません。例えば、シリアルポートなら通信速度、画面ならば表示モードといった部分です。
Linux上のプログラムとして最初に実行されるのは、initプログラムです(編注)。initプロセスは、psコマンドで必ずPIDが「1」と表示されます。
$ ps ax PID TTY STAT TIME COMMAND 1 ? S 0:04 init 2 ? SW 0:00 [keventd] (中略) 493 ? S 0:00 /sbin/dhcpcd -n eth0 580 ? S 0:00 syslogd -m 0 (中略) 890 ? S 0:00 crond 954 ? S 0:00 xfs -droppriv -daemon 1103 tty2 S 0:00 /sbin/mingetty tty2 (中略) 21157 ? S 0:00 smbd -D 21162 ? S 0:01 nmbd -D (中略) 32610 ? S 0:00 /usr/sbin/sshd 32611 pts/0 S 0:00 -bash 32646 pts/0 R 0:00 ps ax
Linux上で動くすべてのプログラムは、このinitプログラムから実行されます。ユーザーが実行するプログラムはシェルから実行されますが、そのシェルも元をたどればinitから実行されたプログラムです。そのため、親子関係になぞらえて「initはすべてのプロセスの親である」と表現したりします。
デーモンといっても、悪魔(demon)ではなく守護神(daemon)なので、本当は「ダイモン」と発音すべきなのでしょうが、慣例的にデーモンと発音するようです。
initに続いて、キャッシュマネージャやスワップを制御するプログラム、ハードディスクへのデータ書き込みを制御するプログラムなどが実行されます。こうした、縁の下の力持ち的に各種のサービスを提供するプログラムを「デーモン」と呼びます。
では、initがプログラムを実行する方法を見ていきましょう。
initがどのような処理をしているのかは、/etc/inittabを見れば分かります。このファイルは、initが行うべき処理を定義しているもので、各種confファイルのようなものだと考えればよいでしょう。
/etc/inittabの各行は、
id:runlevel:action:process
という書式になっています。各部の意味は次のとおりです。
id
エントリの識別子。ユニークな文字列(1〜4文字)でなければならない。
runlevel
ランレベルの指定で、1から6までの数字が使える。「2345」など、複数を同時に指定できる。省略するとデフォルトランレベルとなる。
action
プロセスの起動あるいは終了時の動作。actionの内容は表を参照。
action | 意味 |
---|---|
respawn | processで指定したプロセスを起動し、終了したら再起動する |
wait | processで指定したプロセスを起動し、終了を待つ |
once | 指定したランレベルへの移行後に1度だけ実行 |
initdefault | デフォルトランレベルの指定 |
sysinit | ブート時に実行するプロセス |
powerfail | UPSが電源切断を検出したときに実行するプロセス |
powerokwait | UPSが電源オンを検出したときに実行するプロセス |
ctrlaltdel | [Ctrl]+[Alt]+[Delete]キーが押された場合 |
表 指定可能なactionの一部 |
process
起動するプログラム。
構文が分かると、/etc/inittabの各行の意味も理解できるでしょう。
# デフォルトランレベル(ランレベル3を指定) id:3:initdefault: # ブート時の処理(/etc/rc.d/rc.sysinitを実行) si::sysinit:/etc/rc.d/rc.sysinit # ランレベルごとの処理(各ランレベル用のrcスクリプトを実行し、その終了を待つ) l0:0:wait:/etc/rc.d/rc 0 l1:1:wait:/etc/rc.d/rc 1 l2:2:wait:/etc/rc.d/rc 2 l3:3:wait:/etc/rc.d/rc 3 l4:4:wait:/etc/rc.d/rc 4 l5:5:wait:/etc/rc.d/rc 5 l6:6:wait:/etc/rc.d/rc 6 # 1度だけ実行される処理(/sbin/updateを実行) ud::once:/sbin/update # [Ctrl]+[Alt]+[Delete]キーを押したときの処理 ca::ctrlaltdel:/sbin/shutdown -t3 -r now # 電源オフ時の処理 pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down" # 電源オン時の処理 pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled" # 端末制御(ランレベル2〜5で/sbin/mingettyを実行。終了されると再実行) 1:2345:respawn:/sbin/mingetty tty1 2:2345:respawn:/sbin/mingetty tty2 3:2345:respawn:/sbin/mingetty tty3 4:2345:respawn:/sbin/mingetty tty4 5:2345:respawn:/sbin/mingetty tty5 6:2345:respawn:/sbin/mingetty tty6 # ランレベル5時のログイン処理(/etc/X11/prefdmを実行。終了されると再実行) x:5:respawn:/etc/X11/prefdm -nodaemon
/etc/inittabには、initの実行から各種デーモンの起動を経て、ログインプロンプトが表示されるまでの処理が記述されているのが分かります。詳細は後述するとして、大まかな流れを挙げると、
といったことを行っています。
Red Hat Linux 7.2では、ブート時に/etc/rc.d/rc.sysinitというスクリプトを実行するようになっています。/etc/inittabの、
# System initialization. si::sysinit:/etc/rc.d/rc.sysinit
という行で定義されています。ざっとその内容を見ると、
といった処理が行われています(編注)。これらの処理を行った後、指定されたランレベルに対応したrcスクリプト群を実行して、ログインプロンプトを出すことになります。
ブート完了後にinitが行うことは、親プロセスを持たなくなったプロセスと端末の制御があります。
プロセスは自分自身が_exitシステムコールを実行し、親プロセスがwait系システムコールを実行することで初めて終了します。ところが、何かの拍子に親プロセスが止まってしまったりすると、_exitしたまま永遠にwaitを待つことになります。こうしたプロセスを探して、本来の親プロセスに代わってwait系システムコールを実行するわけです。
端末制御は、/etc/inittabの記述に従って、各端末(仮想端末を含む)に標準入出力やエラー出力を割り当て、gettyと総称されるプログラムを起動します。このgetty(Red Hat Linux 7.2ではmingetty)がログインプロンプトを出し、ここでようやくユーザーがログインできるようになるわけです。
Copyright © ITmedia, Inc. All Rights Reserved.