busybox:Busybox-1.7.0
首先列出代码:
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);
}
}
}
一、分析struct init_action *a;定义如下:
/* Set up a linked list of init_actions, to be read from inittab */
struct init_action {
struct init_action *next;//链表
int action; //指示了执行时机(何时执行)
pid_t pid; //进程id
char command[INIT_BUFFS_SIZE];//busybox支持的命令
char terminal[CONSOLE_NAME_SIZE];
};
二、信号量
/* 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);
信号量的机制,以后分析。。。。
三、parse_inittab解析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"); //====》 #define INITTAB "/etc/inittab" 打开/etc/inittab文件是否可读
if (file == NULL) { //====》如果没有这个INITTAB文件,则会填充一些默认的配置
/* 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) { //这表示有/etc/inittab文件的情况,解析inittab
/* 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 */
}
1.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) { //init_action链表
/* 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); // 填充init_action结构体
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);
}
总结一下这个函数的作用:
创建一个init_action结构,填充它,把这个结构放入到init_action_list链表中
2.根据代码中默认代码反推出默认的配置:
/* 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, "");
注意:
INTTAB的格式:
<id>:<runlevels>:<action>:<process>
<id> => /dev/id ,例子:用作终端:stdin,stdout,stderr:printf,scanf,err
<runlevels> :可以被忽略
<action> : 指示了执行时机(何时执行)
# <action>: Valid actions include: sysinit, respawn, askfirst, wait, once,
# restart, ctrlaltdel, and shutdown.
<process> :应用程序或脚本
那么根据格式将上面new_init_action反推出来的配置为:
::ctrlaltdel:reboot
::shutdown:umount -a -r
::shutdown:swapoff -a
::restart:init
::askfirst:-/bin/sh
tty2::askfirst:-/bin/sh
tty3::askfirst:-/bin/sh
tty4::askfirst:-/bin/sh
::sysinit:/etc/init.d/rcS
四、配置文件读取后:
run_actions(SYSINIT);
waitfor(a, 0); //执行应用程序,等待它执行完毕
run(a) //创建process子进程
waitpid(runpid, &status, 0) //等待它结束
delete_init_action(a);//在init_action_list链表里删除
run_actions(WAIT);
waitfor(a, 0); //执行应用程序,等待它执行完毕
run(a) //创建process子进程
waitpid(runpid, &status, 0) //等待它结束
delete_init_action(a);//在init_action_list链表里删除
run_actions(ONCE);
run(a) //创建process子进程
delete_init_action(a);//在init_action_list链表里删除
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
}