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

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

我正在经历一个设置自定义 initramfs 的教程其中指出:

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

并给出了 init 作为 shell 脚本的示例,其开头为#!/bin/busybox sh

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

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

答案1

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

# Boot the real thing.
exec switch_root /mnt/root /sbin/init

exec替换整个流程。最终的 init 仍然是第一个进程 (pid 1),尽管它之前是 Initramfs 中的进程。

Initramfs/init是一个 Busybox shell 脚本,pid 为 1,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) 的内核,或者在这种情况下,您必须直接启动解释器并使其以某种方式加载您的脚本。

答案2

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

当执行的文件以 magic bytes 开头时#!,它们告诉内核使用#!/bin/sh

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

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

./myscript.sh

如果文件以 magic bytes.ELF而不是开头#!,内核将选择 ELF 加载程序来运行它。

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

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

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

相关内容