CentOS比较传统的启动及初始化流程如下图所示:
图示说明:
1. 加电自检;
2. 加载磁盘第一个分区的第一个扇区,即MBR,后有详细说明;
3. GRUB的中间流程stage 1.5;
4. GRUB的真面目stage 2;
5. 加载内核及虚拟文件系统;
6. 加载第一个进程init进程;
7. 启动初始化;
8. 根据运行级别启动或关闭对应的服务;
9. 启动登录界面;
详细说明:
加电自检不用多说,我们从第2个步骤开始说起吧;
第二个步骤的说明:
MBR所在扇区容量512bytes,分为3个部分:446bytes+64bytes+2bytes;
446bytes中存放的是开机启动程序,在此为GRUB启动的stage1,stage1用于引导stage2;
64bytes中存放的是分区表;
2bytes中存放的是有效性校验数据:55AA;
第三个步骤的说明:
是GRUB启动流程的stage1.5,为什么会有stage1.5呢,而不直接stage2呢?为什么不直接把stage2放在MBR中呢?
因为stage2太大,MBR放不下,且stage2存在于文件系统中;stage1为了识别stage2必须得能识别其所在的文件系统,所以才有了stage1.5,stage1.5是在GRUB的安装阶段就生成好的且放置在了磁盘的特定位置——第三个扇区开始向后N个扇区(因文件系统而异);GRUB在安装时候就已经识别了你的文件系统的,且根据你的文件系统来放置对应的stage1.5,所以你才会在/boot/grub/目录下发现那么多的stage1.5文件,但是用到就那么一个;有了stage1.5,GRUB就能识别stage2所在的文件系统,进而找到stage2文件;
第四个步骤说明:
stage2,这个步骤是GRUB启动的最后一个流程,也是我们能够在开机的时候看到的画面,这个画面包含菜单,甚至图片:
注意看下面的文字说明,按e可以编辑选中的项,然后在其二级菜单中选择并给内核传递启动参数,可以进入单人维护模式;或者直接在此画面下按a直接给内核传递启动参数。
我们再看下stage2所在目录吧:
[root@CENTOSLINUX grub]# cd /boot/grub/ [root@CENTOSLINUX grub]# ls -l total 274 -rw-r--r--. 1 root root 63 Nov 9 00:56 device.map -rw-r--r--. 1 root root 13396 Nov 9 00:56 e2fs_stage1_5 -rw-r--r--. 1 root root 12636 Nov 9 00:56 fat_stage1_5 -rw-r--r--. 1 root root 11780 Nov 9 00:56 ffs_stage1_5 -rw-------. 1 root root 845 Nov 9 00:56 grub.conf -rw-r--r--. 1 root root 11772 Nov 9 00:56 iso9660_stage1_5 -rw-r--r--. 1 root root 13284 Nov 9 00:56 jfs_stage1_5 lrwxrwxrwx. 1 root root 11 Nov 9 00:56 menu.lst -> ./grub.conf # 启动菜单文件,是个软链接,链接至同目录下的grub.conf; -rw-r--r--. 1 root root 11972 Nov 9 00:56 minix_stage1_5 -rw-r--r--. 1 root root 14428 Nov 9 00:56 reiserfs_stage1_5 -rw-r--r--. 1 root root 1341 Nov 15 2010 splash.xpm.gz -rw-r--r--. 1 root root 512 Nov 9 00:56 stage1 # stage1正好512bytes,我的理解它差不多就是MBR;(不太确定,欢迎指教。) -rw-r--r--. 1 root root 126116 Nov 9 00:56 stage2 # GRUB的bootloader文件,可以 file stage2 查看,作用是读取启动菜单,引导内核; # 看stage2的大小, MBR放不下的 -rw-r--r--. 1 root root 12040 Nov 9 00:56 ufs2_stage1_5 -rw-r--r--. 1 root root 11380 Nov 9 00:56 vstafs_stage1_5 -rw-r--r--. 1 root root 13980 Nov 9 00:56 xfs_stage1_5 # 这个目录还有好几个stage1.5的文件,其实用到的就那么一个(因文件系统而异);
下面我们再来看看device.map和grub.conf文件吧:
# this device map was generated by anaconda (hd0) /dev/sda # device.map记录的是启动磁盘; [root@CENTOSLINUX grub]# cat grub.conf # grub.conf generated by anaconda # # Note that you do not have to rerun grub after making changes to this file # NOTICE: You have a /boot partition. This means that # all kernel and initrd paths are relative to /boot/, eg. # root (hd0,0) # 意思是说我的启动分区是/boot,/boot就是root (hd0,0) # kernel /vmlinuz-version ro root=/dev/mapper/vg_centoslinux-lv_root # initrd /initrd-[generic-]version.img #boot=/dev/sda default=0 # 启动菜单的默认项,0表示第一项 timeout=5 # 选择等待时间为5s splashimage=(hd0,0)/grub/splash.xpm.gz # 启动菜单的背景图片 hiddenmenu # 隐藏式菜单 title CentOS 6 (2.6.32-504.el6.x86_64) # 菜单项 root (hd0,0) kernel /vmlinuz-2.6.32-504.el6.x86_64 ro root=/dev/mapper/vg_centoslinux-lv_root rd_LVM_LV =vg_centoslinux/lv_root rd_NO_LUKS.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg_centoslinux/lv_swap KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet initrd /initramfs-2.6.32-504.el6.x86_64.img # 最后的3项分别指定了启动所选系统所需的root,kernel,initrd位置及参数; # 你也可以据此创建新的启动菜单,root,kernel,initrd为必须项. # 你甚至可以在选择菜单界面按c进入grub命令行手动指定此三项
第五个步骤说明:
此步开始启动内核并加载临时文件系统(initramfs-2.6.32-504.el6.x86_64.img)至内存中;
这个临时的文件系统值得一提,这个文件是和内核一起加载到内存中的,其在内存中被展开为一个小型的文件系统,这其中就有内核读取硬盘用的驱动文件,而且此文件是在安装操作系统的时候就生成好的;内核读取硬盘用的就是此驱动。
第六个步骤说明:
init为内核启动的第一个进程,也是此后启动的所有进程的父进程;
第七个步骤说明:
init进程启动后,会读取/etc/inittab中定义的初始化语句对系统进行初始化;
即读取si::sysinit:/etc/rc.d/rc.sysinit,执行/etc/rc.d/rc.sysinit这个文件对系统进行初始化;
这个初始化脚本执行的任务有:
1. 设置主机名;
2. 设置欢迎信息;
3. 激活udev和selinux;
4. 挂载/etc/fstab文件中定义的文件系统;
5. 检测根文件系统, 并以读写方式重新挂载根文件系统;
6. 设置系统时钟;
7. 激活swap设备;
8. 根据/etc/sysctl.conf文件设置内核参数;
9. 激活lvm及software raid设备;
10 加载额外设备的驱动程序;
11 清理操作;
第八个步骤说明:
系统初始化完成后,init根据运行级别开启或关闭某些服务,其会读取inittab中的两条语句:
id:3:initdefault:
这条语句定义的是系统默认的运行级别,规定了执行哪条与级别对应的语句,比如此处会执行下面的语句:
l3:3:wait:/etc/rc.d/rc 3(第一个字符为字母l。)
这条语句定义了开启或关闭服务脚本所在的目录,以及wait——等待后面目录的服务执行完毕返回至init;此条语句的服务脚本所在目录为/etc./rc.d/rc3.d:
[root@CENTOSLINUX rc.d]# ls rc3.d K01smartd K74ntpd S08iptables S25netfs K02oddjobd K75ntpdate S10network S26acpid K05wdaemon K75quota_nld S11auditd S26haldaemon K10psacct K76ypbind S11portreserve S26udev-post K10saslauthd K80kdump S12rsyslog S28autofs K15htcacheclean K84wpa_supplicant S13cpuspeed S50bluetooth K15httpd K87restorecond S13irqbalance S55sshd K30spice-vdagentd K88sssd S13rpcbind S57vmware-tools-thinprint K50dnsmasq K89rdisc S15mdmonitor S80postfix K50netconsole K95firstboot S22messagebus S82abrt-ccpp K50snmpd K99rngd S23NetworkManager S82abrtd K50snmptrapd S01sysstat S24nfslock S90crond K60nfs S02lvm2-monitor S24rpcgssd S95atd K69rpcsvcgssd S03vmware-tools S25blk-availability S99certmonger K73winbind S08ip6tables S25cups S99local
我们不难发现一个规律,里面的文件不是以K开头就是以S开头的文件,以K开头表示此服务要被KILL,以S开头表示此服务要被START。init会按照排序依次执行其中的脚本。
同时我们发现字母S和K后面都一个两位的数字,此数是用来排序的,数字越小,排序越靠前,越早被执行;在以K开头的脚本中,数字越小,越早被关闭,说明此服务是依赖于其他服务的程序,数字越大,越晚被关闭,说明服务是被其他服务所依赖的程序;以S开头的脚本中,数字越小,越早被开启,说明此服务是被其他服务所依赖的程序,数字越大,越晚被开启,说明此服务没有其他服务依赖于它,反正可能依赖于其他服务。
需要说明的是这些文件只是软链接,他们实际指向的是/etc/rc.d/init.d/目录下的脚本。
那这些脚本软链接名中的数字怎么来的呢?
其实这个数字也是在脚本中定义的,不是在当前目录的脚本中,而是在这些软链接所指向的脚本中定义的:
[root@CENTOSLINUX rc.d]# ls -l ./rc3.d/S99local lrwxrwxrwx. 1 root root 11 Nov 9 00:50 ./rc3.d/S99local -> ../rc.local [root@CENTOSLINUX rc.d]# ls -l ./rc3.d/S01sysstat lrwxrwxrwx. 1 root root 17 Nov 9 00:52 ./rc3.d/S01sysstat -> ../init.d/sysstat [root@CENTOSLINUX rc.d]# cat ./init.d/sysstat #!/bin/sh # # chkconfig: 12345 01 99 # 是这句定义了S和K后面的数字的大小,其中12345表示要start的level,01表示S后的序号,99表示K后序号。 # description: Reset the system activity logs # # /etc/rc.d/init.d/sysstat # (C) 2000-2009 Sebastien Godard (sysstat <at> orange.fr) # 下面是脚本的执行语句。
如果我们想手动创建一开机启动的服务怎么做到呢?
1. 编写一个脚本,并将其放到/etc/rc.d/init.d/中;
2. 在脚本中定义S和K的数字序号,比如:# chkconfig: 12345 01 99;
3. 在对应的运行级别目录(比如rc3.d)下生成开启和关闭这个脚本的软连接;
这个步骤3其实不需手动执行,而是使用命令完成的,此命令为chkconfig,其使用方法:
[root@CENTOSLINUX init.d]# pwd /etc/rc.d/init.d [root@CENTOSLINUX init.d]# vim mysrv # 创建并编辑mysrv脚本 [root@CENTOSLINUX init.d]# chmod +x mysrv # 给mysrv脚本添加执行权限 [root@CENTOSLINUX init.d]# cat mysrv # 看下mysrv脚本的内容吧: #!/bin/bash # # chkconfig: 2345 20 80 # 此条内容比较重要,2345表示只在2345级别中start,在其他级别中kill,且start的软链接序号为20,kill的 # 软链接序号为80 # description: Reset the system activity logs echo "Hello welcome!" # 在此脚本中只是简单的执行了一条命令 [root@CENTOSLINUX init.d]# chkconfig --add mysrv # 使用chkconfig添加此脚本为启动服务脚本 [root@CENTOSLINUX init.d]# chkconfig --list mysrv # 使用chkconfig查看刚添加的服务 mysrv 0:off 1:off 2:on 3:on 4:on 5:on 6:off # 可见其在2345级别为on,其他级别为off [root@CENTOSLINUX init.d]# ls -l /etc/rc.d/rc3.d/ | grep "mysrv" lrwxrwxrwx. 1 root root 15 Dec 20 15:14 S20mysrv -> ../init.d/mysrv # 在3运行级别目录rc3.d下可以看到生成了start软链接S20mysrv,序号为20 [root@CENTOSLINUX init.d]# ls -l /etc/rc.d/rc6.d/ | grep "mysrv" lrwxrwxrwx. 1 root root 15 Dec 20 15:14 K80mysrv -> ../init.d/mysrv # 在6运行级别中是kill的,其序号为80 [root@CENTOSLINUX init.d]# chkconfig --level 2 mysrv off # 把2运行级别对应的mysrv关闭,注意参数顺序 [root@CENTOSLINUX init.d]# chkconfig --list mysrv mysrv 0:off 1:off 2:off 3:on 4:on 5:on 6:off # 可见2已关闭 [root@CENTOSLINUX init.d]# chkconfig --del mysrv # 删除mysrv开机启动脚本服务 [root@CENTOSLINUX init.d]# chkconfig --list mysrv service mysrv supports chkconfig, but is not referenced in any runlevel (run 'chkconfig --add mysr v') # 提示已经没有mysrv [root@CENTOSLINUX init.d]#
值得一提的是在各运行级别对应的目录下都有一个S99local的软连接指向/etc/rc.d/rc.local脚本:
[root@CENTOSLINUX init.d]# ls -l /etc/rc.d/rc2.d/S99local lrwxrwxrwx. 1 root root 11 Nov 9 00:50 /etc/rc.d/rc2.d/S99local -> ../rc.local [root@CENTOSLINUX init.d]# ls -l /etc/rc.d/rc.local -rwxr-xr-x. 1 root root 220 Oct 16 2014 /etc/rc.d/rc.local [root@CENTOSLINUX init.d]# cat /etc/rc.d/rc.local #!/bin/sh # # This script will be executed *after* all the other init scripts. # You can put your own initialization stuff in here if you don't # want to do the full Sys V style init stuff. touch /var/lock/subsys/local
此脚本是开机运行的,如果你不想或者感觉不需编写单独的服务脚本,可以把要执行的语句写于rc.local中。
附:inittab中语句的定义格式:
label:runlevel:action:process
label:
id 用来定义缺省的init运行的级别
si 是系统初始化的进程
ln 其中的n从1~6,指明该进程可以使用的runlevel的级别
ud 是升级进程
ca 指明当按下Ctrl+Alt+Del是运行的进程
pf 指当UPS表明断电时运行的进程
pr 是在系统真正关闭之前,UPS发出电源恢复的信号时需要运行的进程
x 是将系统转入X终端时需要运行的进程
runlevel:运行级别
0:关机。
1:单用户字符界面。
2:不具备网络文件系统(NFS)功能的多用户字符界面。
3:具有网络功能的多用户字符界面。
4:保留不用。
5:具有网络功能的图形用户界面。
6:重新启动系统。
action:(下面提到的process为label:runlevel:action:process中action之后的process)
respawn 启动并监视第4项指定的process,若process终止则重启它
wait 执行第4项指定的process,并等待它执行完毕
once 执行第4项指定的process
boot 不论在哪个执行等级,系统启动时都会运行第4项指定的process
bootwait 不论在哪个执行等级,系统启动时都会运行第4项指定的process,且一直等它执行完备
off 关闭任何动作,相当于忽略该配置行
ondemand 进入ondemand执行等级时,执行第4项指定的process
initdefault 系统启动后进入的执行等级,该行不需要指定process
sysinit 不论在哪个执行等级,系统会在执行boot 及bootwait之前执行第4项指定的process
powerwait 当系统的供电不足时执行第4项指定的 process,且一直等它执行完毕
powerokwait 当系统的供电恢复正常时执行第4项指定的process,且一直等它执行完毕
powerfailnow 当系统的供电严重不足时执行第4项指定的process
ctrlaltdel 当用户按下【Ctrl+Alt+Del】时执行的操作
kbrequest 当用户按下特殊的组合键时执行第4项指定的process,此组合键需在keymaps文件定义
process:
所要执行的shell命令。任何合法的shell语法均适用于该字段。