我正在尝试在 Linux 系统上调试 init 脚本;我正在尝试传递init=/bin/sh给内核以使其在sh不启动的情况下启动,init以便我可以手动运行 init 序列。
我发现内核init无论如何都在启动。在启动期间,printk 消息之一是命令行,这表明该行设置正确;此外,我可以使用内核命令行影响其他事情。我已经检查以确保路径存在;确实如此。
这是一个busybox系统,init是busybox的符号链接;所以为了确保busybox在PID为1时不会做奇怪的事情,我还尝试将非busybox程序作为init运行;那也没有用。似乎无论我做什么,init 都会运行。
什么可能导致这种行为?
Cir*_*郝海东 13
初始恶作剧
如果您使用的是 initrd 或 initramfs,请记住以下几点:
rdinit= 被用来代替 init=
如果rdinit=未给出,则尝试的默认路径为:/sbin/init, /etc/init, /bin/initand /bin/shbut not/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);
Run Code Online (Sandbox Code Playgroud)
哪里__setup是处理命令行参数的神奇方法。
start_kernel,内核“入口点”调用rest_init,它kernel_init在线程上“调用” :
pid = kernel_thread(kernel_init, NULL, CLONE_FS);
Run Code Online (Sandbox Code Playgroud)
然后,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.");
}
Run Code Online (Sandbox Code Playgroud)
并且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();
}
Run Code Online (Sandbox Code Playgroud)
TODO:明白sys_access。
另请注意,ram inits 和非 ram inits 之间还有进一步的区别,例如控制台处理:使用嵌入式 initramfs 执行 init 与外部 initramfs 的区别?
查看 Linux 内核源代码,我发现如果文件 /init 存在,内核将始终尝试运行它,假设它正在进行 ramdisk 引导。检查您的系统,看看 /init 是否存在,如果存在,那么这可能是您的问题。