资源描述
Linux 启动过程
1、 概述
1.1启动的步骤
1.1.1 启动第一步--加载BIOS
当打开计算机电源,计算机会首先加载BIOS信息,计算机必须在最开始就找到它。BIOS信息所以如此的重要,是因为BIOS中包含了CPU的相关信息、设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP特性等等。
1.1.2 启动第二步--读取MBR
众所周知,硬盘上第0磁道第一个扇区被称为MBR,也就是Master Boot Record,即主引导记录,它的大小是512字节,里面存放了预启动信息、分区表信息。
系统找到BIOS所指定的硬盘的MBR后,就会将其复制到0×7c00地址所在的物理内存中。其实被复制到物理内存的内容就是Boot Loader,而具体到软件,那就是lilo或者grub了。
1.1.3 启动第三步--Boot Loader
Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核做好一切准备。
Boot Loader有若干种,其中Grub、Lilo和spfdisk是常见的Loader。系统读取bootloader配置信息,并依照此配置信息来启动不同的操作系统。
1.1.4 启动第四步--加载内核
根据grub设定的内核映像所在路径,系统读取内存映像,并进行解压缩操作。此时,屏幕一般会输出“Uncompressing Linux”的提示。当解压缩内核完成后,屏幕输出“OK, booting the kernel”。
系统将解压后的内核放置在内存之中,并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备,完成Linux核心环境的建立。至此,Linux内核已经建立起来了,基于Linux的程序应该可以正常运行了。
1.1.5 启动第五步--用户层init依据inittab文件来设定运行等级
内核被加载后,第一个运行的程序便是/sbin/init,该文件会读取/etc/inittab文件,并依据此文件来进行初始化工作。其实/etc/inittab文件最主要的作用就是设定Linux的运行等级。
1.1.6 启动第六步--init进程执行rc.sysinit
在设定了运行等级后,Linux系统执行的第一个用户层文件就是/etc/rc.d/rc.sysinit脚本程序,它做的工作非常多,包括设定PATH、设定网络配置(/etc/sysconfig/network)、启动swap分区、设定/proc等等。
1.1.7 启动第七步--启动内核模块
具体是依据/etc/modules.conf文件或/etc/modules.d目录下的文件来装载内核模块。
1.1.8 启动第八步--执行不同运行级别的脚本程序
根据运行级别的不同,系统会运行rc0.d到rc6.d中的相应的脚本程序,来完成相应的初始化工作和启动相应的服务。
1.1.9 启动第九步--执行/etc/rc.d/rc.local
你如果打开了此文件,里面有一句话,读过之后,你就会对此命令的作用一目了然:
# 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.
rc.local就是在一切初始化工作后,Linux留给用户进行个性化的地方。你可以把你想设置和启动的东西放到这里。
1.1.10 启动第十步--执行/bin/login程序,进入登录状态
系统等待用户输入用户名和密码,用户使用自己的帐号登入系统了。
2、 GRUB
2.1 GRUB概述
GRUB(GRand Unified Bootloader)是 GNU 下的 FSF 组织所推行的一套多重开机管理软件。
计算机如何通过grub引导完成系统的启动?了解linux通过grub引导启动,能帮助我们更深刻理解linux操作系统。
如图所示,这是一个硬盘的linux分区示意图。有用4个主分区,包括boot、root、swap和home;linux引导文件就放在这个硬盘最前面的一段空间里。linux引导文件和windows系统类似,区别的只是grub数据结构的不同。
2.2 启动顺序
BIOSàMBRàstage1.5àstage2àkernel
l BIOS 将控制权交给硬盘的主引导区,MBR。
l MBR 中的 bootloader 通过内置的地址加载stage1.5。
l bootloader 通过 stage1.5 内容,将分区中的stage2 加载。
l stage2 此时就可以在文件系统中将 grub.conf 设置文件加载,让用户看到选项画面。
2.2.1 stage1
stage1 这一步在 GRUB 中是不可或缺的,主要负责当 BIOS 交接给 GRUB 时,载入存在于各分区中的开机文件,也就是所谓的开机管理程序,/boot/grub 中的 stage1 文件大小为 512 Byte。恰好MBR 的大小也是 512 Byte?没错!stage1 文件其实就是 MBR 中 bootloader 的备份文件,或者说是管理程序的备份文件(管理程序有可能装在 bootsector 中),但请注意,这里为何强调是 bootloader,而不说是 MBR?因为该文件只有前446 Byte 和MBR 是一样的,跟着的64 Byte 则和现存的MBR 没有关系。系统赖以辨认的 Partition Table 真正的值,就是这 64 Byte。这一块区域非常重要,千万不能将 stage1 与MBR 中的 Partition Table 相互混用,如果用户不小心用整个 stage1 文件覆盖了全部的 MBR,则 MBR 中的第二部分 Partition Table 就会被取代,造成partition 出错,以致无法开机。
2.2.2 stage1.5
系统中存在若干个stage1.5文件,如 e2fs_stage1_5、fat_stage1_5、jfs_stage1_5 和reiserfs_stage1_5,这些都属于 stage 1.5 阶段功能的文件,其作用就像是连接 stage1 到 stage2 的一个信道,里面唯一存放着的是该系统文件的格式。stage1 加载 stage1.5 后,比如 e2fs_stage1_5(ext2 的文件系统),就可以识别 ext2 文件系统的格式,这是一种非常具有弹性的做法。这一连串过程的顺序让 GRUB 在安装完成后,stage2 可以在被搬移后的情况下,即使不在原本的目录或文件系统中,依然可以被安全地找到。因为 stage1.5 被加载时,就已经赋予 GRUB 访问文件系统目录的能力,所以,自然可以在开始找不到 stage2 的情况下,从文件系统目录中找出stage2 的所在位置,并激活 Linux。
当 stage1 还没加载 stage1.5 时,原则上是不认识 ext2 的,当然也无法找到 stage1.5 这个文件,stage1.5 是存在硬盘最前面的 32K 中(但是要跳过 MBR),当 stage1 调用stage1.5 时,就直接去该区域将 stage1.5 找出来使用。
2.2.3 stage2
这个文件是 GRUB 的核心程序,能让用户以选项方式将操作系统加载、新增参数、修改选项,这些全都是 stage2 的功能。对 GRUB 来说,stage2 除了不能自己激活外,剩下的事情全部由 stage2 完成。stage2 文件存放在各分区的 Bootsector 中,主要的功能如下:
l 提供选项。
l 访问设置文件。
l 连接下一个 boot sector。
GRUB 是一个很强大的程序,可想而知,文件不会太小;但身为一个开机管理程序,若不能将一个程序写进 MBR 中,就无法开机,所以 GRUB 的方法,就是将程序部分放到文件系统中,由 stage1.5 来加载,这样,程序的文件就不会有太多的限制,起码文件可以大一点。
2.3 多重启动
多重开机时又如何?既然 stage2 是专门负责开机选项及 kernel 位置的部分,假设有多个操作系统时(每个操作系统都需要支持多重开机,如 FreeBSD),其他的操作系统在该分区是不需要有这 3 个 stage 中的任何一个的。因为只要有一个主要开机用的操作系统所含的 stage1(每个操作系统的开机文件名不一定都一样,但它们大同小异),加上协助加载 kernel 的 stage2,就可以知道所有操作系统的 kerne 存放位置,以便让多重开机管理系统,加载目前已经安装在各分区中的操作系统。
2.4 GRUB配置
2.4.1 开机设置
当 GRUB 加载 stage2 时的操作,也可以在其中再加入一些高级设置。
l hiddenmenu 参数可将选项隐藏,只让用户看到倒数秒数的部分,如果希望跳过这一阶段,可将此参数的最前面用“#”字号注释起来,或是当开机时,直接在倒数秒数结束前按任意一个键,就可以跳到正常的选项画面。
l Timeout参数,如上面所说,当默认值设置完成后,开机画面会停在该选项,至于要停多久就在 Timeout里设置,以秒为单位。需要注意的是,如果“hiddenmenu”参数存在,则倒数秒数出现在开机画面中,若之前所看到的“hiddenmenu”参数被用户注释掉,则倒数秒数就会在开机画面中出现。所以说,Timeout 的秒数并不会因为“hiddenmenu”参数的存在与否而受到影响,只是看要在哪一个步骤中出现倒数秒数。若用户希望取消倒数的功能,也可以将秒数设置成“-1”,在重新开机后就不会出现倒数的提示功能。
l Default参数是操作系统默认开机系统的设置,即 “title”标记,GRUB 只要看到一个title,就知道有一个操作系统是准备要开机使用的。依此类推,若有 3 个 title 开头的段落,就代表会有 3 个操作系统是需要在选项中显示的。而 Default 的意义就在于设置开机时的“默认开机选项”。
2.4.2 开机选项
开机选项代表每一个操作系统的设置值,其中每个操作系统的区域各有不同的设置,主要分成 4 个部分。
l title 操作系统的名称,可以自行设置。
l root 定义该操作系统所使用的 kernel 及 initrd 文件是存放在哪一块硬盘中的,在这里要用 hd(x,x)的格式注明如果设错,便无法加载 kernel。
简单的硬盘代号对应表
硬盘顺序
第一分区代号
第二分区 代号
第一块
hd(0,0)
hd(0,1)
第二块
hd(1,0)
hd(1,1)
第三块
hd(2,0)
hd(2,1)
根据上表可以推算hd(0,0)代表的是第一块硬盘的第一个分区。
Linux下很多的编号都是从 0 开始。
l kernel 加载 kernel 的位置,当 kernel 被成功加载后,会再检查后方紧接着的 root 参数是哪一个分区,将该分区 mount(Linux 下将设备链接到目录的指令)设置为“/”。 所以,虽然 hd(0,0)与/dev/sda1 是指到同样一个分区,但选项中的第一行 hd(0,0)是提供给 stage2 加载 kernel 用的;kernel 中的 root 参数则是提供加载 kernel 后,使其找到“/”分区,所以其实际的意义不同,且不能省略。在 kernel 参数的最后可以加上开机时要先行加载的核心参数,比如 single mode。
l initrd 加载 initrd 的位置, 其中存放着一些外挂的驱动程序。
l 分区名称 在加载的阶段,每个阶段所需要的设备名称及加载方式都不同,要依据当时的阶段而定,当 stage2 要寻找 kernel 时,是利用 BIOS 的实体位置方式(hd(0,0))找到该分区,再将其目录中的 kernel 访问出来的;到了 kernel 开机的阶段,则使用 Linux 所惯用的文件系统格式(/dev/sda1)来找出根目录所在的位置,因此,这两种格式在不同阶段是不可以混用的,但却可以将kernel 文件及根目录放在不同地方,如图所示。
3、 Init进程
3.1 init进程概述
init进程是非内核进程中第一个被启动运行的,系统所有进程的起点,Linux在完成核内引导以后,就开始运行init程序。因此它的进程编号PID的值总是1。init读它的配置文件/etc/inittab,决定需要启动的运行级别(Runlevel)。从根本上说,运行级别规定了整个系统的行为,每个级别(分别由0到6的整数表示)满足特定的目的。init根据/etc/inittab文件中的定义执行一个命令脚本程序。
3.2 inittab文件
3.2.1 格式
inittab的格式。其中以#开始的行是注释行,除了注释行之外,每一行都有以下格式:
id:runlevel:action:process
3.2.1.1 id
id是指入口标识符,是个字符串,可以任意起名,4个字符以内,要注意的是标识名不能重复,它是唯一的,对于getty或mingetty等其他login程序项,需求id和tty的编号相同,否则getty程序将不能正常工作。
3.2.1.2 runlevel
runlevel是init所处于的运行级别的标识,一般使用0-6及S或s。0、1、6运行级别被系统保留:其中0作为shutdown动作,1作为重启至单用户模式,6为重启;S和s意义相同,表示单用户模式,且无需inittab文件,因此也不在inittab中出现,实际上,进入单用户模式时,init直接在控制台(/dev/console)上运行/sbin/sulogin。在一般的系统实现中,都使用了2、3、4、5几个级别,在 Redhat系统中,2表示无NFS支持的多用户模式,3表示完全多用户模式(也是最常用的级别),4保留给用户自定义,5表示XDM图像登录方式。7- 9级别也是能使用的,传统的Unix系统没有定义这几个级别。runlevel能是并列的多个值,以匹配多个运行级别,对大多数action来说,仅当runlevel和当前运行级别匹配成功才会执行。
3.2.1.3 action
action是描述其后的process的运行方式的。action可取的值包括:initdefault、sysinit、boot、bootwait等。
initdefault是个特别的action值,用于标识缺省的启动级别;当init由核心激活以后,他将读取inittab中的 initdefault项,取得其中的runlevel,并作为当前的运行级别。如果没有inittab文件,或其中没有initdefault项, init将在控制台上请求输入runlevel。
sysinit、boot、bootwait等action将在系统启动时无条件运行,而忽略其中的runlevel。其余的action(不含initdefault)都和某个runlevel相关。各个action的定义在inittab的man手册中有周详的描述。
举例说明:
respawn:表示init应该监视这个进程,即使其结束后也应该被重新启动。
wait: init应该运行这个进程一次,并等待其结束后再进行下一步操作。
once: init需要运行这个进程一次。
boot: 随系统启动运行,所以runlevel值对其无效。
bootwait:随系统启动运行,并且init应该等待其结束。
off: 没有任何意义。
initdefault:系统启动后的默认运行级别;由于进入相应的运行级别会激活对应级别的进程,所以对其指定process字段没有任何意义。如果inittab文件内不存在这一条记录,系统启动时在控制台上询问进入的运行级。
sysinit: 系统启动时准备运行的命令。比如说,这个命令将清除/tmp.可以查看/etc/rc.d/rc.sysinit脚本了解其运行了那些操作。
powerwait:允许init在电源被切断时,关闭系统。当然前提是有U P S和监视U P S并通知init电源已被切断的软件。RH linux默认没有列出该选项。
powerfail: 同powerwait,但init不会等待正在运行的进程结束。RH linux默认没有列出该选项。
powerokwait:当电源监视软件报告“电源恢复”时,init要执行的操作。
powerfailnow:检测到ups电源即将耗尽时,init要执行的操作,和powerwait/powerfail不同的哟。
3.2.1.4 process
process为具体的执行程序。程序后面能带参数。
3.2.2 文件内容分析
3.2.2.1 启动级别与初始化
id:5:initdefault:
表示当前默认启动选项为5
# System initialization.
si::sysinit:/etc/rc.d/rc.sysinit
启动时自动执行/etc/rc.d/rc.sysinit脚本初始化系统
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
按启动级别运行rc脚本
3.2.2.2 登录运行
# Run gettys in standard runlevels
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
在2、3、4、5级别上以ttyX为参数执行/sbin/mingetty程序,打开ttyX终端用于用户登录,如果进程退出则再次运行mingetty程序(respawn)。
# Run xdm in runlevel 5
x:5:respawn:/etc/X11/prefdm –nodaemon
在5级别上运行xdm程序,提供xdm图像方式登录界面,并在退出时重新执行(respawn)。
3.2.2.2 其他
# Trap CTRL-ALT-DELETE
ca::ctrlaltdel:/sbin/shutdown -t3 -r now
在启动过程中允许按CTRL-ALT-DELETE重启系统
# When our UPS tells us power has failed, assume we have a few minutes
# of power left. Schedule a shutdown for 2 minutes from now.
# This does, of course, assume you have powerd installed and your
# UPS connected and working correctly.
pf::powerfail:/sbin/shutdown -f -h +2 "Power Failure; System Shutting Down"
# If power was restored before the shutdown kicked in, cancel it.
pr:12345:powerokwait:/sbin/shutdown -c "Power Restored; Shutdown Cancelled"
UPS选项
3.2.3 文件实际执行内容
3.2.3.1 rc.sysinit
rc.sysinit是个bash shell的脚本,主要是完成一些系统初始化的工作,rc.sysinit是每一个运行级别都要首先运行的重要脚本。主要完成的工作有:激活交换分区,检查磁盘,加载硬件模块及其他一些需要优先执行任务。当rc.sysinit程序执行完毕后,将返回init继续下一步。
3.2.3.2 启动对应运行级别的守护进程
在rc.sysinit执行后,将返回init继续其他的动作,通常接下来会执行到/etc/rc.d/rc程序。以运行级别5为例,init将执行设置文件inittab中的以下这行:
l5:5: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/目录下。而这些rc启动脚本有着类似的用法,他们一般能接受start、stop、 restart、status等参数。
/etc/rc.d/rc5.d/中的rc启动脚本通常是K或S开头的链接文件,对于以S开头的启动脚本,将以start参数来运行。而如果发现存在相应的脚本也存在K打头的链接,而且已处于运行态了(以/var/lock/subsys/下的文件作为标志),则将首先以stop为参数停止这些已启动了的守护进程,然后再重新运行。这样做是为了确保是当init改动运行级别时,所有相关的守护进程都将重启。
至于在每个运行级中将运行哪些守护进程,用户能通过chkconfig或setup中的"System Services"来自行设定。常见的守护进程有:
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继续下一步。
3.2.3.3 建立终端
rc执行完毕后,返回init。这时基本系统环境已设置好了,各种守护进程也已启动了。init接下来会打开6个终端,以便用户登录系统。通过按Alt+Fn(n对应1-6)能在这6个终端中转换。在inittab中的以下6行就是定义了6个终端:
# Run gettys in standard runlevels
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
从上面能看出在2、3、4、5的运行级别中都将以respawn方式运行mingetty程序,mingetty程序能打开终端,设置模式。同时会显示一个文本登录界面,在这个登录界面中会提示用户输入用户名,而用户输入的用户将作为参数传给login程序来验证用户的身份。
3.2.3.4 登录系统,启动完成
对于运行级别为5的图像方式用户来说,他们的登录是通过一个图像化的登录界面。登录成功后能直接进入KDE、Gnome等窗口管理器。而本文主要讲的还是文本方式登录的情况。
当我们看到mingetty的登录界面时,我们就能输入用户名和密码来登录系统了。
Linux的账号验证程序是login,login会接收mingetty传来的用户名作为用户名参数。然后login会对用户名进行分析:如果用户名不是root,且存在/etc/nologin文件,login将输出nologin文件的内容,然后退出。这通常用来系统维护时防止非root用户登录。只有/etc/securetty中登记了的终端才允许root用户登录,如果不存在这个文件,则root能在所有终端上登录。/etc /usertty文件用于对用户作出附加访问限制,如果不存在这个文件,则没有其他限制。
在分析完用户名后,login将搜索/etc/passwd及/etc/shadow来验证密码及设置账户的其他信息,比如:主目录是什么、使用何种shell。如果没有指定主目录,将默认为根目录;如果没有指定shell,将默认为/bin/bash。
login 程序成功后,会向对应的终端在输出最近一次登录的信息(在/var/log/lastlog中有记录),并检查用户是否有新邮件(在/usr/spool /mail/的对应用户名目录下)。然后开始设置各种环境变量:对于bash来说,系统首先寻找/etc/profile脚本文件,并执行它;然后如果用户的主目录中存在.bash_profile文件,就执行它,在这些文件中又可能调用了其他设置文件,所有的设置文件执行后后,各种环境变量也设好了,这时会出现命令行提示符,到此整个启动过程就结束了。
展开阅读全文