c - 编写我自己的 init 可执行文件

标签 c linux linux-kernel boot init

我想为下雪的周末创建自己的 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 

它与 trusty-server-cloudimg-amd64-disk1.img 一起工作得很好(如果你不介意卡在 cloud-init 上),然后我继续复制它并删除它的内容。

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

这是我神奇的初始化:

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 发生了内核 panic 。我通过将 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

所以我想它不应该依赖于任何其他东西。但是我做错了什么,为什么内核 panic ? (没有 printfs 的内核也会崩溃)

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

最佳答案

当您的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 连接到系统控制台。

关于c - 编写我自己的 init 可执行文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35245247/

相关文章:

c - 使用 while(1) 在我的简单代码中出现错误

c - OpenGL纹理无法绘制?

python - 通过 linux 发送格式化的 html 邮件

linux - 由关键字生成的密码

c - Linux 内核从 kzalloc 取消引用 memset 中的 NULL 指针

c - 在 linux 内核中添加了一个新的网络协议(protocol)

C - 通过引用传递已知大小的多维数组

c++ - 如何使用 CMake 添加编译器参数?

linux - 无法停止 Tomcat

c - "Unable to handle kernel NULL pointer dereference at Virtual Address."- 向内核模块发送信号 |哎呀