linux内核笔记五 文件系统建立

文件系统的作用

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的响应函数的运行必须要标准库函数的支持,所以文件系统必须要其支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值