Чи може процес init бути скриптом оболонки в Linux?


14

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

Єдине, чого не вистачає, це / init, виконуваний файл у корені initramfs, який виконується ядром після його завантаження. Оскільки sys-apps / busybox включає повністю функціональну оболонку, це означає, що ви можете написати / init бінарний файл як простий скрипт оболонки (замість того, щоб зробити це складним додатком, написаним в Assembler або 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замінює весь процес на місці. Заключний ініт все ще є першим процесом (pid 1), навіть незважаючи на те, що йому передували ті, які були в Initramfs.

Initramfs /init, що являє собою скрипт оболонки Busybox з pid 1, execs до Busybox switch_root(так це зараз switch_rootpid 1); ця програма змінює ваші точки монтажу, тому /mnt/rootбуде новою /.

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

Звичайно, це було б так само добре, як і з сценарієм Python, якщо вам якимось чином вдалося вписати Python у свій Initramfs. Хоча якщо ви все одно не плануєте включати зайнятий ящик, вам доведеться кропітко повторно реалізувати частину його функціональності (наприклад switch_root, і все інше, що ви зазвичай робите за допомогою простої команди).

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


/не зникає на повітрі - він встановлений (хоча зазвичай його вміст видаляється перед тим, як зберегти пам'ять) . Це все ще є . switch_rootробить syscall 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 спочатку розуміє shebangs

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

  • робити і execсистемний виклик
  • з виконуваним файлом /bin/sh
  • та з аргументом CLI: шлях до поточного сценарію

Це саме те, що відбувається, коли ви запускаєте звичайний сценарій оболонки користувача з:

./myscript.sh

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

Детальніше на сторінці: Чому люди записують #! / Usr / bin / env python 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.