一、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 install
The 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等