busybox init进程分析
本人喜欢用代码+伪代码的方式写笔记。文中的花括号可能是方便记录而已。
如:
hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module)
{
问:怎么获得模块信息的?
答:hardware\libhardware\Hardware.c
...........
}
原创分析, 转载请注明出处:http://www.cnblogs.com/langlang/
作者email: dayhappyhappy@163.com
busybox-1.18.5 分析
文件 init.c
int init_main(int argc UNUSED_PARAM, char **argv)
{
//填充链表init_action_list
parse_inittab();
原型:new_init_action(uint8_t action_type, const char *command, const char *cons)
{
//读取文件 /etc/inittab
parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
//假如 /etc/inittab不存在
if (parser == NULL)
{
new_init_action(CTRLALTDEL, "reboot", "");
原型 new_init_action(uint8_t action_type, const char *command, const char *cons)
{
struct init_action *a, **nextp;
{
注 : struct init_action {
struct init_action *next; //链表指针
pid_t pid; //线程ID
uint8_t action_type; // action的类型 ①
char terminal[CONSOLE_NAME_SIZE]; //运行该command的终端 (*cons)
char command[COMMAND_SIZE]; //command字段用来指定要执行命令(含路径),包括命令行选项。
};
}
nextp = &init_action_list;
假如init_action_list不为空
{
比较查找
}
假如为空
{
a = xzalloc(sizeof(*a));
}
a->action_type = action_type;
safe_strncpy(a->command, command, sizeof(a->command));
safe_strncpy(a->terminal, cons, sizeof(a->terminal));
}
..........
}
else
{
//分析
new_init_action(1 << action, token[3], tty);
}
}
/* Now run everything that needs to be run */
/* First run the sysinit command */
run_actions(SYSINIT);
原型:void run_actions(int action_type)
{
struct init_action *a;
for (a = init_action_list; a; a = a->next) {
if (!(a->action_type & action_type))
continue; //继续查找
if (a->action_type & (SYSINIT | WAIT | ONCE | CTRLALTDEL | SHUTDOWN)) {
pid_t pid = run(a); //执行
{
创建进程
//ASKFIRST类型需要等待回车
if (BB_MMU && (a->action_type & ASKFIRST)) {
static const char press_enter[] ALIGN1 =
"\nPlease press Enter to activate this console. ";
char c;
//输出
dbg_message(L_LOG, "waiting for enter to start '%s'"
"(pid %d, tty '%s')\n",a->command, getpid(), a->terminal);
full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1);
while (safe_read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
continue; //等待回车
}
}
if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN))
waitfor(pid); //待它的command执行完,再继续执行。
}
if (a->action_type & (RESPAWN | ASKFIRST)) {
/* Only run stuff with pid == 0. If pid != 0,
* it is already running
*/
if (a->pid == 0)
a->pid = run(a); //init则不会等待它执行完
}
}
}
check_delayed_sigs();
/* Next run anything that wants to block */
run_actions(WAIT);
check_delayed_sigs();
/* Next run anything to be run only once */
run_actions(ONCE);
while (1) {
/* (Re)run the respawn/askfirst stuff */
run_actions(RESPAWN | ASKFIRST);
maybe_WNOHANG |= check_delayed_sigs();
/* Don't consume all CPU time - sleep a bit */
sleep(1);
maybe_WNOHANG |= check_delayed_sigs();
}
}
① action_type
/* 为init提供初始化命令脚本的路径 */
#define SYSINIT 0x01
/* 告诉init必须等到相应的进程执行完成之后才能继续执行 */
#define WAIT 0x02
/* 仅执行相应的进程一次,而且不会等待它执行完成 */
#define ONCE 0x04
/* 每当相应的进程终止执行时,重新启动该进程 */
#define RESPAWN 0x08
/* 类似respawn,主要用途是减少系统上执行的终端应用程序的数量。
它将会促使init在控制台上显示
“Please press Enter to active this console”的信息,
并在重新启动进程之前等待用户按下“enter”键 */
#define ASKFIRST 0x10
/* 当按下Ctrl+Alt+Delete组合键时,执行相应的进程 */
#define CTRLALTDEL 0x20
/* 当系统关机时,执行相应的进程 */
#define SHUTDOWN 0x40
/* 当init重新启动时,执行相应的进程,通常此处所执行的进程就是init本身 */
文件 init.c
int init_main(int argc UNUSED_PARAM, char **argv)
{
//填充链表init_action_list
parse_inittab();
原型:new_init_action(uint8_t action_type, const char *command, const char *cons)
{
//读取文件 /etc/inittab
parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
//假如 /etc/inittab不存在
if (parser == NULL)
{
new_init_action(CTRLALTDEL, "reboot", "");
原型 new_init_action(uint8_t action_type, const char *command, const char *cons)
{
struct init_action *a, **nextp;
{
注 : struct init_action {
struct init_action *next; //链表指针
pid_t pid; //线程ID
uint8_t action_type; // action的类型 ①
char terminal[CONSOLE_NAME_SIZE]; //运行该command的终端 (*cons)
char command[COMMAND_SIZE]; //command字段用来指定要执行命令(含路径),包括命令行选项。
};
}
nextp = &init_action_list;
假如init_action_list不为空
{
比较查找
}
假如为空
{
a = xzalloc(sizeof(*a));
}
a->action_type = action_type;
safe_strncpy(a->command, command, sizeof(a->command));
safe_strncpy(a->terminal, cons, sizeof(a->terminal));
}
..........
}
else
{
//分析
new_init_action(1 << action, token[3], tty);
}
}
/* Now run everything that needs to be run */
/* First run the sysinit command */
run_actions(SYSINIT);
原型:void run_actions(int action_type)
{
struct init_action *a;
for (a = init_action_list; a; a = a->next) {
if (!(a->action_type & action_type))
continue; //继续查找
if (a->action_type & (SYSINIT | WAIT | ONCE | CTRLALTDEL | SHUTDOWN)) {
pid_t pid = run(a); //执行
{
创建进程
//ASKFIRST类型需要等待回车
if (BB_MMU && (a->action_type & ASKFIRST)) {
static const char press_enter[] ALIGN1 =
"\nPlease press Enter to activate this console. ";
char c;
//输出
dbg_message(L_LOG, "waiting for enter to start '%s'"
"(pid %d, tty '%s')\n",a->command, getpid(), a->terminal);
full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1);
while (safe_read(STDIN_FILENO, &c, 1) == 1 && c != '\n')
continue; //等待回车
}
}
if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN))
waitfor(pid); //待它的command执行完,再继续执行。
}
if (a->action_type & (RESPAWN | ASKFIRST)) {
/* Only run stuff with pid == 0. If pid != 0,
* it is already running
*/
if (a->pid == 0)
a->pid = run(a); //init则不会等待它执行完
}
}
}
check_delayed_sigs();
/* Next run anything that wants to block */
run_actions(WAIT);
check_delayed_sigs();
/* Next run anything to be run only once */
run_actions(ONCE);
while (1) {
/* (Re)run the respawn/askfirst stuff */
run_actions(RESPAWN | ASKFIRST);
maybe_WNOHANG |= check_delayed_sigs();
/* Don't consume all CPU time - sleep a bit */
sleep(1);
maybe_WNOHANG |= check_delayed_sigs();
}
}
① action_type
/* 为init提供初始化命令脚本的路径 */
#define SYSINIT 0x01
/* 告诉init必须等到相应的进程执行完成之后才能继续执行 */
#define WAIT 0x02
/* 仅执行相应的进程一次,而且不会等待它执行完成 */
#define ONCE 0x04
/* 每当相应的进程终止执行时,重新启动该进程 */
#define RESPAWN 0x08
/* 类似respawn,主要用途是减少系统上执行的终端应用程序的数量。
它将会促使init在控制台上显示
“Please press Enter to active this console”的信息,
并在重新启动进程之前等待用户按下“enter”键 */
#define ASKFIRST 0x10
/* 当按下Ctrl+Alt+Delete组合键时,执行相应的进程 */
#define CTRLALTDEL 0x20
/* 当系统关机时,执行相应的进程 */
#define SHUTDOWN 0x40
/* 当init重新启动时,执行相应的进程,通常此处所执行的进程就是init本身 */
#define RESTART 0x80