现在的位置: 首页 > 综合 > 正文

Busybox init进程启动过程分析

2018年01月23日 ⁄ 综合 ⁄ 共 5585字 ⁄ 字号 评论关闭
上一篇文章只是移植了Busybox不过对中间的启动流程还不是很清楚,经过查看资料,终于搞明白了Busybox启动的基本的流程。现把流程记录如下:
一、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 文件中每个条目用来定义一个子进程,并确定它的启动方法,格式如下

<id>:<runlevels>:<action>:<process>
例如:
ttySAC0:askfirst:-/bin/sh
(1)<id>:表示这个进程要使用的控制台(即标准输入、标准输出、标准错误设备)。如果省略,则使用与init进程一样的控制台。
(2)<runlevels>:对于Busybox
init程序,这个字段滑意义,可以省略。
(3)<action>:表示init程序如何控制这个子进程,
(4)<process>:
要执行的程序,它可以是可执行程序,也可以是脚本
如果<process>:字段有"-"字符,表示这个程序被称为“交互的”。在/etc/inittab/文件的控制下,init进程的行为总结如下:
(1)在系统启动前期,init进程首先启动<action>为sysinit
wait once的3类子进程。
(2)在系统正常运行期间,init程序首先启动,<action>为respawn
askfirst的两类子进程,并监视它们,发现某个子进程退出时重新启动它。
(3) 在系统退出时,执行<action> 为shutdown
restart ctrlaltdel的3类子进程之一或全部。
如果根文件系统中没有/etc/initab文件,Busybox
init程序将使用如下默认的inittab条目。

             /etc/inittab文件中<action>字段的意义

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里面的ashbash非常相似

   
这样,Busybox所需的基本的配置文件就完成了。这也是Busybox最基本的文件,当然还可以配置更多的文件,增强Busybox的功能。

抱歉!评论已关闭.