一、busybox是什麼?
(1)busybox是Linux上的一個應用程序(application)。
(2)它整合了許多Linux上常用的工具和命, 如rm, ls, gzip, tftp等。對於這些工具和命令,busybox中的實現可能不是最全的,但卻是最常用的,因此它的特點就是短小精悍,特別適合對尺寸很敏感的嵌入式系統。
(3)busybox的官方網站是http://www.busybox.net/,在這裏你可以找到與busybox相關的所有資料。
二、busybox的下載
最新的busybox的源碼更新都可以在http://www.busybox.net/downloads/ 裏面找到。
三、Busybox目錄結構簡介
四、Busybox中最重要的程序:init進程
(1)Busybox init在嵌入式系統中的應用
大家都知道init進程是由內核啓動的第一個(也是唯一一個)用戶進程(進程ID爲1),init進程根據配置文件決定啓動哪些程序,例如:執行某些腳本、啓動shell或運行用戶程序等等。
由於BusyBox自身的一些特點,BusyBox init非常適合在嵌入式系統開發中使用,被譽爲“嵌入式linux的瑞士軍刀”。 在嵌入式系統中常使用的也是Busybox集成的init程序,通過定製可以將其做得非常精煉。
(2)init的執行流程
移植uboot的目的是啓動內核,啓動內核的目的是運行應用程序,從內核的啓動流程中可以知道內核啓動的第一個應用程序就是busybox裏的/sbin/init進程!
但是我們的最終目的不是啓動init進程,而是運行客戶的程序!
那麼init進程是如何選擇性的運行客戶的程序呢?我們猜測init進程肯定需要:
(1) 讀取一個配置文件
(2) 解析該配置文件
(3) 根據配置文件執行客戶的程序
接下來分析busybox中init程序的源碼,看看我們上述猜測的流程是否相同。
由於init_main很長,所以我們簡化其代碼,就流程中的幾個重點部分代碼進行分析:
init_main()在init/init.c的中,以下按照重點代碼順序依次分析:
1.在設置信號後,初始化/dev/console
console_init();
2.讀取配置文件,並解析它
if (argv[1]
&& (strcmp(argv[1], "single") == 0 || strcmp(argv[1], "-s") == 0 || LONE_CHAR(argv[1], '1'))
) {
new_init_action(RESPAWN, bb_default_login_shell, "");
}
else {
parse_inittab();
}
因爲內核啓動/sbin/init是沒有傳如何參數,所以上述程序進入parse_inittab()函數。
我們進入到parse_inittab()函數:
首先遇到的是這段程序:
parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
由此可以知道init進程讀取的配置文件就是/etc/inittab,busybox中的inittab文件中規定了/etc/inittab內容的填寫格式如下:
<id>:<runlevel>:<action>:<process>
Id:id會加上一個/dev前綴作爲一個控制終端(stdin,stdout,stderr)
Runlevel:忽略
Action:執行的時機,包括SYSINIT,WAIT,ONCE, RESPAWN,ASKFIRST等
Process:要執行的應用程序或者腳本
接着繼續分析 parse_inittab()剩餘的程序:
if (parser == NULL)
{
new_init_action(SYSINIT, INIT_SCRIPT, "");
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(CTRLALTDEL, "reboot", "");
new_init_action(SHUTDOWN, "umount -a -r", "");
new_init_action(SHUTDOWN, "swapoff -a", "");
new_init_action(RESTART, "init", "");
return;
}
如果配置文件/etc/inittab不存在的話則執行if語句,也就是說如果沒/etc/inittab的話init進程會直接調用new_init_action來構造默認配置項,根據if語句裏的內容,我們可以反推出等效的/etc/inittab的內容如下:
::SYSINIT:/etc/init.d/rcS
::ASKFIRST:-/bin/ah
tty2:: ASKFIRST:-/bin/sh
tty3:: ASKFIRST:-/bin/sh
tty4:: ASKFIRST:-/bin/sh
::CTRLALTDEL:reboot
::SHUTDOWN:umount -a –r
::RESTART:init
這裏 new_init_action()函數是配置的核心,其主要作用是將/etc/inittab裏的每一條配置項做成一個init_action結構體並添加到具有相同執行時機的init_action_list中去,最終將它們連接成單鏈表。
也就是說解析/etc/inittab這個配置文件就是爲了把各配置項添加到對應的init_action_list中去。
到這裏,parse_inittab()這個函數就結束了,我們繼續回到init_main()這個函數的分析。
3.運行parse_inittab()幫我們添加到init_action_list中的程序或腳本
run_actions(SYSINIT);
run_actions(WAIT);
run_actions(ONCE);
while (1)
{
run_actions(RESPAWN);
run_actions(ASKFIRST);
}
run_actions爲運行一類程序或腳本,這裏的一類就是按照執行時機來分類的。
總結上述對於init_main()函數的分析,我們看到init進程的執行流程與我們猜測的基本相同。init進程起來後,首先會去讀取/etc/inittab配置文件,如果沒/etc/inittab的話init進程會直接調用new_init_action來構造默認配置項;然後解析這個配置文件,將/etc/inittab裏的每一條配置項做成一個init_action結構體並添加到具有相同執行時機的init_action_list;最後,根據init_action_list來運行其中的程序和腳本。
五、busybox的配置、編譯和安裝
在busybox的INSTALL文件已經說明我們應該如何配置、編譯和安裝busybox。
Building:
=========The BusyBox build process is similar to the Linux kernel build:
make menuconfig # This creates a file called ".config"
make # This creates the "busybox" executable
make install # or make CONFIG_PREFIX=/path/from/root installThe full list of configuration and install options is available by typing:
make help
文件中寫的很明確,編譯busybox和編譯linux kernel差不多。即首先要make menuconfig生成配置文件.config。然後make生成busybox可執行文件。最後make install安裝busybox。
第一步,執行 make menuconfig:
執行過後會出現圖形界面,這方便了我們對busybox的配置,這裏我們只需要手動選擇需要編譯安裝的項目,最後進行保存就可以了。最後Exit,save即可。
第二步,執行make命令生成可執行busybox文件。
第三步,make install進行安裝。
這樣,經過簡單的配置、編譯和安裝我們便可以使用busybox了。
關於busybox的配置、編譯和安裝可以詳細參考博客: busybox詳解 中的構造自己的根文件系統部分。
六、關於busybox的使用
busybox的使用很簡單,有以下三種方式:
(1) busybox後直接跟命令,如
busybox ls
busybox tftp
(2) 直接將busybox重命名,如
cp busybox tftp
cp busybox tar
然後再執行tftp, tar
(3) 創建符號鏈接(symbolic link), 如
ln -s busybox rm
ln -s busybox mount
然後就可以執行rm,mount等