启动流程一览
启动管理程序 (Boot Loader):目前各大 Linux distributions 的主流为 grub,但早期 Linux 默认是使用 LILO ,台湾地区则很多朋友喜欢使用 spfdisk 。
假设以个人计算机架设的 Linux 主机为例,当你按下电源按键后计算机硬件会主动的读取 BIOS 来加载硬件资讯及进行硬件系统的自我测试,之后系统会主动的去读取第一个可启动的装置 (由 BIOS 配置的) ,此时就可以读入启动管理程序了。
启动管理程序可以指定使用哪个核心文件来启动,并实际加载核心到内存当中解压缩与运行,此时核心就能够开始在内存内活动,并侦测所有硬件资讯与加载适当的驱动程序来使整部主机开始运行,等到核心侦测硬件与加载驱动程序完毕后,操作系统就开始在你的 PC 上面跑了。
主机系统开始运行后,此时 Linux 才会呼叫外部程序开始准备软件运行的环境,并且实际的加载所有系统运行所需要的软件程序!最后系统就会开始等待你的登陆与操作!
- 加载 BIOS 的硬件资讯与进行自我测试,并依据配置取得第一个可启动的装置;
- 读取并运行第一个启动装置内 MBR 的 boot Loader (亦即是 grub, spfdisk 等程序);
- 依据 boot loader 的配置加载 Kernel ,Kernel 会开始侦测硬件与加载驱动程序;
- 在硬件驱动成功后,Kernel 会主动呼叫 init 程序,而 init 会取得 run-level 资讯;
- init 运行 /etc/rc.d/rc.sysinit 文件来准备软件运行的作业环境 (如网络、时区等);
- init 运行 run-level 的各个服务之启动 (script 方式);
- init 运行 /etc/rc.d/rc.local 文件;
- init 运行终端机模拟程序 mingetty 来启动 login 程序,最后就等待使用者登陆;
BIOS, boot loader 与 kernel 加载
- BIOS, 启动自我测试与 MBR
在个人计算机架构下,你想要启动整部系统首先就得要让系统去加载 BIOS (Basic Input Output System),并透过 BIOS 程序去加载 CMOS 的资讯,并且藉由 CMOS 内的配置值取得主机的各项硬件配置,例如 CPU 与周边设备的沟通时脉、启动装置的搜寻顺序、硬盘的大小与类型、系统时间、各周边汇流排的是否启动 Plug and Play (PnP, 随插即用装置)啊、各周边设备的 I/O 位址、以及与 CPU 沟通的 IRQ 岔断等等的资讯。
在取得这些资讯后,BIOS 还会进行启动自我测试 (Power-on Self Test, POST) 。然后开始运行硬件侦测的初始化,并配置 PnP 装置,之后再定义出可启动的装置顺序,接下来就会开始进行启动装置的数据读取了 (MBR 相关的任务开始)。
由於我们的系统软件大多放置到硬盘中!所以 BIOS 会指定启动的装置好让我们可以读取磁碟中的操作系统核心文件。但由於不同的操作系统他的文件系统格式不相同,因此我们必须要以一个启动管理程序来处理核心文件加载 (load) 的问题,因此这个启动管理程序就被称为 Boot Loader 了。那这个 Boot Loader 程序安装在哪里呢?就在启动装置的第一个磁区 (sector) 内,也就是我们一直谈到的 MBR (Master Boot Record, 主要启动记录区)。
既然核心文件需要 loader 来读取,那每个操作系统的 loader 都不相同,这样的话 BIOS 又是如何读取 MBR 内的 loader 呢?其实 BIOS 是透过硬件的 INT 13 中断功能来读取 MBR的,也就是说,只要 BIOS 能够侦测的到你的磁碟 (不论该磁碟是 SATA 还是 IDE 介面),那他就有办法透过 INT 13这条通道来读取该磁碟的第一个磁区内的 MBR ! boot loader 也就能够被运行!
Tips: 每颗硬盘的第一个磁区内含有 446 bytes的 MBR 区域,那么如果我的主机上面有两颗硬盘的话,系统会去哪颗硬盘的 MBR 读取 boot loader 呢?这个就得要看 BIOS 的配置了。基本上,我们常常讲的『系统的 MBR』其实指的是 第一个启动装置的 MBR 才对!所以,改天如果你要将启动管理程序安装到某颗硬盘的 MBR 时,要特别注意当时系统的『第一个启动装置』是哪个,否则会安装到错误的硬盘上面的 MBR !重要重要! |
- Boot Loader 的功能
Loader 的最主要功能是要认识操作系统的文件格式并据以加载核心到主内存中去运行。由於不同操作系统的文件格式不一致,因此每种操作系统都有自己的 boot loader!用自己的 loader才有办法加载核心文件!既然你 (1)必须要使用自己的 loader 才能够加载属於自己的操作系统核心,而 (2)系统的 MBR 只有一个,那你怎么会有办法同时在一部主机上面安装 Windows 与 Linux 呢?
其实每个文件系统 (filesystem, 或者是 partition) 都会保留一块启动磁区 (boot sector) 提供操作系统安装 boot loader ,而通常操作系统默认都会安装一份 loader 到他根目录所在的文件系统的 boot sector 上。如果我们在一部主机上面安装 Windows与 Linux 后,该 boot sector, boot loader 与 MBR 的相关性会有点像下图:
![boot loader 安装在 MBR, boot sector 与操作系统的关系 boot loader 安装在 MBR, boot sector 与操作系统的关系](http://vbird.dic.ksu.edu.tw/linux_basic/0510osloader_files/mbr_boot_sector.gif)
图 1.2.1、 boot loader 安装在 MBR, boot sector 与操作系统的关系
如上图所示,每个操作系统默认是会安装一套 boot loader 到他自己的文件系统中 (就是每个 filesystem 左下角的方框),而在 Linux 系统安装时,你可以选择将 boot loader 安装到 MBR 去,也可以选择不安装。如果选择安装到 MBR 的话,那理论上你在 MBR 与 boot sector 都会保有一份 boot loader 程序的。至於 Windows 安装时,他默认会主动的将 MBR 与 boot sector 都装上一份 boot loader!所以你会发现安装多重操作系统时,你的 MBR 常常会被不同的操作系统的 boot loader 所覆盖!
虽然各个操作系统都可以安装一份 boot loader 到他们的 boot sector 中,这样操作系统可以透过自己的 boot loader 来加载核心了。问题是系统的 MBR 只有一个!你要怎么运行 boot sector 里面的 loader?boot loader主要的功能如下:
- 提供菜单:使用者可以选择不同的启动项目,这也是多重启动的重要功能!
- 加载核心文件:直接指向可启动的程序区段来开始操作系统;
- 转交其他 loader:将启动管理功能转交给其他 loader 负责。
由於具有菜单功能,因此我们可以选择不同的核心来启动。而由於具有控制权转交的功能,因此我们可以加载其他 boot sector内的 loader!不过 Windows 的 loader 默认不具有控制权转交的功能,因此你不能使用 Windows 的 loader来加载 Linux 的 loader!这也是为啥第三章谈到 MBR 与多重启动时,会特别强调先装 Windows 再装 Linux 的缘故。
![启动管理程序的菜单功能与控制权转交功能示意图 启动管理程序的菜单功能与控制权转交功能示意图](http://vbird.dic.ksu.edu.tw/linux_basic/0510osloader_files/loader_menu.gif)
图 1.2.2、 启动管理程序的菜单功能与控制权转交功能示意图
如上图所示,我的 MBR 使用 Linux 的 grub 这个启动管理程序,并且里面假设已经有了三个菜单,第一个菜单可以直接指向 Linux 的核心文件并且直接加载核心来启动;第二个菜单可以将启动管理程序控制权交给 Windows来管理,此时 Windows 的 loader 会接管启动流程,这个时候他就能够启动 windows 了。第三个菜单则是使用 Linux 在 boot sector 内的启动管理程序,此时就会跳出另一个 grub 的菜单
而最终 boot loader 的功能就是『加载 kernel 文件』!
- 加载核心侦测硬件与 initrd 的功能
当我们藉由 boot loader 的管理而开始读取核心文件后,接下来, Linux 就会将核心解压缩到主内存当中,并且利用核心的功能,开始测试与驱动各个周边装置,包括储存装置、CPU、网络卡、声卡等等。此时 Linux 核心会以自己的功能重新侦测一次硬件,而不一定会使用 BIOS 侦测到的硬件资讯!也就是说,核心此时才开始接管 BIOS 后的工作了。那么核心文件在哪里?一般来说,他会被放置到 /boot 里面,并且取名为 /boot/vmlinuz 才对!
[root@www ~]# ls --format=single-column -F /boot config-2.6.18-92.el5 <==此版本核心被编译时选择的功能与模块配置档 grub/ <==就是启动管理程序 grub 相关数据目录 initrd-2.6.18-92.el5.img <==虚拟文件系统档! System.map-2.6.18-92.el5 <==核心功能放置到内存位址的对应表 vmlinuz-2.6.18-92.el5 <==就是核心文件啦!最重要者! |
此版本的 Linux 核心为 2.6.18-92.el5!为了硬件开发商与其他核心功能开发者的便利,因此 Linux 核心是可以透过动态加载核心模块的,这些核心模块就放置在 /lib/modules/ 目录内。由於模块放置到磁碟根目录内 (要记得 /lib 不可以与 / 分别放在不同的 partition !),因此在启动的过程中核心必须要挂载根目录,这样才能够读取核心模块提供加载驱动程序的功能。而且为了担心影响到磁碟内的文件系统,因此启动过程中根目录是以唯读的方式来挂载的。
一般来说,非必要的功能且可以编译成为模块的核心功能,目前的 Linux distributions 都会将他编译成为模块。因此 U盘, SATA, SCSI... 等磁碟装置的驱动程序通常都是以模块的方式来存在的。现在来思考一种情况,假设你的 linux 是安装在 SATA 磁碟上面的,你可以透过 BIOS 的 INT 13 取得 boot loader 与 kernel 文件来启动,然后 kernel 会开始接管系统并且侦测硬件及尝试挂载根目录来取得额外的驱动程序。
问题是,核心根本不认识 SATA 磁碟,所以需要加载 SATA 磁碟的驱动程序,否则根本就无法挂载根目录。但是 SATA 的驱动程序在 /lib/modules 内,你根本无法挂载根目录又怎么读取到 /lib/modules/ 内的驱动程序?在这个情况之下,你的 Linux 是无法顺利启动的!那怎办?没关系,我们可以透过虚拟文件系统来处理这个问题。
虚拟文件系统 (Initial RAM Disk) 一般使用的档名为 /boot/initrd,这个文件的特色是,他也能够透过 boot loader 来加载到内存中,然后这个文件会被解压缩并且在内存当中模拟成一个根目录,且此模拟在内存当中的文件系统能够提供一支可运行的程序,透过该程序来加载启动过程中所最需要的核心模块,通常这些模块就是 U盘, RAID, LVM, SCSI 等文件系统与磁碟介面的驱动程序!等加载完成后,会帮助核心重新呼叫 /sbin/init 来开始后续的正常启动流程。
![BIOS 与 boot loader 及核心加载流程示意图 BIOS 与 boot loader 及核心加载流程示意图](http://vbird.dic.ksu.edu.tw/linux_basic/0510osloader_files/0510osloader-flow.jpg)
图 1.2.3、 BIOS 与 boot loader 及核心加载流程示意图
如上图所示,boot loader 可以加载 kernel 与 initrd ,然后在内存中让 initrd 解压缩成为根目录,kernel 就能够藉此加载适当的驱动程序,最终释放虚拟文件系统,并挂载实际的根目录文件系统,就能够开始后续的正常启动流程。
# 1. 先将 /boot/initrd 复制到 /tmp/initrd 目录中,等待解压缩: [root@www ~]# mkdir /tmp/initrd [root@www ~]# cp /boot/initrd-2.6.18-92.el5.img /tmp/initrd/ [root@www ~]# cd /tmp/initrd [root@www initrd]# file initrd-2.6.18-92.el5.img initrd-2.6.18-92.el5.img: gzip compressed data, ... # 原来是 gzip 的压缩档!因为是 gzip ,所以扩展名给他改成 .gz! # 2. 将上述的文件解压缩: [root@www initrd]# mv initrd-2.6.18-92.el5.img initrd-2.6.18-92.el5.gz [root@www initrd]# gzip -d initrd-2.6.18-92.el5.gz [root@www initrd]# file initrd-2.6.18-92.el5 initrd-2.6.18-92.el5: ASCII cpio archive (SVR4 with no CRC) # 搞了老半天,原来还是 cpio 的命令压缩成的文件!解压缩看看! # 3. 用 cpio 解压缩 [root@www initrd]# cpio -ivcdu < initrd-2.6.18-92.el5 [root@www initrd]# ll drwx------ 2 root root 4096 Apr 10 02:05 bin drwx------ 3 root root 4096 Apr 10 02:05 dev drwx------ 2 root root 4096 Apr 10 02:05 etc -rwx------ 1 root root 1888 Apr 10 02:05 init -rw------- 1 root root 5408768 Apr 10 02:00 initrd-2.6.18-92.el5 drwx------ 3 root root 4096 Apr 10 02:05 lib drwx------ 2 root root 4096 Apr 10 02:05 proc lrwxrwxrwx 1 root root 3 Apr 10 02:05 sbin -> bin drwx------ 2 root root 4096 Apr 10 02:05 sys drwx------ 2 root root 4096 Apr 10 02:05 sysroot # 是否很像根目录!尤其也是有 init 这个运行档!务必看一下权限! # 4. 观察 init 文件内较重要的运行项目 [root@www initrd]# cat init #!/bin/nash <==使用类似 bash 的 shell 来运行 mount -t proc /proc /proc <==挂载内存的虚拟文件系统 ....(中间省略).... echo Creating initial device nodes mknod /dev/null c 1 3 <==创建系统所需要的各项装置! ....(中间省略).... echo "Loading ehci-hcd.ko module" insmod /lib/ehci-hcd.ko <==加载各项核心模块,就是驱动程序! ....(中间省略).... echo Creating root device. mkrootdev -t ext3 -o defaults,ro hdc2 <==尝试挂载根目录啦! ....(底下省略).... |
例题:
是否没有 initrd 就无法顺利启动?
答:
不见得的!需要 initrd 最重要的原因是,当启动时无法挂载根目录的情况下,此时就一定需要 initrd ,例如你的根目录在特殊的磁碟介面 (U盘, SATA, SCSI) ,或者是你的文件系统较为特殊 (LVM, RAID) 等等,才会需要 initrd。
如果你的 Linux 是安装在 IDE 介面的磁碟上,并且使用默认的 ext2/ext3 文件系统,那么不需要 initrd 也能够顺利的启动进入 Linux 的! |
在核心完整的加载后,您的主机应该就开始正确的运行了,接下来,就是要开始运行系统的第一支程序: /sbin/init。
第一支程序 init 及配置档/etc/inittab 与 runlevel
在核心加载完毕、进行完硬件侦测与驱动程序加载后,此时你的主机硬件应该已经准备就绪了 (ready) ,此时核心会主动的呼叫第一支程序,那就是 /sbin/init。 init 的 PID 号码是一号。/sbin/init 最主要的功能就是准备软件运行的环境,包括系统的主机名称、网络配置、语系处理、文件系统格式及其他服务的启动等。而所有的动作都会透过 init 的配置档,亦即是 /etc/inittab 来规划,而 inittab 内还有一个很重要的配置项目,那就是默认的 runlevel (启动运行等级)!
- Run level:运行等级有哪些?
Linux 就是藉由配置 run level 来规定系统使用不同的服务来启动,让 Linux 的使用环境不同。基本上,依据有无网络与有无 X Window而将 run level 分为 7 个等级,分别是:
- 0 - halt (系统直接关机)
- 1 - single user mode (单人维护模式,用在系统出问题时的维护)
- 2 - Multi-user, without NFS (类似底下的 runlevel 3,但无 NFS 服务)
- 3 - Full multi-user mode (完整含有网络功能的纯文字模式)
- 4 - unused (系统保留功能)
- 5 - X11 (与 runlevel 3 类似,但加载使用 X Window)
- 6 - reboot (重新启动)
由於 run level 0, 4, 6 不是关机、重新启动就是系统保留的,所以:『 您当然不能将默认的 run level 配置为这三个值 』,否则系统就会不断的自动关机或自动重新启动 如何取得系统的 run level 的?是 /etc/inittab 配置的!
- /etc/inittab 的内容与语法
[root@www ~]# vim /etc/inittab id:5:initdefault: <==默认的 runlevel 配置, 此 runlevel 为 5 si::sysinit:/etc/rc.d/rc.sysinit <==准备系统软件运行的环境的脚本运行档 # 7 个不同 run level 的,需要启动的服务的 scripts 放置路径: l0:0:wait:/etc/rc.d/rc 0 <==runlevel 0 在 /etc/rc.d/rc0.d/ l1:1:wait:/etc/rc.d/rc 1 <==runlevel 1 在 /etc/rc.d/rc1.d/ l2:2:wait:/etc/rc.d/rc 2 <==runlevel 2 在 /etc/rc.d/rc2.d/ l3:3:wait:/etc/rc.d/rc 3 <==runlevel 3 在 /etc/rc.d/rc3.d/ l4:4:wait:/etc/rc.d/rc 4 <==runlevel 4 在 /etc/rc.d/rc4.d/ l5:5:wait:/etc/rc.d/rc 5 <==runlevel 5 在 /etc/rc.d/rc5.d/ l6:6:wait:/etc/rc.d/rc 6 <==runlevel 6 在 /etc/rc.d/rc6.d/ # 是否允许按下 [ctrl]+[alt]+[del] 就重新启动的配置项目: ca::ctrlaltdel:/sbin/shutdown -t3 -r now # 底下两个配置则是关於不断电系统的 (UPS),一个是没电力时的关机,一个是复电的处理 pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down" pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled" 1:2345:respawn:/sbin/mingetty tty1 <==其实 tty1~tty6 是由底下这六行决定的。 2:2345:respawn:/sbin/mingetty tty2 3:2345:respawn:/sbin/mingetty tty3 4:2345:respawn:/sbin/mingetty tty4 5:2345:respawn:/sbin/mingetty tty5 6:2345:respawn:/sbin/mingetty tty6 x:5:respawn:/etc/X11/prefdm -nodaemon <==X window 则是这行决定的! |
首先,这个文件的语法是利用冒号 (:) 将配置分隔成为四个栏位,每个栏位的意义与说明如下:
[配置项目]:[run level]:[init 的动作行为]:[命令项目] |
- 配置项目:最多四个字节,代表 init 的主要工作项目,只是一个简单的代表说明。
- run level:该项目在哪些 run level 底下进行的意思。如果是 35 则代表 runlevel 3 与 5 都会运行。
- init 的动作项目:主要可以进行的动作项目意义有:
inittab 配置值 意义说明 initdefault 代表默认的 run level 配置值 sysinit 代表系统初始化的动作项目 ctrlaltdel 代表 [ctrl]+[alt]+[del] 三个按键是否可以重新启动的配置 wait 代表后面栏位配置的命令项目必须要运行完毕才能继续底下其他的动作 respawn 代表后面栏位的命令可以无限制的再生 (重新启动)。举例来说, tty1 的 mingetty 产生的可登陆画面,在你注销而结束后,系统会再开一个新的可登陆画面等待下一个登陆。
- 命令项目:亦即应该可以进行的命令,通常是一些 script 。
- init 的处理流程
事实上 /etc/inittab 的配置也有点类似 shell script,因为该文件内容的配置也是一行一行的从上往下处理的,因此我们可以知道 CentOS 的 init 依据 inittab 配置的处理流程会是:
- 先取得 runlevel 亦即默认运行等级的相关等级 (以鸟哥的测试机为例,为 5 号);
- 使用 /etc/rc.d/rc.sysinit 进行系统初始化
- 由於 runlevel 是 5 ,因此只进行『l5:5:wait:/etc/rc.d/rc 5』,其他行则略过
- 配置好 [ctrl]+[alt]+[del] 这组的组合键功能
- 配置不断电系统的 pf, pr 两种机制;
- 启动 mingetty 的六个终端机 (tty1 ~ tty6)
- 最终以 /etc/X11/perfdm -nodaemon 启动图形介面!
- 如果不想让使用者利用 [crtl]+[alt]+[del] 来重新启动系统,可以将『ca::ctrlaltdel:/sbin/shutdown -t3 -r now 』加上注解 (#) 来取消该配置
- 规定启动的默认 run level 是纯文字的 3 号或者是具有图形介面的 5 号 ,可经由『 id:5:initdefault: 』那个数字来决定!以鸟哥自己这个文件为例,我是使用默认的图形介面。如果你想要关闭图形介面的话,将该行 5 改成 3 即可。
- 如果不想要启动六个终端机 (tty1~tty6),那么可以将『6:2345:respawn:/sbin/mingetty tty6』关闭数个。但务必至少启动一个!
一般来说,我们默认都是 3 或者是 5 来作为默认的 run level 的。但有时后可能需要进入 run level 1,也就是单人维护模式的环境当中。这个 run level 1 有点像是 Windows 系统当中的『安全模式』,专门用来处理当系统有问题时的操作环境。此外,当系统发现有问题时,举例来说,不正常关机造成filesystem 的不一致现象时,系统会主动的进入单人维护模式!
i nit 处理系统初始化流程 (/etc/rc.d/rc.sysinit)/etc/inittab 里头有这一句『 si::sysinit:/etc/rc.d/rc.sysinit 』,这表示:『我开始加载各项系统服务之前,得先做好整个系统环境,我主要利用/etc/rc.d/rc.sysinit 这个 shell script 来配置好我的系统环境的。』。
这个文件的档名在各不同的 distributions 当中都不相同,例如 SuSE server 9 就使用 /etc/init.d/boot 与 /etc/init.d/rc 来进行的。所以,你最好还是自行到 /etc/inittab 去察看一下系统的工作! |
如果你使用 vim 去查阅过 /etc/rc.d/rc.sysinit 的话,那么可以发现他主要的工作大抵有这几项:
- 取得网络环境与主机类型:
读取网络配置档 /etc/sysconfig/network ,取得主机名称与默认通讯闸 (gateway) 等网络环境。 - 测试与挂载内存装置 /proc 及 U盘 装置 /sys:
除挂载内存装置 /proc 之外,还会主动侦测系统上是否具有 usb 的装置,若有则会主动加载 usb 的驱动程序,并且尝试挂载 usb 的文件系统。 - 决定是否启动 SELinux :
- 启动系统的乱数产生器
乱数产生器可以帮助系统进行一些口令加密演算的功能,在此需要启动两次乱数产生器。 - 配置终端机 (console) 字形:
- 配置显示於启动过程中的欢迎画面 (text banner);
- 配置系统时间 (clock) 与时区配置:需读入 /etc/sysconfig/clock 配置值
- 周边设备的侦测与 Plug and Play (PnP) 参数的测试:
根据核心在启动时侦测的结果 (/proc/sys/kernel/modprobe ) 开始进行 ide / scsi /网络 / 音效 等周边设备的侦测,以及利用以加载的核心模块进行 PnP 装置的参数测试。 - 使用者自订模块的加载
使用者可以在 /etc/sysconfig/modules/*.modules 加入自订的模块,则此时会被加载到系统当中 - 加载核心的相关配置:
系统会主动去读取 /etc/sysctl.conf 这个文件的配置值,使核心功能成为我们想要的样子。 - 配置主机名称与初始化电源管理模块 (ACPI)
- 初始化软件磁盘阵列:主要是透过 /etc/mdadm.conf 来配置好的。
- 初始化 LVM 的文件系统功能
- 以 fsck 检验磁碟文件系统:会进行 filesystem check
- 进行磁碟配额 quota 的转换 (非必要):
- 重新以可读写模式挂载系统磁碟:
- 启动 quota 功能:所以我们不需要自订 quotaon 的动作
- 启动系统虚拟乱数产生器 (pseudo-random):
- 清除启动过程当中的缓存文件:
- 将启动相关资讯加载 /var/log/dmesg 文件中。
在 /etc/rc.d/rc.sysinit 将基本的系统配置数据都写好了,也将系统的数据配置完整!而如果你想要知道到底启动的过程中发生了什么事情?那么就运行『 dmesg 』。另外,基本上,在这个文件当中所进行的很多工作的默认配置档,其实都在 /etc/sysconfig/ 当中!所以,请记得将 /etc/sysconfig/ 内的文件好好的瞧一瞧
在这个过程当中,比较值得注意的是自订模块的加载!在 CentOS 当中,如果我们想要加载核心模块的话,可以将整个模块写入到 /etc/sysconfig/modules/*.modules 当中,在该目录下,只要记得档名最后是以 .modules 结尾即可。这个过程是非必要的,因为我们目前的默认模块实在已经很够用了,除非是您的主机硬件实在太新了,非要自己加载新的模块不可,否则,在经过 /etc/rc.d/rc.sysinit 的处理后,你的主机系统应该是已经跑得很顺畅了!就等著你将系统相关的服务与网络服务启动!
启动系统服务与相关启动配置档 (/etc/rc.d/rc N & /etc/sysconfig)
加载核心让整个系统准备接受命令来工作,再经过 /etc/rc.d/rc.sysinit的系统模块与相关硬件资讯的初始化后,你的 CentOS 系统应该已经顺利工作了。只是,我们还得要启动系统所需要的各项『服务』!这样主机才能提供我们相关的网络或者是主机功能!依据我们在 /etc/inittab 里面提到的 run level 配置值,就可以来决定启动的服务项目了。举例来说,使用 run level 3 就不需要启动 X Window 的相关服务
那么各个不同的 run level 服务启动的各个 shell script 放在哪?还记得 /etc/inittab 里面提到的:
l0:0:wait:/etc/rc.d/rc 0 l1:1:wait:/etc/rc.d/rc 1 l2:2:wait:/etc/rc.d/rc 2 l3:3:wait:/etc/rc.d/rc 3 l4:4:wait:/etc/rc.d/rc 4 l5:5:wait:/etc/rc.d/rc 5 <==本例中,以此项目来解释 l6:6:wait:/etc/rc.d/rc 6 |
上面提到的就是各个 run level 要运行的各项脚本放置处!主要是透过 /etc/rc.d/rc 这个命令来处理相关任务!由於鸟哥使用默认的 runlevel 5 ,因此我们主要针对上述特殊字体那行来解释好了: /etc/rc.d/rc 5 的意义是这样的(建议您自行使用 vim 去观察一下 /etc/rc.d/rc 这个文件):
- 透过外部第一号参数 ($1) 来取得想要运行的脚本目录。亦即由 /etc/rc.d/rc 5 可以取得 /etc/rc5.d/ 这个目录来准备处理相关的脚本程序;
- 找到 /etc/rc5.d/K??* 开头的文件,并进行『 /etc/rc5.d/K??* stop 』的动作;
- 找到 /etc/rc5.d/S??* 开头的文件,并进行『 /etc/rc5.d/S??* start 』的动作;
透过上面的说明我们可以知道所有的项目都与 /etc/rc5.d/ 有关,那么我们就来瞧瞧这个目录下有些什么玩意儿!
[root@www ~]# ll /etc/rc5.d/ lrwxrwxrwx 1 root root 16 Sep 4 2008 K02dhcdbd -> ../init.d/dhcdbd ....(中间省略).... lrwxrwxrwx 1 root root 14 Sep 4 2008 K91capi -> ../init.d/capi lrwxrwxrwx 1 root root 23 Sep 4 2008 S00microcode_ctl -> ../init.d/microcode_ctl lrwxrwxrwx 1 root root 22 Sep 4 2008 S02lvm2-monitor -> ../init.d/lvm2-monitor ....(中间省略).... lrwxrwxrwx 1 root root 17 Sep 4 2008 S10network -> ../init.d/network ....(中间省略).... lrwxrwxrwx 1 root root 11 Sep 4 2008 S99local -> ../rc.local lrwxrwxrwx 1 root root 16 Sep 4 2008 S99smartd -> ../init.d/smartd ....(底下省略).... |
主要具有几个特点:
- 档名全部以 Sxx 或 Kxx ,其中 xx 为数字,且这些数字在文件之间是有相关性的!
- 全部是连结档,连结到 stand alone 服务启动的目录 /etc/init.d/ 去
服务的启动主要是以『/etc/init.d/服务档名 {start,stop}』来启动与关闭的,那么透过刚刚 /etc/rc.d/rc 程序的解说,我们可以清楚的了解到了 /etc/rc5.d/[SK]xx 其实就是跑到 /etc/init.d/ 去找到相对应的服务脚本,然后分别进行 start (Sxx) 或 stop (Kxx) 的动作而已!举例来说,以上述的表格内的 K91capi 及 S10network 为例好了,透过 /etc/rc.d/rc 5 的运行,这两个文件会这样进行:
- /etc/rc5.d/K91capi stop --> /etc/init.d/capi stop
- /etc/rc5.d/S10network start --> /etc/init.d/network start
所以说,你有想要启动该 runlevel 时就运行的服务,那么利用 Sxx 并指向 /etc/init.d/ 的特定服务启动脚本后,该服务就能够在启动时启动!单!问题是,你需要自行处理这个 K, S 开头的连结档吗?并不需要的, chkconfig 就是在负责处理这个连结档!
那么为什么 K 与 S 后面要有数字呢?因为各不同的服务其实还是互有关系的。举例来说,如果要启动 WWW 服务,总是得要有网络?所以 /etc/init.d/network 就会比较先被启动!在 S 或者是 K 后面接的数字是运行的顺序
使用者自订启动启动程序 (/etc/rc.d/rc.local)
在完成默认 runlevel 指定的各项服务的启动后,如果我还有其他的动作想要完成时,举例来说,我还想要寄一封 mail 给某个系统管理帐号,通知他,系统刚刚重新启动完毕,那么是否应该要制作一个 shell script 放置在 /etc/init.d/ 里面,然后再以连结方式连结到/etc/rc5.d/ 里面呢?不需要! /etc/rc.d/rc.local这个文件就可以运行您自己想要运行的系统命令了。
也就是说,我有任何想要在启动时就进行的工作时,直接将他写入 /etc/rc.d/rc.local ,那么该工作就会在启动的时候自动被加载!而不必等我们登陆系统去启动!一般来说,鸟哥就很喜欢把自己制作的 shell script 完整档名写入/etc/rc.d/rc.local ,如此一来,启动就会将我的 shell script 运行过!
根据 /etc/inittab 之配置,加载终端机或 X-Window 介面
在完成了系统所有服务的启动后,接下来 Linux 就会启动终端机或者是 X Window 来等待使用者登陆!实际参考的项目是 /etc/inittab 内的这一段:
1:2345:respawn:/sbin/mingetty tty1 2:2345:respawn:/sbin/mingetty tty2 3:2345:respawn:/sbin/mingetty tty3 4:2345:respawn:/sbin/mingetty tty4 5:2345:respawn:/sbin/mingetty tty5 6:2345:respawn:/sbin/mingetty tty6 x:5:respawn:/etc/X11/prefdm -nodaemon |
这一段代表,在 run level 2, 3, 4, 5 时,都会运行 /sbin/mingetty ,而且运行六个,这也是为何我们 Linux 会提供『六个纯文字终端机』的配置所在!因为 mingetty 就是在启动终端机的命令。
要注意的是那个 respawn 的 init 动作项目,他代表『当后面的命令被终止 (terminal) 时,init 会主动的重新启动该项目。』这也是为何我们登陆 tty1 终端机介面后,以 exit 离开后,系统还是会重新显示等待使用者输入的画面的原因!
如果改天您不想要有六个终端机时,可以取消某些终端机介面吗?当然可以!就将上面表格当中的某些项目注解掉即可!例如不想要 tty5 与 tty6 ,就将那两行注解,则下次重新启动后,您的 Linux 就只剩下『 F1 ~ F4 』有效而已
除了这六个终端机之外, init 还会运行 /etc/X11/prefdm -nodaemon那个命令!
启动过程会用到的主要配置档
我们在 /sbin/init 的运行过程中有谈到许多运行脚本,包括 /etc/rc.d/rc.sysinit 以及 /etc/rc.d/rc 等等,其实这些脚本都会使用到相当多的系统配置档,这些启动过程会用到的配置档则大多放置在 /etc/sysconfig/ 目录下。同时,由於核心还是需要加载一些驱动程序 (核心模块),此时系统自订的装置与模块对应档 (/etc/modprobe.conf) 就显的挺重要了!
- 关於模块: /etc/modprobe.conf
/etc/rc.d/rc.sysinit 当中谈到的加载使用者自订模块的地方吗?就是在 /etc/sysconfig/modules/ 目录下!虽然核心提供的默认模块已经很足够我们使用了,但是,某些条件下我们还是得对模块进行一些参数的规划,此时就得要使用到 /etc/modprobe.conf!举例来说,鸟哥的 CentOS 主机的 modprobe.conf 有点像这样:
[root@www ~]# cat /etc/modprobe.conf alias eth0 8139too <==让 eth0 使用 8139too 的模块 alias scsi_hostadapter pata_sis alias snd-card-0 snd-trident options snd-card-0 index=0 <==额外指定 snd-card-0 的参数功能 options snd-trident index=0 |
这个文件大多在指定系统内的硬件所使用的模块!这个文件通常系统是可以自行产生的,所以你不必手动去订正他!不过,如果系统捉到错误的驱动程序,或者是你想要使用升级的驱动程序来对应相关的硬件配备时,你就得要自行手动的处理一下这个文件了。
以上表的第一行为例,鸟哥使用螃蟹卡 (Realtek 的芯片组) 来作为我的网络卡,那螃蟹卡使用的模块就是 8139too!当我要启动网络卡时,系统会跑到这个文件来查阅一下,然后加载 8139too 驱动程序来驱动网络卡罗!
- /etc/sysconfig/*
- authconfig:
这个文件主要在规范使用者的身份认证的机制,包括是否使用本机的 /etc/passwd, /etc/shadow 等,以及 /etc/shadow 口令记录使用何种加密演算法,还有是否使用外部口令服务器提供的帐号验证 (NIS, LDAP) 等。系统默认使用 MD5 加密演算法,并且不使用外部的身份验证机制;
- clock:
此文件在配置 Linux 主机的时区,可以使用格林威治时间(GMT),也可以使用台湾的本地时间 (local)。基本上,在 clock 文件内的配置项目『 ZONE 』所参考的时区位於 /usr/share/zoneinfo 目录下的相对路径中。而且要修改时区的话,还得将 /usr/share/zoneinfo/Asia/Taipei 这个文件复制成为 /etc/localtime 才行!
- i18n:
i18n 在配置一些语系的使用方面,例如最麻烦的文字介面下的日期显示问题!如果你是以中文安装的,那么默认语系会被选择 zh_TW.UTF8 ,所以在纯文字介面之下,你的文件日期显示可能就会呈现乱码!这个时候就需要更改一下这里!更动这个 i18n 的文件,将里面的 LC_TIME 改成 en 即可!
- keyboard & mouse:
keyboard 与 mouse 就是在配置键盘与鼠标的形式;
- network:
network 可以配置是否要启动网络,以及配置主机名称还有通讯闸 (GATEWAY) 这两个重要资讯!
- network-scripts/:
Run level 的切换
事实上,与 run level 有关的启动其实是在 /etc/rc.d/rc.sysinit 运行完毕之后。也就是说,其实 run level 的不同仅是 /etc/rc[0-6].d 里面启动的服务不同而已。不过,依据启动是否自动进入不同 run level 的配置,我们可以说:
- 要每次启动都运行某个默认的 run level ,则需要修改 /etc/inittab 内的配置项目,亦即是『 id:5:initdefault: 』里头的数字;
- 如果仅只是暂时变更系统的 run level 时,则使用 init [0-6] 来进行 run level 的变更。但下次重新启动时,依旧会是以 /etc/inittab 的配置为准。
假设原本我们是以 run level 5 登陆系统的,但是因为某些因素,想要切换成为 run level 3 时,该怎么办呢?运行『 init 3 』即可切换。但是 init 3 这个动作到底做了什么呢?我们不是说了吗?事实上,不同的 run level 只是加载的服务不同罢了,亦即是 /etc/rc5.d/ 还有 /etc/rc3.d 内的 Sxxname 与 Kxxname 有差异而已。所以说,当运行 init 3 时,系统会:
- 先比对 /etc/rc3.d/ 及 /etc/rc5.d 内的 K 与 S 开头的文件;
- 在新的 runlevel 亦即是 /etc/rc3.d/ 内有多的 K 开头文件,则予以关闭;
- 在新的 runlevel 亦即是 /etc/rc3.d/ 内有多的 S 开头文件,则予以启动;
也就是说,两个 run level 都存在的服务就不会被关闭!如此一来,就很容易切换 run level 了,而且还不需要重新启动!真方便。那我怎么知道目前的 run level 是多少?直接在 bash 当中输入 runlevel 即可啊!
[root@www ~]# runlevel N 5 # 左边代表前一个 runlevel ,右边代表目前的 runlevel。 # 由於之前并没有切换过 runlevel ,因此前一个 runlevel 不存在 (N) |
# 将目前的 runlevel 切换成为 3 (注意, tty7 的数据会消失!) [root@www ~]# init 3 NIT: Sending processes the TERM signal Applying Intel CPU microcode update: [ OK ] Starting background readahead: [ OK ] Starting irqbalance: [ OK ] Starting httpd: [ OK ] Starting anacron: [ OK ] # 这代表,新的 runlevel 亦即是 runlevel3 比前一个 runlevel 多出了上述 5 个服务 [root@www ~]# runlevel 5 3 #前一个是 runlevel 5 ,目前的是 runlevel 3! |
那么你能不能利用 init 来进行关机与重新启动呢?可以的啦!利用『 init 0 』就能够关机,而『 init 6 』就能够重新启动!为什么?往前翻一下 runlevel 的定义即可了解吧!