Linux 学习笔记 -- 第五部分 Linux 系统管理员 -- 第20章 启动流程、模块管理与 Loader

来源:互联网 发布:linux gcc安装 编辑:程序博客网 时间:2024/05/22 10:33
启动流程、模块管理与 Loader
Linux 的启动流程分析
启动流程一览
系统启动的过程如下:
1.加载 BIOS 的硬件信息与进行自我测试,并依据设置取得第一个可启动的设备;
2.读取并执行第一个启动设备内 MBR 的 boot Loader (即是 grub,spfdisk 等程序);
3.依据 boot loader 的设置加载 Kernel,Kernel 会开始检测硬件与加载驱动程序;
4.在硬件驱动成功后,Kernel 会主动调用 init 进程,而 init 会取得 run-level 信息;
5.init 执行 /etc/rc.d/rc/sysinit 文件来准备软件执行的操作环境 (如网络、时区等);
6.init 执行 run-level 的各个服务的启动 (script);
7.init 执行 /etc/rc.d/rc.local 文件
8.init 执行终端机模拟程序 mingetty 来启动 login 进程,最后就等待用户登录


BIOS,boot loader 与 kernel 加载
BIOS,开机自我测试与 MBR
Boot Loader 的功能
提供菜单:用户可以选择不同的启动选项,这也是多重引导的重要功能
加载内核文件:直接指向可启动的程序区段来开始操作系统
转交其他 loader:将引导装在功能转交给其他 loader 负责

Windows 的 loader 默认不具有控制权转交的功能,因此不能使用 Windows 的 loader 来
加载 Linux 的 loader。这也是为什么要先安装 Windows 再装 Linux 的缘故。


加载内核检测硬件与 initrd 的功能
内核文件的位置:
ls --format=single-column -F /boot

为了硬件开发商与其他内核功能开发者的便利,因此 Linux 内核是可以通过动态加载内核
模块的(即驱动程序),这些内核模块就放置在 /lib/modules 目录内。由于模块放置到磁盘
根目录内 (要记得 /lib 不可以与 / 分别放在不同的分区),因此在启动的过程中内核必须
要挂载根目录,这样才能够读取内核模块提供加载驱动程序的功能,而且为了避免影响到磁
盘内的文件系统,因此启动过程中根目录是以只读的方式来挂载。


虚拟文件系统 (InitialRAM Disk) 一般使用的文件名为 /boot/initrd,这个文件的特色是,
它也能够通过 boot loader 来加载到内存中,然后这个文件会被解压缩并且在内存当中仿真
成一个根目录,此仿真在内存当中的文件系统能够提供一个可执行的程序,通过该程序来加载
启动过程中所最需要的内核模块,通常这些模块就是 USB,RAID,LVM,SCSI 等文件
系统与磁盘接口的驱动程序。


第一个进程 init 及配置文件 /etc/inittab 与 runlevel
/sbin/init 最主要的功能就是准备软件执行的环境,包括系统的主机名、网络设置、语系处理、文件系统
格式及其他服务的启动等。而所有的操作都会通过 init 的配置文件,即 /etc/inittab 来规划,而 inittab
内还有一个很重要的设置选项,那就是默认的 run level (启动执行等级)


run level:执行等级
Linux 就是通过设置 run level 来规定系统使用不用的服务来启动,让 Linux 的使用环境不同。
基本上,已具有无网络与有无 X Window 而将 run level 分为7个等级,分别是:

0 - halt (系统直接关机)
1 - single user mode (单用户维护模式,用在系统出问题时的维护)
2 - Multi-user, without NFS (类似下面的 runlevel3,但无 NFS 服务)
3 - Full multi-user mode (完整含有网络功能的纯文本模式)
4 - unused (系统保留功能)
5 - X11 (与 runlevel3 类似,但加载使用 X Window)
6 - reboot (重新启动)

init 的处理流程
1.先取得 run level 即默认执行等级的相关等级 (默认为5)
2.使用 /etc/rc.d/rc.sysinit 进行系统初始化
3.由于 run level 是5,因此只进行 "5:5:wait:/etc/rc.d/rc5",其他行则略过
4.设置好 [ctrl]+[alt]+[del] 这组的组合键功能
5.设置不断电系统的 pf,pr 两种机制
6.启动 mingetty 的6个终端机 (tty1-tty6)
7.最终以 /etc/X11/perfdm -nodaemon 启动图形界面


init 处理系统初始化流程 (/etc/rc.d/rc.sysinit)
/etc/inittab 中的 "si::sysinit:/etc/rc.d/rc.sysinit" 表示开始加载各项系统服务之前,得先设置好整个
系统环境,主要利用 /etc/rc.d/rc.sysinit 这个 shell script 来设置好系统环境。


用 vim 查阅 /etc/rc.d/rc.sysinit,可以发现它的主要工作大抵有:
1.取得网络环境与主机类型
2.测试与挂载内存设备 /proc 及 USB 设备 /sys
3.决定是否启动 SELinux
4.启动系统的随机数生成器
5.设置终端机 (console) 字体
6.设置显示于启动过程中的欢迎界面 (textbanner)
7.设置系统时间 (clock) 与时区设置:需读入 /etc/sysconfig/clock 设置值
8.接口设备的检测与 Plug and Play (PnP) 参数的测试
9.用户自定义模块的加载
10.加载内核的相关设置
11.设置主机名与初始化电源管理模块 (ACPI)
12.初始化软件磁盘阵列:主要是通过 /etc/mdadm.conf 来设置好的
13.初始化 LVM 的文件系统功能
14.以 fsck 检验磁盘文件系统:会进行 filesytem check
15.进行磁盘配额 quota 的转换 (非必要)
16.重新以可读写模式挂载系统磁盘
17.启动 quota 功能:所以我们不需要自定义 quotaon 的操作
18.启动系统伪随机数生成器 (pseudo-random)
19.清除启动过程当中的临时文件
20.将启动相关信息加载 /var/log/dmesg 文件中

启动系统服务与相关启动配置文件 (/etc/rc.d/rc N & /etc/sysconfig )
/etc/rc.d/rc5的意义:
1.通过外部第一号参数 ($1) 来取得想要执行的脚本目录,即由 /etc/rc.d/rc 5 可以
         取得 /etc/rc5.d/ 这个目录来准备处理相关的脚本程序
2.找到 /etc/rc5.d/K??* 开头的文件,并进行"/etc/rc5.d/K??*stop"的操作
3.找到 /etc/rc5.d/S??* 开头的文件,并进行"/etc/rc5.d/S??*start"的操作

所以,当有想要启动该 run level 时就执行的服务,那么利用 Sxx 并指向 /etc/init.d/
的特定服务启动脚本后,该服务就能够在启动时启动。


用户自定义开机启动程序 ( /etc/rc.d/rc.local )

根据 /etc/inittab 的设置加载终端机或 X Window 界面

启动过程会用到的主要配置文件
关于模块: /etc/modprobe.conf (对应 /etc/rc.d/rc.sysinit 第9条)

/etc/sysconfig/* 服务的相关配置文件,启动过程里经常读取到。
authconfig 主要设置用户的身份认证机制


clock 设置 Linux 主机的时区

i18n 用于设置一些语系的使用方面


keyboard & mouse


network

network-scripts/


Run level 的切换
依据启动是否自动进入不同 run level 的设置,我们可以说:
1.要每次启动都执行某个默认的 run level,则需要修改 /etc/inittab 内的设置选项,
 即是"id:5:initdefault:"里头的数字
2.如果仅只是暂时更改系统的 run level 时,则使用 init[0-6] 来进行 run level 的更
 改,但下次重新启动时,依旧会是以 /etc/inittab 的设置为准


查看目前的 run level 等级:runlevel
N 5 左边代表前一个 run level,右边代表目前的 run level
切换成为 3 (tty7 的数据会消失)
init 3
init 0 (关机) init 6 (重新启动)


内核与内核模块
内核:/etc/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)/kernel 当中,里面主要
还分成几个目录:
arch:与硬件平台有关的选项,例如 CPU 的等级等
crypto:内核所支持的加密技术,例如 md5 或者是 des 等
drivers:一些硬件的驱动程序,例如显卡、网卡、PCI 相关硬件等
fs:内核所支持的文件系统,例如 vfat,reiserfs,nfs 等
lib:一些函数库
net:与网络有关的各项协议数据,还有防火墙模块 (net/ipv4/netfilter/*) 等
sound:与音效有关的各项模块


/lib/modules/$(uname -r)/modules.dep 记录了在内核支持的模块的各项依赖性
利用 depmod 创建 /lib/modules/$(uname -r)/modules.dep
depmod [-Ane]
-A 不加任何参数时,depmod 会主动去分析目前内核的模块,并且重新写入
  /lib/modules/$(unmae -r)/modules.dep 当中。若加入 -A 参数时,则
  depmod 会查找比 modules.dep 内还要新的模块,如果真找到新模块,才
  会更新
-n 不写入 modules.dep,而是将结果输出到屏幕上(standard out)
-e 显示出目前已加载的不可执行的模块名称

若我做好一个网卡驱动程序,文件名为a.ko,如何更新内核依赖性
cp a.ko /lib.modules/$(uname -r)/kernel/drivers/net
depmod

内核模块的查看
lsmod 查看目前内核加载了多少模块

modinfo [-adln] [module_name|filename] 查看某个模块的信息
-a 仅列出作者名称
-d 仅列出 modules 的说明 (description)
-l 仅列出授权 (license)
-n 仅列出该模块的详细路径


modinfo mii


modiinfo a.ko

内核模块的加载与删除
insmod [/full/path/module_name] [parameters] 完全由用户自行加载一个完整文件名的模块,
    并不会主动分析模块依赖性
insmod /lib/modules/$(uname -r)/kernel/fs/cifs/cifs.ko
lsmod | grep cifs


rmmod [-fw] module_name
-f 强制将该模块删除掉,不论是否正被使用
-w 若该模块正被使用,则 rmmod 会等待该模块被使用完毕后才删除它

rmmod cifs

insmod /lib/modules/$(uname -r)/kernel/fs/vfat/vfat.ko

modperobe [-lcfr] module_name
-c 列出目前系统所有的模块!(更详细的代号对应表)
-l 列出目前在 /lib/modules/`uname -r`/kernel 当中的所有模块完整文件名
-f 强制加载该模块
-r 类似 rmmod,就是删除某个模块

modprobe cifs (加载 cifs 模块)

modprobe -r cifs (删除 cifs 模块)


modprobe vfat
lsmod | grep vfat
modprobe -r vfat 


内核模块的额外参数设置:/etc/modprobe.conf
vim /etc/modprobe.conf
alias eth0 ne
alias eth1 ne
options eth0 io=0x300 irq=5
options eth1 io=0x320 irq=7


Boot Loader:Grub
boot loader 的两个 stage
Stage 1:执行boot loader 主程序
Stsge 2:主程序家在配置文件 (/boot/grub/menu.list)
grub 的配置文件 /boot/grub/menu.lst 与菜单类型
硬盘与分区在 grub 中的代号
硬盘代号以小括号 () 括起来
硬盘以 hd 表示,后面会接一组数字
以“查找顺序”作为硬盘的编号,而不是依照硬盘扁平电缆的排序!(重要)
第一个查找到的硬盘为0号,依序类推


/boot/grub/menu.lst 配置文件
vim /boot/grub/menu.lst
default=0 <==默认启动选项,使用第1个启动菜单 (title)
timeout=5 <==若 5 秒内未动键盘,使用默认菜单启动
splashimage=(hd0,0)/grub/splash.xpm.gz <==后台图示所在的文件
hiddenmenu <==读秒期间是否显示出完整的菜单界面(默认隐藏)
title CentOS (2.6.18-92.e15) <==第一个菜单的内容
     root (hd0,0) (内核放置的那个分区)
     kernel /vmlinuz-2.6.18-92.el5 ro root=LABEL=/1 rhgb quiet
     initrd /initrd-2.6.18-92.e15.img


直接指定内核启动
root (hd0,0) (内核放置的那个分区)
kernel /vmlinuz-2.6.18-92.e15 ro root=LABEL/1 RHGG
initrd /initrd-2.6.18-92.e15.img


kernel (hd0,0)/vmlinuz-2.6.18-92.e15 ro root=LABEL=/1 rhgb quiet
initrd (hd0,0)/initrd-2.6.18.92.e15.img


利用 chain loader 的方式转交控制权
title Windows partition
root (hd0,0) <==设置使用此分区
chainloader +1 <== +1 可以想成第一个扇区,即是 boot sector


title Windows partition
rootnoverify (hd0,0) <== 不检验此分区
chainloader +1
makeactive <== 设置此分区为活动的 (active)

title Windows partition
hide (hd0,4) <== 隐藏 (hd0,4) 这个分区
rootnoverify (hd0,0)
chainloader +1
makeactive


initrd 的重要性与创建新 initrd 文件
内核模块放置于 /lib/modules/$(uname -r)/kernel/ 当中,这些模块必须要根目录 (/) 被挂载时才
能够被读取。但是如果内核本身不具备磁盘的驱动程序时,当然无法挂载根目录,也就没有办法取得
驱动程序,因此造成两难的地步。


initrd 内所包含的模块大多是与启动过程有关,而主要以文件系统及硬盘模块 (如 usb、SCSI等)为主的。


一般来说,需要 initrd 的时刻为:
根目录所在磁盘为 SATA、USB 或 SCSI 等连接接口
根目录所在文件系统为 LVM、RAID 等特殊格式
根目录所在文件系统为非传统 Linux “认识”的文件系统时
其他必须要在内核加载时提供的模块


SATA 硬盘流行起来后,没有 initrd 就没办法启动了,因为 SATA 硬盘使用的是 SCSI 模块来驱动的,而
Linux 默认将 SCSI 功能编译成为模块

mkinitrd [-v] [--with=模块名称] initrd 文件名 内核版本
-v 显示 mkinitrd 的运行过程
--with=模块名称 模块名称指的是模块的名字而已,不需要填写文件名。举例来说,目前内核版
本的 ext3 文件系统模块为下面的文件名:
/lib/modules/$(uname -r)/kernul/fs/ext3/ext3.ko
那你应该要写成“--with=ext3”就好了 (省略.ko)
initrd文件名 你所要创建的 initrd 文件名,尽量取有意义又好记的名字
内核版本 某一个内核的版本,如果是目前的内核则是“$(uname -r)”


mkinitrd -v initrd_$(uname -r) $(uname -r)
ll initrd*
mkinitrd -v --with=8139too initrd_vbirdtest $(uname -r)


测试与安装 grub
grub-install [--root=directory=DIR] INSTALL_DEVICE
-root-directory=DIR 那个 DIR 为实际的目录,使用 grub-install 默认会将 grub 所有的文件都
   复制到 /boot/grub/*,如果想要复制到其他目录与设备中,就得要用 INSTALL
   DEVICE 这个参数
INSTALL DEVICE  安装的设备代号

grub-install /dev/hda (将 grub 安装在目前系统的 MBR 下面,即 /dev/hda)
grub-install --root-directory=/home /dev/hda3 (将 grub 安装到 /dev/hda3 (boot sector))
ll /home/boot/grub/


grub-install 是安装 grub 相关的文件(例如文件系统定义文件)到你的设备上面去等待在启动时被读取,但还
需要设置好配置文件(menu.lst)后,再以 grub shell 来安装 grub 主程序到 MBR 或者是 boot sector 上面去。


grub
# 先设置一下含有 grub 目录的那个分区
root (hd0,0)
find /boot/grub/stage1 (查找一下是否存在 stage1 这个信息文件)
find /grub/stage1 (因为 /boot/ 是独立的)
find /boot/vmlinuz-2.6.18-92.e15 (查找一下是否可以找到内核 /boot/vmlinuz-2.6.18-92.e15)
find /vmlinuz-2.6.18-92.e15 (因为 /boot/ 是独立的)
setup (hd0) (将主程序安装到 MBR 看看)
setup (hd0,0) (将主程序安装到 boot sector)
quit


总结:
1.如果是从其他 boot loader 转成 grub 时,得先使用 grub-install 安装 grub 配置文件
2.开始编辑 menu.lst 这个重要的配置文件
3.通过 grub 来讲主程序安装到系统中,如 MBR 的 (hd0) 或 boot sector 的 (hd0,0) 等




启动前的额外功能修改

关于内核功能当中的 vga 设置
grep 'FRAMEBUFFER_CONSOLE' /boot/config-2.6.18-92.e15
CONFIG_FRAMEBUFFER_CONSOLE=y (等于 y 就是支持)


vim /boot/grub/menu.lst


BIOS 无法读取大硬盘的问题
当进入 Linux 内核功能后,它会主动再去检测一下整个系统,因此 BIOS 识别不到的硬件在 Linux 内核
反而可能会可以捉到而正常使用。


由于 BIOS 至少可以读到大磁盘的 1024 柱面的数据,因此就能够读取内核与虚拟文件系统的文件,所以,
新建 /boot 独立分区,并将 /boot 放置到最前面就可以解决 BIOS 无法读取大容量磁盘内的 kernel 与
initrd 文件的问题。


为某个菜单加上密码
grub-md5-crypt
Password: <== 输入密码
Retype password: <== 再输入一次
$1$kv1IO/$byrbNgkt/.REKPQdfg287 <==这就是产生的 md5 密码


vim /boot/grub/menu.lst
title CentOS (2.6.18-92.e15)
password --md5 $1$kv1IO/$byrbNgkt/.REKPQdfg287



vim /boot/grub/menu.lst
password --md5 $1$kv1IO/$byrbNgkt/.REKPQdfg287
title CentOS (2.6.18-92.e15)
lock


启动过程的问题解决
忘记 root 密码的解决之道
1.重新启动
2.启动进入 grub 菜单后,在你要进入的菜单上面点'e'进入详细设置;将光标移动到 kernel 上方并点'e'
 进入编辑界面;然后出现如下界面来处理:
 grub edit> kernel /vmlinuz-2.6.18-92.e15 ro root=LABEL=/ rhgb quiet single
 按下[enter]再按下 b 就能够启动进入单用户维护模式了
3.进入单用户维护模式后,系统会以 root 的权限直接给你一个 shell,此时你就能够执行“password”
 命令来重建 root 的密码。然后直接执行 “init5"就可以成为

init 配置文件错误
grube edit> kernel /vmlinuz-2.6.18-92.e15 ro root=LABEL=/ rhgb quiet init=/bin/bash
因为我们指定了内核调用的第一个进程(init)变成 /bin/bash,因此 /sbin/init 就不会被执行。又根据
启动流程的说明,我们知道此时虽然可以利用 root 取得 bash 来工作,但此时除了根目录外,其他的目录
都没有被挂载;根目录被挂载成为只读状态。因此我们要执行 mount -0 remount,rw / 来讲根目录挂在成为
可读写,然后再执行 mount -a 根据 /etc/fstab 的内容重新挂在文件系统。然后修改 /etc/inittab 配置
文件后 reboot 重启。


BIOS 磁盘对应的问题 (device.map)
通过 /boot/grub/device.map 这个文件写死每个设备对 grub 磁盘代号的对应关系


cat /boot/grub/device.map
(fd0) /dev/fd0
(hd0) /dev/hda


grub-install --recheck /dev/hda1 (主动更新 device.map)


因文件系统错误而无法启动
/etc/fstab 文件编辑错误:mount -o remount,rw / 将根目录挂载成可读写后继续编辑
扇区错乱:fsck 出错的文件系统


利用 chroot 切换到另一块硬盘工作
1.用尽任何方法进入一个完整的 Linux 系统 (run level 3 或 run level 5)
2.假设有问题的 Linux 磁盘在 /dev/hdb1 上面,且它整个系统的排列是:
挂载点 设备文件名
    //dev/hdb1
/var /dev/hdb2
/home /dev/hdb3
/usr /dev/hdb5


 若如此的话,那么在我目前的这个 Linux 下面,我可以新建一个目录,然后可以这样做:
挂载点 设备文件名
/chroot/ /dev/hdb1
/chroot/var/ /dev/hdb2
/chroot/home/ /dev/hdb3
/chroot/usr/ /dev/hdb5
5.全部挂载完毕后,再输入”chroot /chrrot”,你就会发现,跟目录 (/) 变成那个 /dev/hdb1 的环境了。
0 0