我正在构建一个非常小的 Linux 系统,仅由内核 (v4.1-rc5) 和填充了 busybox (v1.23.2) 的 initramfs 组成。它在大多数情况下工作正常,但我观察到无论我使用嵌入式 initramfs 还是外部 initramfs,/init 中命令执行的行为都有所不同。
/init 脚本是:
#!/bin/sh
dmesg -n 1
mount -t devtmpfs none /dev
mount -t sysfs none /sys
mount -t proc none /proc
echo "Welcome"
while true
do
setsid cttyhack /bin/sh
done
然后我要么将内核 .config 中的 CONFIG_INITRAMFS_SOURCE 选项设置为包含 initramfs 的所有文件夹的目录,要么运行
find . | cpio -H newc -o | gzip > ../rootfs.cpio.gz
来建造它。
然后,当我编译内核时,无论是否设置了 CONFIG_INITRAMFS_SOURCE,我最终都会得到系统的两个变体:
嵌入 initramfs 的 bzImage
bzImage + rootfs.cpio.gz(外部initramfs)
当我现在开始使用那些qemu
qemu-system-x86_64 -enable-kvm -kernel bzImage
或者
qemu-system-x86_64 -enable-kvm -kernel bzImage -initrd rootfs.cpio.gz
我得到以下行为差异:
使用版本 2(外部 initramfs)一切正常,显示“欢迎”并且我收到提示。然而,对于版本 1(嵌入式 initramfs),我收到警告
unable to open an initial console
未显示“欢迎”,但我收到提示。
据我了解该过程,这两个版本的 initramfs 应该包含相同的文件,因为我从相同的文件夹构建它(或让内核构建它)。
我想知道是否有人可以帮我解释这种行为?
* 更新 *
正如 mikeserv 在评论中所说,内核默认包含一个最小的嵌入式 initramfs。当使用外部时,它仍然存在,但如果您嵌入自己的,则会被覆盖。我发现与规范相反,这确实不是空的,而是包含一个 dev 文件夹、一个根文件夹和 /dev/console 设备。然后,当使用外部 initramfs 时会使用该设备,但如果您嵌入自己的设备,则会被覆盖。因此,mknod -m 622 initramfs_src/dev/console c 5 1
在嵌入您自己的设备时,您必须在 initramfs 源中包含 /dev/console 设备。
非常感谢 mikeserv、frostschutz 和 JdeBP 帮助我解决这个问题!
答案1
它们真的一模一样吗?
您可以在 bzImage 中找到或从 bzImage 中提取内置的图像/usr/src/linux/usr/initramfs_data.cpio.gz
,如下所述:https://wiki.gentoo.org/wiki/Custom_Initramfs#Salvaging
如果您使用内置的并将其用作外部的,它可以工作吗?
如果仍然不同,内核本身是否相同? (/proc/config.gz
两者比较)
应该有一些区别。我不知道内核关心 initramfs 来自哪里。我宁愿怀疑qemu
在传递参数时使用不同的设置-initrd
......
顺便说一句,/init
对我来说,你看起来就像是在产卵无限的贝壳。setsid
不是exec
。我错了吗?
答案2
您可能还对 Buildroot 2018.02 如何处理这个问题感兴趣。
每当您使用 initramfs ( BR2_TARGET_ROOTFS_INITRAMFS=y
) 或 initrd ( BR2_TARGET_ROOTFS_CPIO=n
) 时,它都会将以下内容添加/init
到您的 rootfs 中https://github.com/buildroot/buildroot/blob/2018.02/fs/cpio/init
#!/bin/sh
# devtmpfs does not get automounted for initramfs
/bin/mount -t devtmpfs devtmpfs /dev
exec 0</dev/console
exec 1>/dev/console
exec 2>/dev/console
exec /sbin/init "$@"
副本是由https://github.com/buildroot/buildroot/blob/2018.02/fs/cpio/cpio.mk:
# devtmpfs does not get automounted when initramfs is used.
# Add a pre-init script to mount it before running init
define ROOTFS_CPIO_ADD_INIT
if [ ! -e $(TARGET_DIR)/init ]; then \
$(INSTALL) -m 0755 fs/cpio/init $(TARGET_DIR)/init; \
fi
endef
了解 init 路径/init
用于 initramfs 也很有用,与/sbin/init
其他情况不同:什么会导致将 init=/path/to/program 传递给内核而不是像 init 一样启动程序?