玩式草子─ソフトウェアとたわむれる日々

第10回P-Plamoの内部構造その2]

前回はP-Plamo独自のinitスクリプトの前半、squashfsのイメージファイルを見つけるまでの処理を紹介しました。今回は引き続いてinitスクリプトの後半の処理を紹介しましょう。

この部分では書き込み不可なsquashfsをルートファイルシステムとして利用するための作業が中心で、多くの処理がaufsに関する操作になるため、まずaufsについて紹介してからinitスクリプトの解説に移ります。

aufsとは

aufsについては、前の連載でも簡単に紹介したように、linuxにおけるunion mountの実装のひとつです。

aufsはJunjiro Okajima氏が開発しているunion mountの実装で、Another Union FSという名称が示すように、元々はStony Brooks UniversityのErez Zadok教授のチームが開発していたUnion FSを元に、独自のアイデアや実装を追加して開発したファイルシステムです。

Erez Zadok教授のUnion FSは、より大きなFiST(Stackable Filesystem Language and Template)というプロジェクトの 一部で、このプロジェクトは重ね合わせ可能(Stackable)な汎用的ファイルシステムを作ることを目指しているそうです。Union FSもaufsと刺激しあいながら進歩を続け、現在はバージョン2.5.4が公開されています。

aufsについて理解するには、実際の動作を見てもらうのが手っ取り早いでしょう。aufsは公式のカーネルには含まれておらず、必要なファイルはgit経由で入手する必要がありますが、Plamo-4.72ではあらかじめaufs機能を組み込んだカーネルを用意していますので、aufsモジュールドライバをmodprobeで組み込めばすぐに使用できるようになります。

# modprobe aufs
# dmesg | tail
aufs 2-standalone.tree-32-20100208

aufsの典型的な使い方として、ROなCD/DVDメディアに擬似的に書き込む例を紹介しましょう。以下の例では/cdromにP-PlamoのDVDをマウントしています。

% df
Filesystem           1K-ブロック    使用   使用可 使用% マウント位置
/dev/sda4             27435156  15801396  10240100  61% /
none                   1557276       192   1557084   1% /dev
/media                 1557276         0   1557276   0% /media
 ....
/dev/sr0               1632774   1632774         0 100% /cdrom
% ls /cdrom
ChangeLog  initrd  isolinux/

/tmpにaufs用の領域を用意し、/cdrom上に重ねます。

# mkdir /tmp/aufs ; chmod 777 /tmp/aufs
# mount -t aufs -o br:/tmp/aufs:/cdrom none /cdrom
# df
Filesystem           1K-ブロック    使用   使用可 使用% マウント位置
/dev/sda4             27435156  15803972  10237524  61% /
none                   1557276       192   1557084   1% /dev
/media                 1557276         0   1557276   0% /media
....
/dev/sr0               1557276     26180   1531096   2% /cdrom
none                   1557276     26180   1531096   2% /cdrom

この状態で/cdromを見ると、以前と同じようにDVDメディアの中身が表示されます。

% ls /cdrom
ChangeLog  initrd  isolinux/

一方、本来は書き込みできないはずの/cdromディレクトリに一般ユーザから書き込むことができます。

% touch /cdrom/aufs_test
% ls -l /cdrom
合計 6,299,136
-r--r--r-- 1 root   root      5,271  3月 28日  23:53 ChangeLog
-rw-r--r-- 1 kojima users         0  5月  3日  10:42 aufs_test
-r--r--r-- 1 root   root  6,291,456  3月 28日  01:47 initrd
dr-xr-xr-x 2 root   root      2,048  3月 28日  11:13 isolinux/

ChangeLogは本来DVDメディア上に存在する変更不可なファイルですが、ファイルの所有者(root)の権限で書き込み許可を与えると、aufsのレイヤで複製され、一般ユーザからも修正することができます。

% sudo chmod a+rw /cdrom/ChangeLog
パスワード: *****
% emacs /cdrom/ChangeLog
...

% ls -l cdrom
合計 6,309,888
-rw-rw-rw- 1 root   root      5,305  5月  3日  10:46 ChangeLog
-rw-rw-rw- 1 kojima users     5,271  3月 28日  23:53 ChangeLog~
-rw-r--r-- 1 kojima users         0  5月  3日  10:42 aufs_test
-r--r--r-- 1 root   root  6,291,456  3月 28日  01:47 initrd
dr-xr-xr-x 2 root   root      2,048  3月 28日  11:13 isolinux/

ファイルの先頭を見ると、確かに変更した内容が記録されています。

% head /cdrom/ChangeLog
-*- text -*-

平成22年5月3日(月)

テストの入力

平成22年3月28日(日)
...

また、このファイルは削除することもできます。

% rm /cdrom/ChangeLog
% ls -al /cdrom
 合計 6,305,792
drwxrwxrwx  5 root   root        160  5月  3日  10:57 ./
drwxr-xr-x 26 root   root      4,096  4月 30日  13:59 ../
-rw-rw-rw-  1 kojima users     5,271  3月 28日  23:53 ChangeLog~
-rw-r--r--  1 kojima users         0  5月  3日  10:42 aufs_test
-r--r--r--  1 root   root  6,291,456  3月 28日  01:47 initrd
dr-xr-xr-x  2 root   root      2,048  3月 28日  11:13 isolinux/

この例のように、aufsを使えば本来は変更不可能なCD/DVDメディア上に擬似的にデータを書き込むことが可能になります。これらの修正はaufsを外す(umount)と元の状態に戻ります。

% sudo umount /cdrom
% df 
Filesystem           1K-ブロック    使用   使用可 使用% マウント位置
/dev/sda4             27435156  15804032  10237464  61% /
none                   1557276       192   1557084   1% /dev
..
/dev/sr0               1632774   1632774         0 100% /cdrom
% ls -al /cdrom
合計 6,299,136
-r--r--r-- 1 root root     5,271  3月 28日  23:53 ChangeLog
-r--r--r-- 1 root root 6,291,456  3月 28日  01:47 initrd
dr-xr-xr-x 2 root root     2,048  3月 28日  11:13 isolinux/

aufsに書き込まれたデータは、実際には先に作った/tmp/aufs/に保存されているので、必要に応じて別途利用することもできます。

% ls -al /tmp/aufs/
合計 8,192
drwxrwxrwx  4 root   root    160  5月  3日  10:57 ./
drwxrwxrwt 15 root   root    660  5月  3日  11:00 ../
-r--r--r--  2 root   root      0  5月  3日  10:38 .wh..wh.aufs
drwx------  2 root   root     40  5月  3日  10:38 .wh..wh.orph/
drwx------  2 root   root     40  5月  3日  10:38 .wh..wh.plnk/
-r--r--r--  2 root   root      0  5月  3日  10:38 .wh.ChangeLog
-rw-rw-rw-  1 kojima users 5,271  3月 28日  23:53 ChangeLog~
-rw-r--r--  1 kojima users     0  5月  3日  10:42 aufs_test

今回はROメディアを例に用いましたが、aufsを使えば、システム上の通常は書き込み不可の領域にユーザの一時的な変更を許可し、必要が無くなれば元の状態に戻す、といった処理も簡単に実現できます。aufsはこのようにさまざまな場面で応用可能な便利なファイルシステムです。

initスクリプトの解説(後半)

それではP-Plamoのinitスクリプトの後半部分を紹介していきましょう。実のところ、この部分の処理のほとんどは、変更不可なsquashfs上に、aufsを用いてPlamo Linuxの動作に必要な書き込み可能領域を設定するための作業になっています。

なお、initスクリプトの後半部分にはあれこれ試行錯誤していたコメント行を多数残していますが、今回はそれらコメント行は省略し、実際の処理の部分のみを見て行きます。行番号もコメント行は省いて振り直しているので、前回のリストとは多少ズレているのでご注意ください。

以下の行番号はgrep -v "^#" init | uniq | cat -nという処理で採番しています。

72	losetup /dev/loop0 /cdrom/isolinux/rootimg.squash
73	mount -t squashfs /cdrom/isolinux/rootimg.squash /loop
74	

見つかったsquashfsのイメージをloopback形式で /loop にマウントしています。この結果、/loop以下にsquashfs経由でファイルシステム一式が見えるようになります。最終的には、この/loop以下にルートファイルシステムを切り替えて、Plamo-4.72相当の環境を動作させます。

75	mount -t tmpfs none /loop/tmp
76	
77	mkdir -p /loop/tmp/ow/var
78	mount -t aufs -o br:/loop/tmp/ow/var:/loop/var none /loop/var
79	mkdir -p /loop/tmp/ow/usr
80	mount -t aufs -o br:/loop/tmp/ow/usr:/loop/usr none /loop/usr
81	

squashfsを書き込み可能にするための作業領域として/loop/tmpにtmpfsをマウントしています。tmpfsはメモリ上に作られる仮想的なファイルシステムで、メモリ上に記録されているため電源を切ると消えてしまいますが、事前にmkfsコマンドでファイルシステムを作らなくても利用できるので、一時作業用には便利なファイルシステムです。P-Plamoではtmpfsをマウントした/loop/tmp/にow(over write)というディレクトリを作り、squashfs上で書き込みが必要な領域にはow/以下に該当するディレクトリを作成してaufsで重ね合わせるようにしています。

77~78行目は/var79~80行目は/usrをそれぞれ/tmp/ow/以下に作り、それらの領域を/loop上のsquashfsのディレクトリに重ねています。

82	mkdir -p /loop/tmp/lib/firmware
83	mount -t aufs -o br:/loop/tmp/lib/firmware:/loop/lib/firmware none /loop/lib/firmware
84	
85	firm_chk=`ls /lib/firmware | wc -l`
86	if [ $firm_chk -gt 0 ] ; then
87	    echo "copying /lib/firmware to /loop/lib/firmware"
88	    cp -a /lib/firmware/* /loop/lib/firmware
89	fi
90	
/lib/firmwareは各種周辺機器が動作するのに必要なfirmwareを置く領域です。firmwareはそれぞれの周辺機器のメーカーが提供しており、カーネルのソースコードと共に配布されているfirmwareもいくつかありますが、多くの場合はメーカのサイト等から別途入手する必要があります。

P-Plamoでは、それらカーネルとは別配布になっているfirmwareはinitrd上の/lib/firmwareディレクトリに用意しておき、85行目からの処理で起動後の/lib/firmware/になる領域(/loop/lib/firmware)にコピーしています。82~83行はそのための領域をsquashfs上に用意する作業です。

 91	mkdir -p /loop/tmp/ow/etc
 92	mount -t aufs -o br:/loop/tmp/ow/etc:/loop/etc none /loop/etc
 93	echo "copyinng modified rc.S and rc.M to /etc/rc.d/"
 94	cp /etc/rc.S.modified /loop/etc/rc.d/rc.S
 95	cp /etc/rc.M.modified /loop/etc/rc.d/rc.M
 96	cp /etc/rc.4.modified /loop/etc/rc.d/rc.4
 97	cp /etc/rc.6.modified /loop/etc/rc.d/rc.6
 98	cp /etc/csh.login /loop/etc/csh.login
 99	cp /etc/rc.keymap /loop/etc/rc.d/rc.keymap
100	cp /etc/modprobe.conf /loop/etc/modprobe.conf
101	chmod -x /loop/etc/rc.d/init.d/wnn.r
102	
103	for i in inittab fstab passwd shadow ; do
104	    echo "copying modified $i to /etc/$i"
105	    cp /etc/$i /loop/etc/$i
106	done
107	

P-Plamoでは、できるだけPlamo-4.72の環境をそのまま利用することを目指している、と言いましたが、実際に試してみるとシステムの初期化用スクリプトを中心にいくつかのファイルには修正が必要になりました。

たとえば、システム初期化の第一段階である/etc/rc.d/rc.Sでは/procや/sysをマウントしたり、ルートファイルシステムをチェック(fsck)したりしますが、/procや/sysは前回紹介したようにinitスクリプトの最初にすでにマウント済みですし、書き込むことができないsquashfsをfsckする必要はありません。

rc.S以外にも、標準のPlamo-4.72から修正したい部分はいくつかあったので、それらはinitrdの/etc以下に修正済みのファイルを用意して、それらを起動時にsquashfs上の対応する領域(たいていは/etc以下)にコピーするようにしてみました。こうしておけばP-Plamoでの変更箇所を簡単に識別できるでしょう。91~92行目はそのために/etcを書き変え可能にするための処理です。

squashfsはファイルシステムの圧縮処理にかなり時間がかかるため、あまり頻繁には作り直せません。そのため、開発効率の面からも微調整が必要なファイルはinitrd側に用意する方が便利ですが、tmpfsにファイルをコピーすれば、その分空きメモリの容量が減るので痛し痒しというところです。

101行目はかな漢字変換システムWnnの起動スクリプトを実行しないようにする処理で、P-PlamoではWnnの変換サーバが辞書読み込みエラーで起動しないため、暫定的に停止しています。なお、この問題は解決のメドが付いたようなので、次回リリースでは解除する予定です。

108	mkdir -p /loop/tmp/ow/home
109	mount -t aufs -o br:/loop/tmp/ow/home:/loop/home none /loop/home
110	

ユーザのホームディレクトリを書き込み可能にする操作です。P-Plamoではdemoというデモ用のユーザしか登録していないので、/home/demo/のみを書き込み可能にするだけでもいいのですが、/home全体を書き換え可能にしておけば新しいユーザを登録することもできるので、より可能性は広がるでしょう。

111	mkdir -p /loop/dev
112	mount -t tmpfs tmpfs /loop/dev
113	cp -a /dev/console /loop/dev
114	

デバイスファイル用の領域を書き込み可能にし、現在使っている/dev/consoleを新しい環境に引き継ぐ処理です。最近のPlamoでは、実際のデバイスファイルはudevを使って起動時に作成されるので、/dev/console以外の必要なデバイスは自動的に新規作成されます。

なお、111行目で/loop/devを作ろうとしていますが、squashfs上にdevディレクトリはあらかじめ作ってあるので、この処理は不要(というかsquashfs上にディレクトリを作ることはできない)で、直接112行目のようにtmpfsをマウントするだけでいいはずです。

115	echo "CD_DEV:$CD_DEV"
116	echo $CD_DEV > /loop/etc/cd_dev

起動されたDVD/USBデバイスの位置を/loop/etc/cd_devに記録しています。終了時には、このファイルを調べてDVDを取り出すデバイスを決めます。

117	mount --bind /proc /loop/proc
118	mount --bind /sys /loop/sys
119	

現在使っている/proc/sysファイルシステムを新しいルートファイルシステム上に引き継ぐために、マウントのbind オプションを使って/loop上のそれぞれのディレクトリから利用できるようにしています。

120	echo "pivot_root to /loop"
121	sleep 5
122	cd /loop
123	/bin/pivot_root  . loop
124	exec chroot . /loop/sbin/init
125	

以上で/loop上にマウントしたsquashfsをルートファイルシステムにするために必要な作業が終ったので、pivot_rootコマンドを使ってルートファイルシステムを切り替える処理に移ります。123行目のpivot_rootコマンドで、カーネルが認識しているルートファイルシステムは/loopにマウントしていたsquashfsに切り替わると共に、古いルートファイルシステムだった、initrdは(squashfs上の)loopディレクトリにマウントし直します。

一方、このスクリプトを実行しているシェルはルートファイルシステムが切り替わったことを知りませんので、124行目のchrootコマンドでルートファイルシステムを変更し、そこにある/sbin/init(シェルが理解しているフルパス指定で)実行して、自らの処理を終えます。

この時点で、書き込みが必要な領域は/tmp/ow以下の領域をaufsでマウントして自由に書き込めるようになっているので、以後、処理を引きついだ(squashfs上の)/sbin/initは通常のPlamo-4.72と同様に、⁠事前に修正版をコピーした)/etc/rc.d/rc.S等を実行して初期化処理を進めていきます。

おすすめ記事

記事・ニュース一覧