/sbin/initの疑問(2)?


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のヘッダー情報がリンクの場合だけで、他で設定している箇所はありませんでした。ここでは、parse_header()で、collectedのヘッダー情報か各情報を取得し、そのmodeがリンクなら、state = Collectで次にデータを読み込んで、next_state = GotSymlinkで、それでもってdo_symlink()がコールされるということです。従って、cpio内にリンクとして/sbin/initが無いと、rootfs内にも/sbin/initは作成されないということなのですが・・・?
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;
}

static void __init parse_header(char *s)
{
       unsigned long parsed[12];
       char buf[9];
       int i;

       buf[8] = '\0';
       for (i = 0, s += 6; i < 12; i++, s += 8) {
               memcpy(buf, s, 8);
               parsed[i] = simple_strtoul(buf, NULL, 16);
       }
       ino = parsed[0];
       mode = parsed[1];
       uid = parsed[2];
       gid = parsed[3];
       nlink = parsed[4];
       body_len = parsed[6];
       major = parsed[7];
       minor = parsed[8];
       rdev = new_encode_dev(MKDEV(parsed[9], parsed[10]));
       name_len = parsed[11];
}


最終更新 2013/04/28 17:38:24 - north
(2013/04/27 18:25:35 作成)


検索

アクセス数
2534245
最近のコメント
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
Adsense
広告情報が設定されていません。