根文件系统有许多命令,比如 ls cp,cd,这些命令其实也就是相当于一个应用程序。这些程序都封装在busybox中。编译busybox后就可以得到busybox,ls等命令就是到busybox的链接,执行ls等命令其实执行的是busybox程序。 busybox应用程序中,ls对应的是ls.c,cp对应的是cp.c。ubbot目的是启动内核,内核的目的是启动应用程序。内核如何启动应用程序呢?内核启动的第一个是init进程。不同的设备有不同的驱动程序,init如何区分呢?下面我们分析程序。
init.c
/* Check if we are supposed to be in single user mode */
/*linux内核启动应用程序的时候并没有给他什么参数,所以argc = 1*/
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();
}
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;
/*打开配置文件*/
/*inittab格式
<id>:<runlevels>:<action>:<process>
id => /dev/id,用作中断:stdin,stdout,stderr:printf,scanf,err
runlevels:忽略
<action>: Valid actions include: sysinit, respawn, askfirst, wait, once,
restart, ctrlaltdel, and shutdown.
action:指示何时执行
process:应用程序或者脚本
*/
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, "");
/*static void new_init_action(int action,const char -cmmand,const *cons)*/
/*new_init_action(ASKFIRST, "-/bin/sh", "/dev/tty2");*/
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;
/*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];
/*从默认的new_init_action反推出默认的配置文件*/
/*
inittab格式
<id>:<runlevels>:<action>:<process>
id => /dev/id,用作中断:stdin,stdout,stderr:printf,scanf,err
runlevels:忽略
<action>: Valid actions include: sysinit, respawn, askfirst, wait, once,
restart, ctrlaltdel, and shutdown.
action:指示何时执行
process:应用程序或者脚本
*/
/* Reboot on Ctrl-Alt-Del */
/*::CTRLALTDEL:reboot*/
new_init_action(CTRLALTDEL, "reboot", "");
/* Umount all filesystems on halt/reboot */
/*::SHUTDOWN:umount -a -r*/
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 */
/*::RESTART:init*/
new_init_action(RESTART, "init", "");
/* Askfirst shell on tty1-4 */
/*new_init_action(ASKFIRST, "-/bin/sh", "/dev/tty2");*/
/*::ASKFIRST:-/bin/sh*/
/*tty2::ASKFIRST:-/bin/sh*/
/*tty3::ASKFIRST:-/bin/sh*/
/*tty4::ASKFIRST:-/bin/sh*/
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, "");
/**/
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);
}
}
}
}
}
};
/*信号量*/
/*当我们按下ctrlaltdel,内核会给init进程发一个信号。接收到信号后,会执行ctrlaltdel_signal*/
signal(SIGINT, ctrlaltdel_signal);
/**/
static void ctrlaltdel_signal(int sig ATTRIBUTE_UNUSED)
{
run_actions(CTRLALTDEL);//执行这一类的应用程序
}
init进程流程以及涉及的项 busybox ->init_main parse_inittab file = fopen(INITTAB, “r”); new_init_action //创建一个结构体,填充 //把这个结构放入init_action_list链表 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); "\nPlease press Enter to activate this console. "; while (read(0, &c, 1) == 1 && c != ‘\n’)//等待回车 创建进程 } wpid = wait(NULL);//等待子进程退出 while (wpid > 0) { a->pid = 0;//退出后,就设置pid为0 } } 最小的根文件系统需要的项: /dev/console /dev/null init程序,即busybox /etc/inittab 配置文件指定的应用程序 库(某些函数的C库)