Разница в выполнении init со встроенными и внешними initramfs?


10

Я создаю очень минимальную систему Linux, которая состоит из ядра (v4.1-rc5) и initramfs, заполненных busybox (v1.23.2). По большей части он работает нормально, но я наблюдаю разницу в поведении выполнения команд в / init, использую ли я встроенный initramfs по сравнению с внешним.

Сценарий / 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_INITRAMFS_SOURCE в ядре .config в каталог, содержащий все папки для initramfs, либо запускаю

find . | cpio -H newc -o | gzip > ../rootfs.cpio.gz

построить это.

Когда я затем скомпилирую ядро ​​с набором CONFIG_INITRAMFS_SOURCE или без него, я получаю два варианта моей системы:

  1. bzImage со встроенными initramfs

  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) все работает нормально, отображается «Добро пожаловать», и я получаю подсказку. Однако с версией 1 (встроенные initramfs) я получаю предупреждение

unable to open an initial console

«Добро пожаловать» не отображается, и я получаю подсказку.

Насколько я понимаю, эти две версии initramfs должны содержать одинаковые файлы, так как я собираю их (или собираю ядро) из одинаковой папки.

Интересно, кто-нибудь может мне помочь с объяснением этого поведения?

* ОБНОВИТЬ *

Как сказал в комментариях mikeserv, ядро ​​включает минимальное количество встроенных initramfs по умолчанию. Это все еще присутствует при использовании внешнего, но перезаписывается, если вы вставляете свой собственный. Я обнаружил, что вопреки спецификации, он действительно не пустой, но содержит папку dev, корневую папку и устройство / dev / console. Это устройство затем используется при использовании внешних initramfs, но перезаписывается, если вы встраиваете свое собственное. Поэтому вы должны включить устройство / dev / console в исходный код initramfs mknod -m 622 initramfs_src/dev/console c 5 1при встраивании своего собственного.

Большое спасибо mikeserv, frostschutz и JdeBP за помощь в этом!


Какие разрешения включены /dev/consoleна вашем встроенном? Я думаю, что разница может заключаться в том, кто делает упаковку в двух случаях.
mikeserv

Аналогичный вопрос, конечно, stackoverflow.com/questions/10437995 .
JdeBP

@mikeserv консольное устройство имеет идентичные права доступа и владельца в обеих сборках.
CLW

@JdeBP Я не уверен, что это похоже, так как в обоих случаях я загружаюсь, получаю подсказку и получаю консольное устройство. Только то, что в одном init выполняет эхо, а в другом - нет.
CLW

1
Как могли разрешения быть одинаковыми в initramfs, если у вас их вообще не было?
mikeserv

Ответы:


2

Они действительно идентичны?

Встроенный, который вы можете найти /usr/src/linux/usr/initramfs_data.cpio.gzили извлечь из bzImage, как описано здесь: https://wiki.gentoo.org/wiki/Custom_Initramfs#Salvaging

Если вы используете этот встроенный и вместо этого используете его как внешний, он работает?

Если он все еще другой, само ядро ​​идентично? (сравните /proc/config.gzдля обоих)

Должна быть какая-то разница. Я не знаю, что ядру важно, откуда взялись initramfs. Я бы скорее заподозрил qemuиспользование разных настроек при передаче -initrdпараметра ...

С одной стороны, /initдля меня ты выглядишь как бесконечный снаряд. setsidне exec. Я ошибся?


1
Этот ответ, кажется, все вопросы.
JdeBP

1
@JdeBP: Вы не думаете о четвертом измерении!
frostschutz

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блоков до выхода из этой оболочки.
stefanjunker

@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

Также полезно знать, что путь инициализации предназначен /initдля initramfs, в отличие от /sbin/initдругих: что может заставить передачу init = / path / to / program в ядро ​​не запускать программу как init?

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.