Unterschied in der Ausführung von init mit eingebetteten vs. externen initramfs?

10

Ich baue ein sehr minimales Linux-System, das nur aus dem Kernel (v4.1-rc5) und einem mit Busybox (v1.23.2) bestückten Initramfs besteht. Es funktioniert größtenteils einwandfrei, aber ich beobachte einen Unterschied im Verhalten der Befehlsausführung in / init, unabhängig davon, ob ich ein eingebettetes initramfs oder ein externes verwende.

Das / init-Skript lautet:

#!/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

Dann setze ich entweder die Option CONFIG_INITRAMFS_SOURCE im Kernel .config auf das Verzeichnis, das alle Ordner für die initramfs enthält, oder ich führe aus

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

um es zu bauen.

Wenn ich dann den Kernel kompiliere, entweder mit oder ohne CONFIG_INITRAMFS_SOURCE, habe ich zwei Varianten meines Systems:

  1. bzImage mit eingebettetem initramfs

  2. bzImage + rootfs.cpio.gz (externe initramfs)

wenn ich jetzt anfange diese zu benutzen qemu

qemu-system-x86_64 -enable-kvm -kernel bzImage

oder

qemu-system-x86_64 -enable-kvm -kernel bzImage -initrd rootfs.cpio.gz

Ich habe folgenden Verhaltensunterschied:

Mit Version 2 (externes Initramfs) funktioniert alles einwandfrei. "Willkommen" wird angezeigt und ich erhalte eine Eingabeaufforderung. Mit Version 1 (Embedded Initramfs) bekomme ich jedoch die Warnung

unable to open an initial console

"Willkommen" wird nicht angezeigt und ich erhalte meine Eingabeaufforderung.

Soweit ich den Prozess verstehe, sollten diese beiden Versionen von initramfs dieselben Dateien enthalten, da ich sie aus einem identischen Ordner erstelle (oder vom Kernel erstellen lasse).

Ich frage mich, ob mir jemand mit einer Erklärung für dieses Verhalten helfen kann.

* UPDATE *

Wie MikeServ in den Kommentaren sagte, enthält der Kernel standardmäßig ein minimales eingebettetes Initramfs. Dies ist weiterhin vorhanden, wenn Sie ein externes verwenden, wird jedoch überschrieben, wenn Sie Ihr eigenes einbetten. Ich habe festgestellt, dass dies entgegen der Spezifikation zwar nicht leer ist, sondern einen Entwicklungsordner, einen Stammordner und das Gerät / dev / console enthält. Dieses Gerät wird dann bei Verwendung eines externen Initramfs verwendet, aber überschrieben, wenn Sie Ihr eigenes einbetten. Sie müssen also das Gerät / dev / console in Ihre initramfs-Quelle aufnehmen, mknod -m 622 initramfs_src/dev/console c 5 1wenn Sie Ihr eigenes einbetten.

Vielen Dank an mikeserv, frostschutz und JdeBP, die mir dabei geholfen haben, mich darum zu kümmern!

clw
quelle
Welche Berechtigungen sind /dev/consolefür Ihre integrierte Version festgelegt? Ich denke, der Unterschied könnte darin bestehen, wer in beiden Fällen die Verpackung übernimmt.
Mikeserv
Eine ähnliche Frage ist natürlich stackoverflow.com/questions/10437995 .
JdeBP
@mikeserv Das Konsolengerät verfügt in beiden Builds über identische Berechtigungen und Eigentumsrechte.
Clw
@JdeBP Ich bin mir nicht sicher, ob es so ähnlich ist, da ich in beiden Fällen boote, eine Eingabeaufforderung erhalte und ein Konsolengerät habe. Nur dass in einem Init das Echo ausgeführt wird und in dem anderen nicht.
Clw
1
Wie könnten die Berechtigungen in initramfs gleich gewesen sein, wenn Sie sie überhaupt nicht gehabt hätten?
Mikesserv

Antworten:

2

Sind sie wirklich identisch?

Die integrierte /usr/src/linux/usr/initramfs_data.cpio.gzVersion, die Sie in bzImage finden oder daraus extrahieren können, wie hier beschrieben: https://wiki.gentoo.org/wiki/Custom_Initramfs#Salvaging

Wenn Sie dieses integrierte Gerät verwenden und es stattdessen als externes verwenden, funktioniert es dann?

Wenn es immer noch anders ist, ist der Kernel selbst identisch? (Vergleiche /proc/config.gzfür beide)

Es sollte einen Unterschied geben. Mir ist nicht bewusst, dass es dem Kernel wichtig ist, woher die Initramfs stammen. Ich würde eher vermuten qemu, beim Übergeben des -initrdParameters andere Einstellungen zu verwenden ...

Nebenbei bemerkt, Sie sehen /initaus, als würden mir unendlich viele Muscheln erscheinen. setsidist nicht exec. Liege ich falsch?

Frostschutz
quelle
1
Diese Antwort scheint alle Fragen zu sein.
JdeBP
@JdeBP: Du denkst nicht viertdimensional!
Frostschutz
1
@frostschutz Vielen Dank für Ihre Antwort! Wenn ich die vom Kernel erstellten initramfs (usr / initramfs_data.cpio.gz) als extern verwende, funktioniert das auch einwandfrei! Wenn ich den Kernel, der mit den eingebetteten Initramfs kompiliert wurde, mit einem externen Kernel versorge, wird die Warnung angezeigt, obwohl der externe den eingebetteten Kernel überschreiben sollte ( kernel.org/doc/Documentation/filesystems/… ). Es ist also wahrscheinlich auch nicht qemu-initrd, sondern etwas im Kernel selbst. Ich habe nichts anderes geändert als CONFIG_INITRAMFS_SOURCE ..
clw
@frostschutz Beantwortung Ihrer Frage On a sidenote, your /init looks like its spawning infinite shells to me. setsid is not exec. Am I wrong?: Die Schleife ahmt getty oder ähnliche Tools nach, da die shBlöcke aufgerufen werden, bis diese Shell beendet wird.
Stefanjunker
@stefanjunker und das wäre in Ordnung, außer setsid blockiert überhaupt nicht ...
Frostschutz
1

Vielleicht interessiert Sie auch, wie Buildroot 2018.02 damit umgeht.

Wenn Sie initramfs ( BR2_TARGET_ROOTFS_INITRAMFS=y) oder initrd ( BR2_TARGET_ROOTFS_CPIO=n) verwenden, wird /initIhrem rootfs Folgendes hinzugefügt: 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 "$@"

Die Kopie wird von https://github.com/buildroot/buildroot/blob/2018.02/fs/cpio/cpio.mk erstellt :

# 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

Es ist auch nützlich zu wissen, dass der Init-Pfad /initfür initramfs ist, im Gegensatz zu /sbin/initanderen: Was kann dazu führen, dass die Übergabe von init = / path / to / program an den Kernel das Programm nicht als init startet?

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
quelle