起動プロセス
requirements.boot.processも参照してください。
このガイドは最新ではありません!またprocdには触れていません。
このガイドは以下を理解する時に役立ちます。
- OpenWrt FailSafeがどのように動作するか?
- いつtmpfsがマウントされ、
/tmp
や/var
へシンボリックリンクされるのか? - Preinit mount(起動前)、ルートマウント、初回ブートスクリプト
- Init Scripts(初期スクリプト)実装の参考
- Block Mount(ブロックデバイスのマウント)
プロセストリニティ
装置への電源投入時、極めて基本的な最下層のハードウェア要素が実行されます。JTAG Portへの接続を通して命令を発行できます。
ブートローダ(bootloader)
- フラッシュ上の bootloader が読み込まれます。
- ブートローダーは下層ハードウェアの初期化(POST)を実行します。
- ブートローダはフラッシュメモリにある圧縮されたカーネルイメージをメインメモリ(=RAM)へ展開します。
- ブートローダーは
init=...
オプション(デフォルトは/etc/preinit
)と共にカーネルを実行します。
カーネル(Kernel)
- カーネルはブートストラップ自体を進めます。 (原文!)
- コマンド/オペレーションコード
start_kernel
を発行します。 - カーネルは有効なスーパーブロックとして、mtdパーティションのrootfsを探し、見つけたらSquashFSパーティション (
/etc
を含む) をマウントします。(詳しくは、technical.details) /etc/preinit
は初期化事前ステップです。(ディレクトリの作成、fsのマウント、/proc、/sys、... )- カーネルはrootfs (root file system)の下に他のパーティション(例えば、jffs2 partition)をマウントします。flash.layout、preinit and root mountを参照、また udev を 確認してください。
- もし“INITRAMFS”が定義されていない場合は
/sbin/init
(全てのプロセスの親)が呼ばれます。 - 最後に、カーネルスレッドが ユーザスペースのプロセス
init
になります。
Init
カーネルがrootfsをマウントするとユーザスペースが開始され、実行の初期プログラム(デフォルト)は/sbin/init
です。 アプリケーションとカーネル間のインターフェースは、clib
とsyscallsであることを思い出してください。
- initは“sysinit”の入り口として
/etc/inittab
を読みます。 (デフォルトは“::sysinit:/etc/init.d/rcS S boot”) - initは
/etc/init.d/rcS S boot
を呼び出します。 rcS
は executes the symlinks to the actual startup scripts located in/etc/rc.d/S##xxxxxx
に置かれた実際のスタートアップスクリプトへのシンボリックリンクを“start”
オプションと共に実行します。- rcSの完了後、システムが立上げ実行されます。
オリジナルスタートアップスクリプト
注: opkg
にてインストールするPackagesは おそらく追加的なスクリプトになります。
S05defconfig | OpenWRTインストール後の最初に起動時にプラットフォーム用のconfigファイルをデフォルト値で作成します。(/etc/defconfig/$board/から/etc/config/へコピーします。) |
S10boot | hotplug-script、ファイルシステムのマウント、starts ..、starts syslogd, ...開始 |
S39usb | mount -t usbfs none /proc/bus/usb |
S40network | ネットワークサブシステム(run /sbin/netifd, up interfaces and wifi)の開始 |
S45firewall | /etc/config/firewallからファイヤウォールルールの作成と実装 |
S50cron | crond の開始。/etc/crontabs/root をご参照ください。 |
S50dropbear | dropbear 開始。 /etc/config/dropbear をご参照ください。 |
S50telnet | root パスワードのチェック。設定されていない場合は/usr/sbin/telnetd からスタート |
S60dnsmasq | dnsmasq の開始。 /etc/config/dhcp をご参照ください。 |
S95done | /etc/rc.local の実行。 |
S96led | /etc/config/system からLEDの設定読込とセットアップ。(/sys/class/leds/*/*へ値を書き込み) |
S97watchdog | watchdog daemonの開始。 (/sbin/watchdog) |
S99sysctl | /etc/sysctl.conf 解釈 |
init
デーモンは常に実行され、シャットダウンコマンドにて、 init
は、
- シャットダウンのため
/etc/inittab
読込。(デフォルトは“::shutdodwn:/etc/init.d/rcS K stop”) /etc/init.d/rcS K stop
呼び出し。- rcSは、/etc/rc.d/K##xxxxxx に置かれたシャットダウンスクリプトを“stop”オプションと共に実行。
- システムは停止/リブート
K50dropbear | dropbearの全てのインスタンスを終了 |
K90network | 全てのインターフェースの停止とnetifdの終了 |
K98boot | ロガーデーモンの終了: /sbin/syslogd and /sbin/klogd |
K99umount | キャッシュのディスクへの書き出し、ファイルシステムのアンマウント |
詳細な起動シーケンス
ブートローダ(Boot loader)
ブートローダ(この事例ではgrub)の初期化およびブートメニューのオプション解析の後、カーネルをロードします。
通常ブートのopenwrt-x86-ext2-image.kernelファイル記載の事例:
- “kernel /boot/vmlinuz root=/dev/hda2 init=/etc/preinit [rest of options]”
このboot/grub/menu.lstファイルの記載は、カーネルは/bootの下のディレクトリにあるファイル名vmlnuzであることをgrubへ伝えます。 他のラインは、カーネルに渡されるオプションです。カーネルがどのように開始されるかを知るために/proc/cmdlineファイルを読むことでオプションが調べられます。デバイスへのログインによって、どのようなオプションがgrubから引き渡されたのかを“cat /proc/cmdline”とタイプすることで確認できます。
テストシステムのロード時にカーネルへ引き渡されたオプションは以下です。:
- “root=/dev/hda2 rootfstype=ext2 init=/etc/preinit noinitrd console=ttyS0,38400,n,8,1 reboot=bios”
オプションは:
- root: OpenWrtのその他のシステムが置かれたルートデバイス/パーティション。
- rootfstype: ルートパーティションのフォーマット - この例ではext2。
- init: カーネルのロード、初期化後の最初のコール
- noinitrd: カーネルへビルドされたシステムの他の部分にアクセスするための全てのドライバ
- console: フロー制御なしの38400速度、8bitデータと1ストップビット時のttyyS0(最初のシリアルポート)への通信からログインコンソールコマンドを許容するデバイス。他のオプションはカーネルドキュメント参照。
- reboot: 不明確であるが、リブートがどのように振る舞うかをカーネルに伝えるオプションと考える。
ブートローダのカーネルオプションのエントリへカーネル読み込後、最初のプログラムがコールされます。grubでは、エントリは/boot/grub/menu.lstファイル内にopnewrt-イメージカーネルイメージファイルとして置かれている。
[ 注: 全てのgrubパラメータ知るにはgrubのマニュアルを参照] この事例の記載、“init=/etc/preinit”は初期化後の最初のプログラムの実行は、“/dev/hda”ディスク上の“hda2”パーティションに置かれた“/etc”ディレクトリで見つけられる“preinit”であることをカーネルに伝えています。
/etc/preinit スクリプト
preinitスクリプトの主要な目的はスタートアップスクリプトの残り部分の初期チェックと設定です。/procと/sysを疑似ファイルシステムとしてマウントすることが主要な仕事の一つで、ステータス情報へのアクセスやいくつかの制御機能が利用可能になります。もう一つの主要な機能は、コンソール、tty、メディアデバイスのようなものへのアクセスするために/devディレクトリのを準備します。最後の仕事はinitデーモンプロセス自体の開始です。
Busybox init
Initは、デーモンの開始、ランレベルの変更、デーモンへアクセスするコンソール/疑似コンソール/ttyの設定やその他の管理も行うことから「全てのプロセスの親」と考えられています。
initが開始されると/etc/inittabのコンフィグレーションファイルを読み、特定の活動のためにどのプロセスを開始、監視し、関連するプログラムのコールのきっかけの活動がいつかを示します。
Busyboxによるinitプログラムは最小限のデーモンです。それはランレベルのような情報を持たず、通常のinitコンフィグファイルと比べて多少省略されています。 もしデスクトップのLinuxが実行されているならば、“man inittab”にて通常のinitプロセスとエントリについて確認できます。フィールドはコロンで区切られ、以下の様に定義されます。
- [ID] : [Runlevel(s)] : [Action] : [Process to execute ]
busybox initは、“ID” (1番目)、 “Action” (3番目)と“Process” (4番目)のフィールドのみ必要とされます。BusyBox initは通常のinitに対し、いくつかの注意点があります。IDフィールドはTTY/コンソールの制御に使われ、ランレベルは定義されません。最小の/etc/inittabは以下です。
- ::sysinit:/etc/init.d/rcS S boot
- ::shutdown:/etc/init.d/rcS K stop
- tts/0::askfirst:/bin/ash --login
- ttyS0::askfirst:/bin/ash --login
- tty1::askfirst:/bin/ash --login
IDフィールドが空欄のライン1と2は、特定のターミナルやコンソールが無いことを示します。
Notice that both the “sysinit”と“shutdown”動作は同じプログラム(“/etc/init.d/rcS”)が呼ばれていることに注意してください。rcSスクリプトへ渡すオプションが違うだけです。これは後に明確になります。
この時点で、initはコンフィグレーションファイルを解析して、次に何をするかを探しているので、sysinitエントリに“S”と“boot”オプションで/etc/init.d/rcSが呼ばれています。
スタート時の/etc/rc.d/rcS スクリプト
この時点で基本的な設定は完了し、全てのプログラムとシステム/構成ファイルが利用できます。そして、その他のプロセスへの準備状態になります。
rcSスクリプトの機能はかなり簡略化されています。- その一つ目的が、適切なオプションによる/etc/rc.d ディレクトリ内のスクリプトの実行です。sysinitエントリをよく見ると“S”と“boot”オプションと共にrcSスクリプトが呼ばれていることが分かります。rcSは2つのオプション(“S”と“boot”)で呼ばれたため、rcSは$1を“S”、$2を“boot”に置き換えます。rcSに関連するラインは以下です。
- for i in /etc/rc.d/$1* ; do 2. [ -x $i ] && $i $2 3. done
基本的な解析:
- “S”で始まる/etc/rc.d ディレクトリ内の全てのエントリ(ファイル/リンク)を順次実行します。
- もしファイルが実行形式であれば、“boot”オプションと共にファイルが実行されます。
- $iを次のファイル名に置き換え、ファイルが見つからなくなるまでステップ1を繰り返します。
マイクロソフトのプログラムと違い、Linuxではファイル拡張子ではなく、ファイルパーミッションによって実行形式かどうかが示されます。ファイルパーミッションの説明については、Linux/Unixマシンの“man chmod”にてパーミッションと実行形式ファイルを参照してください。
/etc/rc.d ディレクトリを見るとスタートアップのための関連リンクや、shutdown時には無いスクリプト(すなわち/etc/init.d/httpd)や一方でスタートアップには無いshutdownのスクリプト(すなわち/etc/init.d/umount)があることに気付くかもしれません。
httpd(Webサーバ)の場合、それが死んでいるかどうかは問題ではないので、退去時にクリーンアップする必要がありません。
一方で、ストレージメディアに関連するumountスクリプトは、全てのデータがメディアへフラッシュされたことを確認しシャットダウン前に必ず、実行されなければなりません。さもなくばデータの破損が起こり得ます。どこか(/etc/preinitのような)でメディアのストレージマウントは取り扱われるので、スタートアップ時にはumountを呼ぶ必要はありませんので、スタートアップスクリプトにはこれはありません。
最後のスタートアップスクリプトが実行されると完全なOpenwrtシステムとなります。
ノート
- 一般的なブートプロセスについては Bootingも参照してください。
- log.essentials busybox-klogdとbusybox-syslogd