|
摘自:http://blog.mcuol.com/User/luozhen0810/Article/8143_1.htm
首先,主板的BIOS会读取硬盘的主引导记录(MBR),MBR中存放的是一段很小的程序,他的功能是从硬盘读取操作系统核心文件并运行,因为这个小程序太小了,因此通常这个小程序不具备直接引导系统内核的能力,他先去引导另一个稍微大一点的小程序,再由这个大一点的小程序去引导系统内核.在linux系统中这样的小程序有LILO和GRUB.在这个项目中,我决定用LILO来做系统引导程序.在软盘上启动linux系统的过程和在硬盘上启动的过程相似.
Linux系统内核被引导程序装入内核并运行后,linux内核会检测系统中的各种硬件.并做好各种硬件的初始化工作,使他们在系统正式运行后能正常工作.之后内核做的最后一个工作是运行
/sbin下的init程序,init是英文单词initialization(初始化)的简称,init程序的工作是读取/etc/inittab文件中描述的指令,对系统的各种软硬件环境做最初化设定.最后运行mingetty等待用户输入用户名登录系统.所有的工作就这么简单,虽然linux启动的时候有很多内容,看上去十分高深,但是都不过是对这个过程的扩充.明白了这个道理,你可以写一些脚本程序让他在系统启动的特定时间运行完成任务.事实上系统内核并不关心/sbin下的init是不是真的init,只要是放在/sbin下名叫init的可执行程序他都可以执行.Red Hat Enterprise Linux在电脑的启动阶段,一共经历以下两个阶段:
1.启动内核。在这个阶段,内核装入内存并在初始化每个设备驱动器时打印信息。
2.执行程序init.(系统初始化).装入内核并初始化设备后,运行init程序。init程序处理所有程序的启动,包括重要系统精灵程序和其它指定在启动时装入的软件。
开机---BIOS自检---载入启动程序---加载内核---启动init服务---加载/etc/inittab---Run level---rc.sysinit---rc--- mingetty---rc.local
一.BIOS自检
当电脑开机的时候,电脑会进入BIOS,在PC机中引导LINUX是从BIOS中的地址0xFFFF0处开始的.BIOS的第一个步骤是加电自检,即所谓的POST(Power On Self Test),BIOS的第二个步骤是进行本地设备的枚举和初始化,侦测电脑周边配套设备是否工作正常,如cpu的类型,速度,缓存等;主板类型,内存的速度,容量,硬盘的大小,类型和工作模式,风扇速度等,主要是为了检查这些设备在开机的时候是否能通过检测,说明电脑可以正常的工作.BIOS由两部分组成OST代码和运行时的服务.当POST完成之后,它被从内存中清理了出来,但是,BOIS运行时服务依然保留在内存中,目标操作系统可以使用这些服务
二.载入启动程序
BIOS自检完成后,BIOS会根据用户设置的启动顺序来由哪个设备启动电脑的操作系统,设备需是处于活动状态并且可以引导的,(引导设备可以是软盘,CD-ROM,硬盘上的某个分区,网络上的某个设备,甚至是USB闪存),对于linux这个设备一般是硬盘.也就是进入硬盘的MBR区域,(master boot record,位于磁盘上的第一个扇区中,0道0柱面1扇区),这个区域中有512个字节的大小,其中前446个字节中保存的就是启动程序,(446个字节包含可执行代码和错误消息文本,接下来的64个字节是分区表,其中4个分区的记录,每个记录的大小是16个字节,MBR以两个特殊数字的字节0xAA55结束,这个数字用来进行MBR的有效性检查,当MBR被加载到RAM中之后,BIOS就会将控制权交给MBR),然后由这个小程序来加载存储在其他位置的操作系统,也就是启动grub程序.(grub不像lilo一样使用裸扇区,而是可以从ext2或ext3文件系统中加载LINUX内核).
要看MBR的内容,请使用下面的命令
#从/dev/sda上读取前512个字节的内容,并将其写入mbr.bin文件中
[root@localhost ~]# dd if=/dev/sda of=mbr.bin bs=512 count=1
#以十六进制和ASCII码格式打印这个二进制文件的内容
[root@localhost pam.d]# od -xa mbr.bin
grub程序的这个配置文件是保存在:/boot/grub/grub.conf这个文件中,如果修改这个文件后,设置会立刻生效.
使用cat /boot/grub/grub.conf,就会出现这个文件的内容,最前面是注释。
可以将这个文件逻辑上分为两个部分,第一个部分是基本设定,第二个部分是区分开多个操作系统的设定。
第一个部分中的defaule=0,是指第一组操作系统开机。如果有两组操作系统的开机设定,而defaule=1,那么预设使用第二组操作系统开机。
所谓 第一组和第二组程序就是指的是title开始的部分,这里是区分操作系统的部分。如何知道要使用那一个系统呢,可以看到在title开始的部分的下一行有:
root (hd0,0)
hd0,表示第一个硬盘
0:指的是硬盘的第一个分区,
在括号中的那个0和defaule=0是一一对应的。这就可以知道是启动的是那一个操作系统。
timeout=5是指进入GRUB的画面后,会有5秒的时间让使用者选择使用那个操作系统开机。如果在这个时间没有作出选择那么,那么就使用defaule的设定
splashimage=是开机使用的背景图案。
hd0,表示第一个硬盘
0:指的是硬盘的第一个分区,和上面的一样,
/grub/splash.xpm.gz就是开机使用的背景图案的文件名称
hiddenmenu指令是隐藏开机的选单。
title:开机选单的标题名称。
root (hd0,0):0表示下面要介绍的档案位于那个目录中。(hd0,0)同样是指/boot目录
kernel:存放内核的位置,由于(hd0,0)指的是/boot目录,所以这个文件在boot目录中。
ro root=LABEL=/就是设根目录的位置,ro表示read only,所以有这行的设定,才能读取根目录。
rhgb:red hat图形界面启动,取代以前的文本界面。如果要使用文本界面的形式启动,只要将rhgb删除即可。
quite:在开机过程中不要显示错误的信息。如果要显示错误信息,只要删除quite即可。
initrd:将initrd映像文件加载到内存。这个文件里面存放的都是驱动程序。
三.加载内核
正确的启动了启动程序之后,接下来的工作就是载入操作系统的内核.内核主要作用是取得BIOS所检测到的硬件设备的信息,然后将这些硬件设备自己来管理,这样才能够提供给Linux系统使用。接手了硬件设备后,然后就要加载这些设备的驱动程序。以便于控制电脑上的设备如何正确的工作。
加载完硬件的驱动程序后,接下来就加载文件系统了,也就是加载开机所需要的库文件,程序等,所以/etc /bin /sbin /dev /lib这些目录的根目录必须是同一个分区,否则会造成Linux的开机失败。
上面在grub中有“ro root=LABEL=/”这样的信息,是以只读的方式来加载所需要的文件,程序,这是为什么呢?
是因为Linux的内核在启动的过程中,不知道将会发生什么故障,可能不是很稳定,如果以可读可写的方式来加载,那么启动的过过程组中如果出现异常或者是断电,那么就有可能破坏,为了避免这些问题的发生,就采取只读的方式来挂载文件系统。
LINUX内核一般是压缩保存的,因此,它首先要进行自身的解压缩。内核映象前面的一些代码完成解压缩。内核映像并不是一个可执行的内核,而是一个压缩过的内核映像,它通常是一个zlmage(压缩映像,小于512kb)或一个bzlmage(大于512kb),它是提前使用zlib进行压缩过的.在这个内核映像前面是一个例程,它实现少量硬件设置,并对内核映像中包含的内核进行解压,然后将其放入高端内存中,如果有初始RAM磁盘映像,就会将它移动到内存中,并标明以后使用,然后此例程会调用内核,并开始启动内核引导的过程
当bzlmage被调用时,(以i386为例),我们从./arch/i386/boot/head.S的start汇编例程开始执行,这个例程会执行一些基本的硬件设置,并调用./arch/i386/boot/compressed/headS中的startup_32例程,此例程会设置一个基本的环境(堆栈等),并清楚Block Started by Symbol(BSS),然后调用一个叫做decompress_kernel的C函数(在./arch/i386/boot/compressed/misc.c中)来解压内核.当内核被解压到内存中之后,就可以调用它了.这是另外一个startup_32函数,但是这个函数在./arch/i386/kernel/head.S中.在这个新的startup_32函数(也称为清楚程序或进程0)中,会对页表进行初始化,并起用内存分页功能.然后会为任何可选的浮点单元(FPU)检测CPU的类型,并将其存储起来供以后使用,然后调用start_kernel函数(在init/main.c中),它会将您带入与体系结构无关的Linux内核部分.实际上,这就是Linux内核的main函数.通过调用start_kernel,会调用一系列初始化函数来设置中断,执行进一步的内存配置,并加载初始RAM磁盘.最后,要调用kernel_thread(在arch/i386/kernel/process.c中)来启动init函数,这是第一个用户空间进程(user-space process).最后,启动空任务,现在调度器就可以接管控制权了(在调用cpu_idle之后).通过起用中断,抢占式的调用器就可以周期性地接管控制权,从而提供多任务处理能力.在内核引导过程中,初始RAM磁盘(initrd)是由阶段2引导加载程序加载到内存中的,它会被复制到RAM中并挂载到系统上.这个initrd会作为RAM中的临时根文件系统使用,并允许内核在没有挂载任何物理磁盘的情况下完整地实现引导.由于与外围设备进行交互所需要的模块可能是initrd的一部分,因此内核可以非常小,但是仍然需要支持大量可能的硬件配置.在内核引导之后,就可以正式装备根文件系统了(通过pivot_root),此时会将initrd根文件系统卸载掉,并挂载真正的根文件系统,initrd函数让我们可以创建一个小型的linux内核,其中包括作为可加载模块编译的启动程序,这些可加载的模块作为内核提供了访问磁盘和磁盘上的方法,并为其他硬件提供了驱动程序,由于根文件系统是磁盘上的一个文件系统,因此initrd函数会提供一种启动方法来获得对磁盘的访问,并挂载真正的根文件系统.在一个没有硬盘的嵌入式环境中,initrd可以是最终的根文件系统,也可以通过网络文件系统(NFS)来挂载最终的根文件系统.
在GRUB命令中,我们可以使用initrd映像引导一个特定的内核,方法如下:
grub> kernel /bzImage-2.6.14.2
[Linux-bzImage, setup=0x1400, size=0x29672e]
grub>initrd /initrd-2.6.14.2.img
[Linux-initrd @ 0x5f13000, 0xcc199 bytes]
grub> boot
Uncompressing Linux... Ok, booting the kernel.
如果不知道要引导的内核的名称,只需使用/然后按下Tab键,就会显示内核和initrd映像列表
对grub命令行进行加密
a)使用命令/sbin/grub-md5-crypt来产生grub使用的密码
[root@localhost pam.d]# /sbin/grub-md5-crypt
Password:
Retype password:
$1$3YbPF$zFVRY6J8VxNR9Ok4fXRkr1
b)修改/etc/grub.conf加入password --md5 $1$3YbPF$zFVRY6J8VxNR9Ok4fXRkr1 一定要放在title之前
这样重启系统时在grub的启动grub菜单时,想再按e命令进行编辑时,必须先按p键后输入密码才成.
四.启动init服务
加载完成内核之后,Kernel会启动init这个程序,init进程是所有进程的起点,也是Linux内核启动后的第一个动作,所以这个程序的PID是永远是1,也是Red Hat Enterprise Linux中执行的第一个程序,这个程序会根据Run Level来执行一些相关的程序程序。利用init程序可以方便地定制启动其间装入哪些程序。init进程是所有进程的发起者和控制者,init的任务是启动新进程和退出时重新启动其它进程,例如在大多数Linux系统中,启动时最初装入六个虚拟的控制台进程,退出控制台窗口时,进程死亡,然后init启动新的虚拟登录控制台,因而总是提供六个虚拟登陆控控制台进程.
init进程有以下两个作用。
init进程的第一个作用是扮演终结父进程的角色。因为init进程永远不会被终止,所以系统总是可以确信它的存在,并在必要的时候以它为参照。如果某个进程在它衍生出来的全部子进程结束之前被终止,就会出现必须以init为参照的情况。此时那些失去了父进程的子进程就都会以init作为它们的父进程。
init的第二个作用是在进入某个特定的运行级别时运行相应的程序,以此对各种运行级别进行管理。它的这个作用是由/etc/inittab文件定义的。
启动init服务的目的就是为了用来初始化Linux的环境。也就代表了Linux已经顺利的加载了内核,这个时候的系统启动就进入了另外的一个阶段:系统初始化阶段
init程序其实是去读取/etc/inittab配置文件的配置,根据配置来决定作什么工作,可以使用cat /etc/inittab指令,就可以看到这个文件的内容,里面设置了init需要作哪些系统初始化工作,如设置键盘、字体、装载模块,设置网络等。
1.决定要使用那个run level
Linux有个运行级系统,运行级是表示系统当前状态和init应运行哪个进程并保持在这种系统状态中运行的数字。run level可以从0到6分成7种,一般是为了执行不同的程序或环境而设置的
run level可以从0到6分成7种,一般是为了执行不同的程序或环境而设置的
run level 0:是作关机,所以不能设置initdefault中,也就是id:5:initdefaule的设置。否者一开机就会作关机的动作。
run level 1:是Single user mode模式,只允许root账号登录,主要是作一些系统维护的工作。
run level 2:可以使所有的用户登录,但不会启用NFS working,也就是没有网络功能
run level 3:可以使所有用户登录,并拥有完整的功能。包含run level 2没有的功能,但是开机后是用文本模式
run level 4 :使用者自己定义,但是默认情况下和run level 3完全相同,
run level 5:和run level 3几乎一样,唯一的不同是开机后是图形界面,
run level 6:重启。所以run level 6也不会设置在initdefault中,否者开机后立刻重启
一般情况下我们使用最多的是1,3,5这三个run level,那么这三个有什么不同的呢,主要差别在执行程序的数量不同。
可以使用init指令来定义使用那个run level,只要在命名提示符号的后面输入\"init 3\"就进入文本界面,如果输入\"init 6\"那么电脑就会重启,如果是\"init 0\",那就关机
id:5:initdefault:表示当前默认运行级别是run level 5,是图形界面。
2.执行初始操作系统的程序
在init的配置文件中有如下一行:
si::sysinit:/etc/rc.d/rc.sysinit 表示启动时自动执行/etc/rc.d/rc.sysinit脚本(sysinit)
rc.sysinit是由init执行的第一个脚本,它主要完成一些系统初始化的工作。rc.sysinit是每一个运行级别都要首先运行的重要脚本,它主要完成的工作有:激活交换分区、检查磁盘、加载硬件模块以及其他一些需要优先执行的任务。/etc/rc.d/rc.sysinit主要完成各个运行模式中相同的初始化工作,包括:
设置初始的$PATH变量;
配置网络;
为虚拟内存启动交换;
设置系统的主机名;hostname在/etc/sysconfig/network文件中
检查root文件系统,以进行必要的修复;
检查root文件系统的配额;
为root文件系统打开用户和组的配额;
以读/写的方式重新装载root文件系统;
清除被装载的文件系统表/etc/mtab;
把root文件系统输入到mtab;
使系统为装入模块做准备;
查找模块的相关文件;
检查文件系统,以进行必要的修复;
加载所有其他文件系统;
清除/etc/mtab、/etc/fastboot和/etc/nologin;
删除UUCP的lock文件;
删除过时的子系统文件;
删除过时的pid文件;
设置系统时钟;
激活交换分区;
初始化串行端口;
装入模块。
3.执行run level对应目录中的程序
用来决定启用那些服务,也就是执行rc程序
在rc.sysinit执行后,将返回init,继续执行/etc/rc.d/rc程序,对每一个运行级别来说,在/etc/rc.d子目录中都有一个对应的下级目录。这些运行级别的下级子目录的命名方法上rcX.d, 其中X就是代表运行级别的数字
在各个运行级别的子目录中,都建立有到/etc/rc.d/init.d子目录中命令脚本程序的符号链接
如输入ls -l /etc/rc.d这个指令,就可以看到所有的run level所对应的目录,在这些目录当中,都是内置一些要执行的一些程序。也就是要启动那些服务。本例的run level是5,就会执行rc5.d这个目录中的程序。那么就会启动这个目录中的服务.
输入ls -l /etc/rc.d/rc5.d可以查看这个目录中有哪些内容,这个文件夹中的都是一些链接文件,这些名称链接的格式可以分为主要的三个小段:以K或S开头。K=Kill表示停用,S=Start表示启用服务,并且K先执行,然后执行S;中间是两位的数字,代表执行的先后顺序,数字越小,越先执行;是程序名称。系统会按照这个目录中的程序,先关闭某些程序,然后启动某些需要的服务.一般来说,这些脚本不需要编辑或改变,是系统缺省的。
以运行级别5为例,init将执行配置文件inittab中的以下内容:
l5:5:wait:/etc/rc.d/rc 5 当运行级别为5时,以5为参数运行/etc/rc.d/rc脚本,init将等待其返回(wait)
这一行表示以5为参数运行/etc/rc.d/rc,/etc/rc.d/rc是一个shell脚本,它接受5作为参数,去执行/etc/rc.d/rc5.d/目录下的所有的rc启动脚本,/etc/rc.d/rc5.d/目录中的启动脚本实际上都是一些链接文件(用来呼叫/init.d目录中程序,并带有一个启动或停止服务的参数),而不是真正的rc启动脚本,真正的rc启动脚本实际上都在/etc/rc.d/init.d/目录下。而这些rc启动脚本有着类似的用法,它们一般能接受 start、stop、restart、status等参数。
/etc/rc.d/rc5.d/中的rc启动脚本通常是以K或S开头的链接文件,以S开头的启动脚本将以start参数来运行。如果发现相应的脚本也存在K打头的链接,而且已经处于运行态了(以/var/lock/subsys/下的文件作为标志),则将首先以stop为参数停止这些已经启动了的守护进程,然后再重新运行。这样做是为了保证当init改变运行级别时,所有相关的守护进程都将重启。
至于在每个运行级中将运行哪些守护进程,用户可以通过chkconfig来自行设定。常见的守护进程如下。
amd:自动安装NFS守护进程。
apmd:高级电源管理守护进程。
arpwatch:记录日志并构建一个在LAN接口上看到的以太网地址和IP地址对应的数据库。
autofs:自动安装管理进程automount,与NFS相关,依赖于NIS。
crond:Linux系统下计划任务的守护进程。
named:DNS服务器。
netfs:安装NFS、Samba和NetWare网络文件系统。
network:激活已配置网络接口的脚本程序。
nfs:打开NFS服务。
portmap:RPC portmap管理器,它管理基于RPC服务的连接。
sendmail:邮件服务器sendmail。
smb:Samba文件共享/打印服务。
syslog:一个让系统引导时启动syslog和klogd系统日志守候进程的脚本。
xfs:X Window字型服务器,为本地和远程X服务器提供字型集。
Xinetd:支持多种网络服务的核心守护进程,可以管理wuftp、sshd、telnet等 服务。
这些守护进程启动完毕,rc程序也就执行完了,然后又将返回init继续下一步。
4.再设定某个组合键
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
当启动的过程中按下crtl+alt+del键会执行shutdown -t3 -r now这个指令(重启系统)
5.定义UPS不间断电源系统
pf::powerfail:/sbin/shutdown -f -h +2 \"ower Restored;Shutdown Cancelled\"
如果你的服务器有UPS,当电源发生问题或电源恢复的时候,执行这些程序,
当电源发生问题时,执行shutdown -f -h +2
当电源恢复工作时,执行shutdown -c 表示在关机前取消关机的操作,这个时候必须取消关机操作。
由于UPS可以短暂的为linux服务器提供电力服务,但是UPS不会一直提供电力,到UPS电力用完,可能会造成Linux不正常关机,而是UPS会通知电脑,电源发生问题,要求linux正常的关机,避免内存的资料没有保存到硬盘上。以上的功能必须是UPS支持以上的功能的是够才会发生这些动作,如果UPS不支持这些功能,这两条语句没有任何的作用。
6.产生6个虚拟控制台。也就是tty1到tty6
#Run gettys in standard runlevels
1:12345:respawn:/sbin/minggetty tty1
2:2345:respawn:/sbin/minggetty tty2
3:2345:respawn:/sbin/minggetty tty3
4:2345:respawn:/sbin/minggetty tty4
5:2345:respawn:/sbin/minggetty tty5
6:2345:respawn:/sbin/minggetty tty6
使用mingetty指令分别产生tty1到tty6这6个虚拟控制台
在2.3.4.5级别上以ttyX为参数执行/sbin/mingetty程序,打开ttyX终端用于用户登陆,如果进程退出则再次运行mingetty程序(respawn)
7.如果启用的是run level 5,就会初始化X Windows环境
#Run xdm in runlevel 5
x:5:respawn:/usr/bin/X11/xdm -nodaemon
在5级别上运行xdm程序,提供xdm图形方式登陆界面,并在退出时重新执行(respawn),/etc/X11/prefdm -nodemon:就是初始化X Windows环境
五.执行/etc/ec.d/rc.local
(s99local -> ../rc.local) s后面的99表示最后执行的意思
RHEL 4中的运行模式2、3、5执行Run Level目录中相对的程序链接后,都把/etc/rc.d/rc.local做为初始化脚本中的最后一个,所以用户可以自己在这个文件中添加一些需要在其他初始化工作之后、登录之前执行的命令。在维护Linux系统时一般会遇到需要系统管理员对开机或者关机命令脚本进行修改的情况。如果所做的修改只在引导开机的时候起作用,并且改动不大的话,可以考虑简单地编辑一下/etc/rc.d/rc.local脚本。这个命令脚本程序是在引导过程的最后一步被执行的。我们可以将需要开机执行的程序或者指令写入这个文件中.
六.执行/bin/login程序
login程序会提示使用者输入账号及密码,接着编码并确认密码的正确性,如果账号与密码相符,则为使用者初始化环境,并将控制权交给shell,即等待用户登录。
login会接收mingetty传来的用户名作为用户名参数,然后login会对用户名进行分析。如果用户名不是root,且存在/etc/nologin文件,login将输出nologin文件的内容,然后退出。这通常用来在系统维护时防止非root用户登录。只有在/etc/securetty中登记了的终端才允许root用户登录,如果不存在这个文件,则root可以在任何终端上登录。/etc/usertty文件用于对用户作出附加访问限制,如果不存在这个文件,则没有其他限制。
在分析完用户名后,login将搜索/etc/passwd以及/etc/shadow来验证密码以及设置账户的其他信息,比如:主目录是什么、使用何种shell。如果没有指定主目录,则将主目录默认设置为根目录;如果没有指定shell,则将shell类型默认设置为/bin/bash。
login程序成功后,会向对应的终端再输出最近一次登录的信息(在/var/log/lastlog中有记录),并检查用户是否有新邮件(在/usr/spool/mail/的对应用户名目录下),然后开始设置各种环境变量。对于bash来说,系统首先寻找/etc/profile脚本文件并执行它;然后如果用户的主目录中存在.bash_profile文件,就执行它,在这些文件中又可能调用了其他配置文件,所有的配置文件执行后,各种环境变量也设好了,这时会出现大家熟悉的命令行提示符,至此整个启动过程就结束了。 |
|