Kann der Init-Prozess unter Linux ein Shell-Skript sein?


14

Ich habe ein Tutorial zum Einrichten eines benutzerdefinierten initramfs durchlaufen, in dem Folgendes angegeben ist:

Das einzige, was fehlt, ist / init, die ausführbare Datei im Stammverzeichnis des initramfs, die vom Kernel ausgeführt wird, sobald er geladen ist. Da sys-apps / busybox eine voll funktionsfähige Shell enthält, können Sie Ihre / init-Binärdatei als einfaches Shell-Skript schreiben (anstatt es zu einer in Assembler oder C geschriebenen komplizierten Anwendung zu machen, die Sie kompilieren müssen).

und gibt ein Beispiel für init als Shell-Skript, das mit beginnt #!/bin/busybox sh

Bisher hatte ich den Eindruck, dass init der Hauptprozess ist, der gestartet wird, und dass alle anderen User-Space-Prozesse letztendlich Kinder von init sind. In dem gegebenen Beispiel ist der erste Prozess jedoch tatsächlich der, bin/busybox/ shaus dem später init erzeugt wird.

Ist das eine korrekte Interpertation? Wenn ich zum Beispiel zu diesem Zeitpunkt einen verfügbaren Interpreter hätte, könnte ich init als Python-Skript usw. schreiben.

Antworten:


12

init wird nicht "gespawnt" (als untergeordneter Prozess), sondern sieht folgendermaßen aus exec:

# Boot the real thing.
exec switch_root /mnt/root /sbin/init

execErsetzt den gesamten Prozess. Das endgültige Init ist immer noch der erste Prozess (PID 1), obwohl es mit denen in Initramfs vorangestellt wurde.

Das Initramfs /init, das ein Busybox-Shell-Skript mit PID 1 ist, ist execzu Busybox switch_root(also ist es jetzt switch_rootPID 1); Dieses Programm ändert Ihre Mount-Punkte, damit /mnt/rootdie neuen werden /.

switch_rootdann nochmal execs an /sbin/initdein echtes root Dateisystem; Dadurch wird Ihr echtes Init-System zum ersten Prozess mit PID 1, der wiederum eine beliebige Anzahl von untergeordneten Prozessen hervorrufen kann.

Natürlich könnte es genauso gut mit einem Python-Skript gemacht werden, wenn Sie es irgendwie geschafft haben, Python in Ihr Initramfs zu backen. Auch wenn Sie nicht vorhaben, busybox zu integrieren, müssten Sie einige seiner Funktionen (wie switch_rootund alles andere, was Sie normalerweise mit einem einfachen Befehl tun würden) sorgfältig neu implementieren .

Es funktioniert jedoch nicht auf Kerneln, die keine Skript-Binärdateien ( CONFIG_BINFMT_SCRIPT=y) zulassen , oder in einem solchen Fall müssten Sie den Interpreter direkt starten und Ihr Skript irgendwie laden.


/verschwindet nicht in Luft - es wird über montiert (obwohl normalerweise sein Inhalt gelöscht wird, bevor es Speicher spart) . Es ist immer noch da . Tut switch_rootden Syscall switchroot- das ist es, was die Kernel-Entwickler bereitgestellt haben, als sie den Boot-Prozess in Kernel 2.6 geändert haben. Etwas, das initramfs erfordert. Es ist der Kernel, der die Magie ausübt.
mikeserv

1
Ein switchrootSyscall wäre in der Tat eine Neuigkeit für mich. Hast du eine Quelle dafür? Wenn Sie sich den Quellcode switch_root.c ansehen, scheint es sich um einen ziemlich manuellen Prozess zu handeln, der auch in Documentation / filesystems / ramfs-rootfs-initramfs.txt beschrieben ist. Auch wenn Sie alles löschen und erneut einbinden, ist es an diesem Punkt so gut wie verschwunden, finden Sie nicht auch?
Frostschutz

pivot_rootAuf der anderen Seite ist ein Syscall. Es wird jedoch nicht verwendet switch_rootund kann nicht verwendet werden, ohne durch einige Reifen zu springen, und so oder so spielt es für diese Antwort überhaupt keine Rolle, also habe ich es einfach komplett entfernt. Schade, ich dachte, dass Magie und Verschwinden in Luft sehr gut funktioniert ... :-P
Frostschutz

Nun, vielleicht habe ich eine falsche Vorstellung davon switch_root- was mir leid tut und ich danke Ihnen, dass Sie es mir gezeigt haben -, aber es verschwindet trotzdem nichts. initramfs root bleibt bestehen und ist immer für alle da - es ist root.
mikeserv

1
In den von Ihnen verlinkten Dokumenten heißt es : Aber initramfs ist rootfs: Sie können weder pivot_root rootfs ausführen noch die Bereitstellung aufheben. Löschen Sie stattdessen alles aus rootfs find -xdev / -exec rm '{}' ';', um Speicherplatz freizugeben ( ), hängen Sie rootfs mit dem neuen root ( cd /newmount; mount --move . /; chroot .) über, hängen Sie stdin / stdout / stderr an das neue / dev / console an und führen Sie das neue init aus.
mikeserv

4

Der Exec-Syscall des Linux-Kernels versteht shebangs nativ

Wenn die ausgeführte Datei mit den magischen Bytes beginnt, weisen #!sie den Kernel an, Folgendes zu verwenden #!/bin/sh:

  • tun und execSystemaufruf
  • mit ausführbarer Datei /bin/sh
  • und mit CLI-Argument: Pfad zum aktuellen Skript

Dies ist genau das gleiche, was passiert, wenn Sie ein reguläres Userland-Shell-Skript ausführen mit:

./myscript.sh

Wenn die Datei begonnen hatte , mit der Magie Bytes .ELFstatt #!, würde der Kernel die ELF - Loader wählen , anstatt es zu laufen.

Weitere Informationen finden Sie unter: Warum schreiben die Leute den Python-Shebang #! / Usr / bin / env in die erste Zeile eines Python-Skripts? | Paketüberfluss

Wenn Sie dies einmal bedacht haben, wird es leicht, zu akzeptieren, dass /initdies alles sein kann, was der Kernel ausführen kann, einschließlich eines Shell-Skripts, und warum /bin/shin diesem Fall die erste ausführbare Datei sein wird.

Hier ist ein minimal ausführbares Beispiel für diejenigen, die es ausprobieren möchten: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/cbea7cc02c868711109ae1a261d01fd0473eea0b#custom-init

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.