Що може зробити перехід init = / path / to / program до ядра не запускати програму як init?


13

Я намагаюся налагодити сценарій init в системі Linux; Я намагаюся перейти init=/bin/shдо ядра, щоб запустити його shбез запуску, initщоб я міг пропустити послідовність init вручну.

Я знайшов, що ядро ​​все initодно запускається . Під час завантаження одне з повідомлень printk є командним рядком, і це показує, що рядок задано правильно; крім того, я можу впливати на інші речі за допомогою командного рядка ядра. Я перевірив, щоб переконатися, що шлях існує; це робить.

Це система зайнятої скриньки, а init є символьним посиланням на zasedbox; тому, щоб переконатися, що зайнятий не робить дивної магії, коли його PID дорівнює 1, я також спробував запустити програму, що не займається, як init; це теж не вийшло. Здається, що що б я не робив, init запускається.

Що може спричинити таку поведінку?


Для чого використовується базовий дистрибутив, для якого використовується busybox init? Вони можуть просто ігнорувати командний рядок ... ви можете вивчити initrd і побачити, що насправді роблять сценарії.
Аарон Д. Мараско

Це не будь-який дистрибутив - це моя власна збірка; саме тому я намагаюся налагодити скрипти init.
Шон Дж. Гоф

Відповіді:


3

Дивлячись на джерело ядра Linux, я бачу, що якщо файл / init існує, ядро ​​завжди намагатиметься запустити його за умови, що він робить завантаження ramdisk. Перевірте свою систему, щоб побачити, чи існує / init, якщо вона є, то це, ймовірно, ваша проблема.


Насправді він перевіряє execute_commandспочатку, що походить від параметра командного рядка ядра init=. Якщо він не може його виконати, він друкує попередження і намагається запустити initв різних місцях. Це init/main.cв функції init_post(). Я переглянув повідомлення друку ядра і виявив попередження у виході свого ядра, тому тепер я повинен з'ясувати, чому воно не може запуститися / bin / sh або щось інше, що я намагаюся запустити.
Шон Дж. Гоф

Код, який я переглянув (v3.2.2, я думаю) перевірив встановити ramdisk_execute_command, якщо він не був встановлений, а потім спробував запустити його, тому ви не повинні бути таким поточним. Шкода, тому що я не бачив нічого іншого, що б це пояснило.
Кайл Джонс

Ви повинні використовувати rdinitпід час завантаження з ramdisk, мабуть: unix.stackexchange.com/a/430614/32558
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

8

initrd shenanigans

Якщо ви використовуєте initrd або initramfs, пам’ятайте про наступне:

  • rdinit= використовується замість init=

  • якщо rdinit=не заданий, які намагалися шляху по замовчуванням є: /sbin/init, /etc/init, /bin/initі , /bin/shале не/init

    Якщо не використовується initrd, /initце перший спробуваний шлях, за яким слід інші.

v4.15 RTFS: все міститься у файлі https://github.com/torvalds/linux/blob/v4.15/init/main.c .

Спочатку ми дізнаємось, що:

  • execute_comand це все, що передається: init=
  • ramdisk_execute_command це все, що передається: rdinit=

як видно з:

static int __init init_setup(char *str)
{
    unsigned int i;

    execute_command = str;
    /*
    * In case LILO is going to boot us with default command line,
    * it prepends "auto" before the whole cmdline which makes
    * the shell think it should execute a script with such name.
    * So we ignore all arguments entered _before_ init=... [MJ]
    */
    for (i = 1; i < MAX_INIT_ARGS; i++)
        argv_init[i] = NULL;
    return 1;
}
__setup("init=", init_setup);

static int __init rdinit_setup(char *str)
{
    unsigned int i;

    ramdisk_execute_command = str;
    /* See "auto" comment in init_setup */
    for (i = 1; i < MAX_INIT_ARGS; i++)
        argv_init[i] = NULL;
    return 1;
}
__setup("rdinit=", rdinit_setup);

де __setupмагічний спосіб обробки параметрів командного рядка.

start_kernel, ядро ​​"точка входу", виклики rest_init, яке "дзвонить" kernel_initу потік:

pid = kernel_thread(kernel_init, NULL, CLONE_FS);

Потім kernel_init:

static int __ref kernel_init(void *unused)
{
    int ret;

    kernel_init_freeable();

    [...]

    if (ramdisk_execute_command) {
        ret = run_init_process(ramdisk_execute_command);
        if (!ret)
            return 0;
        pr_err("Failed to execute %s (error %d)\n",
            ramdisk_execute_command, ret);
    }

    [...]

    if (execute_command) {
        ret = run_init_process(execute_command);
        if (!ret)
            return 0;
        panic("Requested init %s failed (error %d).",
            execute_command, ret);
    }
    if (!try_to_run_init_process("/sbin/init") ||
        !try_to_run_init_process("/etc/init") ||
        !try_to_run_init_process("/bin/init") ||
        !try_to_run_init_process("/bin/sh"))
        return 0;

    panic("No working init found.  Try passing init= option to kernel. "
        "See Linux Documentation/admin-guide/init.rst for guidance.");
}

і kernel_init_freeableробить:

static noinline void __init kernel_init_freeable(void)
{

    [...]

    if (!ramdisk_execute_command)
        ramdisk_execute_command = "/init";

    if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) {
        ramdisk_execute_command = NULL;
        prepare_namespace();
    }

ТОДО: зрозумійте sys_access.

Також зауважте, що існують додаткові відмінності між операційними інітами та нераманими inits, наприклад, керування консоллю: різниця у виконанні init із вбудованими та зовнішніми initramfs?


4

На

https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt

Я знайшов:

Під час налагодження звичайної кореневої файлової системи, приємно мати можливість завантажуватися з "init = / bin / sh". Еквівалент initramfs - "rdinit = / bin / sh", і це так само корисно.

Тому, напевно, спробуйте ridinit = / bin / sh


0

Ви можете налаштувати своє ядро ​​Linux і перекомпілювати його. Для ядра 4.9 відредагуйте функцію "kernel_init" в init / main.c і спробуйте спочатку запустити наступний рядок:

try_to_run_init_process("/bin/sh")

Крім того, це може бути викликано параметрами ядра, переданими BootLoader.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.