init 进程可以是 Linux 中的 shell 脚本吗?

The*_*eer 16 linux init-script init

我正在阅读有关设置自定义 initramfs教程,其中指出:

唯一缺少的是 /init,它是 initramfs 根目录中的可执行文件,一旦加载内核就会执行。因为 sys-apps/busybox 包含一个功能齐全的 shell,这意味着您可以将 /init 二进制文件编写为一个简单的 shell 脚本(而不是使它成为一个必须编译的用汇编程序或 C 编写的复杂应用程序)。

并给出了一个以 init 开头的 shell 脚本示例 #!/bin/busybox sh

到目前为止,我的印象是 init 是启动的主进程,所有其他用户空间进程最终都是 init 的子进程。但是,在给定的示例中,第一个进程实际上是bin/busybox/ sh从中产生后来的 init 的。

这是正确的解释吗?例如,如果我当时有一个可用的解释器,我可以将 init 编写为 Python 脚本等吗?

fro*_*utz 14

init 不是“生成”的(作为子进程),而是exec像这样:

# Boot the real thing.
exec switch_root /mnt/root /sbin/init
Run Code Online (Sandbox Code Playgroud)

exec将整个过程替换到位。最后的 init 仍然是第一个进程(pid 1),即使它在 Initramfs 之前。

Initramfs /init,这是一个带有pid 1的Busybox shell脚本,execs到Busybox switch_root(所以现在switch_root是pid 1);该程序会更改您的挂载点,因此/mnt/root新的/.

switch_root然后再次exec访问/sbin/init您真正的根文件系统;因此,它使您真正的 init 系统成为第一个 pid 为 1 的进程,这反过来可能会产生任意数量的子进程。

当然,如果您以某种方式设法将 Python 烘焙到您的 Initramfs 中,它也可以用 Python 脚本完成。尽管如果您无论如何不打算包含 busybox,您将不得不煞费苦心地重新实现它的一些功能(例如switch_root,以及您通常使用简单命令执行的所有其他操作)。

但是,它不适用于不允许脚本二进制文件 ( CONFIG_BINFMT_SCRIPT=y) 的内核,或者在这种情况下,您必须直接启动解释器并使其以某种方式加载您的脚本。

  • 正如[你链接的文档](https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt):*但initramfs是rootfs:你既不能pivot_root rootfs,也不能卸载它. 而是删除 rootfs 中的所有内容以释放空间(`find -xdev / -exec rm '{}' ';'`),使用新根目录重载 rootfs(`cd /newmount; mount --move . /; chroot .`),将 stdin/stdout/stderr 附加到新的 /dev/console,然后执行新的 init.* (2认同)

Cir*_*郝海东 6

Linux 内核的 exec 系统调用本机理解 shebangs

当执行的文件以魔法字节开始时#!,它们告诉内核使用#!/bin/sh

  • 做和exec系统调用
  • 带有可执行文件 /bin/sh
  • 并使用 CLI 参数:当前脚本的路径

这与运行常规用户空间 shell 脚本时发生的情况完全相同:

./myscript.sh
Run Code Online (Sandbox Code Playgroud)

如果文件以魔法字节.ELF而不是开头#!,内核将选择 ELF 加载器来运行它。

更多细节在:为什么人们在 Python 脚本的第一行写 #!/usr/bin/env python shebang?| 堆栈溢出

一旦你记住了这一点,就很容易接受/init内核可以执行的任何东西,包括 shell 脚本,以及为什么/bin/sh在这种情况下将成为第一个可执行文件。

对于那些想要尝试的人,这是一个最小的可运行示例:https : //github.com/cirosantilli/linux-kernel-module-cheat/tree/cbea7cc02c868711109ae1a261d01fd0473eea0b#custom-init