Establishment of linux kernel file system

Posted by crowezr on Fri, 17 Dec 2021 15:03:37 +0100

Role of file system

1. Is a directory for disk management
2. Is the way to operate all hardware devices in linux
3. Functional mechanism of the system

File system is also called application program. Writing application program should not only exist in the file system, but also use many functions of the file system.
Most embedded companies are making file systems, such as system interface, system boot screen, system ROM, system functions, pre installed software and so on

macroscopic:

linux file system

System structure

1. After the board is powered on, uboot starts to initialize the board, moves the linux kernel to memory and runs it.
2. The linux kernel initializes itself and mounts the first application, that is, the root file system. (be professional linuxrc)
3. The root file system provides disk management services, glibx device nodes, configuration files, applications, and shell s
Command (android is a linux with multiple file systems) lib + Framework
lib provides a variety of messy libraries.

The file system includes many important structures.
1. Standard library: glibc, OpenCL, media
2. Configuration file: / etc / init If D / rcS wants to start up, run any software, load any screen and execute any command, it can be written in rcS
3. Device node: linux uses files to operate linux. Files have nodes. You must mount two file nodes
/dev/console console node
/dev/null
Create node mknod
4. Architecture program: encapsulate system interfaces for a variety of services and functions
File control program, or file after encapsulation.
5. Shell implementation: all shell commands are in the file system

Root file system:

/bin necessary user commands, such as ls, cp, etc
/sbin requires system administrator commands, such as ifonfig, reboot, etc
/dev device files, such as mtdblock0, ttyl, etc
/ETC system configuration files, including startup files, such as Ubuntu tab, etc
/lib necessary link libraries, such as C link library and kernel module
/Home the home directory of a normal user
/Root user home directory
/usr/bin is not a necessary user program, such as find, du, etc
/usr/sbin is not a necessary Administrator program, such as chroot, inetd, etc
/usr/lib library file
/Variable files stored by var daemons and utilities, such as log files
/proc is a virtual file system used to provide kernel and process information. The contents of the directory are automatically generated by the kernel
/sys is a virtual file system used to provide kernel and device information. The kernel automatically generates the contents of the directory
/The hook point of mnt file system, which is used to temporarily install the file system
/tmp temporarily hung files will be automatically cleared after restart

/bin
Store binary executable files (ls,cat,mkdir, etc.), and common commands are generally here.
/etc
Store system management and configuration files
/home
The root directory where all user files are stored is the base point of the user's home directory. For example, the user's home directory is / home/user, which can be represented by ~ user
/usr
It is used to store system applications. The more important directory is / usr/local, the local system administrator software installation directory (installing system level applications). This is the largest directory, and almost all the applications and files to be used are in this directory.
/usr/x11r6 directory where x window is stored
/usr/bin numerous applications
/Some management programs of usr/sbin super user
/usr/doc linux documentation
/Usr / include header files required for developing and compiling applications under Linux
/Configuration files of dynamic link libraries and software packages commonly used in usr/lib
/usr/man help documentation
/usr/src source code, the source code of linux kernel is placed in / usr/src/linux
/usr/local/bin commands added locally
/usr/local/lib locally added Libraries
/opt
Where additional installed optional application packages are placed. In general, we can install tomcat here.
/proc
Virtual file system directory is the mapping of system memory. You can directly access this directory to obtain system information.
/root
Home directory of super user (system administrator) (privilege class o)
/sbin
Store binary executable files, which can only be accessed by root. Here are the system level management commands and programs used by the system administrator. Such as ifconfig.
/dev
Used to store equipment files.
/mnt
The system administrator installs the mount point of the temporary file system. The system provides this directory for users to temporarily mount other file systems.
/boot
Store various files used for system boot
/lib
Store shared libraries and kernel modules required for running programs in the file system. The shared library is also called dynamic link shared library, and its function is similar to that in windows dll file, which stores the shared files required by the root file system program.
/tmp
It is used to store various temporary files. It is a public temporary file storage point.
/var
Files used to store data that needs to be changed during operation are also overflow areas of some large files, such as log files of various services (system startup logs, etc.).
/lost+found
This directory is usually empty. The "homeless" file (what's the name. chk under windows) left by the abnormal shutdown of the system is here

Disk C: smallest file system

microcosmic:
busybox is a file system, which is downloaded under the official website for 1.7 Analysis of 0
/init/init.c
init_main is the main function that just started running

1. File system component analysis

requirement
Hierarchy of file system
Be familiar with what is in each folder
Analyze the workflow of the file system (starting point: uboot power on end point: pull the kernel to the memory starting point: start the kernal with the incoming parameters, and ending point: attach the root file system)
Starting point of file system: ending point: other applications can be run and can respond to user commands

Previously, in the signal part, the processing we did was just to push something onto the stack and then jump to run it. Then where is it specifically implemented, that is, in the file system.

There are two key functions, which appear in a large number
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);
				}
			}
		}
	}
}

We found the initialization mechanism of the file system
Create some shell commands and perform various operations according to such commands

Starting point analysis
linux support for file system

We use Linux 2 6 Analysis
We finally ran a kernal_init
kernal_init is the last init_post
Let's see how to mount the root file system

Open the console as standard input, copy standard output, standard error.
If the command string is defined, the sub current command is executed
If not defined, default program execution is performed
run_init_process("/sbin/init")
run_init_process("/etc/init")
run_init_process("/bin/init")
run_init_process("/bin/sh")
After opening, it is busybox.

tagglist uboot: memory parameters, hard disk parameters, video parameters, etc
Parsed bit set_ The up segments are stored in the init. In the code snippet of setup, it is in the form of cmd string
In the two functions, all are stored in init. Command execution of setup snippet
Assign global variables to CMD of various setup segments

Then the linux kernel switches to the running of the commemorative linux RC application in the file system, that is, busybox

Linux RC is the first initialization program to run after the file system is started
So init_main is the first function.

File system start from init_main starts running because linuxrc is in this.
linuxrc is a file that contains instructions that need to be executed before mounting the real root file system.

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);     //Some signals are set
	//When the file system receives the signal, it will execute the later bound signal
	//signal system library function


	/* 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);       //Restart command
#endif


	/* Figure out where the default console should be */
	console_init();                    //Console initialization
	set_sane_term();                   //Make some default settings
	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. What applications does the kernel run after the file system enters
2. Is the initialization mode of the file system the same as that of the kernel
Accept incoming configuration information
What is the format of the incoming parameter
Parsing configuration information
How to parse and identify
Application configuration information
How to use this information

2. The workflow of the file system after the kernel starts the file system

1. Acceptance of parameters
2. Analysis of parameters
3. Application of parameters

UBOOT passes parameters to KERNEL in the form of taglist
What are the parameters passed by kernal to busybox

3. What components are needed in the entire file system

File system from init_main start research
File system initialization process

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);
		}
	}
}

First, parse it

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");     //First, open a file to pay attention to
	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”); // First, open a file to pay attention to
Then, if you have this file written by yourself, follow yours. If not, follow it
#define INITTAB "/etc/inittab"
This file is our configuration file

At the beginning, we accepted the parameters. Where are the parameters in the inittab

Now let's take a look at how the system gives you default if it is default.
Via new_init_action function

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) {   //Here is a linked list. Pay attention
		/* 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);
}

You will find that you have created a linked list node and inserted it into the linked list.

struct init_action {
	struct init_action *next;
	int action;
	pid_t pid;
	char command[INIT_BUFFS_SIZE];
	char terminal[CONSOLE_NAME_SIZE];
};

Is such a node.

First perform a search, that is, this node already exists. Even if there is no such node, it is common to insert such a node.

So let's summarize the method of parameter passing in.
1. User defined / etc/inittab configuration file, in init_ Read the file in main, and create init according to each parameter of the file_ Action structure node, and resolve all configuration items in inittab to init_ The action node forms an init_action_list.
2. If the user does not define / etc/inittab, busybox will establish multiple configuration item nodes by default and form init - action_list linked list.

Default configuration:

How does this work?

/* 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;
			}
		}

Is to add / dev/

Then the inittab function is finished.

Then back to init_main is run_action function.

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);
				}
			}
		}
	}
}

Judge the type and deal with different types differently.

At the same time, we should pay attention to 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;
}

Run the command function corresponding to the action and wait for it to exit.

So let's go back to init again_ Main function.

run_actions(SYSINIT); // Run / etc / init D / RCS script and wait for it to exit
run_actions(WAIT);
run_actions(ONCE); // Run once
while(1){
run_actions(RESPAWN);
run_actions(ASKFIRST); // -/bin/sh shell program
sleep(1);
wpid = wait(NULL);
while(wpid>0){......}
}
After the file system is started, it enters an endless loop, and then there are two actions.
If the application exits, it will start another one. If it does not exit, wait for it to exit.

summary
1. At the beginning, I set the semaphore. What should I do when a signal occurs
2. After configuring the configuration item, it becomes a linked list, each of which has an action (the parameter is passed in and parsed.)
3. Then is the application of parameters. For each item, run the corresponding scripts and commands.
4. After entering the dead loop, wait for the shell command (an ls is passed in, the process disappears, and then open another process)

What does a minimal file system need?
1,/dec/console/
2,init_main function - busybox
3,/ect/init.d/rcS -- the first script to run.
4. Because you need to run the shell command, you need its support function - busybox
5. strcmp function, because the busybox response function must be supported by the standard library function, the file system must be supported.

Topics: Linux CTF