20.1 Linux启动流程分析
Linux启动过程:
按下开机电源后计算机硬件主动读取BIOS来加载硬件信息以及硬件系统的自我测试,之后系统会主动读取第一个可启动的设备(由BIOS设置),此时就可以读入引导加载程序(boot loader)了,引导加载程序指定使用那个内核文件来启动,并实际加载内核到内存中解压缩与执行,此时内核就能够在内存中活动,并检测所有硬件信息与加载适当的驱动程序来使主机运行,等内核检测硬件与加载驱动程序完毕后,就可以登录了。
1)加载BIOS的硬件信息与进行自我测试,并依据设置取得第一个可启动的设备
2)读取并执行第一个启动设备内MBR的boot Loader(即grub,spfdisk等程序)
3)依据boot loader的设置加载内核,内核开始检测硬件和加载驱动程序
4)在硬件驱动成功后,Kernel会主动调用init进程,而init会取得run-level信息
5)init执行/etc/rc.d/rc.sysinit文件来准备软件执行的操作环境
6)init执行run-level的各个服务的启动
7)init执行/etc/rc.d/rc.local文件
8)init执行终端机模拟程序mingetty来启动login进程,最后等待用户登录
Boot Loader的主要功能:
提供菜单:用户可以选择不同的启动选项,也是多重引导的重要功能
加载内核文件:直接指向可启动的程序区段来开始操作系统
转交其他loader:将引导装载功能转交给其他loader负责
问题1):每种操作系统都有自己的boot loader,对于多操作系统,每个操作系统必须使用自己的loader才能加载自己的操作系统内核,而系统的MBR只有一个,怎么能同时在一部主机上安装windows和linux呢
答案:由于boot loader具有菜单功能,因此可以选择不同的内核来启动。由于具有控制权转交的功能,因此可以加载其他boot sector内的loader,(windows的loader默认布局有控制权转交功能,因此不能用windows的loader加载linux的loader)
问题2):假设linuux安装在SATA硬盘上,可以通过BIOS的INT13取得boot loader与kenerl文件来启动,然后kernel会开始接管系统并且检测硬件及尝试挂载根目录来取得额外的驱动程序。但是内核根本不认识SATA磁盘,所以需要加载SATA磁盘的驱动程序,否则根本无法挂载根目录,但是SATA的驱动程序在/lib/modules内,根本无法挂载根目录,又怎么能读取到/lib/modules内的驱动程序呢?
答案:通过虚拟文件系统解决,一般使用的文件名是/boot/initrd。该文件能够通过boot loader加载到内存中,文件被解压缩并在内存中仿真成一个根目录,且此仿真在内存中的文件系统能够提供一个可执行程序,通过该程序来加载启动过程中所需要的内核模块,通常是USB,RAID,LVM,SCSI等文件系统与硬盘接口的驱动程序。等载入完成后,会帮助内核重新调用/sbin/init来开始后续的正常流程
(如果linux安装在IDE接口的磁盘上,且默认使用ext2/ext3文件系统,那么不需要initrd也能顺利启动linux)
内核加载完毕进行完硬件检测与驱动程序加载后,主机硬件就已经准备就绪来,此时内核会主动调用第一个进程,就是/sbin/init (init的PID为1),/sbin/init的主要功能就是准备软件执行的环境,包括系统主机名、网络设置、语系处理、文件系统格式及其他服务的启动。而所有的操作都会通过init的配置文件/etc/inittab来规划
inittab一个很重要的设置选项就是run level
0——halt (系统直接关机)
1——single user mode(单用户维护模式,用在系统出问题时维护)
2——Multi-user,without NFS(类似run level3,但无NFS服务)
3——Full multi-user mode(完整含有网络功能的纯文本模式)
4——unused (系统保留功能)
5——X11(与run level3 类似,但加载使用X Windows)
6——reboot (重新启动)
在/etc/inittab里有一句:"si::sysint:/etc/rc.d/rc.sysinit"表示:开始加载各项系统服务之前,得先设置好整个系统环境,主要利用/etc/rc.d/rc.sysinit这个shell script 来设置好系统环境的
启动系统服务与相关启动配置文件(/etc/rc.d/rc N & /etc/sysconfig)
/etc/rc.d/rc5的意义是这样的:
通过外部第一号参数($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下的文件全部是链接文件,链接到stand alone服务启动的目录/etc/init.d中)
如/etc/rc5.d/K91capistop-->/etc/init.d/capistop
/etc/rc5.d/S10networkstart--> /etc/init.d/networdkstart
S和K后的数字表示文件执行的顺序,S99local就是/etc/rc.d/rc.local是最后执行
用户自定义开机启动程序(/etc/rc.d/rc.local)
如果用户有任何想要在启动时进行的工作,直接将它写入/etc/rc.d/local,那个该工作就会在启动的时候自动加载
启动过程会用到的主要配置文件:
1)模块:/etc/modprobe.conf (这个文件大多在于指定系统内的硬件所使用的模块,如果系统检测到错误的驱动程序,或者你想要使用更新的驱动程序来对应相关的硬件配备时,就得要手动处理该文件)
2)/etc/sysconfig/*下的几个文件:
authconfig 这个文件主要设置用户的身份认证的机制,包括是否使用本地/etc/passwd,/etc/shadow等
clock 该文件用于设置linux主机的失去,可以使用格林威治时间,也可以使用本地时间
i18n 用于设置一些语系的使用方面
keyboard&mouse 设置键盘与鼠标的形式
network 可以设置是否启动网络,以及设置主机名还有网关信息
network-scripts 主要用于设置网卡
切换run level: init N
显示当前的run level :runlevel (输出结果左边代表前一个runlevel,右边代表目前的runlevel)
init 0 关机
init 6 重启
20.2 内核与内核模块
内核和内核模块存放位置:
内核:/boot/vmlinuz或/boot/vmlinuz-version
内核解压所需RAMDisk:/boot/initrd (/boot/initrd-version)
内核模块:/lib/modules/version/kernel或 /lib/modules/$(uname -r)/kernel
内核源码:/usr/src/linux 或/usr/src/kernels(要安装才会有,默认不安装)
内核版本:/proc/version
系统内核功能:/proc/sys/kernel
内核模块与依赖性:
/lib/modules/$(uname -r)/modules.dep文件记录了在内核支持的模块的各项依赖性
例如,做好的网卡驱动程序,文件名为a.ko,如何更新内核依赖性?
使用depmod命令就可以实现(depmod [-Ane])
cp a.ko /lib/module/$(uname -r)/kernel/driver/net
depmod
内核模块的查看:
lsmod
使用lsmod后,系统会显示出目前已存在与内核中的模块,显示包括:模块名称module、模块的大小size、此模块是否被其他模块所使用Used by
modinfo [-adln] [module_name|filename]
如:modinfo wmi
内核模块的加载与删除:
如果想要自行手动加载模块,最简单也建议使用modprobe命令来加载模块,因为modprobe会主动查找modules.dep的内容,先克服了模块的依赖性后,菜决定需要加载的模块有哪些。insmod则完全有用户加载一个完整文件名的模块,并不会主动分析模块依赖性
modprobe [-lcfr] module_name
insmod [/full/path/module_name] [parameters]
例如:尝试载入cifs.ko这个文件系统模块
insmod /lib/module/$(uname -r)/kernel/fs/cifs/cifs.ko
lsmod | grep cifs
删除模块:rmmod [-fw] module_name
20.3 Boot Loader:Grub
boot loader的程序代码执行与设置值加载分为两个阶段来执行
stage1:执行boot loader主程序(这个主程序必须要安装在启动区,即MBR或者boot sector,因为MBR实在太小来,所以MBR或boot sector通常仅安装boot loader最小主程序,并没有安装loader的相关配置文件)
stage2:通过boot loader加载所有配置文件与相关的环境参数文件(包括文件系统定义与主要配置文件menu.lst),一般来说,配置文件都在/boot下
安装在MBR的grub主程序最终要的任务之一就是从磁盘中加载内核文件,以让内核能够顺利驱动整个系统的硬件
grub的硬盘代号如hd(0,0)表示第一块查找到的硬盘代号为(hd0),该硬盘的第一号分区为(hd0,0)
/boot/grub/menu.lst (grub.cfg)
default=0 默认的启动选项,使用第一个启动菜单
timeout=5 若5秒内未动键盘,使用默认菜单启动
hiddenmenu 读秒期间是否显示完整的菜单界面
需要initrd时刻为:
根目录所在磁盘为SATA、USB或SCSI等连接接口
跟母所在文件系统为LVM、RAID等特殊格式
根目录所在文件系统为非传统Linux“认识”的文件系统
其他必须要在内核加载时提供的模块
可以使用mkinitrd命令来重制initrd文件
mkinitrd [-v] [--with=模块名称] initrd文件名 内核版本
例1:以mkinitrd的默认功能创建一个initrd虚拟硬盘文件
mkinitrd -v initrd_$(uanem -r) $(uname -r)
例2:增加8139too这个模块的initrd文件
mkinitrd -v --with=8139too initrd_vbirdtest $(uname -r)
安装grub(grub-install是安装grub相关的文件到设备上去等待在启动时被读取,但还需要设置好配置文件menu.lst后,再以grub shell来安装grub主程序到MBR或者boot sector上面去)
grub-install [--root-directory=DIR] INSTALL_DEVICE
例1:将grub安装到目前系统的MBR下面,我的系统为/dev/had
grub-install /dev/hda
例2:我的/home为独立的/dev/sda3,如何安装grub到/dev/sda3
grub-install --root-directory=/home /dev/sda3
内核功能中的vga设置
解决tty1~tty6的分辨率问题
首先产看是否支持FRAMEBUFFER_CONSOLE这个内核功能参数
grep 'FRAMEBUFFER_CONSOLE' /boot/config-3.2.0-23-generic-pae (如果出现CONFIG FRAMEBUFFER CONSOLE=y表示有支持)
修改分辨率 vi /boot/grub/menu.lst (或者是grub.cfg文件 添加红色部分)
menuentry 'Ubuntu,Linux 3.2.0-67-generic-pae' --class ubuntu --class gnu-linux --class gnu --class os {
recordfail
gfxmode $linux_gfx_mode
insmod gzio
insmod part_msdos
insmod ext2
set root='(hd0,msdos1)'
search --no-floppy --fs-uuid --set=root c6008246-e4ee-490f-bec6-3f72108424dd
linux /boot/vmlinuz-3.2.0-67-generic-pae root=UUID=c6008246-e4ee-490f-bec6-3f72108424dd ro quiet splash $vt_handoff vga=790
initrd /boot/initrd.img-3.2.0-67-generic-pae
}
790对应着1024*768的分辨率,还有其他参数,如784~795,769,771,773,775
20.4启动过程的问题解决
1)忘记密码
a.重新启动
b.启动进入grub菜单后,在要进入的菜单上按“e” 进入菜单设置
grub edit>kernel /vmlinuz-2.6.18-92.e15 ro root=LABEL=/ rhgb quiet single
(我的ubuntu下应该是linux /boot/vmlinuz-3.2.0-67-generic-pae root=UUID=c6008246-e4ee-490f-bec6-3f72108424dd ro quiet splash $vt_handoff single)
按下enter在按b就能够启动进入单用户维护模式
c.进入单用户模式后,就可以执行shell,输入passwd就能够重新root密码,在执行init 5可以切换成X窗口界面
2)init配置文件错误
a.同样启动进入grub后
grub edit>kernel /vmlinuz-2.6.18-92.e15 ro root=LABEL=/ rhgb quiet init=/bin/bash
将内核调用的第一个进程init变成/bin/bash
b.在shell中输入mount -o remount,rw /(将根目录重新挂载成可读写)
mount -a(参考/etc/fstab的内容重新挂载文件系统)
c.然后进行救援工作,完毕后,重启一次就可以了