韦东山uboot_内核_根文件系统学习笔记4.2-第004课_根文件系统-第002节_构建根文件系统之init进程分析

一 busybox的作用

  1. busybox的作用:本质是一个应用程序,它实现了响应shell发送的ls/cp等各种指令。
shell发送ls指令==执行busybox ls指令

验证上述结论:
根目录系统bin文件夹:/bin存放二进制可执行文件(ls,cat,mkdir等),常用命令一般都在这里。
在这里插入图片描述
在这里插入图片描述
上图可以看出:ls指令实际上链接到了busybox文件

  1. busybox的作用:linux内核上电执行的初始进程/sbin/init也是busybox来实现的。
    在这里插入图片描述

二 busybox源码分析1

注:以cp命令和init命令为例说明

  1. cp指令对应cp.c文件,里面有cp_main()子函数
    在这里插入图片描述
  2. init程序:init.c文件如下图。当linux内核调用sbin/init的时候就执行init_main程序。
    在这里插入图片描述

三 busybox源码分析2-init程序分析

init程序的作用:最终目的启动用户程序

设计思路:
(1)读取配置文件
(2)解析配置文件
(3)根据配置文件执行用户程序

init程序的源码分析:

busybox-> init_main
			parse_inittab();
				file = fopen(INITTAB, "r");				//(1)打开配置文件etc/inittab
										   			    //(2)解析文件过程;
				new_init_action(a->action, command, id);//(3)根据配置文件执行用户程序
														//a->action:inittab配置文件<action>
														//command:inittab配置文件<process>
														//id:inittab配置文件格式<id>
			run_actions(SYSINIT);
				waitfor(a, 0);//执行应用程序,等待它执行完毕
				delete_init_action(a);把SYSINIT对应的应用程序从链表中删除,即只允许执行一次
			run_actions(WAIT);
			run_actions(ONCE);
			while(1){
			...
			}


inittab配置文件格式:
<id>:<runlevels>:<action>:<process>

<id>=> /dev/id,用作终端:stdin,stdout,stderr:printf,scanf,err
<runlevels>:=>忽略
<action>:执行时机
 		 有效取值: sysinit, respawn, askfirst, wait, once,restart, ctrlaltdel, and shutdown.
<process>:应用程序或者脚本
  1. 按键信号处理:例如按住ctrl+alt+del按键的时候会进行特定处理
    在这里插入图片描述
  2. linux调用本程序的时候无参数输出,所以argc=1执行parse_inittab();
    在这里插入图片描述

四 busybox源码分析3-分析函数parse_inittab()

  1. 进入parse_inittab();函数进行分析:
    (1)打开配置文件INITTAB
    在这里插入图片描述
    INITTAB文件存放地址参见下图。
    在这里插入图片描述
    INITTAB配置文件格式:(参见busybox-1.7.0\examples\inittab)
# <id>:<runlevels>:<action>:<process>

INITTAB配置文件包含的信息:指定哪个用户程序;程序何时执行;
(2)如果没有默认的配置文件会进行下面若干处理
在这里插入图片描述
(3)解析INITTAB文件:
a.如果出现#字符或者回车字符直接忽略整行
在这里插入图片描述
b.把id字符串前面加上/dev/,最终执行LINE846行代码:进入new_init_action();函数
在这里插入图片描述

  1. 分析new_init_action(int action, const char *command, const char *cons);函数:
    new_init_action(ASKFIRST, bb_default_login_shell, VC_2);new_init_action(0x004, "-/bin/sh", "/dev/vc/2");为例分析
    下表是重点!!!!!!
例子中传入的参数										参数含义							函数声明原型
ASKFIRST:0x004------------------------>inittab配置文件<action>调用时机------------>int action
bb_default_login_shell:"-/bin/sh"----->inittab配置文件<process>应用程序或者脚本---->const char *command
VC_2:"/dev/tty2"---------------------->inittab配置文件格式<id>用作终端------------->const char *cons

设计思路:创建一个init_action结构,用传入的参数进行初始化;把该结构放入init_action_list链表
在这里插入图片描述
里面init_action结构体定义如下图:
在这里插入图片描述

struct init_action *next;为链表用。
action : 执行时机
pid : 进程号
command : 对应执行程序 (-/bin/sh)
terminnal : 对应终端(/dev/tty2)

首先,分析代码LINE705~LINE716该函数遍历链表所有数据,检查链表中是否存在某个数据和和传进来的 action,*command,*cons 具有一样的参数。如果有就直接返回;
初次进入本函数,该链表为空,所以该条件不成立。
在这里插入图片描述
其次,分析代码LINE718~LINE730行,

LINE718:给结构体指针new_action分配了一个空间和位置;
LINE719~LINE723:如果init_action_list链表为空,则直接放置在首地址上,如果非空则放置在最末尾
LINE724~LINE726:把本次输入的参数存储进入结构体

在这里插入图片描述

  1. 根据上一节分析的结论,new_init_action()函数会向链表中添加传入的参数。那么,如果需要传递一些默认的配置参数就可以通过反复调用本函数完成。
  2. 回到函数parse_inittab();的代码:如果存在默认的配置文件会进行解析后完成后续操作,如果不存在默认的配置文件,代码也会提供默认配置,如下图代码所示:
    在这里插入图片描述
  3. 根据以上代码反推出默认的配置文件
    根据new_init_action()函数原型和init_tab说明文件:
    在这里插入图片描述

'action’有效取值: sysinit, respawn, askfirst, wait, once,restart, ctrlaltdel, and shutdown.

inittab配置文件格式:<id>:<runlevels>:<action>:<process>
配置文件默认取值:

::CTRLALTDEL:reboot
::SHUTDOWN:umount -a -r
::RESTART:init
::ASKFIRST:-/bin/sh
/dev/tty2::ASKFIRST:-/bin/sh
/dev/tty3::ASKFIRST:-/bin/sh
/dev/tty4::ASKFIRST:-/bin/sh
::SYSINIT:/etc/init.d/rcS

五 busybox源码分析4-继续init程序分析

  1. 剩余的步骤简写如下:
run_actions(SYSINIT);
run_actions(WAIT);
run_actions(ONCE);
while (1) 
{
	run_actions(RESPAWN);
			if (a->pid == 0) 
					a->pid = run(a);
	run_actions(ASKFIRST);
			if (a->pid == 0) 
					a->pid = run(a);
									打印Please press Enter to activate this console. 
									等待回车按键
									创建进程
	wpid = wait(NULL);					//等待以上两个子进程退出
	while (wpid > 0)
		a->pid = 0;							//哪个子进程退出,就设置其pid=0,然后继续执行
}
  1. 分析函数run_actions(SYSINIT);/run_actions(WAIT);
    在这里插入图片描述

LINE533:init_action_list链表是刚刚new_init_action函数添加了若干个默认初始值的链表。此时该链表已经有了初始化值;

LINE535:遍历链表中的每个值,若与传入的参数”action“一致则执行下面操作

LINE539~LINE541:
首先传入的参数是SYSINIT,则执行
LINE540waitfor(a, 0);//执行应用程序,等待它执行完毕;
delete_init_action(a);把SYSINIT对应的应用程序从链表中删除,即只允许执行一次

//----------------------------------------------------------------------------------------
插叙
分析:函数waitfor()
LINE513:执行应用程序a run(a)—创建process子进程
LINE514~LINE524:等待子进程执行结束

在这里插入图片描述
//----------------------------------------------------------------------------------------//

  1. 分析函数run_actions(ONCE);
    直接执行

LINE543:run(a); 不等待执行完毕
LINE544:delete_init_action(a);

在这里插入图片描述
4. 分析函数run_actions(RESPAWN);run_actions(ASKFIRST);
参考上图,直接执行LINE548~LINE549:只有进程号pid为0的时候才会执行

/* Only run stuff with pid==0.  If they have* a pid, that means it is still running */
if (a->pid == 0) 
	a->pid = run(a);
  1. 那么RESPAWNASKFIRST有什么区别呢?需要分析run()函数

在这里插入图片描述

LINE464:如果是ASKFIRST那么打印的信息
LINE478:等待控制台输入回车,否则会在这里死循环

在这里插入图片描述

LINE500:创建子进程

六 busybox源码分析4-ctrlaltdel, and shutdown.

以上我们知道action允许值的sysinit, respawn, askfirst, wait, once,restart均在源码中有所反应,还有ctrlaltdel, shutdown没有出现在代码中。

action的合理值
action: Valid actions include: sysinit, respawn, askfirst, wait, once,restart, ctrlaltdel, shutdown.

  1. 回到init_main函数,如下图所示。
    当键盘按下“crtl+alt+del”的时候,会给内核发送SIGINT信号;
    内核代码init_main接收到SIGINT信号时执行ctrlaltdel_signal函数。
    在这里插入图片描述

  2. 分析ctrlaltdel_signal函数

在这里插入图片描述
进入run_actions(CTRLALTDEL)函数,该函数上面有分析。
所以,当键盘按下“crtl+alt+del”的时候,内核执行CTRLALTDEL程序。
对于其他的信号,内核会在1.signal的程序对应执行相关代码。

七 最小的根文件系统需要的项(笔记4.1 4.2小结)

(init 进程需要)

  1. 打开终端: /dev/console, /dev/NULL
    不设置 inittab 格式中的 id(标准输入、输出和标准错误)时,就定位到 /dev/NULL 中去。
  2. /sbin/init(init 程序):它本身就是 busybox .
  3. /etc/inittab:需要配置文件
    配置文件若指定了某些应用程序或执行脚本–这些必须存在,不存在会有默认的。
  4. 应用程序需要的库(printf,fopen、 fwrite 等函数需要库函数) 。

猜你喜欢

转载自blog.csdn.net/xiaoaojianghu09/article/details/104196982