Cosa può far passare il programma init = / path / to / program al kernel non avviare il programma come init?


13

Sto cercando di eseguire il debug di uno script init su un sistema Linux; Sto provando a passare init=/bin/shal kernel per farlo partire shsenza avviarlo in initmodo da poter eseguire manualmente la sequenza init.

Quello che ho scoperto è che il kernel si sta avviando initcomunque. Durante l'avvio, uno dei messaggi di printk è la riga di comando e ciò indica che la riga è stata impostata correttamente; inoltre, posso influenzare altre cose usando la riga di comando del kernel. Ho verificato per accertarmi che il percorso esista; lo fa.

Questo è un sistema busybox e init è un collegamento simbolico a busybox; quindi per essere sicuro che busybox non faccia strane magie quando il suo PID è 1, ho anche provato a eseguire un programma non busybox come init; neanche quello ha funzionato. Sembra che qualunque cosa io faccia, init è in esecuzione.

Cosa potrebbe causare questo comportamento?


A cosa serve la distro di base che sta usando busybox init? Potrebbero semplicemente ignorare la riga di comando ... potresti voler esaminare initrd e vedere cosa stanno effettivamente facendo gli script.
Aaron D. Marasco,

Non è una distro - è la mia build; ed è per questo che sto cercando di eseguire il debug degli script init.
Shawn J. Goff

Risposte:


3

Osservando la fonte del kernel Linux, vedo che se il file / init esiste, il kernel tenterà sempre di eseguirlo supponendo che stia eseguendo un avvio ramdisk. Controlla il tuo sistema per vedere se / init esiste, in caso affermativo, probabilmente questo è il tuo problema.


In realtà, controlla execute_commandprima, che proviene dal init=parametro della riga di comando del kernel . Se non è in grado di eseguirlo, stampa un avviso e tenta di eseguire initin varie posizioni. Questo è nella init/main.cfunzione init_post(). Ho guardato i messaggi del kernel printk e ho trovato l'avvertimento nell'output del mio kernel, quindi ora devo capire perché non è possibile avviare / bin / sh o qualsiasi altra cosa che provo ad avviare.
Shawn J. Goff,

Il codice che ho guardato (v3.2.2 credo) ha controllato set ramdisk_execute_command se non era impostato e poi ha provato a eseguirlo, quindi non devi essere così aggiornato. Peccato, perché non ho visto nient'altro che potesse spiegarlo.
Kyle Jones,

È necessario utilizzare rdinitquando si avvia da ramdisk apparentemente: unix.stackexchange.com/a/430614/32558
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

8

initrd shenanigans

Se si utilizza initrd o initramfs, tenere presente quanto segue:

  • rdinit= viene utilizzato al posto di init=

  • se rdinit=non è dato, i percorsi predefiniti tentativi sono: /sbin/init, /etc/init, /bin/inite /bin/shma non/init

    Quando non si utilizza initrd, /initviene tentato il primo percorso, seguito dagli altri.

v4.15 RTFS: tutto è contenuto nel file https://github.com/torvalds/linux/blob/v4.15/init/main.c .

Innanzitutto apprendiamo che:

  • execute_comand è ciò che viene passato a: init=
  • ramdisk_execute_command è ciò che viene passato a: rdinit=

come si può vedere da:

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

dove __setupè un modo magico di gestire i parametri della riga di comando.

start_kernel, il "punto di ingresso" del kernel, chiama rest_init, che "chiama" kernel_initsu un thread:

pid = kernel_thread(kernel_init, NULL, CLONE_FS);

Quindi, kernel_initfa:

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

e kernel_init_freeablefa:

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: capire sys_access.

Si noti inoltre che ci sono ulteriori differenze tra gli ingressi RAM e gli ingressi non RAM, ad esempio la gestione della console: Differenza nell'esecuzione di init con initramfs incorporato o esterno?



0

Puoi personalizzare il tuo kernel Linux e ricompilarlo. Per il kernel 4.9, modificare la funzione "kernel_init" in init / main.c e provare a eseguire prima la riga seguente:

try_to_run_init_process("/bin/sh")

Inoltre, potrebbe essere causato dai parametri del kernel passati da BootLoader.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.