Qu'est-ce qui peut faire passer init = / path / to / program au noyau pour ne pas démarrer le programme comme init?

13

J'essaie de déboguer un script d'initialisation sur un système Linux; J'essaie de passer init=/bin/shau noyau pour le faire démarrer shsans démarrer initafin que je puisse exécuter manuellement la séquence d'initialisation.

Ce que j'ai trouvé, c'est que le noyau démarre de inittoute façon. Lors du démarrage, l'un des messages printk est la ligne de commande, ce qui montre que la ligne est définie correctement; en plus, je peux affecter d'autres choses en utilisant la ligne de commande du noyau. J'ai vérifié pour m'assurer que le chemin existe; Cela fait.

Il s'agit d'un système busybox et init est un lien symbolique vers busybox; donc pour m'assurer que busybox ne fait pas de magie étrange lorsque son PID est 1, j'ai également essayé d'exécuter un programme non occupé comme init; cela n'a pas fonctionné non plus. Il semble que peu importe ce que je fais, init est lancé.

Quelle pourrait être la cause de ce comportement?

Shawn J. Goff
la source
À quoi sert la distribution de base qui utilise busybox init? Ils peuvent simplement ignorer la ligne de commande ... vous voudrez peut-être examiner l'initrd et voir ce que les scripts font réellement.
Aaron D. Marasco
Ce n'est pas une distribution - c'est ma propre construction; c'est pourquoi j'essaie de déboguer les scripts d'initialisation.
Shawn J. Goff

Réponses:

3

En regardant la source du noyau Linux, je vois que si le fichier / init existe, le noyau tentera toujours de l'exécuter en supposant qu'il effectue un démarrage sur disque virtuel. Vérifiez votre système pour voir si / init existe, si c'est le cas, alors c'est probablement votre problème.

Kyle Jones
la source
En fait, il vérifie d' execute_commandabord, qui provient du init=paramètre de ligne de commande du noyau . S'il ne peut pas l'exécuter, il affiche un avertissement et essaie de s'exécuter inità divers emplacements. C'est init/main.cdans la fonction init_post(). J'ai parcouru les messages printk du noyau et trouvé l'avertissement dans la sortie de mon noyau, alors maintenant je dois comprendre pourquoi il ne peut pas démarrer / bin / sh ou toute autre chose que j'essaie de démarrer.
Shawn J. Goff,
Le code que j'ai regardé (v3.2.2 je pense) a vérifié set ramdisk_execute_command s'il n'était pas défini et a ensuite essayé de l'exécuter, vous ne devez donc pas être à jour. Dommage, car je n'ai rien vu d'autre qui pourrait l'expliquer.
Kyle Jones
Vous devez utiliser rdinitlors du démarrage à partir de ramdisk apparemment: unix.stackexchange.com/a/430614/32558
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
8

initrd shenanigans

Si vous utilisez initrd ou initramfs, gardez à l'esprit les points suivants:

  • rdinit= est utilisé à la place de init=

  • si rdinit=n'est pas donné, les chemins par défaut concernées sont: /sbin/init, /etc/init, /bin/initet /bin/shnon/init

    Lorsque vous n'utilisez pas initrd, /initle premier chemin est-il essayé, suivi des autres.

v4.15 RTFS: tout est contenu dans le fichier https://github.com/torvalds/linux/blob/v4.15/init/main.c .

Nous apprenons d'abord que:

  • execute_comand est tout ce qui est transmis à: init=
  • ramdisk_execute_command est tout ce qui est transmis à: rdinit=

comme on peut le voir sur:

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

__setupest un moyen magique de gérer les paramètres de ligne de commande.

start_kernel, le noyau "point d'entrée", appelle rest_init, qui "appelle" kernel_initsur un thread:

pid = kernel_thread(kernel_init, NULL, CLONE_FS);

Ensuite, kernel_initfait:

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

et kernel_init_freeablefait:

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

Notez également qu'il existe d'autres différences entre les inits ram et non-ram, par exemple la gestion de la console: Différence dans l'exécution d'init avec des initramfs intégrés et externes?

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
la source
0

Vous pouvez personnaliser votre noyau Linux et le recompiler. Pour le noyau 4.9, modifiez la fonction "kernel_init" dans init / main.c et essayez d'exécuter la ligne suivante en premier:

try_to_run_init_process("/bin/sh")

De plus, cela peut être dû aux paramètres du noyau transmis par BootLoader.

beaucoup de pièces
la source