编写自己的init可执行文件

5

我想在一个雪天里创造自己的init和一些有趣的Linux。我知道,内核在加载一些驱动程序和挂载磁盘后,使用rootfs引导,并将流程传递给/sbin/init。我下载了Ubuntu云镜像,并尝试直接使用kvm进行内核引导:

kvm -m 1G -nographic -kernel vmlinuz-3.19.0-32-generic -initrd initrd.img-3.19.0-32-generic -append "console=ttyS0 root=/dev/sda1 rw init=/myinit" -hda mydisk.img 

如果你不介意在cloud-init处停顿,那么它与trusty-server-cloudimg-amd64-disk1.img相配合工作得还算不错,然后我继续复制它并删除了它的内容。

modprobe nbd
qemu-nbd -c /dev/nbd0 mydisk.img 
fdisk -l /dev/nbd0 # confirm partition
mount /dev/nbd0p1 disk/
# Delete all files with myinit.c and myinit

这里是我的神奇init:

int main(){
    printf("Welcome to my kernel\n");
    printf("Welcome to my kernel\n");
    printf("Welcome to my kernel\n");
    while(1);
}

我使用gcc -static myinit.c -o myinit进行编译。但是由于我的init的问题导致了内核恐慌。我通过将myinit重命名为myinit2并验证无法找到它而没有崩溃来验证这一点。我知道编写init不可能像上面那么简单,但需要哪些步骤呢?我正在阅读upstart源代码。

Begin: Mounting root file system ... Begin: Running /scripts/local-top ... done.
Begin: Running /scripts/local-premount ... [    1.460164] tsc: Refined TSC clocksource calibration: 2394.558 MHz
[    1.866560] input: ImExPS/2 Generic Explorer Mouse as /devices/platform/i8042/serio1/input/input3
done.
[    6.251763] EXT4-fs (sda1): recovery complete
[    6.253623] EXT4-fs (sda1): mounted filesystem with ordered data mode. Opts: (null)
Begin: Running /scripts/local-bottom ... done.
done.
Begin: Running /scripts/init-bottom ... mount: mounting /dev on /root/dev failed: No such file or directory
done.
mount: mounting /sys on /root/sys failed: No such file or directory
mount: mounting /proc on /root/proc failed: No such file or directory
[    6.299404] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000200
[    6.299404] 
[    6.300013] CPU: 0 PID: 1 Comm: init Not tainted 3.19.0-32-generic #37~14.04.1-Ubuntu
[    6.300013] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
[    6.300013]  ffff88003c118700 ffff88003dee7e38 ffffffff817af41b 00000000000017d6
[    6.300013]  ffffffff81a90be8 ffff88003dee7eb8 ffffffff817a925b ffff88003dee8000
[    6.300013]  ffffffff00000010 ffff88003dee7ec8 ffff88003dee7e68 ffffffff81c5ee20
[    6.300013] Call Trace:
[    6.300013]  [<ffffffff817af41b>] dump_stack+0x45/0x57
[    6.300013]  [<ffffffff817a925b>] panic+0xc1/0x1f5
[    6.300013]  [<ffffffff81077b01>] do_exit+0xa11/0xb00
[    6.300013]  [<ffffffff811ec53c>] ? vfs_write+0x15c/0x1f0
[    6.300013]  [<ffffffff81077c7f>] do_group_exit+0x3f/0xa0
[    6.300013]  [<ffffffff81077cf4>] SyS_exit_group+0x14/0x20
[    6.300013]  [<ffffffff817b6dcd>] system_call_fastpath+0x16/0x1b
[    6.300013] Kernel Offset: 0x0 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
[    6.300013] drm_kms_helper: panic occurred, switching back to text console
[    6.300013] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000200
[    6.300013] 

我知道myinit完全是静态的:

# ldd disk/myinit
    not a dynamic executable

我猜应该不依赖其他东西,但是我做错了什么,为什么内核会崩溃?(即使没有printfs也会出现内核崩溃)

我在阅读sysvinit源代码(它应该比upstart、systemd和openrc更简单),但它太长了,但init的主要思想是拥有进程,并且它也在while(1)循环中休息。


2
展示你自己实现的 printf(好吧 - 你说过你没有外部依赖并且是完全静态的) - too honest for this site
1
你的编译器优化掉了 while(1);,因为它具有未定义的行为? - Kerrek SB
1
首先,您的stdin/stdout可能未连接。通常会将/dev/console打开为fd 0、1和2。否则,您的printf可能不可见。(但是:“mount: mounting /dev on /root/dev failed: No such file or directory” - 听起来也有问题)。 - davmac
你认为 sleep 函数是在哪里实现的?(在我们遍历所有其他 glibc 函数之前,请先思考一下) - too honest for this site
1
这些printf应该优化为puts或write(1, combined_string,sizeof(combined_string)); ... write仅是系统调用。尝试向while循环添加sleep并设置init = / pathtoyour / init在initramfs中。 - technosaurus
显示剩余5条评论
1个回答

6

在启动init程序时,您的stdinstdoutstderr可能没有连接。通常在init程序开始时会看到类似以下序列:

    int onefd = open("/dev/console", O_RDONLY, 0);
    dup2(onefd, 0); // stdin
    int twofd = open("/dev/console", O_RDWR, 0);
    dup2(twofd, 1); // stdout
    dup2(twofd, 2); // stderr

    if (onefd > 2) close(onefd);
    if (twofd > 2) close(twofd);

这确保了stdinstdoutstderr与系统控制台连接。

如果不采取这些步骤,是什么决定它是否连接? - Ciro Santilli OurBigBook.com
1
使用预制的静态/dev,其中包含控制台、标准输入、标准输出和标准错误,或将dev挂载为devtmpfs也可以。 - technosaurus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接