Le processus init peut-il être un script shell sous Linux?

14

Je suivais un tutoriel sur la configuration d'un initramfs personnalisé où il est indiqué:

La seule chose qui manque est / init, l'exécutable à la racine des initramfs qui est exécuté par le noyau une fois qu'il est chargé. Parce que sys-apps / busybox inclut un shell entièrement fonctionnel, cela signifie que vous pouvez écrire votre binaire / init comme un script shell simple (au lieu d'en faire une application compliquée écrite en Assembleur ou en C que vous devez compiler).

et donne un exemple d'init comme script shell qui commence par #!/bin/busybox sh

Jusqu'à présent, j'avais l'impression que init est le processus principal qui est lancé et que tous les autres processus de l'espace utilisateur sont finalement des enfants d'init. Cependant, dans l'exemple donné, le premier processus est en fait à bin/busybox/ shpartir duquel init est généré plus tard.

Est-ce une interpertation correcte? Si je disposais, par exemple, d'un interprète disponible à ce stade, je pourrais écrire init en tant que script Python, etc.?

TheMeaningfulEngineer
la source

Réponses:

12

init n'est pas "généré" (comme un processus enfant), mais plutôt execcomme ceci:

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

execremplace l'ensemble du processus en place. L'init final est toujours le premier processus (pid 1), même s'il a été précédé de ceux des Initramfs.

Initramfs /init, qui est un script shell Busybox avec pid 1, execs vers Busybox switch_root(alors maintenant switch_rootc'est pid 1); ce programme modifie vos points de montage /mnt/rootsera donc le nouveau /.

switch_rootpuis à nouveau execsur /sbin/initvotre véritable système de fichiers racine; ainsi, il fait de votre véritable système d'initialisation le premier processus avec pid 1, qui à son tour peut engendrer un nombre illimité de processus enfants.

Certes, cela pourrait tout aussi bien être fait avec un script Python, si vous avez réussi à intégrer Python dans vos Initramfs. Bien que si vous ne prévoyez pas d'inclure busybox de toute façon, vous devrez réimplémenter soigneusement certaines de ses fonctionnalités (comme switch_root, et tout ce que vous feriez habituellement avec une simple commande).

Cependant, cela ne fonctionne pas sur les noyaux qui n'autorisent pas les binaires de script ( CONFIG_BINFMT_SCRIPT=y), ou plutôt dans un tel cas, vous devrez démarrer l'interpréteur directement et lui faire charger votre script d'une manière ou d'une autre.

frostschutz
la source
/ne disparaît pas dans l'air - il est monté dessus (bien que généralement son contenu soit supprimé avant qu'il ne soit pour économiser de la mémoire) . Elle est toujours là . switch_rootfait le syscall switchroot- qui est ce que les développeurs du noyau ont fourni lorsqu'ils ont changé le processus de démarrage dans le noyau 2.6.quelque chose pour exiger initramfs. C'est le noyau qui fait la magie.
mikeserv
1
Un switchrootsyscall serait en effet une nouvelle pour moi. Avez-vous une source pour cela? Si vous regardez le code source switch_root.c, il semble être un processus assez manuel, et le même que celui décrit dans Documentation / filesystems / ramfs-rootfs-initramfs.txt. De plus, si vous supprimez tout et que vous le montez, c'est presque disparu à ce stade, vous ne pensez pas?
frostschutz
pivot_root, d'autre part, est un appel système. Il n'est cependant pas utilisé pour switch_rootet ne peut pas être utilisé sans sauter à travers certains cerceaux, et de toute façon cela n'a aucune importance pour cette réponse, donc je viens de le supprimer complètement. Dommage, je pensais que la magie et s'évanouir dans l'air mince fonctionnait vraiment bien ... :-P
frostschutz
Eh bien, peut-être que j'ai eu une mauvaise idée switch_root- pour laquelle je suis désolé, et je vous remercie de m'avoir montré - mais cela ne disparaît de toute façon pas. initramfs persiste racines et est toujours là pour tout le monde - il est racine.
mikeserv
1
Comme les documents que vous avez liés disent : Mais initramfs est rootfs: vous ne pouvez ni pivot_root rootfs, ni le démonter. Au lieu de cela, supprimez tout de rootfs pour libérer de l'espace ( find -xdev / -exec rm '{}' ';'), surmontez rootfs avec le nouveau root ( cd /newmount; mount --move . /; chroot .), attachez stdin / stdout / stderr au nouveau / dev / console et exécutez le nouveau init.
mikeserv
4

L'appel système du noyau Linux comprend nativement les shebangs

Lorsque le fichier exécuté commence par les octets magiques #!, ils indiquent au noyau d'utiliser #!/bin/shcomme:

  • faire et execappel système
  • avec exécutable /bin/sh
  • et avec l'argument CLI: chemin d'accès au script actuel

C'est exactement la même chose qui se produit lorsque vous exécutez un script shell utilisateur normal avec:

./myscript.sh

Si le fichier avait commencé avec les octets magiques .ELFau lieu de #!, le noyau choisirait le chargeur ELF à la place pour l'exécuter.

Plus de détails sur: Pourquoi les gens écrivent le shebang python #! / Usr / bin / env sur la première ligne d'un script Python? | Débordement de pile

Une fois que vous avez cela à l'esprit, il devient facile d'accepter que cela /initpuisse être tout ce que le noyau peut exécuter, y compris un script shell, et aussi pourquoi ce /bin/shsera le premier exécutable dans ce cas.

Voici un exemple exécutable minimal pour ceux qui veulent l'essayer: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/cbea7cc02c868711109ae1a261d01fd0473eea0b#custom-init

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