与嵌入式和外部initramfs一起执行init的区别?


10

我正在构建一个非常小的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,编译内核时,最终都会遇到系统的两个变体:

  1. 嵌入了initramfs的bzImage

  2. 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),一切正常,显示“ Welcome”,并且出现提示。但是,对于版本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帮助我解决了这个问题!


/dev/console内置的权限设置为什么?我认为这可能与在两种情况下由谁负责打包有关。
mikeserv

当然,类似的问题是stackoverflow.com/questions/10437995
JdeBP 2015年

在两个版本中,@ mikeserv控制台设备具有相同的权限和所有权。
clw

@JdeBP我不确定它是否类似,因为在两种情况下我都启动,得到提示并具有控制台设备。仅在一个init中执行回显,而在另一个init中则不执行。
clw

1
如果您根本没有权限,initramfs中的权限怎么可能一样?
mikeserv

Answers:


2

他们真的一样吗?

您可以在/usr/src/linux/usr/initramfs_data.cpio.gzbzImage中找到或从中提取内置的内容,如此处所述:https : //wiki.gentoo.org/wiki/Custom_Initramfs#Salvaging

如果您使用该内置组件并将其用作外部组件,那么它是否有效?

如果仍然不同,内核本身是否相同?(/proc/config.gz两者比较)

应该有一些区别。我不知道内核关心initramfs的来源。我会很快怀疑qemu在传递-initrd参数时会使用其他设置...

在旁注中,您/init看起来对我来说像是它产生了无数的贝壳。setsid不是exec。我错了吗?


1
这个答案似乎是所有问题。
JdeBP 2015年

1
@JdeBP:您不是在三维思维!
弗罗斯特斯2015年

1
@frostschutz非常感谢您的回复!当我将内核构建的initramfs(usr / initramfs_data.cpio.gz)用作外部内核时,它也可以正常工作!另外,当我将使用嵌入式initramfs编译的内核提供给外部内核时,即使外部内核应覆盖嵌入式(kernel.org/doc/Documentation/filesystems/…),也会出现警告。因此它也可能不是qemu -initrd,而是内核本身中的某个东西。我什么都没改变,然后CONFIG_INITRAMFS_SOURCE ..
clw

@frostschutz回答On a sidenote, your /init looks like its spawning infinite shells to me. setsid is not exec. Am I wrong?:循环模仿了getty或类似的工具,因为调用会sh阻塞直到该shell退出。
stefanjunker '18

@stefanjunker,那很好,除非setsid根本不会阻止...
frostschutz

1

您可能还对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

知道/initinitramfs 的init路径也很有用,这与/sbin/init其他情况不同:是什么可以使将init = / path / to / program传递给内核而不是像init那样启动程序?

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.