我们都知道按下电脑电源键后,屏幕上会一闪而过很多信息,然后显示登录界面,然后输入用户名,密码就可以畅享网络世界了。那么这中间到底发生了什么呢,今天就让我们来简单探讨一下CentOS的简易版开机启动流程吧。

    第一阶段:通电自检过程

      我们都知道电脑所有数据指令都是在内存上才能被cpu处理的吧,我们还知道内存在断电后其上面的所有数据都会丢失吧,那么开机的时候内存应该是没有东西的吧,那上面都不能干了,更别说启动一个操作系统了,其实啊,我们内存并不只是我们常见的那个内存卡,很多硬件都会映射一段内存到cpu的寻址空间上,比如说BIOS,显卡等等,而我们知道BIOS是写在主板芯片上的,而且是用闪存做成的ROM上 的,虽然也可以修改里面的数据,但是我们还是习惯称之为只读存储器,那么问题也来了,通电后,cpu怎么知道在内存的哪个地址段是BIOS代码段呢,这是因为cpu在制作的时候的设置的,当通电瞬间,cpu会进入实模式状态,然后把内存寻址控制在大概1MB的样子,然后其内的IP寄存器和CS寄存器会将地址指向内存的一个位置(只需要知道在一个位置,因为只是简介嘛),而这个位置恰恰是BIOS代码段开始的位置,然后显而易见cpu就开始执行这些代码啦,然后就会看到我们熟悉的各种BIOS自检信息啦,当然最重要的是在内存中生成中断向量表(记录了中断向量程序在内存中的位置)和中断向量程序,而我们都设置过BIOS吧,最起码设置里面的boot选项吧,就是将自己想要启动的装有系统的硬盘尽量往前面位置调(因为BIOS只认第一个),这是因为当BIOS检测到这块硬盘里含有操作系统的时候就会给CPU发一个中断信号,然后CPU通过名字找到内存中的中断向量表中的这个中断所指向的中断向量程序的位置,然后就执行这部分的程序,然后这个程序就会将我们的硬盘的第一个扇区(512字节也叫MBR)加载到内存中,我们也知道硬盘的MBR中的前446K装的是引导启动程序代码,中间64K装的是我们硬盘的分区表,最后2个字节是MBR有效标志(如果是55AA就有效,BIOS就是通过这个来分辨硬盘中是否有操作系统的),然后BIOS就去打瞌睡去了,做了甩手掌柜,把一起都交给了引导程序这个店小二了。

    第二阶段:引导程序装载内核过程

      我们都懂没有驱动程序的硬件只能自我娱乐,而硬盘也必须格式成某种格式的文件系统才能在操作系统下存储东东,那么引导程序这个店小二想要加载硬盘上的操作系统就必须有支持这个文件系统格式的驱动才行,遗憾的是区区446K的空间并不能做到,因此在MBR随后的扇区中会有这个驱动程序,然后第二阶段就去寻找他的真爱了,在Linux中通常在/boot/vmlinuz-版本-发型号,然后内核就被解压加载到内存中了(内核也只是个程序而已)。

    第三阶段:内核加载到PID为1的进程init过程

       内核加载到内存中开始运行,但是相同的问题又来了,操作系统上的硬盘必须是一种文件系统才可以存放数据,那么是不是可以把所有的文件系统的驱动程序都写入到内核中呢,当然可以但又不可以,因为那样的话不仅内核会特别的大,而且一个机器上也就仅仅能用到很少很少的一部分而已,所以不可以这样,但是写进去后确实也能达到目的,所以又可以,而Linux虽然是单内核,但是其充分吸取了微内核的高级理念,以为其支持动态加载模块,上面意思呢,就是将很多功能可以写成一个个模块,然后加载到内核中就可以了,当然也可以直接编译进内核,甚至有些模块必须编译进内核。而众多的驱动程序就是被写成了模块,只保留基本功能就行。(请注意,我这里不是在捧windows,虽然它是微内核,但是也因为如此而使得其要想达到内部协调就必须写更多的代码,从而变得很臃肿还容易出问题,所以辣鸡一词用在上面最合适不过了),但是这样的话那就没能解决启动操作系统啊,其实呢,内核会在内存中使用randis技术将一部分内存虚拟化为硬盘使用,通过这个虚拟化一个小根文件系统来,你可以看看你的/boot下是不是有一个initramfs-版本-发型号的文件(版本和发型号和内核一样在CentOS 5中是initrd-版本-发型号,如果看看其下面的文件,会发现里面就是一小文件系统,通过这个来加载文件系统驱动程序,然后再去加载真正的根文件系统,紧接着就运作啊运作,生成0号进程,然后因为自己没什么本事就去生个儿子叫1号进程init,儿子比老爹就厉害多了(虽然还是脑子不好,但起码四肢俱全啊)

    第四阶段:1号进程init干的那些事

        在CentOS 5上:init自己也是刚开过光,学老爹,不过他志向比他爹大多了,因为他要生一窝儿子,直到自己儿子们组成一个完整的操作系统(Linux中通过fork()复制,exec()运行的进程会比自己爸爸功能强大),首先这厮会很“轴”,非要去找/etc/inittab这个文件,这个文件里面主要定义了默认终端,系统初始化,关闭和开启相应终端下的程序,然后获得可以登录的终端。格式为

        id:默认终端级别:action:process

            默认终端级别有:

               0:关机, shutdown
               1:单用户模式(single user),root用户,无须认证;维护模式;
               2、多用户模式(multi user),会启动网络功能,但不会启动NFS;维护模式;
               3、多用户模式(mutli user),完全功能模式;文本界面;
               4、预留级别:目前无特别使用目的,但习惯以同3级别功能使用;
               5、多用户模式(multi user), 完全功能模式,图形界面;
               6、重启,reboot

            action:

               wait:等待切换至此任务所在的级别时执行一次;
               respawn:一旦此任务终止,就自动重新启动之;
               initdefault:设定默认运行级别;此时,process省略;
               sysinit:设定系统初始化方式,此处一般为指定/etc/rc.d/rc.sysinit脚本;

            process:

               /etc/rc.d/rc[0-6],会关闭相应终端级别下的K##开头的程序,开启相应终端级别下的S##开头的程序,如果你ll其下面的文件会发现都是链接到/init.d下的除K##和S##的同名程序。

        那么其顺序就是,先id:默认终端等级:initdefault:,来知道默认终端,然后就是si::sysinit:/etc/rc,d/rc.sysinit,来初始化,再接着是id号:默认终端等级:wait:/etc/rc.d/rc[0-6],实现开启关闭相应终端下的服务脚本,最后是tty[1-6]:默认终端等级:respawn:/usr/sbin/mingget tty[1-6],来获取登录终端。

        其中初始化实现的内容有:

            (1) 设置主机名;
            (2) 设置欢迎信息;
            (3) 激活udev和selinux;
            (4) 挂载/etc/fstab文件中定义的所有文件系统;
            (5) 检测根文件系统,并以读写方式重新挂载根文件系统;
            (6) 设置系统时钟;
            (7) 根据/etc/sysctl.conf文件来设置内核参数;
            (8) 激活lvm及软raid设备;
            (9) 激活swap设备;
            (10) 加载额外设备的驱动程序;
            (11) 清理操作;

        最后执行在/etc/rc.d/rc.local里面的作业,这个文件没有链接到/etc/init.d目录下的任何脚本,他只是为了让不想写脚本来实现开机服务的人懒一下

        那么怎么写可以开机运行或关闭的脚本呢。其实只要看一下/etc/init.d下或者/etc/rc.d/init.d(前面的只是链接到后面)的脚本就知道,在脚本开始部分加上#chconfig:终端(可以是多个):开启优先级:关闭优先级,然后这个脚本就可以被chconfig命令管理,当然你得把这个脚本弄到/etc/init.d或者/etc/rc.d/init.d下,可以链接也可以直接建在这目录下。然后通过chconfig --add 脚本名就会添加到相应终端等级的/etc/rc.d/rc[0-6]目录下自动生成相应的K##开头和S##开头的文件。然后就可以用service 脚本名 {start|restart|status|stop}来运行重启查看停止此服务脚本了

 

        chkconfig命令

            chkconfig --list [脚本名]:查看其在各终端等级的开启关闭状态

            chkconfig --add 脚本名:将指定脚本生成在相应终端下的K##开头和S##开头的的文件了,其实chkconfig 程序名 on/off就是这个机制罢了,但是只是这样的话不会再其他终端生成文件,只会在脚本指定的终端中生成开启或关闭文件。

            chkconfig --del 脚本名:与上面相反。

            chkconfig --level 指定终端(可以多个,默认为2345) 脚本名 on/off。这就是所谓的开机运行和关闭了,其实也就是在相应终端下生成S##文件和K##文件罢了。

            另外如果脚本中终端等级为-表示所有终端等级下都关闭(只生成K##),为其他数字的就代表在与这些终端上对应的/etc/rc.d/rc[0-6]里面生成相应的文件。

            K##的这两个数字表示的是停止优先级,数字越小越优先停止,表示依赖别的程序

            S##的这两个数字表示开启优先级,数字越小越优先启动,表示其被其他程序所依赖

        在CentOS 6上用的是upstart并不是5上面经典的SYS V,但是其还是兼容5,因此其/etc/inittab还是有效,只是这文件只设置默认终端了,因此只有id:指定默认等级:initdefault:

但是其里面说明了初始化脚本在/etc/init/rcS.conf,开启和关闭相应终端等级的脚本配置文件是/etc/init/rc.conf,然后再看这两个文件会发现还是指向了/etc/rc.d/目录下的脚本。所以没什么好说的,只需要知道5上面的配置文件是/etc/inittab,而6的配置文件有/etc/inittab和/etc/init/*.conf,但是他们的脚本都在/etc/init.d(/etc/rc.d/init.d)

        在CentOS 7上用的是systemd,改变非常的大,但是还是能兼容5,6,特别是5,其配置文件在

/etc/systemd/system和/usr/lib/systemd/system下。已经说了虽然改变很大但是并不代表不能像5,6那也使用。因此这方面待续。。。。。