ARM-Linux移植之(三)——init進程啓動流程分析
K-Style
轉載請註明來自於衡陽師範學院08電2 K-Style http://blog.csdn.net/ayangke,QQ:843308498 郵箱:[email protected]
我們通常使用Busybox來構建根文件系統的必要的應用程序。Busybox通過傳入的參數來決定執行何種操作。當init進程啓動時,實際上調用的是Busybox的init_main()函數,下面我們來分析這個函數,看init進程究竟是怎樣一個流程。我分析的Busybox源碼是1.7.0版本的,其他版本會略有不同。部分代碼省略我們只看關鍵性代碼。
首先看init_main函數
int init_main(int argc, char **argv);
int init_main(int argc, char **argv)
{
……………………………..
……………………………..
//初始化控制檯
console_init();
………………………………
if (argc > 1
&& (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1'))
) {
new_init_action(RESPAWN, bb_default_login_shell, "");
} else {
//因爲我們啓動的init進程沒有任何參數,所有argc==1,執行的是這一句
parse_inittab();
}
…………………………………………
…………………………………………
run_actions(SYSINIT); //運行inittab配置文件中acthion爲SYSINIT的進程
run_actions(WAIT); //運行inittab配置文件中action爲WAIT的進程
run_actions(ONCE); //運行inittba配置文件中action爲ONCE的進程
………………………………………………
while (1) {
/*
運行inittab配置文件中action爲RESPAWN和ASKFIRST的進程,一旦退出則重新啓動
*/
run_actions(RESPAWN);
run_actions(ASKFIRST);
wpid = wait(NULL);
while (wpid > 0) {
a->pid = 0;
}
wpid = waitpid(-1, NULL, WNOHANG);
}
}
parse_inittab實際上對/etc/inittab文件裏面的配置進行解釋,如果沒有,則設置一些默認設置。
我們先來看看這個inittab這個文件裏面的配置格式,這個在busybox文件裏面的inittab文件裏面有說明
<id>:<runlevels>:<action>:<process>
id表示輸出輸入設備,這個不需要設置,因爲/etc/console已經設爲標準輸入輸出了,如不設置,則從控制檯輸入輸出。
runlevels 這個參數完全忽略
action 運行時機,它表示inittab解釋後的運行順序,它有sysinit, respawn, askfirst, wait, once,restart, ctrlaltdel, andshutdown.這個值可選擇。
process 就是要啓動的進程。
下面來看prase_inittab這個函數
static void parse_inittab(void)
{
…………………………………………………
…………………………………………………
/*INITTAB是一個宏 #define INITTAB "/etc/inittab"
可以看得出來它打開了/etc/inittab這個文件*/
file = fopen(INITTAB, "r");
//如果沒有這個文件,則調用new_init_action進行一些默認的操作
if (file == NULL) {
new_init_action(CTRLALTDEL, "reboot", "");
new_init_action(SHUTDOWN, "umount -a -r", "");
if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", "");
new_init_action(RESTART, "init", "");
new_init_action(ASKFIRST, bb_default_login_shell, "");
new_init_action(ASKFIRST, bb_default_login_shell, VC_2);
new_init_action(ASKFIRST, bb_default_login_shell, VC_3);
new_init_action(ASKFIRST, bb_default_login_shell, VC_4); new_init_action(SYSINIT, INIT_SCRIPT, "");
return;
}
…………………………………………………
…………………………………………………
/*果inittab文件裏面有內容就將裏面的內容一行一行讀出來,然後調用new_init_action進行操作*/
while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {
/* Ok, now process it */
for (a = actions; a->name != 0; a++) {
if (strcmp(a->name, action) == 0) {
if (*id != '\0') {
if (strncmp(id, "/dev/", 5) == 0)
id += 5;
strcpy(tmpConsole, "/dev/");
safe_strncpy(tmpConsole + 5, id,
sizeof(tmpConsole) - 5);
id = tmpConsole;
}
new_init_action(a->action, command, id);
break;
}
}
…………………………………………………
…………………………………………………
}
fclose(file);
}
這個new_init_action函數,它實際上是將inittab裏面的action相同的操作串成一個鏈表。
下面我們再來分析init_main執行prase_inittab之後執行的操作
可以看出init_main執行prase_initab對inittab文件裏面的配置進行解釋之後,會先執行運行時機爲SYSINIT的進程,讓執行WAIT時機的,接着是ONCE的,然後在一個while(1)函數裏面運行RESPAWN和ASKFIRST時機的,一旦這兩個時機裏面的進程被殺死,就會把他們的pid賦爲0,然後跳到while(1)函數的開始處又去啓動他們。所有說運行時機爲RESPAWN和ASKFIRST的進程永遠無法殺死,除非reboot或者shutdown。