构建根文件系统之busybox(一)浅析
目錄
- busybox(一)淺析
- 引入
- 讀取inittab
- 創(chuàng)建執(zhí)行腳本鏈表
- 執(zhí)行腳本
- 小結(jié)
busybox(一)淺析
源碼包在busybox-1.7.0.tar.bz2,一個(gè)命令對應(yīng)著一個(gè)c文件,執(zhí)行init命令,則是有init.c,有函數(shù)init_main
int init_main(int argc, char **argv);最終的目的是啟動(dòng)客戶的應(yīng)用程序,需要指定具體的環(huán)境
1. 配置文件讀取 2. 解析配置文件 3. 執(zhí)行用戶程序help
相關(guān)的幫助可以搜索下/examples下的文件,比如搜索inittab,里面有相關(guān)說明
#define SYSINIT 0x001 //執(zhí)行一次等待結(jié)束后從鏈表刪除 #define RESPAWN 0x002 //while循環(huán)執(zhí)行 #define ASKFIRST 0x004 //while循環(huán)執(zhí)行,會(huì)打印信息,等待回車 #define WAIT 0x008 //執(zhí)行一次等待結(jié)束后從鏈表刪除,在SYSINIT后 #define ONCE 0x010 //與SYSINIT 區(qū)別在于不等待其執(zhí)行結(jié)束 #define CTRLALTDEL 0x020 //輸入信號(hào)后執(zhí)行 #define SHUTDOWN 0x040 //輸入信號(hào)后執(zhí)行 #define RESTART 0x080 //輸入信號(hào)后執(zhí)行流程圖
引入
從init_main函數(shù)入口分析,Linux 是按照run_init_process("/sbin/init");形式調(diào)用,沒有傳遞參數(shù),所以執(zhí)行else分支,解析配置表
if (argc > 1&& (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1')) ) {/* Start a shell on console */new_init_action(RESPAWN, bb_default_login_shell, ""); } else {/* Not in single user mode -- see what inittab says *//* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,* then parse_inittab() simply adds in some default* actions(i.e., runs INIT_SCRIPT and then starts a pair* of "askfirst" shells */parse_inittab(); }讀取inittab
parse_inittab();讀取inittab配置表,可以搜索下example下查看例子幫助,查閱如下格式
Format for each entry: <id>:<runlevels>:<action>:<process> <id>: WARNING: This field has a non-traditional meaning for BusyBox init! <runlevels>: The runlevels field is completely ignored. <action>: Valid actions include: sysinit, respawn, askfirst, wait, once,restart, ctrlaltdel, and shutdown. <process>: Specifies the process to be executed and it's command line.| id | 自動(dòng)加上/dev/的前綴,用作終端,stdin,stdout,stderr:printf,scanf,err 可以省略 |
| runlevels | 可以忽略 |
| action | 指示何止執(zhí)行 |
| process | 應(yīng)用程序或者可執(zhí)行腳本 |
最終執(zhí)行new_init_action運(yùn)行腳本程序
默認(rèn)的配置表讀取
#define INITTAB "/etc/inittab" /* inittab file location */ static void parse_inittab(void) {file = fopen(INITTAB, "r"); }創(chuàng)建執(zhí)行腳本鏈表
for (a = actions; a->name != 0; a++) {if (strcmp(a->name, action) == 0) {if (*id != '\0') {if (strncmp(id, "/dev/", 5) == 0) //這里為id加上/dev/的前綴id += 5;strcpy(tmpConsole, "/dev/");safe_strncpy(tmpConsole + 5, id,sizeof(tmpConsole) - 5);id = tmpConsole;}new_init_action(a->action, command, id);break;} }當(dāng)不存在這個(gè)配置表的時(shí)候也會(huì)有一個(gè)默認(rèn)配置文件,這里以默認(rèn)的其中一個(gè)腳本解析
new_init_action(ASKFIRST, bb_default_login_shell, VC_2);# define VC_2 "/dev/tty2" #define ASKFIRST 0x004 const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; #define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh"也就是最終執(zhí)行
new_init_action(ASKFIRST, "-/bin/sh", "/dev/tty2"); ASKFIRST 執(zhí)行的時(shí)機(jī) -/bin/sh 腳本程序 /dev/tty2 id終端,加上了/dev/,符合上述描述分析下new_init_action函數(shù)內(nèi)部,
由此,可以理解當(dāng)配置文件不存在的時(shí)候,會(huì)去創(chuàng)建配置表
#define INITTAB "/etc/inittab" /* inittab file location */file = fopen(INITTAB, "r");if (file == NULL) {/* No inittab file -- set up some default behavior *//* Reboot on Ctrl-Alt-Del */new_init_action(CTRLALTDEL, "reboot", "");/* Umount all filesystems on halt/reboot */new_init_action(SHUTDOWN, "umount -a -r", "");/* Swapoff on halt/reboot */if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", "");/* Prepare to restart init when a HUP is received */new_init_action(RESTART, "init", "");/* Askfirst shell on tty1-4 */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);/* sysinit */new_init_action(SYSINIT, INIT_SCRIPT, "");return;} >>>>>>>>>>>>>>>>>>>>>>>>>>>>>↓ 創(chuàng)建類似的inittatb ↓ >>>>>>>>>>>>>>>>>>>>>>>>>>>>>↓ ::CTRLALTDEL:reboot ::SHUTDOWN:umount -a -r ::RESTART:init ::ASKFIRST:-/bin/sh: tty2::ASKFIRST:-/bin/sh tty3::ASKFIRST:-/bin/sh tty4::ASKFIRST:-/bin/sh ::SYSINIT:/etc/init.d/rcS執(zhí)行腳本
腳本有多種類型,不同類型執(zhí)行方式與時(shí)機(jī)不同
#define SYSINIT 0x001 //執(zhí)行一次等待結(jié)束后從鏈表刪除 #define RESPAWN 0x002 //while循環(huán)執(zhí)行 #define ASKFIRST 0x004 //while循環(huán)執(zhí)行,會(huì)打印信息,等待回車 #define WAIT 0x008 //執(zhí)行一次等待結(jié)束后從鏈表刪除,在SYSINIT后 #define ONCE 0x010 //與SYSINIT 區(qū)別在于不等待其執(zhí)行結(jié)束 #define CTRLALTDEL 0x020 //輸入信號(hào)后執(zhí)行 #define SHUTDOWN 0x040 //輸入信號(hào)后執(zhí)行 #define RESTART 0x080 //輸入信號(hào)后執(zhí)行 run_actions(SYSINIT);waitfor(a, 0);//執(zhí)行a,等待執(zhí)行結(jié)束run(a);//執(zhí)行創(chuàng)建process子進(jìn)程waitpid(runpid, &status, 0);delete_init_action(a);//刪除鏈表/* Next run anything that wants to block */run_actions(WAIT);waitfor(a, 0);//執(zhí)行a,等待執(zhí)行結(jié)束run(a);//執(zhí)行創(chuàng)建process子進(jìn)程waitpid(runpid, &status, 0);delete_init_action(a);//刪除鏈表/* Next run anything to be run only once */run_actions(ONCE);run(a);delete_init_action(a);/* Now run the looping stuff for the rest of forever */while (1) {//重新運(yùn)行pid已經(jīng)退出的子進(jìn)程run_actions(RESPAWN);if (a->pid == 0) { //默認(rèn)pid為0a->pid = run(a);}run_actions(ASKFIRST);if (a->pid == 0) {a->pid = run(a);}//打印"\nPlease press Enter to activate this console. ";,//等待輸入回車//創(chuàng)建子進(jìn)程wpid = wait(NULL);//等待子進(jìn)程退出while (wpid > 0) {a->pid--;//推出后pid=0}}}小結(jié)
所以一個(gè)最小的根文件系統(tǒng)必備的一些資源
dev/console dev/null sbin/init-------------busybox提供,至少需要這個(gè)應(yīng)用程序,這是linux啟動(dòng)的第一個(gè)應(yīng)用程序 etc/inittab-----------配置文件,定義了一些應(yīng)用程序 配置文件制定的應(yīng)用程序----配置文件指定的應(yīng)用程序 C庫--------------------應(yīng)用程序的C庫總結(jié)
以上是生活随笔為你收集整理的构建根文件系统之busybox(一)浅析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从0写bootloader
- 下一篇: 构建根文件系统之启动第1个程序init