(对于没有涉及到源码的部分内容是参考网上资料,涉及到源码部分分析的是 2.3.35.4 的源码)
鸟哥的开机关机流程与 Loader :
1. 整个开机流程是
(1) 载入 BIOS 的硬件信息,并取得第一个开机装置的代号
(2) 读取第一个开机装置的 MBR 的 boot Loader (grub) 的开机信息
(3) 载入 OS Kernel 信息,解压 Kernel ,尝试驱动硬件
(4) Kernel 执行 init 程序并获得 run-lebel 信息 ( 如 3 或 5)
(5) init 执行 /etc/rc.d/rc.sysinit
(6) 启动内核外挂模块 (/etc/modprobe.conf)
(7) init 执行 run-level 的各种 Scripts ,启动服务
(8) init 执行 /etc/rc.d/rc.local
(9) 执行 /bin/login ,等待用户 Login
(10)Login 后进入 Shell
但是发现,在我的 ubuntu 系统中没有上面描述的文件,例如在 ubuntu10.10 中没有 /etc/modprobe.config 文件。
在网上搜索发现 linux 的不同发行版的开机过程中所使用的方法可能不同,本文主要针对 ubuntu 。其区别为: linux 流程是 init 方式的开机, UBUNTU 中把 init 替换成了 upstart.
首先来分析一下流行的 init 开机方式,因为 upstart 与之有很多类似的地方。
流行的 init 开机方式: 可以略过直接阅读 ubuntu 的启动方式 upstart
参考网页: http://hi.baidu.com/janux/blog/item/c607d2c840d24e167e3e6f47.html
BIOS
当第一次启动计算机或重启时,计算机的处理器会在一个众所周知的位置开始执行,即基本输入 / 输出系统( BIOS )。 BIOS 通常存储在系统主板的一个闪存设备中。 BIOS 需要执行很多工作,例如对基本组件(例如系统内存)进行初始测试,确定如何引导操作系统。由于基于 PC 的计算机都非常灵活,因此引导设备可以是连接到主板上的各种设备之一,包括硬盘、 CD-ROM 或其他设备,例如网络接口。
通过选择最经常引导的设备(通常是硬盘)可以优化确定引导设备的过程。不过到目前为止, BIOS 阶段最耗时的过程就是内存测试。将这个测试的某些部分禁用(例如内存完全测试)确实有助于加快引导速度,不过这样做的代价是丢失了引导时对系统的完整性测试。
内核引导
找到引导设备后,开始 Linux 内核引导过程。这个过程发生在两个阶段(大约) —— 第一阶段引导 和 第二阶段引导 。 第一阶段包含了一个简单的引导加载程序(这可以在引导设备的主引导记录 MBR 中找到),其作用是加载第二阶段的引导加载程序。第一阶段的引导加载程序使用分区表来找到第二阶段的引导加载程序。第一阶段的引导加载程序对表进行扫描, 查找活动分区;当加载程序找到分区时,就将第二阶段的引导加载程序加载到 RAM 中并调用它。
在第二阶段的引导加载程序加载到 RAM 中之后,Linux 内核映像和初始 RAM 磁盘映像(initrd
)也会被加载到 RAM 中。当调用内核时,它会自解压到高端内存中,并拷贝 initrd
以供稍后安装和使用。
|
init
进程。
系统初始化
init
进程是内核引导过程完成时创建的第一个进程。 Linux 使用了 init
进程来对组成 Linux 的服务和应用程序进行初始化。
当 init
进程启动时,它会打开一个名为 /etc/inittab 的文件。这个文件是 init
的配置文件,定义了如何对系统进行初始化。这个文件还包含了有关出现电源故障时执行的操作(如果系统支持)、以及在检测到 Ctrl-Alt-Delete 键序列时应该如何反应的信息。请参看 清单 1 中该文件的简短片段,了解它所提供的内容。
inittab
配置文件使用通用格式定义了几项内容:id:runlevels:action:process 。其中 id 是惟一标识该项的字符序列。runlevels 定义了操作所使用的运行级别。action 指定了要执行的特定操作。最后,process 定义了要执行的进程。
清单 1. inittab 文件摘录
# The default runlevel id:2:initdefault # Boot-time system configuration/initialization script si::sysinit:/etc/init.d/rcS # Runlevels l0:0:wait:/etc/init.d/rc 0 l1:1:wait:/etc/init.d/rc 1 l2:2:wait:/etc/init.d/rc 2 l3:3:wait:/etc/init.d/rc 3 l4:4:wait:/etc/init.d/rc 4 l5:5:wait:/etc/init.d/rc 5 l6:6:wait:/etc/init.d/rc 6 z6:6:respawn:/sbin/sulogin # How to react to ctrl-alt-del ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now |
若要继续阅读,请参看网页 http://hi.baidu.com/janux/blog/item/c607d2c840d24e167e3e6f47.html
upstart 和 ubuntu 启动过程
开机过程中的第一到第三步都是相似的,不同开始于第四步。
替换 init
的另外一种选择是 upstart
, upstart
是一个基于事件的 init
的替代程序,这意味着服务的启动和停止都基于事件的通信。
Upstart
要求您更新初始化脚本来支持基于事件的操作模式。 upstart
维护自己的在系统启动时启动的 init
进程(对于所有其他方法也是如此)。 那么 init 进程是如何开启系统中的其它进程的呢?
在阐述这个问题之前,大致地说明一下目前 ubuntu 中与 init 相关的几个目录和应用程序,可以方便后面的论述。这些目录和程序包括:
init
telinit
runlevel
/etc/event.d/
/etc/init.d/
/etc/rcX.d/
前三个是应用程序 ( 注意哦,它们都不是 shell 脚本),可以理解为是由内核调用的。关于它们的功能,从 manpage 查看就可以了。我们的重点是后面给出的三个目录,这三个目录也可以找到,其中的 /etc/rcX.d/ 中的 X=0~6,S 。
首先是 /etc/event.d/ 目录,这是 upstart 的核心, upstart 不同于原有的 init 的地方就在于它引入了 event 机制。 Event 机制通俗的讲就是将所有进程的触发、停止等等都看作 event( 事件 ) 。 /etc/event.d/ 中就存放了目前 upstart 需要识别的 event 。 这其中主要有三种 rc-default, rcX(x=0,1,...6,S) 以及 ttyX 。这 rc-default 就类似于那大名鼎鼎的 inittab 文件,它就是设置默认运行级别的 [ 注: upstart 中实际并没有运行级别的概念,这么称呼是为了 init 向后的兼容性 ] 。 现在你应该知道了 ubuntu 里没有了 inittab 文件后该 到哪里设置默认运行级别的了吧! cat rc-default 一下吧! rcX 文件是发生相应运行级别事件 ( 可以注意到 event 这个词在 upstart 里真是无处不见啊 ) 时,需要运行程序的脚 本,而 ttyX 则是设置伪终端数目的,也就是你 Ctrl+Alt+F(1~6) 调出的那个 Console 。
以 rc2 为例, cat /etc/rc2.d:
start on runlevel 2
stop on runlevel [!2]
console output
script
set $(runlevel --set 2 || true)
if [ "$1" != "unknown" ]; then
PREVLEVEL=$1
RUNLEVEL=$2
export PREVLEVEL RUNLEVEL
fi
exec /etc/init.d/rc 2
end script
不去考虑细节 , 只要注意到前两行和倒数第二行就可以了 . 可以看到 ,rc2 文件是定义在发生运行级别 2 的
时候所要执行的东西 , 核心就是这句: exec /etc/init.d/rc 2. 这样 , 我们就可以自然地过渡到下一个重要的目录 ,/etc/init.d/ 了 .
你可以ls /etc/init.d/ 看一下里面的内容, 对它有个大致的了解./etc/init.d/ 中存放的是服务(services) 或者任务(tasks) 的 执行脚本. 可以这么说, 只要你安装了一个程序( 特别是服务程序daemon), 它可以在系统启动的时候运行, 那么它必定会在/etc/init.d/ 中有 一个脚本文件. 我们还回到上面的rc2 文件, 它执行了一个exec /etc/init.d/rc 2 的命令. 也就是说, 给/etc/init.d/rc 脚本传递了一个参数"2", 让它执行. 我们仔细查看一下rc 脚本( 很长, 耐心点), 能看到这样的一 段
:
# Now run the START scripts for this runlevel.
# Run all scripts with the same level in parallel
.......
for s in /etc/rc$runlevel.d/S*
.......
这说明 , 当给 rc 脚本传递一个数字参数 "X" 的时候 , 它在经过一系列的设置后 , 将会开始执行 /etc/rcX.d/ 下 S 开头的脚本 . 这就过渡到下一个目录 /etc/rcX.d/ 了 .
进入/etc/rcX.d/,ls -l /etc/rcX.d/ 看看有些什么内容?哈哈, 没错, 都是一些到/etc/init.d/ 中脚本的符号链接. 不同的是它们的开头加上了S 和一个数字. 熟 悉原本init 的人应该知道,S 表示在启动时运行, 数字则表示执行的先后顺序.
这样一来,upstart 管理的ubuntu 启动过程应该就清楚了. 梳理一下:
1, 内核启动init
2,init 找到/etc/event.d/rc-default 文件, 确定默认的运行级别(X)
3, 触发相应的runlevel 事件, 开始运行/etc/event.d/rcX
4,rcX 运行 /etc/init.d/rc, 传入参数 X
5,/etc/init.d/rc 脚本进行一系列设置 , 最后运行相应的 /etc/rcX.d/ 中的脚本
6,/etc/rcX.d/ 中的脚本按事先设定的优先级依次启动 , 直至最后给出登录画面 ( 启动 X 服务器和 GDM)
理解了这些, 手动配置开机服务的启动与否就很简单了.Ubutnu 默认的启动级别是2, 不想启动的程序, 只要把相应的符号链接从/etc/rc2.d/ 中删去即可!