Il processo init può essere uno script di shell in Linux?


14

Stavo seguendo un tutorial sull'impostazione di un initramfs personalizzato in cui si afferma:

L'unica cosa che manca è / init, l'eseguibile nella radice di initramfs che viene eseguito dal kernel una volta caricato. Poiché sys-apps / busybox include una shell completamente funzionale, questo significa che puoi scrivere il tuo binario / init come un semplice script di shell (invece di renderlo un'applicazione complicata scritta in Assembler o C che devi compilare).

e fornisce un esempio di init come script di shell che inizia con #!/bin/busybox sh

Finora, ho avuto l'impressione che init sia il processo principale che viene avviato e che tutti gli altri processi dello spazio utente siano infine figli di init. Tuttavia, nell'esempio dato, il primo processo è in realtà bin/busybox/ shdal quale viene generato successivamente init.

Si tratta di un'interpretazione corretta? Se, ad esempio, avessi a disposizione un interprete disponibile a quel punto, potrei scrivere init come script Python ecc.?

Risposte:


12

init non è "generato" (come un processo figlio), ma piuttosto execcosì:

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

execsostituisce l'intero processo in atto. L'iniz finale è ancora il primo processo (pid 1), anche se è stato preceduto da quelli in Initramfs.

Initramfs /init, che è uno script della shell Busybox con pid 1, execs su Busybox switch_root(quindi ora switch_rootè pid 1); questo programma modifica i punti di montaggio, quindi /mnt/rootsarà il nuovo /.

switch_rootpoi di nuovo execs al /sbin/inittuo vero filesystem di root; quindi rende il tuo vero sistema init il primo processo con pid 1, che a sua volta può generare un numero qualsiasi di processi figlio.

Certamente potrebbe anche essere fatto con uno script Python, se in qualche modo sei riuscito a inserire Python nei tuoi Initramfs. Anche se se non prevedi di includere busybox in ogni caso, dovresti reimplementare scrupolosamente alcune delle sue funzionalità (come switch_roote qualsiasi altra cosa che di solito faresti con un semplice comando).

Tuttavia, non funziona su kernel che non consentono script binari ( CONFIG_BINFMT_SCRIPT=y), o piuttosto in tal caso dovresti avviare direttamente l'interprete e farlo caricare lo script in qualche modo.


/non svanisce nel nulla - è montato sopra (anche se di solito i suoi contenuti vengono tutti cancellati prima di salvare memoria) . E ' ancora lì . switch_rootfa il syscall switchroot- che è quello che gli sviluppatori del kernel hanno fornito quando hanno cambiato il processo di avvio nel kernel 2.6. qualcosa per richiedere initramfs. È il kernel che fa la magia.
Mikeserv,

1
Una switchrootsyscall sarebbe davvero una novità per me. Hai una fonte per questo? Se guardi il codice sorgente switch_root.c, sembra essere un processo abbastanza manuale, e lo stesso è descritto nella Documentazione / filesystems / ramfs-rootfs-initramfs.txt. Inoltre, se elimini tutto e lo monti sopra, è praticamente svanito a questo punto, non credi?
frostschutz,

pivot_rootd'altra parte, è un syscall. Però non è usato switch_roote non può essere usato senza saltare attraverso alcuni cerchi, e in ogni caso non importa nulla per questa risposta, quindi l'ho rimosso del tutto. Peccato, pensavo che la magia e svanire nel nulla funzionasse davvero bene ... :-P
frostschutz,

Beh, forse ho avuto un'idea sbagliata switch_root- per cui mi dispiace, e ti ringrazio per avermelo mostrato - ma non svanisce comunque nulla. La radice di initramfs persiste ed è sempre lì per tutti - è radice.
Mikeserv,

1
Come dicevano i documenti collegati : Ma initramfs è rootfs: non puoi né pivot_root rootfs, né smontarlo. Invece elimina tutto da rootfs per liberare spazio ( find -xdev / -exec rm '{}' ';'), monta rootfs con il nuovo root ( cd /newmount; mount --move . /; chroot .), collega stdin / stdout / stderr al nuovo / dev / console ed esegui il nuovo init.
Mikeserv,

4

La scala di esecuzione del kernel Linux sottostà a shebang nativamente

Quando il file eseguito inizia con i byte magici #!, dicono al kernel di usare #!/bin/shcome:

  • fare e execchiamata di sistema
  • con eseguibile /bin/sh
  • e con argomento CLI: percorso dello script corrente

Questo è esattamente lo stesso che succede quando si esegue un normale script shell userland con:

./myscript.sh

Se il file fosse iniziato con i byte magici .ELFanziché #!, il kernel avrebbe invece scelto il caricatore ELF per eseguirlo.

Maggiori dettagli su: Perché le persone scrivono il #! / Usr / bin / env python shebang sulla prima riga di uno script Python? | Stack Overflow

Una volta che lo hai in mente, diventa facile accettare che /initpuò essere qualsiasi cosa che il kernel possa eseguire, incluso uno script di shell, e anche perché /bin/shsarà il primo eseguibile in quel caso.

Ecco un esempio eseguibile minimo per coloro che vogliono provarlo: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/cbea7cc02c868711109ae1a261d01fd0473eea0b#custom-init

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.