¿Qué puede hacer que pasar init = / path / to / program al kernel no inicie el programa como init?

13

Estoy tratando de depurar un guión de inicio en un sistema Linux; Estoy tratando de pasar init=/bin/shal kernel para que se inicie shsin iniciar initpara poder ejecutar la secuencia de inicio manualmente.

Lo que he encontrado es que el núcleo está comenzando de inittodos modos. Durante el arranque, uno de los mensajes de printk es la línea de comando, y eso muestra que la línea se está configurando correctamente; Además, puedo afectar otras cosas usando la línea de comando del núcleo. He comprobado para asegurarme de que el camino existe; lo hace.

Este es un sistema busybox, e init es un enlace simbólico a busybox; así que para asegurarme de que busybox no haga magia extraña cuando su PID es 1, también intenté ejecutar un programa que no sea busybox como init; eso tampoco funcionó. Parece que no importa lo que haga, init se ejecuta.

¿Qué podría estar causando este comportamiento?

Shawn J. Goff
fuente
¿Para qué es la distribución base que está usando busybox init? Es posible que simplemente estén ignorando la línea de comando ... es posible que desee examinar el initrd y ver qué están haciendo realmente los scripts.
Aaron D. Marasco el
No es ninguna distribución, es mi propia construcción; Por eso estoy tratando de depurar los guiones de inicio.
Shawn J. Goff el

Respuestas:

3

Al mirar la fuente del kernel de Linux, veo que si el archivo / init existe, el kernel siempre intentará ejecutarlo suponiendo que se está iniciando un disco RAM. Verifique su sistema para ver si / init existe, si es así, entonces ese es probablemente su problema.

Kyle Jones
fuente
En realidad, se comprueba execute_commandprimero, que proviene del init=parámetro de línea de comando del núcleo . Si no puede ejecutarlo, imprime una advertencia e intenta ejecutarse initen varias ubicaciones. Esto está en init/main.cla función init_post(). Miré a través de los mensajes printk del kernel y encontré la advertencia en la salida de mi kernel, así que ahora tengo que descubrir por qué no puede iniciar / bin / sh o cualquier otra cosa que intento iniciar.
Shawn J. Goff
El código que miré (v3.2.2 creo) verificó el conjunto ramdisk_execute_command si no estaba configurado y luego trató de ejecutarlo, por lo que no debe estar tan actualizado. Lástima, porque no vi nada más que lo explicara.
Kyle Jones el
rdinitAl parecer, debe usar al iniciar desde ramdisk: unix.stackexchange.com/a/430614/32558
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
8

travesuras initrd

Si está utilizando initrd o initramfs, tenga en cuenta lo siguiente:

  • rdinit= se usa en lugar de init=

  • Si rdinit=no se da, los intentos de rutas predeterminadas son: /sbin/init, /etc/init, /bin/inity /bin/shaunque no/init

    Cuando no se usa initrd, /inites el primer camino que se intenta, seguido por los demás.

v4.15 RTFS: todo está contenido dentro del archivo https://github.com/torvalds/linux/blob/v4.15/init/main.c .

Primero aprendemos que:

  • execute_comand es lo que se pasa a: init=
  • ramdisk_execute_command es lo que se pasa a: rdinit=

como se puede ver en:

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

donde __setupes una forma mágica de manejar los parámetros de la línea de comandos.

start_kernel, el "punto de entrada" del núcleo, llama rest_init, que "llama" kernel_initen un hilo:

pid = kernel_thread(kernel_init, NULL, CLONE_FS);

Entonces, kernel_inithace:

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

y kernel_init_freeablehace:

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

También tenga en cuenta que hay más diferencias entre inits ram y no inits ram, por ejemplo, manejo de consola: ¿ Diferencia en la ejecución de init con initramfs incrustado versus externo?

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

Puede personalizar su kernel de Linux y recompilarlo. Para el kernel 4.9, edite la función "kernel_init" en init / main.c e intente ejecutar primero la siguiente línea:

try_to_run_init_process("/bin/sh")

Además, podría deberse a los parámetros del kernel pasados ​​por BootLoader.

muchrooms
fuente