Что может заставить передачу 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.

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