Was kann dazu führen, dass die Übergabe von init = / path / to / program an den Kernel das Programm nicht als init startet?

13

Ich versuche, ein Init-Skript auf einem Linux-System zu debuggen. Ich versuche, init=/bin/shan den Kernel zu übergeben, damit er startet, shohne gestartet zu werden, initdamit ich die Initialisierungssequenz manuell durchlaufen kann.

Was ich gefunden habe ist, dass der Kernel initsowieso startet . Während des Startvorgangs ist eine der printk-Meldungen die Befehlszeile, die anzeigt, dass die Zeile richtig eingestellt ist. Außerdem kann ich über die Kernel-Befehlszeile andere Dinge beeinflussen. Ich habe überprüft, ob der Pfad existiert. es tut.

Dies ist ein Busybox-System, und init ist ein Symlink zu busybox. um sicherzustellen, dass busybox keine seltsame Magie ausführt, wenn die PID 1 ist, habe ich auch versucht, ein Nicht-Busybox-Programm als init auszuführen. das hat auch nicht geklappt. Es scheint, dass, egal was ich tue, init ausgeführt wird.

Was könnte dieses Verhalten verursachen?

Shawn J. Goff
quelle
Was ist die Basisdistribution, für die busybox verwendet wird init? Möglicherweise ignorieren sie einfach die Befehlszeile. Vielleicht möchten Sie die initrd untersuchen und sehen, was die Skripte tatsächlich tun.
Aaron D. Marasco
Es ist keine Distribution - es ist mein eigener Build; Aus diesem Grund versuche ich, die Init-Skripte zu debuggen.
Shawn J. Goff

Antworten:

3

Wenn ich mir die Linux-Kernelquelle anschaue, sehe ich, dass der Kernel, wenn die Datei / init existiert, immer versucht, sie auszuführen, unter der Annahme, dass ein RAM-Disk-Boot ausgeführt wird. Überprüfen Sie Ihr System, um festzustellen, ob / init vorhanden ist. Wenn dies der Fall ist, liegt dies wahrscheinlich an Ihrem Problem.

Kyle Jones
quelle
Tatsächlich wird execute_commandzuerst geprüft , welcher Wert vom Kernel-Befehlszeilenparameter stammt init=. Wenn es nicht ausgeführt werden kann, wird eine Warnung ausgegeben und versucht, initan verschiedenen Orten ausgeführt zu werden. Dies ist init/main.cin der Funktion init_post(). Ich habe die Kernel-Printk-Meldungen durchgesehen und die Warnung in der Ausgabe meines Kernels gefunden. Jetzt muss ich herausfinden, warum / bin / sh nicht gestartet werden kann oder was ich sonst noch zu starten versuche.
Shawn J. Goff am
Der Code, den ich angeschaut habe (v3.2.2, glaube ich), hat set ramdisk_execute_command überprüft, wenn er nicht gesetzt war, und dann versucht, ihn auszuführen, sodass Sie nicht so aktuell sein müssen. Schade, denn ich habe nichts anderes gesehen, was es erklären könnte.
Kyle Jones
Sie müssen rdinitbeim Booten von Ramdisk anscheinend verwenden: unix.stackexchange.com/a/430614/32558
Ciro Santilli Am
8

initrd shenanigans

Wenn Sie initrd oder initramfs verwenden, beachten Sie Folgendes:

  • rdinit= wird anstelle von verwendet init=

  • wenn rdinit=nicht angegeben, sind die versuchten Standardpfade: /sbin/init, /etc/init, /bin/initund , /bin/shaber nicht/init

    Wenn initrd nicht verwendet wird, /initwird der erste Pfad ausprobiert, gefolgt von den anderen.

v4.15 RTFS: Alles ist in der Datei https://github.com/torvalds/linux/blob/v4.15/init/main.c enthalten.

Zuerst lernen wir, dass:

  • execute_comand ist was auch immer übergeben wird an: init=
  • ramdisk_execute_command ist was auch immer übergeben wird an: rdinit=

wie man sieht aus:

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);

Wo __setupist ein magischer Weg, um Kommandozeilenparameter zu verarbeiten.

start_kernelruft der Kernel "Einstiegspunkt rest_init" kernel_initauf, der einen Thread "aufruft" :

pid = kernel_thread(kernel_init, NULL, CLONE_FS);

Dann kernel_initmacht:

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.");
}

und kernel_init_freeablemacht:

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();
    }

TODO: Verstehe sys_access.

Beachten Sie auch, dass es weitere Unterschiede zwischen RAM-Inits und Nicht-RAM-Inits gibt, z. B. beim Konsolen-Handling: Unterschied bei der Ausführung von init mit eingebetteten vs. externen Initramfs?

Ciro Santilli ist ein Schauspieler
quelle
0

Sie können Ihren Linux-Kernel anpassen und neu kompilieren. Bearbeiten Sie für 4.9-Kernel die Funktion "kernel_init" in init / main.c und versuchen Sie zuerst, die folgende Zeile auszuführen:

try_to_run_init_process("/bin/sh")

Darüber hinaus kann dies an den von BootLoader übergebenen Kernel-Parametern liegen.

muchrooms
quelle