PICKLESっぽいFreeBSDを構築する方法

ここで説明するのはFreePICKLESについてではなく、PICKLESの思想を反映させた っぽいFreeBSDの環境を構築する方法です。 2002年6月のIPSJ DSM研究会で発表した内容の元になった文章に実装についての 情報を書き加えたものになります。一部に 「これをこう作れば良いけど作ってない」とか「これを考えないと いけないけど考えていない」などが現れますが、気にしてはいけません。 DSMの論文はここに PDFがあります
この文書がターゲットとしている読者は、PICKLESのことを知っていて、FreeBSDの ことも知っていて、FreeBSDをPICKLESっぽく使いたいなと思っている人か、 PICKLESが本当はやりたかったことをFreePICKLESで実現しようとする人 (例えばオレ)なんかになります。

PICKLESとは

PICKLESのページは こちら ですが、その技術的なポイントは以下の二点に集約できます。

共通アプリケーション集

あるバージョンのあるPICKLESなら同じアプリケーションが使えるはずで、 何か問題が生じてもそれはすべてのユーザで同じはずです。この結果、問題と その解決方法の共有が図れます。例えば大学の研究室などでは、古くから こういう環境での教育が行なわれてきました。
FreeBSDでこの目標を実現するために、POPSを 提供しています。
だからこれについては、とりあえずヨシ。

システムディスクとユーザディスクの切り分け(初級編)

で、問題はこれ。
全てのホストで共通の領域と、ホスト個有の領域を明確に分離しておけば、 前者のバージョンアップなどが安全かつ簡単に行なえます。
では何がユーザディスクに含まれるのかというと、 まず/etcの下の諸々の設定ファイル。これはシステム標準がまずあって、それに 対する変更または追加という形を取ります。また一部はホスト共通であったりも します(motdとか)。

次に/varが挙げられます。/varの中にもシステム個有と言えないこともない情報が ありますが、ほとんどが標準値を定めていて後はホストごとに変更されるはずの ものばかりです。だいたい/varという名前からして、常に変更される可能性がある ものが集まっているはずです。ここはディレクトリごとホスト個有だと考えて 良いでしょう。

最後がそれ以外のhome directoryなどです。これは一つのディレクトリにまとめて しまいましょう。私は/local/にしています。

さて整理すると、以下のようになります。


/            ルートパーティション(全ホストで共通)
/usr         アプリケーションなど(全ホストで共通)
/etcの一部   /etcのうちホスト個有の情報
/var         ホストごとに異なる。
/local/      homeなど。ホストごとに異なる。

さてBSD/OS版PICKLESでは、/etcの一部を/etc3というディレクトリに置き、/etcの 下の対応ファイルからsymbolic linkを作成していました。しかしこの方法だと、 /etcの下のファイルを直接編集するアプリケーション(passwdなど)を改造する 必要がありましたし、人間が編集する場合にうっかり/etcの下のファイルをemacsで 編集してしまってsymbolic linkが壊れるといった事故も置きました。

そこでunion file systemを使ってこれを解決します。

最初に/usr/local/etc/を/etc/に下に移動しなければいけません。例えば /etc/usr.local.etc/とかいう名前にしてみましょう。そしてsymbolic linkを作り ます。


# mv /usr/local/etc /etc/usr.local.etc
# ln -s /etc/usr.local.etc /usr/local/etc

次に /uと/u/etcというディレクトリを作り、/u/etcを/etcにunion mountします。これに よって/etc/の下を編集すると、更新したファイルだけが/u/etc/に置かれます。

そして、上記のように分離した情報を、別のパーティションに置きます。 こういう方針の下で作ったdisklabelとfstabが、例えばこんな感じ。


disklabel:
8 partitions:
#        size   offset    fstype   [fsize bsize bps/cpg]
  a:   262144        0    4.2BSD        0     0     0   # (Cyl.    0 - 16*)
  b:   786432   262144      swap                        # (Cyl.   16*- 65*)
  c: 12723480        0    unused        0     0         # (Cyl.    0 - 791)
  e:  4194304  1048576    4.2BSD        0     0     0   # (Cyl.   65*- 326*)
  f:     8192  5242880    4.2BSD        0     0     0   # (Cyl.  326*- 326*)
  g:  1048576  5251072    4.2BSD        0     0     0   # (Cyl.  326*- 392*)
  h:  6423832  6299648    4.2BSD        0     0     0   # (Cyl.  392*- 791*)

fstab:
# Device                Mountpoint      FStype  Options         Dump    Pass#
/dev/ad0s3b             none            swap    sw              0       0
/dev/ad0s3a             /               ufs     rw              1       1
/dev/ad0s3h             /local          ufs     rw              2       2
/dev/ad0s3f             /u              ufs     rw              2       2
/dev/ad0s3e             /usr            ufs     rw              2       2
/dev/ad0s3g             /var            ufs     rw              2       2
/u/etc                  /etc            union   rw              0       0

つまり、a,b,eパーティションがシステムディスクになって、f,g,hパーティション がユーザディスクになるわけです。

BSD/OS版PICKLESでは/usrはhパーティション固定だったので、少し気持ち悪いの ですが、FreeBSDのインストーラのdisklabelエディタではディスク内の順番と パーティション番号を好きなように編集することが出来ないので、我慢しましょう。

さて、次にこうして分離した内容をちゃんと機能するようにしなければいけません。 そのためにFreeBSDで必要なのは/etc/rcの編集です。ここで編集するのはunion mount する前のルートパーティションのファイルなので注意してください。編集する内容は、 mountを実行した後で、再度/etc/rc.confの読みこみを行なうということです。
FreeBSD 4.5-RELEASEの/etc/rcに対するpatchはこんな感じになります。


*** rc~ Mon Jan 28 22:13:17 2002
--- rc  Mon Feb 25 13:48:19 2002
***************
*** 213,218 ****
--- 213,226 ----
        ;;
  esac
  
+ # If there is a global system configuration file, suck it in.
+ #
+ if [ -r /etc/defaults/rc.conf ]; then
+       . /etc/defaults/rc.conf
+       source_rc_confs
+ elif [ -r /etc/rc.conf ]; then
+       . /etc/rc.conf
+ fi
  
  adjkerntz -i


これでとりあえずPICKLESっぽい(しかも/etcの管理についてはPICKLESより一歩 進んだ)FreeBSDができ上がります。

ここまでの内容を、インストール時の手順に照らし合わせておさらいします。

  1. 普通のfdisk partitionを作る
  2. disklabelを編集する。この時、以下のようにする。
  3. その後のインストールは普通に進める。
  4. インストール直後の状態では、アカウントの追加などはせずに、reboot。 ただし安全のため、rootのパスワードだけは設定しておいた方が良いかも しれない。
  5. /etc/rcを書き変えて、mount後に/etc/rc.confを再読み込みするようにする。
  6. mkdir /u/etcをする。
  7. /etc/fstabに、/u/etcを/etcにunion mountする行を追加する。
  8. 念のため、この後mount /etc; find /etcしておく。
  9. rebootする。
  10. あとはsysinstallで適当にやるなり、POPSをインストールするなりする。

システムディスクとユーザディスクの切り分け(中級編)

上記でそれっぽくはなりますが、実はまだ完全には分離できていません。なぜならば、 ユーザディスクのパーティション情報が、システムディスク側のfstabに書かれて いるからです。BSD/OS版PICKLESではまずユーザディスクのうちの/etc3の パーティションを検索し、その中のfstab.userdiskというファイルをユーザディスク のfstabとしていました。ここでもユーザディスクにfstab.userdiskを置く方法を 考えます。

問題になるのは、fstabを参照するプログラムで、これを 調べてみると、dump, dumpfs, fsck, fsdb, mount, quotacheck, rdump, swapon, tunefs, umountなどですが、libcに含まれるgetfsentなどの関数で fstabを参照しているので、根元的にはこれです。

やらないといけないのは、/etc/fstabを見に行こうとしたときに、/etc/fstabと /etc/fstab.userdiskという二つのファイルをマージした内容を参照してくれる ようにすることです。ルートパーティションの/etcには/u/etc/fstab.userdiskへの symbolic linkでfstab.userdiskを作って置きます。こうすることで、/etcの上に union mountされている状態でもされていない状態でもfstab.userdiskを正しく 参照できることになります。

これを実現するために、/usr/src/lib/libc/gen/fstab.cを修正します。 パッチはこれです。FreeBSD 4.6-RELEASE用のパッチ ですが、このソースは4.3BSDからほとんど変わっていないようなので、すべての FreeBSDに適用可能でしょう。/sbin/fsckや/sbin/mountなど起動時の処理に関って くるものはstatic linkされているので、libcのshared libraryを置き換えただけ では不充分で、必要なプログラムを再compileする必要があります。
(注: とりあえずmountコマンドでだけ動作確認しました)

次に作る必要があるのが checkuserdisk というプログラムで、こいつは ユーザディスクを探しだして、その中の/uに相当するパーティションを/uに mountするという処理をします。
BSD/OS版PICKLESでは同じ名前のプログラムがあって、こいつは/etc3を探して mountして、そのパーティションのデバイス名を返すプログラムでした。/etc3を /uに置き換えて、あとは同じ仕様で良いのではないかと思います。
ここで、整理しつつcheckuserdiskのやるべき処理を挙げると、以下のように なります。

checkuserdiskの結果が"false"だったら、systemdiskだけで起動するモードに 入ります。そうでなかったら、userdiskが存在して、/u/に相当するパーティションが mountされているものとして、普通にfsckとmountという風に処理を進めます。

BSD/OS版PICKLESでは、systemdiskとuserdiskのfsck, mountを別の処理でやって いたのですが、前述のような改造を加えたfsckとmountであれば、もっと楽に なります。ただし、/uをmountしてから/etcのunion mountを実行しなければならない ため、ここの部分を以下のどちらかの方法で行なう必要があります。

システムディスクとユーザディスクの切り分け(上級編)

ここまで述べただけでは、完全ではありません。上級編というか、残りの細かな 問題点をこまめに潰していく必要があります。
まず、systemdiskだけで立ち上げるモード の処理が抜けています。このための/etc/rcの改造などが更に必要になります。 また、本来userdiskにあるべきでありながら/usrの下にある情報が以外に残って います。例えば、 目指すは/usrはread onlyでmountすることです。しばらく使ってfindすれば、 使っているうちに更新されるファイルを発見できるでしょうから、これをどんどん userdiskに追い出す作業をしないといけません。

またパーティション構成などをPICKLES的にするために、インストーラの改善が 必要になります。

更にPICKLESにするためには、userdiskのupdate scriptなども作らないといけません。 ここらへんは手間の問題です。


Masahiko KIMOTO <kimoto@ohnolab.org>
Last modified: Sun Aug 4 18:36:28 2002