linux inittab 时间,linux根文件系统制作之inittab启动分析
之前讲过虚拟文件系统挂载根文件系统之后,会执行用户程序,参见博文:
http://blog.chinaunix.net/uid-29401328-id-4909649.html
但只提了一下内核会启动init进程,没详细讲,今天就从这里开始讲下文件系统的启动过程
linux-2.6.30.4内核, busybox-1.16.0
根据之前那篇博文我们知道,文见系统挂载最后调用的函数为:init_post,源码如下:
点击(此处)折叠或打开
static noinline int init_post(void)
__releases(kernel_lock)
{
/* need to finish all async __init code before freeing the memory */
async_synchronize_full();
free_initmem();
unlock_kernel();
mark_rodata_ro();
system_state = SYSTEM_RUNNING;
numa_default_policy();
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
(void) sys_dup(0);
(void) sys_dup(0);
current->signal->flags |= SIGNAL_UNKILLABLE;
if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command);
}
/*
* We try each of these until one succeeds.
*
* The Bourne shell can be used instead of init if we are
* trying to recover a really broken machine.
*/
if (execute_command) {
run_init_process(execute_command);
printk(KERN_WARNING "Failed to execute %s. Attempting "
"defaults...\n", execute_command);
}
run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh");
panic("No init found. Try passing init= option to kernel.");
}
20行:ramdisk_execute_command值通过“rdinit=”指定,如果未指定,往下执行;
这个参数解析是在:
linux-2.6.30.4\init\Main.c
static int __init rdinit_setup(char *str)
{
unsigned int i;
ramdisk_execute_command = str;
/* See "auto" comment in init_setup */
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
__setup("rdinit=", rdinit_setup);
32行:execute_command通过“init=”指定,最常见的是在uboot的参数中设置“init=/linuxrc”。如果设置了这个参数,则上述函数直接执行到:
run_init_process(execute_command);
后面的讲都不会再执行,因为run_init_process通过调用kernel_execve替换了整个进程。
init参数解析是在:
linux-2.6.30.4\init\Main.c
static int __init init_setup(char *str)
{
unsigned int i;
execute_command = str;
/*
* In case LILO is going to boot us with default command line,
* it prepends "auto" before the whole cmdline which makes
* the shell think it should execute a script with such name.
* So we ignore all arguments entered _before_ init=... [MJ]
*/
for (i = 1; i < MAX_INIT_ARGS; i++)
argv_init[i] = NULL;
return 1;
}
__setup("init=", init_setup);
37行:如果rdinit和init都未设置,则直接调用/sbin/init。如果没找到/sbin/init,则一次回去寻找/etc/init、/bin/init、/bin/sh,如果都没找到,则会打印“No init found. Try passing init= option to kernel”
如果uboot设置了“init=/linuxrc”(我的yaffs2文件系统的uboot启动就设置了),那么将会执行linuxrc,但是后来我发现把linuxrc删除,系统也会正常启动,没任何影响,这是为什么?
经CU论坛“arm-linux-gcc”兄弟指点和网上查阅资料,总结如下:
linuxrc其实会被当作init来使用,在busybox中busybox-1.16.0\include\Applets.h232行有:
IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, _BB_DIR_ROOT, _BB_SUID_DROP, linuxrc))
意思就是如果设置了“init=/linuxrc”,其实调用的也是/sbin/init,没有设置也会调用它。
所以我们的第一个程序就是/sbin/init。
后来又做了一个测试:把linuxrc文件改写成脚本文件,文件系统将不能正确启动,会提示“Kernel panic - not syncing: No init found”。
这里应该是因为执行了linuxrc,不再去执行/sbin/init,而linuxrc又被我们改写了,不会再被当成init使用了,所以/sbin/init得不到
执行,挂载失败,No init
下面说说/sbin/init这个进程:
init进程是第一个进程,所有进程的父进程,有了它,后面才能有shell等进程。
通过top查看:
1 0 root S 2096 3.4 0 0.0 init
可以看出它的PID为1
根据之前对busybox的分析可知,它调用的其实就是busybox里的init_main函数
源码太长,这里就不贴了,而且大部分不会涉及到,涉及到文件系统启动的最主要函数就是parse_inittab。
parse_inittab函数主要涉及到的文件就是/etc/inittab,这里先说一下/etc/inittab的格式:
busybox-1.16.0\include\usage.h 1918行说明了它的格式:
:::
这段解释是被定义在一个宏里的,#define init_notes_usage
从这个宏里我们可以获得比较详细的解释,下面说一下(基本上是从这段英文翻译过来的):
:用来指定所启动进程的controlling tty,如果是空,会被默认设置为console
:init会忽略这一项,就是当做你不存在
:所执行的程序的属性说明,这么说有点拗口,看完它的各个值的含义就明白了。
有效的取值有8种,又可以分为两种,一种是只运行一次的程序,另一种是会重复运行的程序:
运行一次的:
sysinit:就是启动运行的第一个程序,直到它所指定的执行完,才进行下一步动作
wait:在sysinit指定的程序执行完,开始执行,等到它执行完,init才能继续
once:只执行一次的进程,而且它和init是异步的,意思就是,init的只负责启动它,不需等它执行完
restart:重启时运行的程序,默认所执行的进程是init本身
ctrlaltdel:同时按下CTRL-ALT-DEL键执行的程序,常用的是reboot
shutdown:系统关机时,执行的程序
运行多次的(在运行一次的程序运行完之后才运行这里的程序):
respawn:如果这里的程序被终止了,init会自动重启它的
askfirst:和respawn功能类似,但会在启动程序之前在控制台打印“Please press Enter to activate this console”。
和respawn不同在于,respawn能够直接启动一个程序,而askfirst要等用户敲了Enter键后才能启动程序
这里把我的开发板的inittab文件贴出来当做示例理解:
# /etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::once:/usr/sbin/telnetd -l /bin/login
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
了解了inittab的格式,下面来看一下parse_inittab的源码:
点击(此处)折叠或打开
/* 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). If CONFIG_FEATURE_USE_INITTAB
* _is_ defined, but /etc/inittab is missing, this
* results in the same set of default behaviors.
*/
static void parse_inittab(void)
{
#if ENABLE_FEATURE_USE_INITTAB
char *token[4];
parser_t *parser = config_open2("/etc/inittab", fopen_for_read);
if (parser == NULL)
#endif
{
/* No inittab file - set up some default behavior */
/* 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 QUIT is received */
new_init_action(RESTART, "init", "");
/* Askfirst shell on tty1-4 */
new_init_action(ASKFIRST, bb_default_login_shell, "");
//TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users
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
/* optional_tty:ignored_runlevel:action:command
* Delims are not to be collapsed and need exactly 4 tokens
*/
while (config_read(parser, token, 4, 0, "#:",
PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) {
/* order must correspond to SYSINIT..RESTART constants */
static const char actions[] ALIGN1 =
"sysinit\0""wait\0""once\0""respawn\0""askfirst\0"
"ctrlaltdel\0""shutdown\0""restart\0";
int action;
char *tty = token[0];
if (!token[3]) /* less than 4 tokens */
goto bad_entry;
action = index_in_strings(actions, token[2]);
if (action < 0 || !token[3][0]) /* token[3]: command */
goto bad_entry;
/* turn .*TTY -> /dev/TTY */
if (tty[0]) {
if (strncmp(tty, "/dev/", 5) == 0)
tty += 5;
tty = concat_path_file("/dev/", tty);
}
new_init_action(1 << action, token[3], tty);
if (tty[0])
free(tty);
continue;
bad_entry:
message(L_LOG | L_CONSOLE, "Bad inittab entry at line %d",
parser->lineno);
}
config_close(parser);
#endif
}
12行:打开/etc/inittab文件
14行:如果没有/etc/inittab文件或打开失败,则系统会用new_init_action执行一些默认的配置,这个函数下面再说
42行:逐行去读取/etc/inittab文件,读出来之后同样用new_init_action去执行
来看一下new_init_action函数:
点击(此处)折叠或打开
static void new_init_action(uint8_t action_type, const char *command, const char *cons)
{
struct init_action *a, **nextp;
/* Scenario:
* old inittab:
* ::shutdown:umount -a -r
* ::shutdown:swapoff -a
* new inittab:
* ::shutdown:swapoff -a
* ::shutdown:umount -a -r
* On reload, we must ensure entries end up in correct order.
* To achieve that, if we find a matching entry, we move it
* to the end.
*/
nextp = &init_action_list;
while ((a = *nextp) != NULL) {
/* Don't enter action if it's already in the list,
* This prevents losing running RESPAWNs.
*/
if (strcmp(a->command, command) == 0
&& strcmp(a->terminal, cons) == 0
) {
/* Remove from list */
*nextp = a->next;
/* Find the end of the list */
while (*nextp != NULL)
nextp = &(*nextp)->next;
a->next = NULL;
break;
}
nextp = &a->next;
}
if (!a)
a = xzalloc(sizeof(*a));
/* Append to the end of the list */
*nextp = a;
a->action_type = action_type;
safe_strncpy(a->command, command, sizeof(a->command));
safe_strncpy(a->terminal, cons, sizeof(a->terminal));
dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n",
a->command, a->action_type, a->terminal);
}
new_init_action函数主要做了这些工作:
1、创建init_action结构,并填充。
2、把这个结构放入init_action_list链表
现对parse_inittab函数总结如下:
如果我们没有配置文件inittab存在,会执行默认配置,根据new_init_action执行的默认配置,我们可以反推出默认inittab配置文件的内容:
::CTRLALTDEL:reboot
::SHUTDOWN:umount -a -r
::RESTART:init
::ASKFIRST:-/bin/sh
tty2::ASKFIRST:-/bin/sh
tty3::ASKFIRST:-/bin/sh
tty4::ASKFIRST:-/bin/sh
::SYSINIT:/etc/init.d/rcS
如果配置文件inittab存在,则会逐行读出,然后对每一行调用new_init_action函数在init_main函数里,执行完parse_inittab(),后续会顺序调用:
run_actions(SYSINIT);
run_actions(WAIT);
run_actions(ONCE);
然后才调用:
run_actions(RESPAWN | ASKFIRST);
无论对于默认的inittab配置文件,还是对于我们自己文件系统中的inittab配置文件,SYSINIT对应的程序一般是/etc/init.d/rcS,下面我们去看看这个文件
linux inittab 时间,linux根文件系统制作之inittab启动分析相关推荐
- Linux内核移植和根文件系统制作(详细步骤精讲)
第一章移植内核 1.1 Linux内核基础知识 1.1.1 Linux版本 1.1.2 什么是标准内核 1.1.3 Linux操作系统的分类 1.1.4 linux内核的选择 1.2 Linux内核启 ...
- s5pv210 linux内核移植,简单根文件系统制作 - S5PV210 Linux3.8.3内核移植_Linux编程_Linux公社-Linux系统门户网站...
1.这里为什么选nfs文件系统呢? 在产品开发阶段,因为nfs根文件系统并不需要编译进内核,方便调试. 2.制作根文件系统需要用到BusyBox 解压进入busybox目录: root@linuxid ...
- linux不启动修改rcs文件,linux根文件系统制作之rcS文件分析
先把我的rcS文件贴出来,然后逐行解析: ***************************************************************************** # ...
- linux 内核移植和根文件系统的制作【转载】
原文地址:http://www.cnblogs.com/hnrainll/archive/2011/06/09/2076214.html 1.1 Linux内核基础知识 在动手进行Linux内核移植之 ...
- 嵌入式Linux根文件系统制作
嵌入式Linux根文件系统制作 一.根文件系统简介 根文件系统首先是一种文件系统,该文件系统不仅具有普通文件系统的存储数据文件的功能,但是相对于普通的文件系统而言它还是内核启动时所挂载(mount)的 ...
- 嵌入式linux启动根文件系统,嵌入式Linux根文件系统制作和挂载
嵌入式Linux系统由三部分组成: uboot.kernel.根文件系统, 还是这张老图 这里的根文件系统可以说是包含两个部分: 一个是根,一个是文件系统 那么什么是根呢?哈哈 其实根表示的就是第一个 ...
- 嵌入式Linux内核以及根文件系统制作
内核制作 注意: 我测试的使用nandflsh中bootloader启动,sd卡bootloader启动有问题 制作嵌入式平台使用的Linux内核,方法和制作PC平台的Linux内核基本一致. 清除原 ...
- linux开发 | nfs挂载根文件系统失败、处理过程
NFS挂载根文件系统失败 [ 5.552903] s5p-tvout s5p-tvout: hpd status is cable removed [ 5.563919] DBUG_PORT must ...
- linux内核开文件系统,新手,Linux内核无法挂载根文件系统
新手求助,Linux内核无法挂载根文件系统 一块开发板,厂商已经提供好了uboot,kernel,ramdisk文件系统跟安卓镜像 有:uboot.bin, zImage, ramdisk-uboot ...
最新文章
- vue element upload 控件用form-data上传方式导入xls文件
- 强化学习笔记5:learningplanning, explorationexploitation
- 【二分答案】【哈希表】【字符串哈希】bzoj2946 [Poi2000]公共串
- Android Pie 引入 Keystore 新特性,安全防护再升级
- 一种新的图像清晰度评价函数
- 微信上了一个新功能,吐槽的人有点多
- 周鸿祎IOT发布会思考
- docsys安装_DocSys文件系统部署
- android 编译 sdl,SDL编译 - Android本地视频播放器开发_Linux编程_Linux公社-Linux系统门户网站...
- SmtpClient 类
- 信息系统综合知识二 信息化基础知识
- 一些神奇的小函数(一)——gotoxy篇
- 西门子/软件/博途/TIA PORTAL V14 SP1
- correspondence analysis of drug and genotype(spss)
- Linux 自动挂载U盘 实现热插拔
- oracle11g认证,ORACLE11g-OCP认证(甲骨文专家级数据库工程师)
- 跟着小马哥学系列之 Spring AOP(Pointcut 组件详解)
- 用深度学习做命名实体识别(五)-模型使用
- QRCode插件的使用(二维码识别与生成)
- c语言 ll1文法实验报告,C语言文法 LL(1)文法
热门文章
- 医程通 服务器维护,启用医程通,妇幼版“抢车位”有望缓解
- python函数画圆_python圆形_python圆形绘制_python圆形函数 - 云+社区 - 腾讯云
- Linux 利器- Python 脚本编程入门(一)
- TX2 Linux配置组播(Multicast)
- jQuery水平手风琴图片插件
- combox绑定总结
- 【C++】黑马程序员-C++核心编程学习笔记
- css图片宽高自适应盒子(宽>高就限制宽,高>宽就限制高)
- Linux 查看网关
- 【计算机专业漫谈】【计算机系统基础学习笔记】W1-计算机系统概述