でびあんの initrd (13)

klibc-utils パケジに run-init があります。ソースをチェキ。
ありかは usr/kinit/run-init/ 配下な模様。Kbuild というファイルがあるんですがちょっと意味不明。最近 Makefile を追い掛けるナニが多いんですが規模がでかくなればなるほど微妙になる傾向があるんでしょうか。
# とはいえ、kernel のソレは分かりやすい

とりあえず

main() 関数はざっくり以下なカンジ。

  • 引数のパースと退避
  • run-init() 関数の呼び出し
    • この関数は失敗したら戻ります
  • 戻った場合のエラー処理

main() から呼び出される run-init() 関数の目視確認なソレをざっくり以下に。
# それぞれ異常検知で return してます

  • カレントディレクトリを realroot (引数) に変更
  • "/" と "." の stat 取得
    • stat って正常だったら 0 を戻す、というナニが微妙
  • "/" と "." のデバイス ID が同じかどうかを確認
  • "/init" の stat 取得して通常ファイルかどうかを確認
  • / の statfs 取得
  • / の f_type 属性が RAMFS とか TMPFS のどちらかである事を確認
  • / を nuke_dir
  • カレントディレクトリを / として mount
  • chroot してカレントディレクトリを "/" に
  • /dev/console を O_RDWR で open
  • 0, 1, 2 で dup2 して /dev/console は close
  • init を execv で kick

CentOS で動いたのは 2 な関数使ってるからなのかな。run_init() 関数が以下。

const char *run_init(const char *realroot, const char *console,
		     const char *init, char **initargs)
{
	struct stat rst, cst, ist;
	struct statfs sfs;
	int confd;

	/* First, change to the new root directory */
	if (chdir(realroot))
		return "chdir to new root";

	/* This is a potentially highly destructive program.  Take some
	   extra precautions. */

	/* Make sure the current directory is not on the same filesystem
	   as the root directory */
	if (stat("/", &rst) || stat(".", &cst))
		return "stat";

	if (rst.st_dev == cst.st_dev)
		return "current directory on the same filesystem as the root";

	/* The initramfs should have /init */
	if (stat("/init", &ist) || !S_ISREG(ist.st_mode))
		return "can't find /init on initramfs";

	/* Make sure we're on a ramfs */
	if (statfs("/", &sfs))
		return "statfs /";
	if (sfs.f_type != RAMFS_MAGIC && sfs.f_type != TMPFS_MAGIC)
		return "rootfs not a ramfs or tmpfs";

	/* Okay, I think we should be safe... */

	/* Delete rootfs contents */
	if (nuke_dir("/"))
		return "nuking initramfs contents";

	/* Overmount the root */
	if (mount(".", "/", NULL, MS_MOVE, NULL))
		return "overmounting root";

	/* chroot, chdir */
	if (chroot(".") || chdir("/"))
		return "chroot";

	/* Open /dev/console */
	if ((confd = open(console, O_RDWR)) < 0)
		return "opening console";
	dup2(confd, 0);
	dup2(confd, 1);
	dup2(confd, 2);
	close(confd);

	/* Spawn init */
	execv(init, initargs);
	return init;		/* Failed to spawn init */
}

2 な関数ばっかり、とは言え klibc パケジにて同梱されてないと駄目なのか。initrd の中にある lib ディレクトリには klibc な shared objects があります。