Linux 시스템에서 init 스크립트를 디버깅하려고합니다. init=/bin/sh
커널을 시작 sh
하지 않고 시작 init
하도록 초기화 하려고 하므로 초기화 시퀀스를 수동으로 실행할 수 있습니다.
내가 찾은 것은 init
어쨌든 커널이 시작되고 있다는 것입니다. 부팅하는 동안 printk 메시지 중 하나가 명령 줄이며, 해당 줄이 올바르게 설정되어 있음을 나타냅니다. 또한 커널 명령 줄을 사용하여 다른 것에 영향을 줄 수 있습니다. 경로가 존재하는지 확인했습니다. 그렇습니다.
이것은 busybox 시스템이며 init는 busybox에 대한 심볼릭 링크입니다. 따라서 busybox가 PID가 1 일 때 이상한 마술을하지 않도록하기 위해 비 busybox 프로그램을 init로 실행 해 보았습니다. 그것도 작동하지 않았다. 내가 무엇을하든 초기화가 실행되는 것 같습니다.
이 문제의 원인은 무엇입니까?
답변
리눅스 커널 소스를 살펴보면, / init 파일이 존재하면 커널은 항상 램 디스크 부팅을하고 있다는 가정하에 커널을 실행하려고 시도합니다. 시스템에 / init가 있는지 확인하십시오. 존재하는 경우 문제 일 수 있습니다.
답변
initrd shenanigans
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
커널 “entry point”는을 호출 하고 스레드에서 rest_init
“호출” kernel_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를 사용한 초기화 실행의 차이?
답변
의 위에
https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt
나는 찾았다 :
일반적인 루트 파일 시스템을 디버깅 할 때는 “init = / bin / sh”로 부팅하는 것이 좋습니다. initramfs에 해당하는 “rdinit = / bin / sh”이며 유용합니다.
따라서 아마도 ridinit = / bin / sh를 시도하십시오
답변
Linux 커널을 사용자 정의하고 다시 컴파일 할 수 있습니다. 4.9 커널의 경우 init / main.c에서 “kernel_init”함수를 편집하고 다음 행을 먼저 실행하십시오.
try_to_run_init_process("/bin/sh")
또한 BootLoader가 전달한 커널 매개 변수로 인해 발생할 수 있습니다.