/sbin/initの疑問(2)?
Rev.1を表示中。最新版はこちら。
unpack_to_rootfs()からwrite_buffer()をコールすることで、cpioフォーマットをrootfs下に展開していくのですが、cpioはtarと違って、それぞれのファイル毎に管理情報が配置しているのだそうです。其れゆえの実装なのだろうと、思いますが、我々のレベルから見ると、でも何でこんなマドロッコシイ実装しての? ってちょっと疑問に思ってしまう程です。actions配列にコールバックを設定し、state変数に設定したインデックス()で、順次actions[]()をコールする事で展開します。unpack_to_rootfs()からstate=Startでwrite_buffer()がコールされ、スタティックのcountにサイズ、victimに読み込みファイル位置が設定されます。(で、なんぜvictimなの?) で、actions[state]()がnot 0まで、コールバックをコールし続けます。なお各コールバック関数において、次にコールバック関数として、stateにenum stateのどれかが設定されていくという按配です。
static __initdata int (*actions[])(void) = {
[Start] = do_start,
[Collect] = do_collect,
[GotHeader] = do_header,
[SkipIt] = do_skip,
[GotName] = do_name,
[CopyFile] = do_copy,
[GotSymlink] = do_symlink,
[Reset] = do_reset,
};
static __initdata enum state {
Start,
Collect,
GotHeader,
SkipIt,
GotName,
CopyFile,
GotSymlink,
Reset
} state, next_state;
static int __init write_buffer(char *buf, unsigned len)
{
count = len;
victim = buf;
while (!actions[state]())
;
return len - count;
}
最初にコールされる関数が、do_start()です。read_into()でファイルサイズが110以上なら、引数のnextのstate = GotHeaderで、そうでないならstate = Collectとして、次のコールバック関数が設定されます。なお、変数next_stateはCollectコールバック関数の次にコールされるコールバック関数となります。こんな感じで、(*actions[])(void)を順繰りに呼び出すことで、rootfsにイメージを複写しています。
static int __init do_start(void)
{
read_into(header_buf, 110, GotHeader);
return 0;
}
static void __init read_into(char *buf, unsigned size, enum state next)
{
if (count >= size) {
collected = victim;
eat(size);
state = next;
} else {
collect = collected = buf;
remains = size;
next_state = next;
state = Collect;
}
}
で、/initが/sbin/initにリンクされているかな。との思いで、do_symlink()は以下の通りで、collectedの名前のリンクをsys_symlink()で作成し、uid/gidを設定しているだけです。
static int __init do_symlink(void)
{
collected[N_ALIGN(name_len) + body_len] = '\0';
sys_symlink(collected + N_ALIGN(name_len), collected);
sys_lchown(collected, uid, gid);
state = SkipIt;
next_state = Start;
return 0;
}
なお、stateにGotSymlinkを設定しているのは、do_header()内で、cpioのヘッダー情報がリンクの場合だけで、他で設定している箇所はありませんでした。
static int __init do_header(void)
{
if (memcmp(collected, "070701", 6)) {
error("no cpio magic");
return 1;
}
parse_header(collected);
next_header = this_header + N_ALIGN(name_len) + body_len;
next_header = (next_header + 3) & ~3;
if (dry_run) {
read_into(name_buf, N_ALIGN(name_len), GotName);
return 0;
}
state = SkipIt;
if (name_len <= 0 || name_len > PATH_MAX)
return 0;
if (S_ISLNK(mode)) {
if (body_len > PATH_MAX)
return 0;
collect = collected = symlink_buf;
remains = N_ALIGN(name_len) + body_len;
next_state = GotSymlink;
state = Collect;
return 0;
}
if (S_ISREG(mode) || !body_len)
read_into(name_buf, N_ALIGN(name_len), GotName);
return 0;
}





