Linux启动过程
1. 启动过程(1) 机器启动后,首先是 BIOS 被加载执行,获取第一个启动设备(通常是硬盘)编号。
(2)读取启动设备 MBR 中的引导加载程序 (BootLoader,如 lilo、grub 等)。
演示: 抓取 MBR 数据
~$ sudo dd if=/dev/sda of=mbr.bin bs=512 count=1
[sudo] password for yuhen: 1+0 records in 1+0 records out 512 bytes (512 B) copied, 0.000291654 s, 1.8 MB/s
~$ od -x mbr.bin
0000000 48eb 1090 d08e 00bc b8b0 0000 d88e c08e 0000020 befb 7c00 00bf b906 0200 a4f3 21ea 0006 0000040 be00 07be 0438 0b75 c683 8110 fefe 7507 0000060 ebf3 b416 b002 bb01 7c00 80b2 748a 0203 0000100 00ff 2000 0001 0000 0200 90fa f690 80c2 ... ...
MBR 中包含了引导程序代码(BootLoader 446B)和分区表信息(64B)。Boot Loader 通过分区表找到激活主分区,然后载入并执行激活分区的启动记录。
(3) 开始加载内核程序,初始化内存盘(可选 initrd)。内核程序(vmlinuz)开始解压缩,尝试驱动硬件设备。
/$ ls -l
drwxr-xr-x 3 root root 4096 2009-07-21 17:22 boot lrwxrwxrwx 1 root root 33 2009-07-19 14:17 initrd.img -> boot/initrd.img-2.6.28-11-generic lrwxrwxrwx 1 root root 30 2009-07-19 14:17 vmlinuz -> boot/vmlinuz-2.6.28-11-generic
初始化内存盘用于创建临时根文件系统,在内核引导成功并挂载真正根文件系统时被卸载。
(4) 执行 init 程序,获取运行信息。
/sbin/init的 PID = 1,是所有进程的起点。init 程序需要读取配置文件/etc/inittab (Ubuntu 默认没有该文件)。
# # inittab This file describes how the INIT process should set up # the system in a certain run-level. # # Author: Miquel van Smoorenburg, <[email protected]> # Modified for RHS Linux by Marc Ewing and Donnie Barnes # # Default runlevel. The runlevels used by RHS are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not havenetworking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # ### 表示当前缺省运行级别为 5(initdefault); id:5:initdefault: ### 启动时自动执行 /etc/rc.d/rc.sysinit 脚本(sysinit) # System initialization. si::sysinit:/etc/rc.d/rc.sysinit ### 当运行级别为 5 时,以 5 为参数运行 /etc/rc.d/rc 脚本,init将等待其返回(wait) 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 ### 在启动过程中允许按 CTRL-ALT-DELETE 重启系统 # Trap CTRL-ALT-DELETE ca::ctrlaltdel:/sbin/shutdown -t3 -r now # 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" ### 在2、3、4、5级别上以ttyX为参数执行 /sbin/mingetty 程序,打开 ttyX 终端用于用户登录, ### 如果进程退出则再次运行mingetty程序(respawn) # 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 ### 在 5 级别上运行 xdm 程序,提供 xdm 图形方式登录界面,并在退出时重新执行 (respawn) # Run xdm in runlevel 5 x:5:respawn:/etc/X11/prefdm -nodaemon
(5) init 执行系统初始化脚本文件/etc/rc.d/rc.sysinit (Ubuntu 同样没有该文件)。
rc.sysinit 完成硬件初始化和载入系统模块,我们在 Linux 启动时看到那一大堆启动信息多数都是这个脚本的 "成果"。rc.sysinit 会将启动信息写入/var/log/dmesg 文件中,我们可以用 dmesg 或者如下命令进行翻页查看。
/$less /var/log/dmesg
[ 0.016920] CPU: L1 I cache: 32K, L1 D cache: 32K [ 0.016954] CPU: L2 cache: 4096K [ 0.017662] Checking 'hlt' instruction... OK. [ 0.040417] SMP alternatives: switching to UP code [ 0.249126] Freeing SMP alternatives: 18k freed [ 0.249661] ACPI: Core revision 20080926 [ 0.254227] ACPI: Checking initramfs for custom DSDT [ 0.630876] ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1 [ 0.671217] CPU0: Intel(R) Core(TM)2 Duo CPU T7300 @ 2.00GHz stepping 0b [ 0.673828] Brought up 1 CPUs [ 0.673891] Total of 1 processors activated (3990.00 BogoMIPS). [ 0.675449] CPU0 attaching NULL sched-domain. [ 0.682358] net_namespace: 776 bytes [ 0.682729] Booting paravirtualized kernel on bare hardware [ 0.684399] Time: 8:28:36 Date: 08/05/09 [ 0.684564] regulator: core version 0.5 [ 0.686307] NET: Registered protocol family 16 [ 0.691383] EISA bus registered [ 0.691651] ACPI: bus type pci registered [ 0.693500] PCI: MCFG configuration 0: base e0000000 segment 0 buses 0 - 255 [ 0.693663] PCI: MCFG area at e0000000 reserved in E820 [ 0.693710] PCI: Using MMCONFIG for extended config space [ 0.693788] PCI: Using configuration type 1 for base access
(6) 启动系统服务。
通过 /etc/inittab 提供的设置决定启动服务。
/etc/inittab
id:5:initdefault: l5:5:wait:/etc/rc.d/rc 5
注:"/etc/rc.d/rc" 是一个脚本程序。
根据运行等级,其对应的目录是/etc/rc.d/rc5.d (Ubuntu 直接存放在 /etc 目录中)。该目录下都是以 S (开机时需要启动的服务) 或 K (关机时需要停止的服务) 开头的链接文件,其文件名中的数字表示执行顺序。
/etc/rc5.d$ ls -l
lrwxrwxrwx 1 root root 19 2009-07-19 14:03 S01policykit -> ../init.d/policykit lrwxrwxrwx 1 root root 15 2009-07-19 14:03 S10acpid -> ../init.d/acpid lrwxrwxrwx 1 root root 14 2009-07-19 14:03 S10apmd -> ../init.d/apmd lrwxrwxrwx 1 root root 18 2009-07-19 14:03 S10sysklogd -> ../init.d/sysklogd lrwxrwxrwx 1 root root 15 2009-07-19 14:03 S11klogd -> ../init.d/klogd
文件名规则说明:
S: 表示开机时需要启动的服务。S11klogd 表示开机时执行../init.d/klogd start。
K: 表示关机时需要停止的服务。执行 stop 。
数字: 表示执行顺序。
如果我们不想某个服务在开机时被启动,可以移除链接文件。正规一点可以用 chkconfig进行管理。
在任何时候,我们还可以手工停止或者启动某个服务 (类似 Windows CMD 中的 net start / net stop)。
/etc/rc5.d$ sudo /etc/init.d/atd stop
* Stopping deferred execution scheduler atd [ OK ]
/etc/rc5.d$ sudo /etc/init.d/atd start
* Starting deferred execution scheduler atd [ OK ]
(7) 执行自定义引导程序
/etc/rc.d/rc.local 类似于 Windows 的 Autoexec.bat 和 Config.sys。我们可以在该文件中写入自定义启动脚本。
(8) 加载终端或 X-Window
依旧是根据 /etc/inittab 中配置进行。
# Default runlevel. The runlevels used by RHS are: # 0 - halt (Do NOT set initdefault to this) # 1 - Single user mode # 2 - Multiuser, without NFS (The same as 3, if you do not havenetworking) # 3 - Full multiuser mode # 4 - unused # 5 - X11 # 6 - reboot (Do NOT set initdefault to this) # id:5:initdefault: # 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 # Run xdm in runlevel 5 x:5:respawn:/etc/X11/prefdm -nodaemon
该配置表示创建 6 个文字终端,另外在等级 5 时启动 X-Window。
respawn 的意思是:其后面的命令被终止时,自动重启该命令。比如我们用 exit 退出终端后,同名终端会重启,等待我们重新登录使用。
(9) 接下来自然是等待用户登录了。
2. 变换运行等级
如果我们不想修改/etc/inittab 中的默认启动运行等级,那么可以用 init 命令进行,重启后失效。
/etc/rc3.d$runlevel
N 2 # 分别表示切换前的等级和现在的等级,N 表示 None。
/etc/rc3.d$ sudo init 3
/etc/rc3.d$ runlevel
2 3
切换等级仅仅调整运行服务而已。
(1) 比较各自目录中的服务链接文件 (S、K 开头的文件)。
(2) 停止在新等级中不存在的服务。
(3) 启动新等级中未启动的服务。