Что может заставить передачу init = / path / to / program в ядро ​​не запускать программу как init?

13

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

Я обнаружил, что ядро initвсе равно запускается. Во время загрузки одно из сообщений printk является командной строкой, и это показывает, что строка установлена ​​правильно; кроме того, я могу влиять на другие вещи, используя командную строку ядра. Я проверил, чтобы убедиться, что путь существует; оно делает.

Это система busybox, а init - это символическая ссылка на busybox; поэтому, чтобы убедиться, что busybox не выполняет странную магию, когда его PID равен 1, я также попытался запустить программу non-busybox в качестве init; это тоже не сработало. Кажется, что независимо от того, что я делаю, init запускается.

Что может быть причиной такого поведения?

Шон Дж. Гофф
источник
Для чего нужен базовый дистрибутив, который использует busybox init? Возможно, они просто игнорируют командную строку ... вы можете изучить initrd и посмотреть, что на самом деле делают скрипты.
Аарон Д. Мараско
Это не какой-то дистрибутив - это моя собственная сборка; Вот почему я пытаюсь отладить сценарии инициализации.
Шон Дж. Гофф

Ответы:

3

Глядя на исходный код ядра Linux, я вижу, что если файл / init существует, ядро ​​всегда будет пытаться запустить его, исходя из предположения, что оно выполняет загрузку с виртуального диска. Проверьте вашу систему, чтобы увидеть, если / init существует, если он существует, то это, вероятно, ваша проблема.

Кайл Джонс
источник
На самом деле, он execute_commandсначала проверяет , что происходит из параметра командной строки ядра init=. Если он не может выполнить его, он печатает предупреждение и пытается запустить initв разных местах. Это init/main.cв функции init_post(). Я просмотрел сообщения printk ядра и нашел предупреждение в выводе моего ядра, так что теперь я должен выяснить, почему он не может запустить / bin / sh или что-либо еще, что я пытаюсь запустить.
Шон Дж. Гофф
Код, который я посмотрел (я думаю, v3.2.2), проверил set ramdisk_execute_command, если он не был установлен, а затем попытался запустить его, так что вы не должны быть таким актуальным. Жаль, потому что я не видел ничего другого, что могло бы объяснить это.
Кайл Джонс
Вы должны использовать rdinitпри загрузке с ramdisk: unix.stackexchange.com/a/430614/32558
Ciro Santilli 新疆 18 中心 法轮功 六四 事件 六四
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.

Также обратите внимание, что существуют дополнительные различия между начальными и начальными частями , например, консольная обработка: разница в выполнении 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.

muchrooms
источник