在 BusyBox 的 init 实现中,run 函数负责解析并执行 inittab 中的条目(如 console::once:/path/to/script.sh)。以下是它的关键实现位置和逻辑分析:
1. run 函数定义位置
- 源代码文件:
BusyBox 的init相关代码位于:
busybox/init/init.c(具体路径可能因版本略有不同)。 - 函数定义:
搜索关键字static void run(struct init_action *a),通常在较新版本的 BusyBox 中可找到类似实现。
2. run 函数的执行流程
当 BusyBox init 处理到 inittab 中的某个条目(如 console::once:/etc/init.sh)时:
解析条目:
将条目拆解为<terminal>:<action>:<process>,存入struct init_action。struct init_action { char terminal[TERMINAL_NAME_SIZE]; // e.g., "console" char action_type; // e.g., 'o' (once), 'r' (respawn) char command[INIT_COMMAND_SIZE]; // e.g., "/etc/init.sh" pid_t pid; // Child process PID };调用
run():
根据动作类型(如once,respawn,askfirst),决定如何运行命令:static void run(struct init_action *a) { pid_t pid = fork(); if (pid == 0) { // Child process setsid(); // Start a new session if (a->terminal[0]) { open_terminal(a->terminal); // Open /dev/console or other TTY } exec_cmd(a->command); // Execute the script (e.g., via /bin/sh) _exit(EXIT_FAILURE); // If exec fails } else { // Parent process (PID=1) a->pid = pid; } }绑定终端 (
/dev/console):
如果条目指定了终端(如console::...),子进程会通过以下步骤关联控制台:- 调用
open_terminal("/dev/console")→ 打开设备文件。 - 使用
dup2()将/dev/console绑定到 stdin/stdout/stderr。
- 调用
执行脚本:
最终通过/bin/sh -c /etc/init.sh(或直接 execve())运行脚本。
3. /dev/console vs Shell
- 关键区别:
如果脚本未显式重定向输出,其 stdout/stderr 自动继承父进程的文件描述符,即指向/dev/console. - 验证方法:
在脚本中添加调试命令查看文件描述符:
#!/bin/sh
ls -l /proc/$$/fd # $$ = current PID, check fd 0(stdin),1(stdout),2(stderr)
echo "Hello" > /dev/tty # Direct write to current terminal
4. FAQ
(1) Q: Why doesn’t my script output appear on console?
- A: Check:
- Kernel是否启用了控制台输出(检查内核参数如
console=ttyS0,115200n8)。 /dev/concole是否存在且可写:ls -l /dev/concole && echo test > /dev/concole- Script是否有权限执行 (
chmod +x /etc/initsh.sh)
- Kernel是否启用了控制台输出(检查内核参数如
(2) Q: How to debug inittab execution?
- A: Enable BusyBox debug logging by recompiling with:
make EXTRA_CFLAGS="-DDEBUG_INIT"
Or add logging in your script:
“`sh
#!/bin/sh
exec > /tmp/debug.logs.txt
exec
内容由零声教学AI助手提供,问题来源于学员提问




