文件系统的作用
1、是磁盘管理的目录
2、是linux中操作所有硬件设备的方式
3、系统的功能机制
文件系统也叫应用程序,写应用程序不仅要存在文件系统中,并且还要使用文件系统的诸多功能。
大多数的嵌入式公司都在做文件系统,比如系统界面,系统的开机画面,系统的ROM,系统的功能,预装的软件等等
宏观:
linux文件系统
系统结构
1、板卡上电后首先由uboot启动初始化板卡,将linux内核移到内存中并运行。
2、由linux内核自行做初始化等操作并挂载了第一个应用程序,也就是根文件系统。(专业一点 linuxrc)
3、根文件系统会提供磁盘管理服务,glibx设备节点,配置文件,应用程序,shell
命令(android就是一个linux多了个文件系统) lib + Framework
lib里面提供了各种乱七八糟的库。
文件系统包括了很多重要结构。
1、标准库:glibc OpenCL、media
2、配置文件: /etc/init.d/rcS 想要开机运行什么软件 载入什么画面 执行什么命令 都可以写在rcS中
3、设备节点:linux是用文件操作linux, 文件是有节点的,必须得挂载两个文件节点
/dev/console 控制台节点
/dev/null
创建节点 mknod
4、架构程序 :对多种服务和功能进行系统接口封装
文件控制程序,封装之后还是文件。
5、shell的实现:所有的shell命令都在文件系统中
根文件系统:
/bin 必备的用户命令,例如ls,cp等
/sbin 必备的系统管理员命令,例如ifonfig、reboot等
/dev 设备文件,例如mtdblock0,ttyl等
/etc 系统的配置文件,包括启动文件,例如ubuttab等
/lib 必要的链接库 例如C链接库、内核模块
/home 普通的用户主目录
/root root用户主目录
/usr/bin 非必备的用户程序,例如find、du等
/usr/sbin 非必备的管理员程序,例如chroot、inetd等
/usr/lib 库文件
/var 守护程序和工具程序所存放的可变文件,例如日志文件
/proc 用来提供内核与进程信息的虚拟文件系统,由内核自动生成目录下的内容
/sys 用来提供内核与设备信息的虚拟文件系统,由内核自动生成目录下的内容
/mnt 文件系统的挂接点,用于临时安装文件系统
/tmp 临时挂的文件,重启后将自动清除
/bin
存放二进制可执行文件(ls,cat,mkdir等),常用命令一般都在这里。
/etc
存放系统管理和配置文件
/home
存放所有用户文件的根目录,是用户主目录的基点,比如用户user的主目录就是/home/user,可以用~user表示
/usr
用于存放系统应用程序,比较重要的目录/usr/local 本地系统管理员软件安装目录(安装系统级的应用)。这是最庞大的目录,要用到的应用程序和文件几乎都在这个目录。
/usr/x11r6 存放x window的目录
/usr/bin 众多的应用程序
/usr/sbin 超级用户的一些管理程序
/usr/doc linux文档
/usr/include linux下开发和编译应用程序所需要的头文件
/usr/lib 常用的动态链接库和软件包的配置文件
/usr/man 帮助文档
/usr/src 源代码,linux内核的源代码就放在/usr/src/linux里
/usr/local/bin 本地增加的命令
/usr/local/lib 本地增加的库
/opt
额外安装的可选应用程序包所放置的位置。一般情况下,我们可以把tomcat等都安装到这里。
/proc
虚拟文件系统目录,是系统内存的映射。可直接访问这个目录来获取系统信息。
/root
超级用户(系统管理员)的主目录(特权阶级o)
/sbin
存放二进制可执行文件,只有root才能访问。这里存放的是系统管理员使用的系统级别的管理命令和程序。如ifconfig等。
/dev
用于存放设备文件。
/mnt
系统管理员安装临时文件系统的安装点,系统提供这个目录是让用户临时挂载其他的文件系统。
/boot
存放用于系统引导时使用的各种文件
/lib
存放跟文件系统中的程序运行所需要的共享库及内核模块。共享库又叫动态链接共享库,作用类似windows里的.dll文件,存放了根文件系统程序运行所需的共享文件。
/tmp
用于存放各种临时文件,是公用的临时文件存储点。
/var
用于存放运行时需要改变数据的文件,也是某些大文件的溢出区,比方说各种服务的日志文件(系统启动日志等。)等。
/lost+found
这个目录平时是空的,系统非正常关机而留下“无家可归”的文件(windows下叫什么.chk)就在这里
C盘:最小的文件系统
微观:
busybox 是一个文件系统 下载在官网 下面都是对1.7.0的分析
/init/init.c
init_main 是刚开始运行的主函数
1、文件系统成分分析
要求
文件系统的层次
熟悉每个文件夹里面有啥
分析文件系统的工作流程 (起点:uboot上电 终点:把内核牵引到内存启动 起点:用传入参数启动kernal 终点 :挂接根文件系统 )
文件系统的起点 : 终点:可以运行其它应用程序,并且可以响应用户的命令
之前在信号部分,我们做的处理仅仅是说把一些东西压到堆栈里面,然后跳过去去运行,那么它到底是在哪里被具体实现,就是在文件系统。
里面有两个重点函数,在里面大量的出现
new_init_action
static void new_init_action(int action, const char *command, const char *cons)
{
struct init_action *new_action, *a, *last;
if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST))
return;
/* Append to the end of the list */
for (a = last = init_action_list; a; a = a->next) {
/* don't enter action if it's already in the list,
* but do overwrite existing actions */
if ((strcmp(a->command, command) == 0)
&& (strcmp(a->terminal, cons) == 0)
) {
a->action = action;
return;
}
last = a;
}
new_action = xzalloc(sizeof(struct init_action));
if (last) {
last->next = new_action;
} else {
init_action_list = new_action;
}
strcpy(new_action->command, command);
new_action->action = action;
strcpy(new_action->terminal, cons);
messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
new_action->command, new_action->action, new_action->terminal);
}
run_action
/* Run all commands of a particular type */
static void run_actions(int action)
{
struct init_action *a, *tmp;
for (a = init_action_list; a; a = tmp) {
tmp = a->next;
if (a->action == action) {
/* a->terminal of "" means "init's console" */
if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {
delete_init_action(a);
} else if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
waitfor(a, 0);
delete_init_action(a);
} else if (a->action & ONCE) {
run(a);
delete_init_action(a);
} else if (a->action & (RESPAWN | ASKFIRST)) {
/* 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);
}
}
}
}
}
我们发现 文件系统的初始化机制
创建一些shell命令,根据此类命令进行各种操作
起点分析
linux对文件系统的支持
我们用linux2.6的进行分析
我们最后运行了一个kernal_init
kernal_init最后是一个init_post
看一下怎么去挂载这个根文件系统
打开控制台作为标准输入,复制了标准输出,标准错误。
如果命令串被定义则执行子当以的命令
如果未定义则进行默认程序执行
run_init_process("/sbin/init")
run_init_process("/etc/init")
run_init_process("/bin/init")
run_init_process("/bin/sh")
打开后都是busybox。
tagglist uboot传入的 内存参数 硬盘参数 视屏参数等等
被解析位set_up的段,都存放在.init.setup的代码段中 ,形式为cmd字符串
在两个函数中进行了所有存放在.init.setup代码段的命令执行
针对各种setup段的CMD进行全局变量的赋值
然后linux内核切换到了文件系统中纪念性linuxrc应用程序的运行,也就是运行了busybox
linuxrc是文件系统启动之后运行的第一个初始化程序
所以init_main是第一个函数。
文件系统开始从init_main开始运行,因为linuxrc在这个里面。
linuxrc是个文件,该文件会包括在挂载真正的根文件系统之前需要执行的指令。
int init_main(int argc, char **argv)
{
struct init_action *a;
pid_t wpid;
die_sleep = 30 * 24*60*60; /* if xmalloc will ever die... */
if (argc > 1 && !strcmp(argv[1], "-q")) {
return kill(1, SIGHUP);
}
#if !ENABLE_DEBUG_INIT
/* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
if (getpid() != 1
&& (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc"))
) {
bb_show_usage();
}
/* Set up sig handlers -- be sure to
* clear all of these in run() */
signal(SIGHUP, exec_signal);
signal(SIGQUIT, exec_signal);
signal(SIGUSR1, shutdown_signal);
signal(SIGUSR2, shutdown_signal);
signal(SIGINT, ctrlaltdel_signal);
signal(SIGTERM, shutdown_signal);
signal(SIGCONT, cont_handler);
signal(SIGSTOP, stop_handler);
signal(SIGTSTP, stop_handler); //设置了一些信号
//当文件系统收到信号之后就会执行后面绑定的信号
//signal系统库函数
/* Turn off rebooting via CTL-ALT-DEL -- we get a
* SIGINT on CAD so we can shut things down gracefully... */
init_reboot(RB_DISABLE_CAD); //重启命令
#endif
/* Figure out where the default console should be */
console_init(); //控制台的初始化
set_sane_term(); //做一些默认设置
chdir("/");
setsid();
{
const char *const *e;
/* Make sure environs is set to something sane */
for (e = environment; *e; e++)
putenv((char *) *e);
}
if (argc > 1) setenv("RUNLEVEL", argv[1], 1);
/* Hello world */
message(MAYBE_CONSOLE | L_LOG, "init started: %s", bb_banner);
/* Make sure there is enough memory to do something useful. */
if (ENABLE_SWAPONOFF) {
struct sysinfo info;
if (!sysinfo(&info) &&
(info.mem_unit ? : 1) * (long long)info.totalram < 1024*1024)
{
message(L_CONSOLE, "Low memory, forcing swapon");
/* swapon -a requires /proc typically */
new_init_action(SYSINIT, "mount -t proc proc /proc", "");
/* Try to turn on swap */
new_init_action(SYSINIT, "swapon -a", "");
run_actions(SYSINIT); /* wait and removing */
}
}
/* Check if we are supposed to be in single user mode */
if (argc > 1
&& (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1'))
) {
/* Start a shell on console */
new_init_action(RESPAWN, bb_default_login_shell, "");
} else {
/* Not in single user mode -- see what inittab says */
/* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
* then parse_inittab() simply adds in some default
* actions(i.e., runs INIT_SCRIPT and then starts a pair
* of "askfirst" shells */
parse_inittab();
}
#if ENABLE_SELINUX
if (getenv("SELINUX_INIT") == NULL) {
int enforce = 0;
putenv((char*)"SELINUX_INIT=YES");
if (selinux_init_load_policy(&enforce) == 0) {
BB_EXECVP(argv[0], argv);
} else if (enforce > 0) {
/* SELinux in enforcing mode but load_policy failed */
/* At this point, we probably can't open /dev/console, so log() won't work */
message(L_CONSOLE, "Cannot load SELinux Policy. "
"Machine is in enforcing mode. Halting now.");
exit(1);
}
}
#endif /* CONFIG_SELINUX */
/* Make the command line just say "init" -- thats all, nothing else */
fixup_argv(argv);
/* Now run everything that needs to be run */
/* First run the sysinit command */
run_actions(SYSINIT);
/* Next run anything that wants to block */
run_actions(WAIT);
/* Next run anything to be run only once */
run_actions(ONCE);
#if ENABLE_FEATURE_USE_INITTAB
/* Redefine SIGHUP to reread /etc/inittab */
signal(SIGHUP, reload_signal);
#else
signal(SIGHUP, SIG_IGN);
#endif /* FEATURE_USE_INITTAB */
/* Now run the looping stuff for the rest of forever */
while (1) {
/* run the respawn stuff */
run_actions(RESPAWN);
/* run the askfirst stuff */
run_actions(ASKFIRST);
/* Don't consume all CPU time -- sleep a bit */
sleep(1);
/* Wait for a child process to exit */
wpid = wait(NULL);
while (wpid > 0) {
/* Find out who died and clean up their corpse */
for (a = init_action_list; a; a = a->next) {
if (a->pid == wpid) {
/* Set the pid to 0 so that the process gets
* restarted by run_actions() */
a->pid = 0;
message(L_LOG, "process '%s' (pid %d) exited. "
"Scheduling it for restart.",
a->command, wpid);
}
}
/* see if anyone else is waiting to be reaped */
wpid = waitpid(-1, NULL, WNOHANG);
}
}
}
1、文件系统进入后内核运行了什么应用程序
2、文件系统的初始化模式是否和内核是一样的
接受配置信息传入
传入参数的格式是什么样的
解析配置信息
如何进行解析 并且进行识别
应用配置信息
如何进行这些信息的使用
2、内核启动文件系统之后,文件系统的工作流程
1、参数的接受
2、参数的解析
3、参数的应用
UBOOT 给KERNEL传入的参数,是以tagglist进行的
kernal 给busybox传入的参数以什么进行
3、在整个文件系统中,都需要什么组件
文件系统从init_main开始研究
文件系统的初始化流程
int init_main(int argc, char **argv)
{
struct init_action *a;
pid_t wpid;
die_sleep = 30 * 24*60*60; /* if xmalloc will ever die... */
if (argc > 1 && !strcmp(argv[1], "-q")) {
return kill(1, SIGHUP);
}
#if !ENABLE_DEBUG_INIT
/* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
if (getpid() != 1
&& (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc"))
) {
bb_show_usage();
}
/* Set up sig handlers -- be sure to
* clear all of these in run() */
signal(SIGHUP, exec_signal);
signal(SIGQUIT, exec_signal);
signal(SIGUSR1, shutdown_signal);
signal(SIGUSR2, shutdown_signal);
signal(SIGINT, ctrlaltdel_signal);
signal(SIGTERM, shutdown_signal);
signal(SIGCONT, cont_handler);
signal(SIGSTOP, stop_handler);
signal(SIGTSTP, stop_handler);
/* Turn off rebooting via CTL-ALT-DEL -- we get a
* SIGINT on CAD so we can shut things down gracefully... */
init_reboot(RB_DISABLE_CAD);
#endif
/* Figure out where the default console should be */
console_init();
set_sane_term();
chdir("/");
setsid();
{
const char *const *e;
/* Make sure environs is set to something sane */
for (e = environment; *e; e++)
putenv((char *) *e);
}
if (argc > 1) setenv("RUNLEVEL", argv[1], 1);
/* Hello world */
message(MAYBE_CONSOLE | L_LOG, "init started: %s", bb_banner);
/* Make sure there is enough memory to do something useful. */
if (ENABLE_SWAPONOFF) {
struct sysinfo info;
if (!sysinfo(&info) &&
(info.mem_unit ? : 1) * (long long)info.totalram < 1024*1024)
{
message(L_CONSOLE, "Low memory, forcing swapon");
/* swapon -a requires /proc typically */
new_init_action(SYSINIT, "mount -t proc proc /proc", "");
/* Try to turn on swap */
new_init_action(SYSINIT, "swapon -a", "");
run_actions(SYSINIT); /* wait and removing */
}
}
/* Check if we are supposed to be in single user mode */
if (argc > 1
&& (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1'))
) {
/* Start a shell on console */
new_init_action(RESPAWN, bb_default_login_shell, "");
} else {
/* Not in single user mode -- see what inittab says */
/* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined,
* then parse_inittab() simply adds in some default
* actions(i.e., runs INIT_SCRIPT and then starts a pair
* of "askfirst" shells */
parse_inittab();
}
#if ENABLE_SELINUX
if (getenv("SELINUX_INIT") == NULL) {
int enforce = 0;
putenv((char*)"SELINUX_INIT=YES");
if (selinux_init_load_policy(&enforce) == 0) {
BB_EXECVP(argv[0], argv);
} else if (enforce > 0) {
/* SELinux in enforcing mode but load_policy failed */
/* At this point, we probably can't open /dev/console, so log() won't work */
message(L_CONSOLE, "Cannot load SELinux Policy. "
"Machine is in enforcing mode. Halting now.");
exit(1);
}
}
#endif /* CONFIG_SELINUX */
/* Make the command line just say "init" -- thats all, nothing else */
fixup_argv(argv);
/* Now run everything that needs to be run */
/* First run the sysinit command */
run_actions(SYSINIT);
/* Next run anything that wants to block */
run_actions(WAIT);
/* Next run anything to be run only once */
run_actions(ONCE);
#if ENABLE_FEATURE_USE_INITTAB
/* Redefine SIGHUP to reread /etc/inittab */
signal(SIGHUP, reload_signal);
#else
signal(SIGHUP, SIG_IGN);
#endif /* FEATURE_USE_INITTAB */
/* Now run the looping stuff for the rest of forever */
while (1) {
/* run the respawn stuff */
run_actions(RESPAWN);
/* run the askfirst stuff */
run_actions(ASKFIRST);
/* Don't consume all CPU time -- sleep a bit */
sleep(1);
/* Wait for a child process to exit */
wpid = wait(NULL);
while (wpid > 0) {
/* Find out who died and clean up their corpse */
for (a = init_action_list; a; a = a->next) {
if (a->pid == wpid) {
/* Set the pid to 0 so that the process gets
* restarted by run_actions() */
a->pid = 0;
message(L_LOG, "process '%s' (pid %d) exited. "
"Scheduling it for restart.",
a->command, wpid);
}
}
/* see if anyone else is waiting to be reaped */
wpid = waitpid(-1, NULL, WNOHANG);
}
}
}
首先要解析它
parse_inittab();
static void parse_inittab(void)
{
#if ENABLE_FEATURE_USE_INITTAB
FILE *file;
char buf[INIT_BUFFS_SIZE], lineAsRead[INIT_BUFFS_SIZE];
char tmpConsole[CONSOLE_NAME_SIZE];
char *id, *runlev, *action, *command, *eol;
const struct init_action_type *a = actions;
file = fopen(INITTAB, "r"); //首先打开了一个文件要注意
if (file == NULL) {
/* No inittab file -- set up some default behavior */
#endif
/* 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 HUP is received */
new_init_action(RESTART, "init", "");
/* Askfirst shell on tty1-4 */
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);
/* sysinit */
new_init_action(SYSINIT, INIT_SCRIPT, "");
return;
#if ENABLE_FEATURE_USE_INITTAB
}
while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {
/* Skip leading spaces */
for (id = buf; *id == ' ' || *id == '\t'; id++);
/* Skip the line if it's a comment */
if (*id == '#' || *id == '\n')
continue;
/* Trim the trailing \n */
//XXX: chomp() ?
eol = strrchr(id, '\n');
if (eol != NULL)
*eol = '\0';
/* Keep a copy around for posterity's sake (and error msgs) */
strcpy(lineAsRead, buf);
/* Separate the ID field from the runlevels */
runlev = strchr(id, ':');
if (runlev == NULL || *(runlev + 1) == '\0') {
message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);
continue;
} else {
*runlev = '\0';
++runlev;
}
/* Separate the runlevels from the action */
action = strchr(runlev, ':');
if (action == NULL || *(action + 1) == '\0') {
message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);
continue;
} else {
*action = '\0';
++action;
}
/* Separate the action from the command */
command = strchr(action, ':');
if (command == NULL || *(command + 1) == '\0') {
message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);
continue;
} else {
*command = '\0';
++command;
}
/* Ok, now process it */
for (a = actions; a->name != 0; a++) {
if (strcmp(a->name, action) == 0) {
if (*id != '\0') {
if (strncmp(id, "/dev/", 5) == 0)
id += 5;
strcpy(tmpConsole, "/dev/");
safe_strncpy(tmpConsole + 5, id,
sizeof(tmpConsole) - 5);
id = tmpConsole;
}
new_init_action(a->action, command, id);
break;
}
}
if (a->name == 0) {
/* Choke on an unknown action */
message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);
}
}
fclose(file);
#endif /* FEATURE_USE_INITTAB */
}
file = fopen(INITTAB, “r”); //首先打开了一个文件要注意
然后呢就是如果你有自己写的这个文件,就按你的来,如果没有就按它给的来
#define INITTAB “/etc/inittab”
这个文件就是我们的配置文件
刚开始我们就是参数的接受,那么参数在哪里,在inittab里面
我们现在来看一下如果默认的话,系统是怎么给你默认的。
通过new_init_action函数
static void new_init_action(int action, const char *command, const char *cons)
{
struct init_action *new_action, *a, *last;
if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST))
return;
/* Append to the end of the list */
for (a = last = init_action_list; a; a = a->next) { //这里有个链表,要注意
/* don't enter action if it's already in the list,
* but do overwrite existing actions */
if ((strcmp(a->command, command) == 0)
&& (strcmp(a->terminal, cons) == 0)
) {
a->action = action;
return;
}
last = a;
}
new_action = xzalloc(sizeof(struct init_action));
if (last) {
last->next = new_action;
} else {
init_action_list = new_action;
}
strcpy(new_action->command, command);
new_action->action = action;
strcpy(new_action->terminal, cons);
messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
new_action->command, new_action->action, new_action->terminal);
}
会发现就是创建了一个链表节点,然后插入到链表里面。
struct init_action {
struct init_action *next;
int action;
pid_t pid;
char command[INIT_BUFFS_SIZE];
char terminal[CONSOLE_NAME_SIZE];
};
就是这样的一个节点。
先进行一个搜索,就是已经存在这个节点,就算了,要是没这也节点,就常见一个这样的节点,然后插进去。
所以我们总结一下参数传入的方法。
1、用户自定义/etc/inittab配置文件,在init_main中进行了文件的读取,并且根据文件的每一项参数,创建init_action结构体节点,并且把inittab中的所有的配置项解析的init_action节点形成一个init_action_list。
2、如果用户没有定义/etc/inittab,那么busybox会默认进行多个配置项节点的建立,并且形成init——action_list链表。
默认配置:
这玩意怎么使用的?
/* Ok, now process it */
for (a = actions; a->name != 0; a++) {
if (strcmp(a->name, action) == 0) {
if (*id != '\0') {
if (strncmp(id, "/dev/", 5) == 0)
id += 5;
strcpy(tmpConsole, "/dev/");
safe_strncpy(tmpConsole + 5, id,
sizeof(tmpConsole) - 5);
id = tmpConsole;
}
new_init_action(a->action, command, id);
break;
}
}
就是添加/dev/
然后inittab这个函数就完事了。
然后回到了init_main,就是运行run_action函数。
static void run_actions(int action)
{
struct init_action *a, *tmp;
for (a = init_action_list; a; a = tmp) {
tmp = a->next;
if (a->action == action) {
/* a->terminal of "" means "init's console" */
if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {
delete_init_action(a);
} else if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
waitfor(a, 0);
delete_init_action(a);
} else if (a->action & ONCE) {
run(a);
delete_init_action(a);
} else if (a->action & (RESPAWN | ASKFIRST)) {
/* 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);
}
}
}
}
}
判断类型,对不同的类型做出不同的处理。
同时我们要关注一下waitfor
static int waitfor(const struct init_action *a, pid_t pid)
{
int runpid;
int status, wpid;
runpid = (NULL == a)? pid : run(a);
while (1) {
wpid = waitpid(runpid, &status, 0);
if (wpid == runpid)
break;
if (wpid == -1 && errno == ECHILD) {
/* we missed its termination */
break;
}
/* FIXME other errors should maybe trigger an error, but allow
* the program to continue */
}
return wpid;
}
运行该action对应的命令函数,并且等待其退出。
所以我们再次回到init_main函数。
run_actions(SYSINIT); //运行/etc/init.d/rcS脚本,并且等待其退出
run_actions(WAIT);
run_actions(ONCE); //运行一次
while(1){
run_actions(RESPAWN);
run_actions(ASKFIRST); // -/bin/sh shell程序
sleep(1);
wpid = wait(NULL);
while(wpid>0){……}
}
文件系统启动后就进入死循环,然后就两个动作。
如果应用程序退出了就又会启动一个,如果没退出就等待退出。
总结
1、刚开始先设置了信号量,当发生了信号的时候干点啥
2、配置了配置项,然后变成了一个链表,每个里面都有一个action(参数的传入和解析就完了。)
3、然后就是参数的应用,对应里面的每一项,运行对应的脚本和命令。
4、进入死循环,就等待shell命令,(传入了一个ls,进程消失,再打开一个进程)
一个最小文件系统都需要什么东西?
1、/dec/console/
2、init_main函数 —busybox
3、/ect/init.d/rcS --脚本 第一个运行的脚本。
4、因为需要运行shell命令,需要其支持函数 —busybox
5、strcmp函数这种东西 因为busybox的响应函数的运行必须要标准库函数的支持,所以文件系统必须要其支持。