initのようなプログラムを起動するのではなく、init = / path / to / programがカーネルに渡されるのはなぜですか?

initのようなプログラムを起動するのではなく、init = / path / to / programがカーネルに渡されるのはなぜですか?

私はLinuxシステムで初期化スクリプトをデバッグしようとしています。初期化シーケンスを手動で実行できるように、起動せずに起動するようにinit=/bin/shカーネルに渡したいと思います。shinit

とにかくカーネルがinit起動することがわかりました。起動中に、printkメッセージの1つはコマンドラインであり、これはその行が正しく設定されていることを示し、カーネルコマンドラインを使用して他のものにも影響を与える可能性があります。パスが存在することを確認しました。

これはビジボックスシステムであり、initはビジボックスへのシンボリックリンクなので、PIDが1のときにビジボックスが奇妙なことをしないようにするために、ビジボックス以外のプログラムもinitとして実行してみました。私が何をしても、initが実行されているようです。

この動作の原因は何ですか?

ベストアンサー1

初期のいたずら

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

さらに、コンソール処理のように、ラム初期化と非ラム初期化との間には、より多くの違いがある。初期化を実行するための組み込みinitramfsと外部initramfsの違いは何ですか?

おすすめ記事