ARM-Linux移植之(三)——init進程啟動流程分析
K-Style
轉載請註明來自于衡陽師範學院08電2 K-Style http://blog.csdn.net/ayangke,QQ:843308498 郵箱:yangkeemail@qq.com
我們通常使用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。
下面我們來總結一下init進程的啟動過程
1.初始化控制台
2.解釋inittab
3.執行inittab運行時機為SYSINIT的進程
4.執行inittab運行時機為WAIT的進程
5.執行inittab運行時機為ONCE的進程
6.執行inittab運行時機為RESPAWN和ASKFRIST的進程,有退出的則重新執行。