次のページ 前のページ 目次へ

6. ユーザランドの構築

ここでは,前節の busybox を軸にユーザランドを整えていきます.

ここでは,まず手作業で問題を解決してみて,自動化はその後,というアプローチでいってみたいと思います. というのは,説明の最初から自動化してしまうと「〜とういファイルに…という内容を」の羅列になってしまって,読んでてもつまんないかな,とも思うわけで.

6.1 proc ファイルシステム

まず,ps コマンド. 実行してみると,こんなエラーが出ます.


# ps
  PID  Uid     VmSize Stat Command
ps: Can't open /proc
# ls /
bin         dev         lost+found  sbin        usr
#

これは,proc ファイルシステムをマウントしてないためです. が,肝心のマウントポイントの /proc がありません. ならば,作ってあげましょう.

  1. ユーザランド作成元ツリーに /proc ディレクトリを作成
  2. コンパイルとインストール節の要領でブートフロッピーを再度作成

それでは,再度チャレンジ.

# mount -t proc proc /proc
# mount
/dev/ram0 on / type ext2 (ro)
/proc on /proc type proc (rw)
# ps
  PID  Uid     VmSize Stat Command
    1 0           236 S   init
    2 0               SW  [keventd]
    3 0               SWN [ksoftirqd_CPU0]
    4 0               SW  [kswapd]
    5 0               SW  [bdflush]
    6 0               SW  [kupdated]
    7 0               SW  [khubd]
   12 0           264 S   -sh
   13 0           236 S   init
   14 0           236 S   init
   15 0           236 S   init
   20 0           264 R   ps
#

最初の mount コマンドで proc ファイルシステムをマウントしています. 次のオプション無しの mount で,現在マウントしているファイルシステムの一覧を表示させています.

で,proc ファイルシステムがマウントされているので,ps コマンドを実行してみると…めでたくプロセス一覧を得ることができました.

6.2 ルートパーティションを書き込み可能に

何かファイルを作ってみようとすると,こんなエラーが出てしまいます.

# cat > hoge
-sh: cannot create hoge: Read-only file system
#

mount コマンドで確認してみると,ルートパーティションがリードオンリーでマウントされています.

# mount
/dev/ram0 on / type ext2 (ro)
/proc on /proc type proc (rw)
#

それでは,とリードライトモードで mount しようとしてみます. が,ルートパーティションは既にマウントされているため,こんなエラーが出てしまいます.

# mount -o rw /dev/ram0 /
mount: Mounting /dev/ram0 on / failed: Device or resource busy

それでは,と,ルートパーティションを umount してみてからだとどうなるか,というと…やはり同じ. ルートパーティションだけは umount してもリードオンリーでマウントされているのでこういうことになってしまうのです.

# umount /
# mount -o rw /dev/ram0 /
mount: Mounting /dev/ram0 on / failed: Device or resource busy

というわけで,正解はこちら.

# mount -o rw,remount /dev/ram0 /
# cat > hoge
hoge
#

ちゃんと書き込みできていますね.

6.3 初期化作業の自動化

では,ここらで今までの作業を自動化してみましょう.

mount コマンドの設定

まずは,/etc/fstab の設定. このファイルを作成すると,mount コマンドでマウント元のデバイスファイルを省略できたり,mount -a コマンドで,通常使うファイルシステムを一括してマウントすることができます.

内容としては,こんなところになります.

/dev/ram0       /       ext2    defaults        1 1
proc            /proc   proc    defaults        0 0

これを元に boot.img を作成し,起動してみます.

# mount
mount: /proc/mounts: No such file or directory
# mount -a
# mount
/dev/ram0 on / type ext2 (ro)
proc on /proc type proc (rw)
#

mount -a で,defaults のファイルシステムが…ありゃ. ルートパーティションがリードオンリーのままです. /etc/fstab に,remount,rw オプションを付け加えて,再度チャレンジ.

/dev/ram0       /       ext2    defaults,remount,rw     1 1
proc            /proc   proc    defaults                0 0

で,起動し,コマンドを実行してみると…今度はうまく行きました.

# mount
mount: /proc/mounts: No such file or directory
# mount -a
# mount
/dev/ram0 on / type ext2 (rw)
proc on /proc type proc (rw)
#

init の設定

さて,init プログラムには,「login プロンプトを表示(させるプロセスを起動)」「孤児プロセスの死に水を取る」という役割の他に,「起動時に初期化プログラムを起動する」という役割もあります. 起動プログラムの設定は /etc/inittab で行います.

が,ここで一つ注意. Linux で一般的な SysVinit と,busybox の init では,概念・動作が大きく異なります. このため,inittab の文法もかなり違います.

一番の違いは,busybox 版ではランレベルの概念が無いということです. ただし,「起動時」「運用時」「シャットダウン時」のような概念はあります. 「ランレベル」は SysVinit が作り出している概念で,それが busybox init で無い,ただそれだけのことです. 実際,小規模なシステムではランレベルなんてものが無くてもあまり困ること はないでしょう.

inittab の文法について詳しくは busybox のドキュメントを参照しましょう. すると,デフォルトでは

::sysinit:/etc/init.d/rcS
::askfirst:/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
::restart:/sbin/init
という動作をするそうです.

というわけで,とりあえず,この通りの内容を /etc/inittab/ に設定してみましょう.

そして,再起動してみると…全く変化がありません. 今のところはこれで正解.

6.4 date コマンドとタイムゾーン

さて,現在の環境で date コマンドを実行してみると

# date
Fri Jan 23 20:25:59 UTC 2004
と出てきます. タイムゾーンが UTC として動作してるようです.

「どのファイルがタイムゾーンを設定しているのだろう」ということで,母艦環境で strace コマンドを使って追跡してみます. strace というのは,そのプログラムが実行したシステムコール(カーネルの呼び出し)をダンプするプログラムです. 設定ファイルを参照していれば,open() システムコールが呼ばれるので,これでわかることになります.

(実は,この設定ファイルの読みだし部分は glibc の方に入っていて,busybox のプログラムをいくら眺めてもわからなかったりします)

strace ./busybox date
execve("./busybox", ["./busybox", "date"], [/* 37 vars */]) = 0
fcntl64(0, F_GETFD)                     = 0
fcntl64(1, F_GETFD)                     = 0
fcntl64(2, F_GETFD)                     = 0
uname({sys="Linux", node="JR0BAK-eden", ...}) = 0
geteuid32()                             = 500
getuid32()                              = 500
getegid32()                             = 100
getgid32()                              = 100
brk(0)                                  = 0x80f6000
brk(0x80f6020)                          = 0x80f6020
brk(0x80f7000)                          = 0x80f7000
time([1087047819])                      = 1087047819
open("/etc/localtime", O_RDONLY)        = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=73, ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
 0
read(3, "TZif\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\0\0\0\2\0"..., 4096) = 73
close(3)                                = 0
munmap(0x40000000, 4096)                = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 4), ...}) = 0
old_mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
 0
write(1, "Sat Jun 12 22:43:39 JST 2004\n", 29Sat Jun 12 22:43:39 JST 2004) = 29
munmap(0x40000000, 4096)                = 0
_exit(0)                                = ?

/etc/localtime というファイルですね.

というわけで,とりあえずはターゲット環境に /etc/localtime をコピーすれば ok です.

6.5 あとは…

必要な(お好きな)アプリケーションを環境に組み込むだけです. とはいえ,one floppy ではかなり制限はありますが.

とは言え,busybox 内に iptables コマンドはあるので,「フロッピー 1 枚で動くルータ」なんてのは簡単にできると思います. ただし,「メニューで設定をいじれるようにする」とか「どの機種でも動作するように」と考え出すとエライことになりますが…


次のページ 前のページ 目次へ