07.构建根文件系统之init进程分析
根文件系统有许多命令,比如 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);//执行这一类的应用程序
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
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库)
文章来源: blog.csdn.net,作者:嵌入式与Linux那些事,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/qq_16933601/article/details/102942848
- 点赞
- 收藏
- 关注作者
评论(0)