上面一篇,etc/init.d/rcS,inittab,fstab,讲的稍微不够仔细
一、BusyBox简介
在构建根文件系统之前,我们先来看一下根文件系统里面大概都有些什么内容,以Ubuntu为例,根文件系统的目录名字为‘/’,没看错就是一个斜杠,所以输入如下命令就可以进入根目录中:
根文件系统里面就是一堆的可执行文件和其他文件组成的?难道我们得一个一个的从网上去下载这些文件?显然这是不现实的!
BusyBox!其名字分为“Busy”和“Box”,也就是忙碌的盒子。盒子是用来放东西的,忙碌的是因为它要提供根文件系统所需的文件,所以忙碌。BusyBox是一个集成了大量的Linux命令和工具的软件,像ls、mv、ifconfig等命令BusyBox都会提供。BusyBox就是一个大的工具箱,这个工具箱里面集成了Linux的许多工具和命令。一般下载BusyBox的源码,然后配置BusyBox,选择自己想要的功能,最后编译即可。
BusyBox可以在其官网下载到,官网地址为:https://busybox.net/
编译BusyBox构建根文件系统
一般我们在Linux驱动开发的时候都是通过nfs挂载根文件系统的,当产品最终上市开卖的时候才会将根文件系统烧写到EMMC或者NAND中。mkdir rootfs,创建好的rootfs子目录就用来存放我们的根文件系统了。
将busybox-1.29.0.tar.bz2发送到Ubuntu中,存放位置大家随便选择。然后使用如下命令将其解压:
tar -vxjf busybox-1.29.0.tar.bz2
解压完成以后进入到busybox-1.29.0目录中,此目录中的文件和文件夹如图
同Uboot和Linux移植一样,打开busybox的顶层Makefile,添加ARCH和CROSS_COMPILE的值,如下所示:
Makefile代码段
164 CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
…
190 ARCH ?= arm
CORSS_COMPILE使用了绝对路径!主要是为了防止编译出错。
busybox中文字符支持
如果默认直接编译busybox的话,在使用SecureCRT的时候中文字符是显示不正常的,中文字符会显示为“?”,比如你的中文目录,中文文件都显示为“?”。不知道从哪个版本开始busybox中的shell命令对中文输入即显示做了限制,即使内核支持中文但在shell下也依然无法正确显示。
所以我们需要修改busybox源码,取消busybox对中文显示的限制,打开文件busybox-1.29.0/libbb/printable_string.c,找到函数printable_string,缩减后的函数内容如下: libbb/printable_string.c代码段
12 const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
13 {
14 char *dst;
15 const char *s;
16
17 s = str;
18 while (1) {
19 unsigned char c = *s;
20 if (c == '\0') {
......
28 }
29 if (c < ' ')
30 break;
31 if (c >= 0x7f)
32 break;
33 s++;
34 }
35
36 #if ENABLE_UNICODE_SUPPORT
37 dst = unicode_conv_to_printable(stats, str);
38 #else
39 {
40 char *d = dst = xstrdup(str);
41 while (1) {
42 unsigned char c = *d;
43 if (c == '\0')
44 break;
45 if (c < ' ' || c >= 0x7f)
46 *d = '?';
47 d++;
48 }
......
55 #endif
56 return auto_string(dst);
57 }
第31和32行,当字符大于0X7F以后就跳出去了。
第45和46行,如果支持UNICODE码的话,当字符大于0X7F就直接输出‘?’。
所以我们需要对这4行代码进行修改,修改以后如下所示:
libbb/printable_string.c代码段
12 const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str)
13 {
14 char *dst;
15 const char *s;
16
17 s = str;
18 while (1) {
......
30 if (c < ' ')
31 break;
32 /* 注释掉下面这个两行代码 */
33 /* if (c >= 0x7f)
34 break; */
35 s++;
36 }
37
38 #if ENABLE_UNICODE_SUPPORT
39 dst = unicode_conv_to_printable(stats, str);
40 #else
41 {
42 char *d = dst = xstrdup(str);
43 while (1) {
44 unsigned char c = *d;
45 if (c == '\0')
46 break;
47 /* 修改下面代码 */
48 /* if (c < ' ' || c >= 0x7f) */
49 if( c < ' ')
50 *d = '?';
51 d++;
52 }
......
59 #endif
60 return auto_string(dst);
61 }
红色部分的代码就是被修改以后的,主要就是禁止字符大于0X7F以后break和输出‘?’。
接着打开文件busybox-1.29.0/libbb/unicode.c,找到如下内容:
示例代码38.2.2.4 libbb/unicode.c代码段
1003 static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
1004 {
1005 char *dst;
1006 unsigned dst_len;
1007 unsigned uni_count;
1008 unsigned uni_width;
1009
1010 if (unicode_status != UNICODE_ON) {
1011 char *d;
1012 if (flags & UNI_FLAG_PAD) {
1013 d = dst = xmalloc(width + 1);
......
1022 *d++ = (c >= ' ' && c < 0x7f) ? c : '?';
1023 src++;
1024 }
1025 *d = '\0';
1026 } else {
1027 d = dst = xstrndup(src, width);
1028 while (*d) {
1029 unsigned char c = *d;
1030 if (c < ' ' || c >= 0x7f)
1031 *d = '?';
1032 d++;
1033 }
1034 }
......
1040 return dst;
1041 }
......
1130
1131 return dst;
1132 }
第1022行,当字符大于0X7F以后,*d++就为‘?’。
第1030和1031行,当字符大于0X7F以后,*d也为‘?’。
修改示例代码38.2.2.4,修改后内容如下所示:
libbb/unicode.c代码段
1003 static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags)
1004 {
1005 char *dst;
1006 unsigned dst_len;
1007 unsigned uni_count;
1008 unsigned uni_width;
1009
1010 if (unicode_status != UNICODE_ON) {
1011 char *d;
1012 if (flags & UNI_FLAG_PAD) {
1013 d = dst = xmalloc(width + 1);
......
1022 /* 修改下面一行代码 */
1023 /* *d++ = (c >= ' ' && c < 0x7f) ? c : '?'; */
1024 *d++ = (c >= ' ') ? c : '?';
1025 src++;
1026 }
1027 *d = '\0';
1028 } else {
1029 d = dst = xstrndup(src, width);
1030 while (*d) {
1031 unsigned char c = *d;
1032 /* 修改下面一行代码 */
1033 /* if (c < ' ' || c >= 0x7f) */
1034 if(c < ' ')
1035 *d = '?';
1036 d++;
1037 }
1038 }
......
1044 return dst;
1045 }
......
1047
1048 return dst;
1049 }
3、配置busybox
根我们编译Uboot、Linux kernel一样,我们要先对busybox进行默认的配置,有以下几种配置选项:
①、defconfig,缺省配置,也就是默认配置选项。
②、allyesconfig,全选配置,也就是选中busybox的所有功能。
③、allnoconfig,最小配置。
我们一般使用默认配置即可,因此使用如下命令先使用默认配置来配置一下busybox:
make defconfig
busybox也支持图形化配置,通过图形化配置我们可以进一步选择自己想要的功能,输入如下命令打开图形化配置界面:
make menuconfig
4、编译busybox
配置好busybox以后就可以编译了,我们可以指定编译结果的存放目录,我们肯定要将编译结果存放到前面创建的rootfs目录中,输入如下命令:
make
make install CONFIG_PREFIX=/home/zuozhongkai/linux/nfs/rootfs
编译完后,生产下面这些目录
rootfs目录下有bin、sbin和usr这三个目录,以及linuxrc这个文件。
前面说过Linux内核init进程最后会查找用户空间的init程序,找到以后就会运行这个用户空间的init程序,从而切换到用户态。
如果bootargs设置init=/linuxrc,那么linuxrc就是可以作为用户空间的init程序,所以用户态空间的init程序是busybox来生成的。
busybox的工作就完成了,但是此时的根文件系统还不能使用,还需要一些其他的文件,我们继续来完善rootfs。
向根文件系统添加lib库
Linux中的应用程序一般都是需要动态库的,当然你也可以编译成静态的,但是静态的可执行文件会很大。如果编译为动态的话就需要动态库,所以我们需要向根文件系统中添加动态库。在rootfs中创建一个名为“lib”的文件夹,
lib文件夹创建好了,库文件从哪里来呢?lib库文件从交叉编译器中获取,前面我们搭建交叉编译环境的时候将交叉编译器存放到了“/usr/local/arm/”目录中。交叉编译器里面有很多的库文件,这些库文件具体是做什么的我们作为初学者肯定不知道,既然我不知道那就简单粗暴的把所有的库文件都放到我们的根文件系统中。这样做出来的根文件系统肯定很大,但是我们现在是学习阶段,还做不了裁剪。如果后面要学习QT的话那占用的空间将更大,不裁剪的话512MB的NAND完全不够用的!而裁剪又是需要经验的,我们都是初学者,哪里来的经验啊。
进入如下路径对应的目录:
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
此目录下有很多的so(是通配符)和.a文件,这些就是库文件,将此目录下所有的so*和.a文件都拷贝到rootfs/lib目录中,拷贝命令如下:
cp so *.a /home/zuozhongkai/linux/nfs/rootfs/lib/ -d
后面的“-d”表示拷贝符号链接,这里有个比较特殊的库文件:ld-linux-armhf.so.3,此库文件也是个符号链接,相当于Windows下的快捷方式。会链接到库ld-2.19-2014.08-1-git.so上
文件ld-linux-armhf.so.3
ld-linux-armhf.so.3后面有个“->”,表示其是个软连接文件,链接到文件ld-2.19-2014.08-1-git.so,因为其是一个“快捷方式”,因此大小只有24B。但是,ld-linux-armhf.so.3不能作为符号链接,否则的话在根文件系统中执行程序无法执行!所以我们需要ld-linux-armhf.so.3完成逆袭,由“快捷方式”变为“本尊”,方法很简单,那就是重新复制ld-linux-armhf.so.3,只是不复制软链接即可,先将rootfs/lib中的ld-linux-armhf.so.3文件删除掉,命令如下:
rm ld-linux-armhf.so.3
然后重新进入到/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib目录中,重新拷贝ld-linux-armhf.so.3,命令如下:
cp ld-linux-armhf.so.3 /home/zuozhongkai/linux/nfs/rootfs/lib/
拷贝完成以后再到rootfs/lib目录下查看ld-linux-armhf.so.3文件详细信息此时ld-linux-armhf.so.3已经不是软连接了,而是实实在在的一个库文件,而且文件大小为724392B。
继续进入如下目录中:
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
此目录下也有很多的的so和.a库文件,我们将其也拷贝到rootfs/lib目录中,命令如下:
cp so *.a /home/zuozhongkai/linux/nfs/rootfs/lib/ -d
rootfs/lib目录的库文件就这些了,完成以后的rootfs/lib目录如图38.2.3.3所示:
向rootfs的“usr/lib”目录添加库文件
在rootfs的usr目录下创建一个名为lib的目录,将如下目录中的库文件拷贝到rootfs/usr/lib目录下:
/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/
usr/lib
将此目录下的so和.a库文件都拷贝到rootfs/usr/lib目录中,命令如下:
cp so *.a /home/zuozhongkai/linux/nfs/rootfs/usr/lib/ -d
完成以后的rootfs/usr/lib目录
5、创建其他文件夹
在根文件系统中创建其他文件夹,如dev、proc、mnt、sys、tmp和root等
将做好文件系统,做成ext4,或yffs2等系统,烧录进系统,设置好bootarg,就可以启动挂载fs了
在进入根文件系统的时候会有下面这一行错误提示:
can’t run ‘/etc/init.d/rcS’: No such file or directory
提示很简单,说是无法运行“/etc/init.d/rcS”这个文件,因为这个文件不存在。
创建/etc/init.d/rcS文件
rcS是个shell脚本,Linux内核启动以后需要启动一些服务,而rcS就是规定启动哪些文件的脚本文件。在rootfs中创建/etc/init.d/rcS文件,然后在rcS中输入如下所示内容:
1 #!/bin/sh
2
3 PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
4 LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
5 export PATH LD_LIBRARY_PATH
6
7 mount -a
8 mkdir /dev/pts
9 mount -t devpts devpts /dev/pts
10
11 echo /sbin/mdev > /proc/sys/kernel/hotplug
12 mdev -s
第1行,表示这是一个shell脚本。
第3行,PATH环境变量保存着可执行文件可能存在的目录,这样我们在执行一些命令或者可执行文件的时候就不会提示找不到文件这样的错误。
第4行,LD_LIBRARY_PATH环境变量保存着库文件所在的目录。
第5行,使用export来导出上面这些环境变量,相当于声明一些“全局变量”。
第7行,使用mount命令来挂载所有的文件系统,这些文件系统由文件/etc/fstab来指定,所以我们一会还要创建/etc/fstab文件。
第8和9行,创建目录/dev/pts,然后将devpts挂载到/dev/pts目录中。
第11和12行,使用mdev来管理热插拔设备,通过这两行,Linux内核就可以在/dev目录下自动创建设备节点。关于mdev的详细内容可以参考busybox中的docs/mdev.txt文档。
示例代码38.4.1.1中的rcS文件内容是最精简的,大家如果去看Ubuntu或者其他大型Linux操作系统中的rcS文件,就会发现其非常复杂。因为我们是初次学习,所以不用搞这么复杂的,而且这么复杂的rcS文件也是借助其他工具创建的,比如buildroot等。
创建好文件/etc/init.d/rcS以后一定要给其可执行权限!
使用如下命令给予/ec/init.d/rcS可执行权限:
chmod 777 rcS
提示找不到/etc/fstab文件,还有一些其他的错误,我们先把/etc/fstab这个错误解决了。说不定把这个问题解决以后其他的错误也就解决了。前面我们说了“mount -a”挂载所有根文件系统的时候需要读取/etc/fstab,因为/etc、fstab里面定义了该挂载哪些文件,好了,接下来就是创建/etc/fstab文件。
创建/etc/fstab文件
在rootfs中创建/etc/fstab文件,fstab在Linux开机以后自动配置哪些需要自动挂载的分区,格式如下:
:要挂载的特殊的设备,也可以是块设备,比如/dev/sda等等。
:挂载点。
:文件系统类型,比如ext2、ext3、proc、romfs、tmpfs等等。
:挂载选项,在Ubuntu中输入“man mount”命令可以查看具体的选项。一般使用defaults,也就是默认选项,
defaults包含了rw、suid、 dev、 exec、 auto、 nouser和 async。
:为1的话表示允许备份,为0不备份,一般不备份,因此设置为0。
:磁盘检查设置,为0表示不检查。根目录‘/’设置为1,其他的都不能设置为1,其他的分区从2开始。一般不在fstab中挂载根目录,因此这里一般设置为0。
按照上述格式,在fstab文件中输入如下内容:etc/fstab文件
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
Linux启动过程
启动成功,而且没有任何错误提示。但是我们要还需要创建一个文件/etc/inittab。
inittab的详细内容可以参考busybox下的文件examples/inittab。init程序会读取/etc/inittab这个文件,inittab由若干条指令组成。每条指令的结构都是一样的,由以“:”分隔的4个段组成,格式如下:
:每个指令的标识符,不能重复。但是对于busybox的init来说,有着特殊意义。对于busybox而言用来指定启动进程的控制tty,一般我们将串口或者LCD屏幕设置为控制tty。
:对busybox来说此项完全没用,所以空着。
:动作,用于指定可能用到的动作。
动作 描述
sysinit 在系统初始化的时候process才会执行一次。
respawn 当process终止以后马上启动一个新的。
askfirst 和respawn类似,在运行process之前在控制台上显示“Please press Enter to activate this console.”。只要用户按下“Enter”键以后才会执行process。
wait 告诉init,要等待相应的进程执行完以后才能继续执行。
once 仅执行一次,而且不会等待process执行完成。
restart 当init重启的时候才会执行procee。
ctrlaltdel 当按下ctrl+alt+del组合键才会执行process。
shutdown 关机的时候执行process。
参考busybox的examples/inittab文件,我们也创建一个/etc/inittab,在里面输入如下内容:
/etc/inittab文件
1 #etc/inittab
2 ::sysinit:/etc/init.d/rcS
3 console::askfirst:-/bin/sh
4 ::restart:/sbin/init
5 ::ctrlaltdel:/sbin/reboot
6 ::shutdown:/bin/umount -a -r
7 ::shutdown:/sbin/swapoff -a
第2行,系统启动以后运行/etc/init.d/rcS这个脚本文件。
第3行,将console作为控制台终端,也就是ttymxc0。
第4行,重启的话运行/sbin/init。
第5行,按下ctrl+alt+del组合键的话就运行/sbin/reboot,看来ctrl+alt+del组合键用于重启系统。
第6行,关机的时候执行/bin/umount,也就是卸载各个文件系统。
第7行,关机的时候执行/sbin/swapoff,也就是关闭交换分区。
/etc/inittab文件创建好以后就可以重启开发板即可,至此!根文件系统要创建的文件就已经全部完成了。接下来就要对根文件系统进行其他的测试,比如我们自己编写的软件运行是否正常、是否支持软件开机自启动、中文支持是否正常以及能不能链接等。
二、配置,etc/init.d/rcS,inittab,fstab
Linux 开机脚本启动顺序:
第一步:启动内核
第二步:执行init (配置文件/etc/inittab)
第三步:启动相应的脚本,执行inittab脚本,并且执行里面的脚本/etc/init.d rc.sysinit rc.d rc.local。。。
第四步:启动login登录界面 login
第五步:在用户登录的时候执行sh脚本的顺序:每次登录的时候都会完全执行的 /etc/profile /etc/bashrc /root/.bashrc /root/.bash_profile
前面讲的比较简单,实际开发项目时,会比较复杂一点,在我前面一篇文章,介绍过稍微详细的设置。
这个是简单点的,项目中,关于系统的设置,脚本配置文件,都是放在这个目录下。
内核启动文件系统后第一个执行的文件(inittab启动脚本分析)
init的进程号为1,是所有进程的父进程,内核初始化完毕之后,init程序开始运行。其他软件也同时开始运行。init程序通过/etc/inittab文件进行配置。
inittab,如下图,开机sysinit,关机shutdown时,要做什么,我在英伟达开发项目时,用的是systemd机制,但是也是类似这样,关机时
要,卸载驱动,卸载挂载的各个分区,文件系统,等等。他这里关机时,执行rcK,执行关机前,调用的脚步文件
在这些目录中,通常包含以 K 开头的符号链接和以 S 开头的符号链接。K 表示 “Kill”,即停止对应的服务,而 S 表示 “Start”,
即启动对应的服务。这些符号链接指向 /etc/init.d/ 目录中的服务脚本,从而实现对服务的管理。
打开rcS脚本文件,可以看到如下,for循环去寻找/etc/init.d/S*结尾的文件,如果$i,判断是否为文件,f是个文件,
就continue
然后判断,case
i
i
n
∗
.
s
h
,意思是
s
h
脚本文件,就去执行
.
号就是运行文件的意思,
i in *.sh,意思是sh脚本文件,就去执行 .号就是运行文件的意思,
iin∗.sh,意思是sh脚本文件,就去执行.号就是运行文件的意思,i start,就是去运行文件,传入start
在这些目录中,通常包含以 K 开头的符号链接和以 S 开头的符号链接。K 表示 “Kill”,即停止对应的服务,而 S 表示 “Start”,即启动对应的服务。这些符号链接指向 /etc/init.d/ 目录中的服务脚本,从而实现对服务的管理。
进入到init.d目录,放了很多脚本文件,关于系统的处理,上面调用rcK,rcS,脚本,会执行对应的下面这些脚本
就拿上面的一个模块文件,打开看看,如果传入的是start命令,会安装驱动ko,stop命令则会执行卸载驱动
如果是reload,或restar命令,就会先执行stop,再执行start,
“”$0“” stop的意思,是第一个参数. 后面跟stop,相当于,source test.sh stop,那么传入的0参数就是sourcce,1参数就是stop
四、详细
/etc/inittab文件每一行包括四个字段
label:
runlevel:
action:
process。
详细解释如下
1.label
登记项标志符,是一个任意指定的、4个字符以内的序列标号,在本文件内必须唯一。
label是1到4个字符的标签,用来标示输入的值。一些系统只支持2个字符的标签。
鉴于此原因,多数人都将标签字符的个数限制在2个以内。该标签可以是任意字符构成的字符串,
但实际上,某些特定的标签是常用的,在Red Hat Linux中使用的标签是:
id 用来定义缺省的init运行的级别
si 是系统初始化的进程
ln 其中的n从1~6,指明该进程可以使用的runlevel的级别
ud 是升级进程
ca 指明当按下Ctrl+Alt+Del是运行的进程
pf 指当UPS表明断电时运行的进程
pr 是在系统真正关闭之前,UPS发出电源恢复的信号时需要运行的进程
x 是将系统转入X终端时需要运行的进程
2.runlevels
系统运行级,即执行登记项的init级别。用于指定相应的登记项适用于哪一个运行级,即在哪一个运行级中被处理。如果该字段为空,那么相应的登记项将适用于所有的运行级。在该字段中,可以同时指定一个或多个运行级,其中各运行级分别以数字0, 1, 2, 3, 4, 5, 6或字母a, b, c表示,且无须对其进行分隔。
0-->Halt,关闭系统.
1-->单用户,在grub启动时加上为kernel加上参数single即可进入此运行等级
2-->无网络多用户模式.
3-->有网络多用户模式.
4-->有网络多用户模式.
5-->X模式
6-->reboot重启系统
S/s-->同运行等级1
a,b,c-->自定义等级,通常不使用.
3.action
表示进入对应的runlevel时,init应该运行process字段的命令的方式,有效的action值如下。
boot:只有在引导过程中,才执行该进程,但不等待该进程的结束。当该进程死亡时,也不重新启动该进程。
bootwait:只有在引导过程中,才执行该进程,并等待进程的结束。当该进程死亡时,也不重新启动该进程。实际上,只有在系统被引导后,并从单用户模式进入多用户模式时,这些登记项才被处理;如果系统的默认运行级设置为2(即多用户模式),那么这些登记项在系统引导后将马上被处理。
initdefault:指定系统的默认运行级。系统启动时,init将首先查找该登记项,如果存在,init将依据此决定系统最初要进入的运行级。具体来说,init将指定登记项"run_level"字段中的最大数字(即最高运行级)为当前系统的默认运行级;如果该字段为空,那么将其解释为"0123456",并以"6"作为默认运行级。如果不存在该登记项,那么init将要求用户在系统启动时指定一个最初的运行级。
off:如果相应的进程正在运行,那么就发出一个告警信号,等待20秒后,再通过关闭信号强行终止该进程。如果相应的进程并不存在,那么就忽略该登记项。
once:启动相应的进程,但不等待该进程结束便继续处理/etc/inittab文件中的下一个登记项;当该进程终止时,init也不重新启动该进程。在从一个运行级进入另一个运行级时,如果相应的进程仍然在运行,那么init就不重新启动该进程。
ondemand:与"respawn"的功能完全相同,但只用于运行级为a、b或c的登记项。
powerfail:只在init接收到电源失败信号时,才执行该进程,但不等待该进程结束。
powerwait:只在init接收到电源失败信号时,才执行该进程,并在继续对/etc/inittab文件进行任何处理前等待该进程结束。
respawn:如果相应的进程还不存在,那么init就启动该进程,同时不等待该进程的结束就继续扫描/etc/inittab文件;当该进程终止时,init将重新启动该进程。如果相应的进程已经存在,那么init将忽略该登记项并继续扫描/etc/inittab文件。
sysinit:只有在启动或重新启动系统并首先进入单用户模式时,init才执行这些登记项。而在系统从运行级1~6进入单用户模式时,init并不执行这些登记项。"action"字段为"sysinit"的登记项在"run_level"字段不指定任何运行级。
wait:启动进程并等待其结束,然后再处理/etc/inittab文件中的下一个登记项。
ctrlaltdel:用户在控制台键盘上按下Ctrl+Alt+Del组合键时,允许init重新启动系统。注意,如果该系统放在一个公共场所,系统管理员可将
Ctrl+Alt+Del组合键配置为其他行为,比如忽略等。
4.process
具体应该执行的命令。并负责在退出运行级时将其终止(当然在进入的runlevel中仍要运行的程序除外)。
当运行级别改变,并且正在运行的程序并没有在新的运行级别中指定需要运行时,那么init会先发送一个SIGTERM 信号终止,然后是SIGKILL。
5、如下设分析
id:5:initdefault:
将系统切换到 initdefault 操作所定义的运行级别即运行级别5。我们可以将运行级别看作是系统的状态。
运行级别 0 定义了系统挂起状态,
运行级别 1 是单用户模式。
运行级别 2 到 5 是多用户状态,
运行级别 6 表示重启
sysinit表示在进行其他工作之前先完成系统初始化.init在处理其它运行等级的脚本之前,首先会执行这一行.是系统的初始化进程.用于设置主机名,挂载文件系统,启动交换分区等.
rcS脚本会调用/etc/rcS.d目录下的所有脚本进行初始化
si::sysinit:/etc/init.d/rcS //在运行boot或bootwait进程之前运行系统初始化的进程
下条语句可以让系统在重新启动、进入单用户模式的时候提示输入超级用户密码。
S同运行等级1,并等待其结束,然后再处理/etc/inittab文件中的下一个登记项。
~~:S:wait:/sbin/sulogin
当运行级别为5时,以5为参数运行/etc/rc5.d下的脚本,init将等待其返回(wait)
rc.sysinit,rcS,rc这些都是shell的脚本,完成大量的系统初始化的工作。
主要工作包括:激活交换分区,检查磁盘,加载硬件模块以及其它一些需要优先执行任务。
执行rc脚本,传入参数为0-6,即会调用/etc/rc0.d-rc6.d目录下的所有文件
//initdefault 指定默认的 init 级别是 5(多用户模式)。在定义初始的运行级别之后,则调用rc脚本以及参数5(运行级别)来启动系统,即rc脚本(参数5)会调用/etc/rc5.d下的所有脚本。
0:wait:/etc/init.d/rc 0 //使用级别0运行此程序
1:wait:/etc/init.d/rc 1
2:wait:/etc/init.d/rc 2
3:wait:/etc/init.d/rc 3
4:wait:/etc/init.d/rc 4
/会运行该/etc/rc5.d下的3个脚本:
S10telnetd脚本:开启telnetd服务 start-stop-daemon --start --quiet --exec $telnetd
S20syslog脚本:开启syslog服务start-stop-daemon -S -b -n syslogd -a /sbin/syslogd – -n $SYSLOG_ARGS start-stop-daemon -S -b -n klogd -a /sbin/klogd – -n
S99rmnologin脚本:删除/etc/nologin文件 rm -f /etc/nologin /etc/nologin.boot
5:wait:/etc/init.d/rc 5
6:wait:/etc/init.d/rc 6
6:respawn:/sbin/sulogin//脚本运行等级为6时才执行
也有这么设计的
在 Linux 系统中,rc0.d, rc1.d, rc2.d, rc3.d, rc4.d, rc5.d 和 rc6.d 是特定的运行级别目录,它们与系统的不同运行级别相关联。
操作系统中,运行级别用于确定系统处于不同状态时运行的服务和进程。
这些目录所对应的运行级别分别是:
rc0.d: 关机(运行级别 0)
rc1.d: 单用户模式(运行级别 1)
rc2.d: 多用户模式,没有网络服务(运行级别 2)
rc3.d: 多用户模式,带网络服务(运行级别 3)
rc4.d: 未分配 (可以由用户自定义)
rc5.d: 图形界面模式(运行级别 5)
rc6.d: 重启(运行级别 6)
在init的配置文件中有这么一行: si::sysinit:/etc/rc.d/rc.sysinit 它调用执行了/etc/rc.d/rc.sysinit,而rc.sysinit是一个bash shell的脚本,它主要是完成一些系统初始化的工作,rc.sysinit是每一个运行级别都要首先运行的重要脚本。
它主要完成的工作有:激活交换分区,检查磁盘,加载硬件模块以及其它一些需要优先执行任务。
:wait:/etc/rc.d/rc 5
这一行表示以5为参数运行/etc/rc.d/rc,/etc/rc.d/rc是一个Shell脚本,它接受5作为参数,去执行/etc/rc.d/rc5.d/目录下的所有的rc启动脚本,/etc/rc.d/rc5.d/目录中的这些启动脚本实际上都是一些链接文件,而不是真正的rc启动脚本,真正的rc启动脚本实际上都是放在/etc/rc.d/init.d/目录下。
总结,上面有的是写在/etc/rc.d/下,有的/etc/init.d下,应该都是可以的,这块不是很好,容易混乱
关机指令为:shutdown ,你可以man shutdown 来看一下帮助文档。
例如你可以运行如下命令关机:
sync 将数据由内存同步到硬盘中。
shutdown 关机指令,你可以man shutdown 来看一下帮助文档。例如你可以运行如下命令关机:
shutdown –h 10 ‘This server will shutdown after 10 mins’ 这个命令告诉大家,计算机将在10分钟后关机,并且会显示在登陆用户的当前屏幕中。
shutdown –h now 立马关机
shutdown –h 20:25 系统会在今天20:25关机
shutdown –h +10 十分钟后关机
shutdown –r now 系统立马重启
shutdown –r +10 系统十分钟后重启
reboot 就是重启,等同于 shutdown –r now
halt 关闭系统,等同于shutdown –h now 和 poweroff
最后总结一下,不管是重启系统还是关闭系统,首先要运行 sync 命令,把内存中的数据写到磁盘中。
关机的命令有 shutdown –h now halt poweroff 和 init 0 //0就是运行级别0
重启系统的命令有 shutdown –r now reboot init 6 //6就是运行级别6