Может ли процесс init быть сценарием оболочки в Linux?


14

Я шел через учебник по настройке пользовательских initramfs, где говорится:

Единственное, чего не хватает - это / init, исполняемый файл в корне initramfs, который выполняется ядром после его загрузки. Поскольку sys-apps / busybox включает в себя полностью функциональную оболочку, это означает, что вы можете написать свой двоичный файл / init в виде простого сценария оболочки (вместо того, чтобы делать его сложным приложением, написанным на ассемблере или C, который нужно скомпилировать).

и дает пример init как сценарий оболочки, который начинается с #!/bin/busybox sh

До сих пор у меня сложилось впечатление, что init - это основной процесс, который запускается, и что все остальные процессы пользовательского пространства в конечном итоге являются потомками init. Тем не менее, в данном примере первый процесс фактически является результатом, bin/busybox/ shиз которого позже создается init.

Это правильная интерпретация? Если бы у меня, например, был доступный интерпретатор, я мог бы написать init как скрипт Python и т. Д.?

Ответы:


12

init не "порожден" (как дочерний процесс), а скорее execтак:

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

execзаменяет весь процесс на месте. Финальный init все еще является первым процессом (pid 1), хотя ему предшествовали те, что были в Initramfs.

Initramfs /init, который является сценарием оболочки Busybox с pid 1, execs для Busybox switch_root(теперь switch_rootэто pid 1); эта программа меняет ваши точки монтирования, поэтому /mnt/rootбудет новой /.

switch_root тогда снова exec с /sbin/initвашей настоящей корневой файловой системы; тем самым она делает вашу настоящую систему инициализации первым процессом с pid 1, который, в свою очередь, может порождать любое количество дочерних процессов.

Конечно, это можно сделать и с помощью скрипта Python, если вам каким-то образом удалось внедрить Python в свои Initramfs. Хотя если вы все равно не планируете включать busybox, вам придется тщательно реализовать некоторые его функции (например,switch_root , и все остальное, что вы обычно делаете с помощью простой команды).

Тем не менее, он не работает с ядрами, которые не допускают двоичные файлы сценариев ( CONFIG_BINFMT_SCRIPT=y), или, скорее, в таком случае вам придется запустить интерпретатор напрямую и заставить его каким-либо образом загрузить ваш сценарий.


/не исчезает в воздухе - он монтируется (хотя обычно все его содержимое удаляется перед тем, как сохранить память) . Это все еще там . switch_rootвыполняет системный вызов switchroot- это то, что разработчики ядра предоставили, когда они изменили процесс загрузки в ядре 2.6. Что-то требующее initramfs. Это ядро ​​делает магию.
mikeserv

1
switchrootСистемный вызов действительно был бы для меня новость. У вас есть источник для этого? Если вы посмотрите на исходный код switch_root.c, то это будет довольно ручной процесс, который описан в Documentation / filesystems / ramfs-rootfs-initramfs.txt. Кроме того, если вы удалите все и смонтируете его, он в значительной степени исчезнет, ​​не так ли?
frostschutz

pivot_rootс другой стороны, это системный вызов. switch_rootХотя он не используется и не может быть использован без прыжков через некоторые обручи, и в любом случае для этого ответа не имеет никакого значения, так что я просто полностью удалил его. Жаль, я думал, что магия и исчезновение в воздухе сработали очень хорошо ... :-P
frostschutz

Ну, может, у меня неправильное представление о том, switch_rootза что я извиняюсь, и я благодарю вас за то, что вы показали мне, но это все равно ничего не пропадает. initramfs корень сохраняется и всегда там для всех - это есть корень.
mikeserv

1
Как вы указалиfind -xdev / -exec rm '{}' ';'cd /newmount; mount --move . /; chroot .
mikeserv

4

Системный вызов exec ядра Linux изначально недооценивает шебанги

Когда исполняемый файл начинается с магических байтов #!, они говорят ядру использовать #!/bin/shкак:

  • делать и execсистемный вызов
  • с исполняемым файлом /bin/sh
  • и с аргументом CLI: путь к текущему сценарию

Это то же самое, что происходит при запуске обычного сценария оболочки пользователя с:

./myscript.sh

Если файл начинался с магических байтов .ELFвместо #!, ядро ​​выберет загрузчик ELF, чтобы запустить его.

Более подробно на: Почему люди пишут #! / Usr / bin / env pyb shebang в первой строке скрипта Python? | Переполнение стека

Как только вы это запомните, становится легко принять, что это /initможет быть все, что может выполнить ядро, включая сценарий оболочки, а также почему /bin/shв этом случае будет первый исполняемый файл.

Вот минимальный работающий пример для тех, кто хочет попробовать это: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/cbea7cc02c868711109ae1a261d01fd0473eea0b#custom-init

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