怎样使将init = / path / to / program传递给内核而不像init那样启动程序?


13

我正在尝试在Linux系统上调试初始化脚本。我试图传递init=/bin/sh给内核以使其不启动sh就开始,init因此我可以手动运行init序列。

我发现内核仍然在启动init。在启动过程中,printk消息之一是命令行,这表明该行设置正确。另外,我可以使用内核命令行来影响其他事情。我已经检查确定路径存在;是的。

这是一个busybox系统,init是到busybox的符号链接。因此,为了确保busybox在PID为1时不会产生奇怪的魔术效果,我还尝试了将一个非busybox程序作为init运行;那也不起作用。看来,无论我做什么,init都会运行。

是什么导致这种现象?


使用busybox的基本发行版是init什么?他们可能只是忽略了命令行...您可能想要检查initrd并查看脚本的实际作用。
亚伦·马拉斯科

这不是发行版,而是我自己的版本;这就是为什么我要调试init脚本的原因。
肖恩·高夫

Answers:


3

查看Linux内核源代码,我看到如果文件/ init存在,则内核将始终在假设其正在执行ramdisk引导的情况下尝试运行它。检查系统以查看/ init是否存在,如果存在,则可能是您的问题。


实际上,它execute_command首先检查,它来自内核命令行init=参数。如果无法执行,则会打印警告并尝试init在各个位置运行。这是在init/main.c功能中init_post()。我查看了内核printk消息,并在内核输出中找到了警告,因此现在我必须弄清楚为什么它无法启动/ bin / sh或其他我尝试启动的内容。
Shawn J. Goff 2012年

我查看的代码(我认为是v3.2.2)检查了set ramdisk_execute_command是否未设置,然后尝试运行它,所以您一定不要那么老。太糟糕了,因为我没有看到其他任何可以解释的信息。
凯尔·琼斯

rdinit从ramdisk引导时,您必须使用以下命令
Ciro Santilli新疆改造中心法轮功六四事件

8

最初的恶作剧

如果使用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_initkernel_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();
    }

TODO:了解sys_access

还要注意,ram初始化和非ram初始化之间还有其他差异,例如,控制台处理:使用嵌入式和外部initramfs执行init的差异?



0

您可以自定义Linux内核并重新编译。对于4.9内核,请在init / main.c中编辑函数“ kernel_init”,然后尝试首先运行以下行:

try_to_run_init_process("/bin/sh")

另外,它可能是由BootLoader传递的内核参数引起的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.