如何将参数传递给 Linux 内核 `init=` bootparam?

Bru*_*sky 7 kernel init linux-kernel

更新:

我已经成功地创建了一个非常简单的演示,使用init=bootparam 来指定应该使用自定义二进制文件(用 golang 编写并编译)来代替标准的 init。该项目中的二进制文件是为 Raspberry Pi 的 ARM 处理器编译的,但源代码应该为任何平台编译。


原帖:

我已经成功地放入init=/bin/bash了我的bootparams并在启动时获得了一个 root shell。现在我想使用 bootparams 来运行“首次启动”安装脚本。

笔记:

我知道可以提供很多替代方案。如果您愿意,请将这些作为对问题的评论。但是,我不能使用它们;这个问题与他们无关;它们不是这个问题的答案。所以,请不要发布替代方案作为答案。* 这对来这里问这个问题的人没有帮助。

我尝试过的失败的事情:

  • init="/bin/bash -c 'mount /dev/mmcblk0p1 /boot; date > /boot/test.txt'"
  • init='/bin/bash -c "mount /dev/mmcblk0p1 /boot; date > /boot/test.txt"'
  • init="/bin/bash"
  • init='/bin/bash'

所以我假设即使引用你的init=参数也不是一种选择。

  1. 如果我在这里错了,请纠正我。

我已阅读有关此事的 Linux 内核文档。它说:

内核将内核命令行中的参数解析为--; 如果它不能识别一个参数并且它不包含 a .,则该参数将传递给 init: 参数并=进入 init 的环境,其他参数作为命令行参数传递给 init。之后的所有内容都--作为参数传递给 init。

...

init=    [KNL]
         Format: <full_path>
         Run specified binary instead of /sbin/init as init
         process.
Run Code Online (Sandbox Code Playgroud)

学过的知识:

Format: <full_path>将解释为什么它不喜欢我在init=

我还阅读了BOOTPARAM(7)(搜索“传递给 init 进程”),他们说:

任何不被接受为上述设置函数的“foo=bar”形式然后被解释为要设置的环境变量。一个(无用的?)示例是使用 'TERM=vt100' 作为引导参数。

任何未被内核选取且未被解释为环境变量的剩余参数然后被传递到 PID 1,它通常是 init(1) 程序。传递给 init 进程的最常见参数是“single”这个词,它指示它以单用户模式启动计算机,而不是启动所有常用的守护进程。检查系统上安装的 init(1) 版本的手册页,看看它接受哪些参数。

  1. 是否有任何使用此信息将参数传递给自定义指定的工作示例init=

如果有,很难找到,这个问题将有助于让它出现在谷歌结果中。如果没有,我们将为社区创建一个工作示例。

Aus*_*arn 6

是的,这就是传统上告诉常规 init 系统要启动到什么状态的方式。如果您正在运行 sysv-init(或几乎任何除 systemd 以外的广泛使用的 init 系统),您可以在内核参数的末尾放置一个 1 到 5 之间的数字,它将引导到该运行级别(1 总是单用户模式,其他是系统定义的,3 或 4 是大多数 Linux 发行版通常使用的默认值)。如果您使用 systemd,您可以传递singleemergency在内核参数的末尾分别引导到这些模式。

然而,使用这种机制来传递任意参数有点困难,因为内核会进行绝对最少的解析,这尤其意味着:

  • 根本无法传递包含空格的参数,因为内核不解析带引号的字符串(即,'some string'被解析为两个参数'someand string')。
  • 您根本无法引用任何环境变量,因为内核不进行变量替换(通常由您运行命令的 shell 在它启动命令之前完成)。
  • 通常,参数必须在 POSIX C 语言环境(本质上是 US ASCII)下可以正确解释,除非您想使用 base64 或 punycode 之类的东西,否则这会将国际化排除在外。
  • 内核参数中可以传递多少数据有一个上限,但我忘记了它是什么。

这些限制加在一起就是为什么你在谷歌上找不到任何关于做这种类型的事情的东西,没有一个头脑清醒的系统集成工程师会这样做,因为解决上述限制比仅仅编写一个脚本要付出更多的努力包含所有必需的参数并调用它。

  • 如果你尝试 `init=/test.sh`,那么当你执行 `/test.sh` 时,真正的根文件系统要么尚未挂载,要么你没有使用 `initramfs` (或 `initrd` ),它很可能以只读方式安装。因此,您的“/test.txt”要么不会被写入(因为只读文件系统),要么被写入“initramfs”的非持久RAM映像,当系统切换到真实系统时,该映像将从内存中删除根文件系统。 (2认同)

小智 5

用于--将内核参数与 init 参数分开

内核从内核命令行解析参数到“ --”;如果它无法识别参数并且不包含“.”,则该参数将传递给 init:带有“=”的参数进入 init 的环境,其他参数作为命令行参数传递给 init。“ --”之后的所有内容都作为参数传递给 init。

  • 啊酷,这个(自 2014 年 v3.15“Shuffling Zombie Juror”起可用)效果出奇的好..允许疯狂的东西,比如测试不同的预读值,而无需重建我们的 https://schulstick.org/ 图像.. `init= /bin/sh -- -c "echo '将 ?da 的 read_head_kb 设置为 2048'; 对于 /sys/block/?da/queue/read_ahead_kb 中的 RA; do echo \$RA; cat \$RA; echo 2048 &gt; \ $RA; cat \$RA; done; lsmod|sort; exec /sbin/init` ($variables 中的&符号必须转义,以免被 grub 解析吃掉) (2认同)