前回はP-Plamo独自のinitスクリプトの前半、squashfsのイメージファイルを見つけるまでの処理を紹介しました。今回は引き続いてinitスクリプトの後半の処理を紹介しましょう。
この部分では書き込み不可なsquashfsをルートファイルシステムとして利用するための作業が中心で、多くの処理がaufs に関する操作になるため、まずaufsについて紹介してからinitスクリプトの解説に移ります。
aufsとは
aufs については、前の連載でも簡単に紹介した ように、linuxにおけるunion mount の実装のひとつです。
aufsはJunjiro Okajima氏が開発しているunion mountの実装で、A nother U nion 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行目は/var 、79~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等を実行して初期化処理を進めていきます。