一、Busybox
Busybo是一个遵循GPLv2协议的开源项目。
Busybox将众多的Linux命令集合进一个很小的可执行程序中,可以用来替换GNU fileutils shellutils等工具集。Busybox中各种命令与相应的GNU工具相比,所能提供的选项较少,但是能够满足一般应用。
Busybox为各种小型 的或者嵌入式系统提供了一个比较完完全的工具集。
Busybox在编写过程中对文件大小进行了优化,并考虑了系统资源有限的情况。与一般的GNU 工具集动辄几MB的体积相比,动态连接的Busybox只有几百KB,即使静态连接也只有1MB左右。有人将Busybox比喻成Linux工具中的瑞士 军刀,简单的说就是好像是Linux的一个大的工具集,包括了Linux中的大部分命令和工具。嵌入式根目录下的bin,sbin和usr目录以及 linuxc通常就是Busybox。Busybox会根据配置的不同自动的生成一些文件,但是有些根文件系统下的文件还是需要用户自己来建立。
二、Busybox启动流程分析
init进程是由内核启动的第一个也是惟一的一个用户进程,它根据配置文件决定启动哪些程序,比如执行某些脚本,启动shell,运行用户指定的程序等。 init进程是后续所有进程的发起者,比如init进程启动/bin/sh程序后,才能够在控制台上输入各种命令。
init进程的执行程序通常是sbin/init,上面讲述的init进程的作用只不过是/sbin/init这个程序的功能。在嵌入式领域,通常使用 Busybox集成的init程序.嵌入式根目录下的bin,sbin和usr目录以及linuxc通常就是Busybox。
1、在kernel/init/main.c的init函数中有如下代码:
if(execute_command)
execve(execute_command,argv_init,envp_init);
execve("/sbin/init",argv_init,envp_init);
bootloader会传给内核的main函数 init=/linuxrc这个参数,于是就会执行下面的这句
execute_command = "linuxrc",busybox中_install目录下的linuxrc是Busybox的一个软链接,指向/bin/busybox,而 /sbin/init也是/bin/busybox的符号链接,因此这个linxrc基本没有实际的意义只是一个连接作用。我们可以重写linuxrc, 添加自己的一些初始化的东西。这样就可以把Linux内核中的init程序和Busybox中的init程序结合起来了。
2、Busybox init进程启动流程
Busybox是目标板系统上执行的第一个应用程序,当调用Busybox它会执行Busybox自身的init进程。
Busybox initt 程序对应的代码在init/init.c文件中。其对应的流程图如下:
其中与构建根文件系统关系密切的是控制台的初始化,对inittab文件的解释及执行。从图中我们可以 看出,
Busybox init启动的第一个函数是int init_main(int argc UNUSED_PARAM, char **argv),在这里可以设置信号的处理函数,初始化控制台,最重要的是解析inittab中内容。
在init_main()函数中会调用parse_inittab(void)函数,parse_inittab(void)函数可以使用一些默认的配置,当/etc/inittab没有配置时。
static void parse_inittab(void) { #if ENABLE_FEATURE_USE_INITTAB char *token[4]; parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
if (parser == NULL) #endif { /* 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 QUIT is received */ new_init_action(RESTART, "init", ""); /* Askfirst shell on tty1-4 */ new_init_action(ASKFIRST, bb_default_login_shell, ""); //TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
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; }
.............. }
|
其中最重要的一个是其中,最重要的一个,就是 new_init_action(SYSINIT, INIT_SCRIPT, ""),也就决定了接下去初始化的脚本是INIT_SCRIPT所定义的值。这个宏的默认值是"/etc/init.d/rcS".
#define INITTAB "/etc/inittab" /* inittab file location */ #ifndef INIT_SCRIPT #define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */ #endif |
1)下面是分析文件系统中/etc/init.d/rcS的内容,这是我的rcS文件中的内容。这个文件会在inittab中使用。在inittab后启动rcS.
#!/bin/sh PATH=/sbin:/bin:/usr/sbin:/usr/bin runlevel=S prevlevel=N umask 022 export PATH runlevel prevlevel //上面几句为启动环境设置必要的环境变量 echo "----------munt all----------------" mount -a //加载文件/etc/fstab文件中的选项, echo /sbin/mdev>/proc/sys/kernel/hotplug mdev -s //在/dev 目录下建立必要的设备节点; echo "***********************************************" echo "****************Studying ARM Embedded ********************* echo "Kernel version:linux-2.6.32.1" echo "Author frank" echo "Date:2010.4.19" echo "***********************************************
/bin/hostname -F /etc/sysconfig/HOSTNAME //设置主机的名字
|
//下面这一句是设置内核的hotplug handler 为 mdev, 即当设备热插拔时,由 mdev 接收来自内核的消息并作出相应的回应, 比如挂载U盘。
echo /sbin/mdev>/proc/sys/kernel/hotplug
|
2)下面是inittab文件的分析:如果存在/etc/inittab文件,Busybox init程序解析它,然后按照它的指示各种子进程,否则使用默认的配置创建子进程
#etc/inittab ::sysinit:/etc/init.d/rcS //作为系统初始化文件. s3c2410_serial0::askfirst:-/bin/sh 在串口启动一个登录会话 ::ctrlaltdel:/sbin/reboot //作为init重启执行程序. ::shutdown:/bin/umount -a –r //告诉init在关机时运行umount命令卸载所有的文件系统,如果卸载失败,试图以只读方式重新挂载。 |
/etc/inittab 文件中每个条目用来定义一个子进程,并确定它的启动方法,格式如下 :
:::
例如:
ttySAC0:askfirst:-/bin/sh
(1):表示这个进程要使用的控制台(即标准输入、标准输出、标准错误设备)。如果省略,则使用与init进程一样的控制台。
(2):对于Busybox init程序,这个字段滑意义,可以省略。
(3):表示init程序如何控制这个子进程,
(4): 要执行的程序,它可以是可执行程序,也可以是脚本
如果:字段有"-"字符,表示这个程序被称为“交互的”。在/etc/inittab/文件的控制下,init进程的行为总结如下:
(1)在系统启动前期,init进程首先启动为sysinit wait once的3类子进程。
(2)在系统正常运行期间,init程序首先启动,为respawn askfirst的两类子进程,并监视它们,发现某个子进程退出时重新启动它。
(3) 在系统退出时,执行 为shutdown restart ctrlaltdel的3类子进程之一或全部。
如果根文件系统中没有/etc/initab文件,Busybox init程序将使用如下默认的inittab条目。
/etc/inittab文件中字段的意义
Action 名称 |
执行条件 |
说明 |
Sysinit |
系统启动后最先执行 |
只执行一次, init 进程等待它结束才继续执行其它动作 |
Wait |
系统执行完 sysinit 进程后 |
只执行一次, init 进程等待它结束才继续执行其它动作 |
Once |
系统执行完 wait 进程后 |
只执行一次 ,init 进程不等待它结束 |
Respawn |
启动完 once 进程后 |
Init 进程监测发现子进程退出时,重新启动它 |
Askfirst |
启动完 respawn 进程后 |
与 respawn 类似,不过 init 进程先输出“ Please press Enter to actvie this console ”,等用户输入驾车键之后才启动子进程 |
Shutdown |
当系统关机时 |
即重启关闭系统命令时 |
Restart |
Busybox 中配置了CONFIG_FEATURE_USE_INITTAB,并且 init 进程接收到 SIGHUP 信号时 |
先重新读取,解析 /etc/initab 文件,再执行 restart 程序 |
Ctrlatldel |
按下 Ctr+Alt+del 组合键时 |
|
3)下面是etc/fstab文件内容,表示执行完“mount -a”命令后将挂载proc tmpfs等系统
#device mount-point type option dump fsck order proc /proc proc defaults 0 0 temps /tmp rpoc defaults 0 0 none /tmp ramfs defaults 0 0 sysfs /sys sysfs defaults 0 0 mdev /dev ramfs defaults 0 0 |
4)/etc/profile文件
这个文件是 sh 用的,当用户获得一个 shell 后, sh 就会根据这个文件配置用户的登陆环境,下面是我的profile 文件。
# Ash profile # vim: syntax= sh # No core file by defaults # ulimit - S - c 0> / dev/ null 2> & 1 USER= "id -un" LOGNAME= $ USER PS1= '[/u@/h=W]#' PATH= $ PATH HOSTNAME= '/bin/hostname' export USER LOGNAME PS1 PATH |
其中PATH环境变量指定当用户键入一个命令时,sh寻找这个命令的路径。PS1指定sh提示符的格式。其它的 export 命令, alias 命令, busybox 里面的 ash 和 bash 非常相似
这样,
Busybox所需的基本的配置文件就完成了。这也是Busybox最基本的文件,当然还可以配置更多的文件,增强Busybox的功能。