・P-Plamo の内部構造(その3)
P-Plamo の初期化処理を行うinit ファイルの 内容を簡単に紹介します. なお、ここに紹介するのは2009 3/3 版の必要最小限な init で、今後、さまざまな改造を追加していく予定で、 内容は適宜変更されますがあしからず。
実際のファイルには試行錯誤的にやってみた形跡をコメントアウトで多数残していますが,それらは略します.
#/bin/sh export PATH=/bin:. mount -t proc proc /proc mount -t sysfs sys /sys for i in aufs.ko unlzma.ko sqlzma.ko squashfs.ko ; do insmod /lib/modules/$i done # nls_euc-jp.ko needs vfat.ko for i in nls_iso8859-1.ko nls_ascii.ko nls_cp932.ko cdrom.ko ide-cd_mod.ko loop.ko sr_mod.ko \ sg.ko fat.ko vfat.ko nls_euc-jp.ko ; do insmod /lib/modules/$i done # this wait is needed for detecting USB CD-ROM via sr_mod.ko sleep 10
まず,PATH変数を設定してから、proc-fs, sys-fs をマウントしてカーネルの各種機能が利用できるようにします.
次に union mount 用の aufs.ko ドライバモジュール,lzma 圧縮に対応した squash-fs 用の unlzma.ko, sqlma.ko モジュールをロードし,最後に squashfs.ko モジュールをロードします.squashfs.ko は unlzma.ko や sqlzma.ko の機能を必要とするので,先に unlama.ko, sqlzma.ko をロードしておかないとエラーになります.
次に iso9660 形式の DVD か VFAT 形式の USB メモリをマウントする際に必要となるモジュール類をロードします. これらも依存関係があるので,順番を違えるとエラーになってきちんとロードしてくれないので注意してください.
# modprobe を使えば自動的に処理してくれるのですが,わざわざ modules.dep 等を作るほどのこともないと思うので
モジュールドライバをロードすると,それらのドライバによってカーネルが新しく認識できるようになった周辺機器を チェックするので,そのためにしばらく時間を置きます.
mount_ok=0 # check CD device for i in hdc hda hdb hdd sr0 sr1 sr2 ; do echo "trying CD device" mount -t iso9660 /dev/$i /cdrom -o ro if [ $? = "0" ]; then if [ -f /cdrom/isolinux/rootimg.squash ]; then echo "found cdrom on /dev/$i" mount_ok=1 break else umount /cdrom fi fi done # check /dev/sdXX for USB CD device if [ "$mount_ok" == "0" ]; then partitions=`cat /proc/partitions | cut -b23-28 | grep sd` for i in $partitions ; do mount /dev/$i /cdrom if [ $? = "0" ]; then if [ -f /cdrom/isolinux/rootimg.squash ]; then echo "found cdrom on /dev/$i" mount_ok=1 break else umount /cdrom fi fi done fi # cannot find any CD device if [ "$mount_ok" == "0" ]; then echo "cannot find partition include squashfs. cannot continue booting. exit" exec /bin/sh fi
DVD あるいは USB メモリを /cdrom にチェックするためのループです.指定したデバイスが /cdrom にマウントでき, そこの isolinux ディレクトリに rootimg.squash があるかで正しい DVD かをチェックしています.
最初のループで IDE の hdc, hda, hdb, hdd,SCSI(SATA) の sr0, sr1, sr2 の順に DVD をチェックし, 見つかれば $mount_ok を 1 にして次のループを飛し,見つからなければ次のループで /proc/partitions にある sd デバイス(USBメモリは sd デバイスとして認識される)を順にマウントして rootimg.squash の有無を調べます.
見つからなければ以後の処理を打ちきって /bin/sh を起動して終了します. 一応,対話的な操作は可能なので busybox の限られたコマンドを使って原因をチェックしてみてください.
# mount squashfs'ed rootfs image into /loop losetup /dev/loop0 /cdrom/isolinux/rootimg.squash mount -t squashfs /cdrom/isolinux/rootimg.squash /loop mount -t tmpfs none /loop/tmp mkdir -p /loop/tmp/ow/var mount -t aufs -o br:/loop/tmp/ow/var:/loop/var none /loop/var mkdir -p /loop/tmp/ow/usr mount -t aufs -o br:/loop/tmp/ow/usr:/loop/usr none /loop/usr mkdir -p /loop/tmp/ow/etc mount -t aufs -o br:/loop/tmp/ow/etc:/loop/etc none /loop/etc echo "copyinng modified rc.S and rc.M to /etc/rc.d/" cp /etc/rc.S.modified /loop/etc/rc.d/rc.S cp /etc/rc.M.modified /loop/etc/rc.d/rc.M cp /etc/rc.4.modified /loop/etc/rc.d/rc.4 cp /etc/csh.login /loop/etc/csh.login for i in inittab fstab passwd shadow ; do echo "copying modified $i to /etc/$i" cp /etc/$i /loop/etc/$i done
rootimg.squash が見つかれば,それを /dev/loop0 に結びつけて,/loop に squash-fs でマウントします. この時点で,/loop の下に(squash-fs 上に構築した)ルートファイルシステムが見えるようになります.
この squash-fs 上のルートファイルシステムの /tmp に tmpfs をマウントして読み書きできるようにして, /var や /us,/etc 等,書き替えが必要となる部分のディレクトリを /tmp 上に取ってから union mount で被せていき, 修正が必要な設定ファイル類を initramfs/etc の下からコピーしています.
union mount したディレクトリに書き込んだファイルは /loop/tmp/ow の下の各ディレクトリに書き込まれ, 元の RO なファイルは見えなくなります.以下,同様の union mount + cp の処理が続くので少し省略します.
mount -t tmpfs tmpfs /loop/dev cp -a /dev/console /loop/dev
/loop に root partition を切り替えた際に使うことになる /loop/dev ディレクトリを書き込み可能にして, 現在使っている /dev/console を使い続けるために /loop/dev にコピーしています. こうしておかないと root partition を切り替えた際にコンソールへのメッセージが出力されなくなります.
mount --move /proc /loop/proc mount --move /sys /loop/sys
/proc と /sys を使い続けるために /loop 以下に移動させ,
# exec /bin/sh echo "switch_root to /loop" sleep 5 cd /loop exec /bin/switch_root -c /dev/console . /sbin/init
"switch_root to /loop" のメッセージを出力して 5 秒後に cd /loop してから /bin/switch_root コマンドを発行し,現在のディレクトリ(/loop)を新しい root partition にして, /sbin/init を実行します.以後の処理は通常の Plamo 同様,/sbin/init が /etc/inittab を元に sysinit に該当する /etc/rc.d/rc.S を起動して,rc.S が udev を起動し,,と進んでいきます.
コメントアウトしている exec /bin/sh を有効にすれば、必要な処理を行った上で対話的な shell が起動されるので、 必要な設定等が行われているかを調べることができます。対話的なshellからも、switch_root コマンドを発行すれば、 squash_fs 上のファイルシステムに切り替えることが可能です。