/sbin の謎 〜/usr マウント前のシンプルコマンド群〜 |
||
SunOS 4.1.4 | YAMAMORI Takenori |
SunOS 4.1.4 の /sbin には、次のように 7つのコマンドのみが存在します。
$ ls /sbin hostconfig ifconfig intr sh hostname init mount |
OSのブート時、これらのコマンドが実行される段階では、まだ /usr はマウントされていません。したがって、libc.so.* もまだ使用できず、/sbin のコマンドはすべて静的リンクされたバイナリです。
そもそもの UNIX のディレクトリ構成は、/bin や /usr/bin に基本コマンドがあり、/etc や /usr/etc にシステム管理用コマンドがあるという感じでした。この時点では /sbin はまだありませんでした。
その後、SunOS 4.1.4 や Solaris 2.x/7/8/9 系では、/bin と /usr/bin が統合されて /bin は単なる /usr/bin へのシンボリックリンクとなりました。同様に /lib も統合されて、ディレクトリごと /usr/lib へのシンボリックリンクです。また、 /etc についても、ここにはバイナリの実行ファイルは直接置かないことになり、例えば /etc/mount などのバイナリが個別に /usr/etc 以下へのシンボリックリンクになりました。 (Solaris 2.x/7/8/9 系では /usr/etc は /usr/sbin と改名されました)
/usr 以下の各ディレクトリは、同じOSのマシン間で全く共通のものであり、 ディスクレスやデータレスのクライアントは /usr をNFS で(リードオンリーで)マウントして共有します。 また、スタンドアロン(ローカルディスク)のマシンであっても、/usr は通常、/ とは別パーティションにします。
なるべく多くのファイルを共有し、ハードディスクの使用効率をよくするためには、なるべく多くのディレクトリやファイルを、共有可能な /usr ディレクトリ以下に配置することが望まれます。/bin と /usr/bin の統合、/lib と /usr/lib の統合、/etc の一部のファイルの個別の /usr/etc へのシンボリックリンクが行なわれたのはこのためと考えられます。
さて、ここでシステムのブート時の問題を考える必要があります。
ブート時に、カーネルは、/ を自らマウントします。問題はそのあとです。init を実行し、/usr をマウントするまでの処理を、/usr 以下の存在しない、/ だけ(/etc はある)の環境で行なわなければならないのです。
以前のシステムでは、/etc に init や mount があり、また、/bin が /usr/bin とは別に存在していたため、これら /etc と /bin とに存在するコマンドだけを使って rc スクリプトを実行し、/usr をマウントすることができました。
ところが、SunOS 4.1.4 などでは /usr のマウント前には、 /bin すら使えず、また、/etc には実行バイナリの実体はありません。
そこで、/usr マウント前にどうしても必要な、 本当に必要最小限のコマンドのみを置くためのディレクトリとして、/sbin が作られたのです。
/sbin に置かれるコマンドは、本当に必要最小限のものです。 /sbin に置く必要の無いコマンドは、すべて /usr 以下の /usr/bin や /usr/etc(/usr/sbin)に置いて NFS で共有するという発想です。
また、/sbin に置かれているコマンドも、それ自体のバイナリは共有可能であり、ただ、/usr のマウント前に必要なために /sbin に置いているに過ぎません。このため、ディスクレスクライアント用の /sbin については、その NFS サーバ上では、複数のディスクレスクライアント用の /sbin 以下の各コマンドをハードリンクして、バイナリ実体を共有するのが普通です。
また、前述の通り /lib も /usr/lib に統合されたため、/sbin にあるコマンドは、libc.so.* を含む、一切の共有ライブラリを使用できず、static link されたバイナリでなければなりません。static link のバイナリは、サイズが大きくなるため、あまり多くのコマンドを置くべきではありません。この意味でも、/sbin に置くバイナリは、必要最小限に厳選しなければなりません。
SunOS 4.1.4 の /sbin に置かれている7つのコマンドを、それらが本当に必要かどうかここで吟味してみましょう。
以上、7つのコマンドのどれもが必然性を持って置かれていることがわかります。
SunOS 4.1.4 では、例えば /etc/hostname.le0 というファイルの中に自分のホスト名を書いておき、/etc/rc.boot の中で、概念的には、
hostname `cat /etc/hostname.le0`を実行することによって、ホスト名を設定します。
このため、単純な発想では 「cat コマンドも必要」ということになってします。しかし、cat を /sbin に置いてしまっては、美しさが失われます。そこで、/etc/rc.boot では、shcat() というシェル関数を定義して、これに cat の代わりをさせているのです。
/usr をマウントするには、その前に fsck しなければなりません。しかし、その fsck コマンドは /usr の下にあります。どうすればいいのでしょうか。その答えは、/usr をまず Read Only でマウントし、その状態で /usr を fsck し、(実際には、多くの場合 clean チェックのみとなりすぐ終る)そこで再度 /usr を Read/Write でマウントするという方法を用いています。
トリッキーな感じがしますが、考えてみれば / ファイルシステム自体、カーネルがまず Read Only でマウントし、それを fsck のあと Read/Write で remount しているのと同じことであるため、なるほどという感じです。
/sbin は /usr をマウントする前だけに必要なものであり、/sbin にある7つのコマンドはすべて、同じ名前のコマンドが /usr 以下にもあります。(というか、/usr 以下にあるものが本来のコマンドで、インストール時にその一部が /sbin にコピーされているのです)
7つのコマンドのうち、以下の5つは同じコマンドが /usr/etc にあります。
hostconfig ifconfig init intr mount
なお、これらは、/usr/kvm/boot にもあります。(カーネルアーキテクチャに依存しないこれらのコマンドが、kvm にあるというのも、また別の謎です)
sh はもちろん /usr/bin(=/bin) に同じものがあります。
(ここで、JLE版の場合は /usr/bin/sh が
JLE版の sh で置き換えられていることがわかります)
また、/usr/kvm/stand にも sh があります。
最後に、hostname は、/usr/bin(=/bin) に同じものがあります。
というわけで、/sbin に置かれているコマンドと同名のコマンドをブート後に実行する場合、/sbin のコマンドは使われません。この事実からも、/sbin はあくまで /usr をマウントする前に使うためだけのものという、徹底したポリシーを感じます。
なお、正確には、ブート時に /etc/rc や /etc/rc.local に処理が移った段階で、すでに /sbin は使われなくなります。/etc/rc.boot や /etc/rc.single では、PATH に /sbin が含まれていますが、/etc/rc や /etc/rc.local では、/sbin が PATH から外されているのがわかると思います。
このため、たとえば ifconfig コマンドに注目してみると、/etc/rc.boot の中で実行される ifconfig は、/sbin/ifconfig であるのに対し、/etc/rc.local の中で実行される ifconfig は、/usr/etc/ifconfig になります。
このような厳格なポリシーを持つ /sbin ですが、その後はどうなったでしょうか。
Solaris 2.x/7/8/9 系では、/sbin に置かれるファイルは SunOS 4.1.4 よりもかなり増えました。/sbin には、static link のバイナリしか置かないはずでしたが、Solaris 2.x/7/8/9 系では、なんと dynamic link のバイナリまで置かれています。/usr がないのにどことリンクしているかというと、/etc/lib 以下に、一部の共有ライブラリを持ってしまっています。libc.so.* こそないものの、これはかなり苦肉の索の感があり、美しさが失われていると言えます。
では、Free系 UNIXの、Linux や NetBSD/OpenBSD/FreeBSD ではどうでしょうか。こちらは /sbin 以前に、依然として /bin と /usr/bin は別で、/lib と /usr/lib も別です。そして、/sbin には、fsck などを含むいろいろな管理コマンドが多数、べたべたと置かれています。SunOS とは違って、/sbin に存在するコマンドは /sbin 以外のディレクトリにはありません。このため、ブート後も /sbin が必要です。
このあたりで、すでに考え方が違っていて、おそらく、「/sbin はシステム管理のための重要な基本コマンド」 というふうに考えられているのだと思います。
しかし、本来の SunOS での /sbin の考え方に立ち戻り、システムとしての美しさも考えるべきだと思います。