Linux系统启动流程

0. 启动流程一览

  • 1.加载BIOS的硬件信息与进行自我测试, 并依据设置取得第一个可启动的设备(1st device)
  • 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进程, 最后等待用户登录
# rhgb = redhat graphical boot - This is a GUI mode booting screen with most of the 
# information hidden while the user sees a rotating activity icon spining and brief 
# information as to what the computer is doing.

# quiet = hides the majority of boot messages before rhgb starts. These are supposed 
# to make the common user more comfortable. They get alarmed about seeing the kernel # and initializing messages, so they hide them for their comfort.

1. BIOS, boot loader与kernel加载

1. BIOS, 开机自我检测与MBR

BIOS --CMOS(取得硬件配置信息)--> 开机自检(Power-on Self Test, POST) --> 执行硬件检测初始化并配置PnP设备(Plug and Play, 即插即用设备) --> 定义可启动的设备顺序 --> 启动设备的读取(MBR相关任务的开始)

由于不同的操作系统的文件系统格式不同, 必须要以对应的boot loader处理内核文件的加载问题

2. BOOT Loader的功能

系统的MBR只有一个, 如何同时在一部主机上安装Windows与Linux呢?

每个操作系统都默认安装一套boot loader到它自己的文件系统中, 而linux在系统安装时, 你可以选择将boot loader安装到MBR中, 也可以选择不安装, 至于windows默认会主动将MBR与boot sector都装上一份boot loader

boot loader提供的主要功能如下:

  • 1.提供菜单

  • 2.加载内核文件

  • 3.转交其他loader

    由于windows的loader默认不具有控制权转交功能, 因此你不能使用windows的loader来加载linux的loader

BIOS无法读取大容量硬盘 (内的kernel与initrd文件) 的问题:

系统使用DVD启动安装时, 可以顺利安装Linux, 但是第一次启动时, 屏幕出现一片黑, 且出现grub>的字样, 而无法进入Linux系统中, 这是什么问题?

  • 使用DVD或CD启动时, 加载内核不是问题, 而内核回去检测系统硬件, 因此可以识别BIOS识别不到的硬盘, 故你确实可以在大容量硬盘上安装Linux且不出现问题
  • 但是进入硬盘启动时, 由于kernel与initrd文件都是通过BIOS的INT 13通道读取的, 因此你的kernel与initrd若放置在BIOS无法读取到的扇区当中, 系统当然无法加载

如何解决?

  • 将kernel与initrd文件放在大硬盘的最前面, 由于BIOS至少可以读取到大磁盘的1024柱面的数据, 股就能读取内核与虚拟文件系统的文件
  • 那么怎么做呢? 新建/boot独立分区, 并将/boot放置到最前面即可

3. 加载内核与检测硬件与initrd的功能

通过boot loader的管理而开始读取内核文件后, linux会将该内核解压到内存中, 利用内核的功能, 重新检测一次硬件, 而不一定会用BIOS检测到的硬件信息, 也就是说, 内核此时才开始接管BIOS后的工作

内核文件路径: /boot/vmlinuz

ls --format=single-column -F /boot
aquota.group
aquota.user
config-2.6.32-642.el6.x86_64    #此版本内核被编译时选择的功能与模块配置文件
efi/
grub/    #引导装载程序grub相关数据目录
initramfs-2.6.32-642.el6.x86_64.img
initrd-2.6.32-642.el6.x86_64kdump.img    #虚拟文件系统文件
lost+found/
symvers-2.6.32-642.el6.x86_64.gz
System.map-2.6.32-642.el6.x86_64
vmlinuz-2.6.32-642.el6.x86_64*    #内核文件, 非常重要!!!

linux内核是可以动态加载内核模块的, 由于模块放置在磁盘根目录内(要记得 /lib 与 / 必须放在同一分区), 启动过程中内核必须挂载根目录, 才能读取内核模块提供加载驱动的功能

USB, SATA, SCSI等磁盘设备的驱动程序通常以模块的方式存在

现在思考一种情况, 假设你的linux安装自SATA硬盘上, 你可以通过BIOS的INT13取得boot loader与kernel文件来启动, 然后kernel会开始接管系统, 检测硬件并尝试挂载根目录来取得额外的驱动程序, 问题是: 内核根本不认识SATA磁盘, 所以需要加载SATA磁盘的驱动程序, 否则无法挂载根目录, 但是SATA的驱动程序在/lib/modules内, 你根本无法挂载根目录, 又怎么读取到/lib/modules内的驱动程序呢?

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

是否没有initrd就无法顺利启动?
不见得, 最需要initrd的原因, 当启动时无法挂载根目录的情况下, 此时就一定需要initrd, 例如你的根目录在特殊的磁盘接口(USB, SATA, SCSI), 或者你的文件系统较为特殊(LVM, RAID等), 才会需要initrd

2. 第一个进程init及配置文件/etc/inittab与runlevel

内核硬件检测完毕与驱动程序加载后, 此时你的主机硬件以准备就绪(ready), 此时内核会主动调用第一个进程: /sbin/init, 它最主要的功能就是准备软件执行的环境, 包括系统的主机名, 网络设置, 语系处理, 文件系统格式以及其他服务的启动等, 而所有的操作都会通过init的配置文件/etc/inttab来规划, 其中一个很重要的设置选项, runlevel, (启动执行等级)

  • runlevel: 执行等级, linux通过设置runlevel来规定系统启动不同的服务

    0 - halt (关机)

    1 - singer user mode (单用户维护模式)

    2 - multi-user, without NFS (类似runlevel3, 无NFS服务)

    3 - full-multi-user mode (完整含有网络功能的纯文本模式)

    4 - unused (系统保留功能)

    5 - X11(与runlevel类似, 加载使用X window)

    6 - (重启)

    注: 不可将默认设置为0, 4, 6这三个值, 否则系统会不断的关机或重启

    ​ 不正常关机造成文件系统的不一致现象时, 系统会主动进入单用户维护模式

#inittab的内容与语法
vi /etc/inittab
id:5:initdefault:    #默认的runlevel设置, 此时runlevel为5
si::sysinit:/etc/rc.d/rc.sysinit    #准备系统软件执行的环境的脚本执行文件
#7个不同的runlevel, 需要启动的服务的script放置路径:
10:0:wait:/etc/rc.d/rc 0
11:1:wait:/etc/rc.d/rc 1
12:2:wait:/etc/rc.d/rc 2
13:3:wait:/etc/rc.d/rc 3
14:4:wait:/etc/rc.d/rc 4
15:5:wait:/etc/rc.d/rc 5
16:6:wait:/etc/rc.d/rc 6
#是否允许按下 [ctrl] + [alt] + [del] 就重新启动的设置选项:
ca::ctrlaltdel:/sbin/shutdown -t 3 -r now
#tty1-tty6是由这六行决定的:
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
#X window是由这行决定的:
x:5:respawn:/etc/X11/prefdm -nodaemon

[设置选项]:[runlevel]:[init的操作行为]:[命令选项]
1.设置选项: 最多四个字符, 只是一个简单的说明
2.runlevel: 如果是35则表示runlevel 3/5都会执行
3.操作行为: 如下表
4.命令选项: 可进行的命令, 通常是一些script
inittab设置值 意义说明
initdefault 默认的runlevel设置值
sysinit 系统初始化的操作选项
ctrlaltdel 代表cril+alt+del三个按键是否可以重启的设置
wait 后面字段设置的命令项目必须要执行完毕才能继续下面的其他操作
respawn 后面字段的命令可以无限再生, 例如: tty1的mingetty产生的登录界面, 在你注销后, 系统会再开一个新的可登陆界面等待下一个登录

3. init处理系统初始化流程(/etc/rc.d/rc.sysinit)

开始各项系统服务之前, 先得设置好整个系统环境, 主要利用的就是/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.用户自定义模块的加载: /etc/sysconfig/modules/*.modules
  • 10.加载内核的相关设置: 系统会主动读取/etc/sysctl.conf的设置值, 使内核成为我们想要的样子
  • 11.设置主机名与初始化电源管理模块(ACPI)
  • 12.初始化软件磁盘阵列: 主要通过/etc/mdadm.conf来设置
  • 13.初始化LVM的文件系统设置
  • 14.以fsck检验磁盘文件系统: 会进行filesystem check
  • 15.进行磁盘配额quota的转换(非必要)
  • 16.重新以可读写模式挂挂载系统磁盘
  • 17.启动quota功能: 所以我们不需要自定义quotaon的操作
  • 18.启动系统的伪随机数生成器(pseudo-random)
  • 19.清除启动过程中的临时文件
  • 20.将启动相关信息加载/var/log/dmesg文件

4. 启动系统服务与相关启动配置文件(/etc/rc.d/rc N & /etc/sysconfig)

经过/etc/rc.d/rc.sysinit的系统模块与相关硬件信息的初始化后, 你的CenOS系统应该已经顺利工作了, 只是, 我们还得要启动系统所需要的各项服务啊!

那么各个不同的runlevel服务启动的的各个shell script放在哪?在/etc/inittab中提到的:

10:0:wait:/etc/rc.d/rc 0
11:1:wait:/etc/rc.d/rc 1
12:2:wait:/etc/rc.d/rc 2
13:3:wait:/etc/rc.d/rc 3
14:4:wait:/etc/rc.d/rc 4
15:5:wait:/etc/rc.d/rc 5    #本例中, 以此选项来解释
16:6:wait:/etc/rc.d/rc 6
  • 通过外部第一号参数($1)来取得想要执行的脚本目录, 即由/etc/rc.d/rc 5可以取得/etc/rc.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/去, super daemon与stand alone的服务主要是以/etc/init.d/服务文件名{start,stop}来启动与关闭的, 也就是说, 如果你有想要启动改runlevel是就执行的服务, 那么利用S??并指向/etc/init.d/的特定服务启动脚本后, 该服务就会在启动时启动, chkconfig就是在负责处理这个连接文件, S或K后面的数字, 代表执行的顺序, 数字越小越先被执行*

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

/etc/rc.d/rc.local这个文件可以在启动时执行你自己想要执行的系统命令

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

在完成了系统所有服务的启动后, 接下来Linux就会启动终端机或者是X Window来等待用户登录, 实际参考/etc/inittab内这一段:

#tty1-tty6是由这六行决定的:
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
#X window是由这行决定的:
x:5:respawn:/etc/X11/prefdm -nodaemon

7. 启动过程中会用到的主要配置文件

/sbin/init的运行过程中有许多执行脚本, 包括/etc/rc.d/rc.sysinit以及/etc/rc.d/rc等, 这些脚本都会使用到相当多的系统配置文件, 这些启动过程中的配置文件大多放在/etc/sysconfig/目录下, 同时, 由于内核还需要加在一些驱动程序(内核模块), 此时系统自定义的设备与模块对应文件(/etc/modprobe.conf)就显得相当重要了

  • 关于模块: /etc/modprobe.conf

    某些条件下我们还是得对模块进行一些参数的规划, 此时就得用到/etc/modprobe.conf

cat /etc/modprobe.conf
alias eth0 8139too    #让eth0使用8139too的模块
alias scsi_hostadapter pata_sis
options snd-card-0 index=0    #额外指定snd-card-0的参数功能
options snd-trident index=0

这个文件大多在于制定系统内硬件所使用的模块, 这个文件通常是系统自行产生的, 一般不需要手动处理, 不过如果系统检测到错误的驱动程序, 或者你想要使用更新的驱动程序来对应相关的硬件设备时, 就要自行手动处理一下这个文件了

  • /etc/sysconfig/*, 总而言之, 这个文件很重要, 启动过程中经常会被读取到

    • authconfig

      主要设置用户的身份认证的机制, 包括是否使用本机的/etc/passwd, /etc/shadow等, 以及/etc/shadow密码记录使用何种加密算法, 还有是否使用外部密码服务器提供的账号验证(NIS, LDAP)等, 系统默认使用md5加密算法, 并且不使用外部的身份验证机制

    • clock

      用于设置Linux主机的时区, 在clock文件内的设置选项“ZONE”所参考的时区位于/usr/share/zoneinfo/目录下的相对路径中, 而且要修改时区的话, 还得将/usr/share/zoneinfo/Asia/Shanghai这个文件复制成为/etc/localtime才行

    • i18n

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

    • keyboard & mouse

      设置键盘与鼠标的形式

    • network

      设置是否要启动网络, 以及设置主机名还有网关

    • network-scripts/

      主要用于设置网卡

8. Run level的切换

与runlevel有关的启动其实是在/etc/rc.d/rc.sysinit执行完毕之后

#如何知道当前的runlevel?
runlevel
N 5    #左边带前一个runlevel, 右边代表目前的runlevel, 若之前没有切换过, 则前一个不存在(N)
#将目前的runlevel切换为3(注意: tty7的数据会消失)
init 3

内核与内核模块

内核一般都是压缩文件, 因此在内核使用之前, 就得要将它解压后才能加载到内存当中

目前内核都是具有可读取模块化驱动程序的功能, 即所谓的“modules(模块化)”功能, 所谓的模块化可以将它想象成是一个“插件” (插件: 可以增加或增强软件功能的辅助性程序)

内核与内核模块放在哪里呢?

  • 内核: /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/

问题来了: 如果我有个新硬件, 偏偏我的操作系统不支持, 该怎么办?

  • 1.重新编译内核, 并加入最新的硬件驱动程序源码
  • 2.将该硬件的驱动程序编译成模块, 在启动时加载该模块

如果想要加载一个已存在的模块时, 该如何是好?

1. 内核模块与依赖性

要处理内核模块, 首先要了解内核提供的模块之间的相关性

/lib/modules/$(uname -r)/kernel/中, 还分为几个目录:
arch    #与硬件平台有关的选项, 例如CPU的等级等
crypto    #内核所支持的加密技术, 例如md5或者des等
drivers    #一些硬件的驱动程序, 例如显卡, 网卡, PCI相关硬件等
fs    #内核所支持的文件系统, 如vfat, reiserfs, nfs等
lib    #一些函数库
net    #与网络有关的各项协议数据, 还有防火墙模块(net/ipv4/netfilter/*)等
sound    #与音效有关的各项模块

如果我们要一个个检查这些模块的主要信息, 然后定义出它们的依赖性, 我们可能会疯掉, linu已经提供一些模块依赖性的解决方案, 那就是检查/lib/modules/$(uname -r)/kernel/modules.dep这个文件, 它记录了内核支持的模块的各项依赖性

#那么这个文件如何创建呢? depmod - program to generate modules.dep and map.files
depmod [-Ane]
-A : --quick, 不加任何参数时, depmod会主动分析目前内核的模块, 并且重新写入/lib/modules/$(uname -r)/kernel/modules.dep当中, 若加入-A选项, 则depmod会查找比modules.dep内还新的模块, 如果真找到新模块, 才会更新
-n : --dry-run, 不写入modules.dep, 而是将结果输出到屏幕上
-e : --errsyms, 显示出目前已加载的不可执行的模块名称

#实例: 若我做好一个网卡驱动程序, 文件名为a.ko, 该如何更新内核依赖性?
cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net
depmod
#注: 内核模块扩张名一定是 .ko 结尾的

2. 内核模块的查看

#查看目前系统加载了多少模块以及模块间的依赖关系?
lsmod - program to show the status of modules in the linux kernel
Module                  Size  Used by
模块名称             模块的大小  此模块是否被其他模块所使用
autofs4                27000  3 
target_core_file        9174  0 
target_core_iblock,target_core_file,target_core_pscsi
configfs               29378  2 target_core_mod

#如何查看每个模块的详细信息或者自己的模块信息?
modinfo - program to show infotmation about a linux kernel module
modinfo [module_name|filename]

3. 内核模块的加载与删除

#modprobe会主动去查找modules.dep的内容, 先克服模块的依赖性之后, 再决定需要加载的模块有哪些
modprobe [-lcfr] module_name
  -l : 列出目前在/lib/modules/$(uname -r)/kernel/中的所有模块的完整文件名
  -c : 列出目前系统的所有模块(更详细的代号对应表), 类似/etc/modprobe.conf
* -f : 强制加载该模块
* -r : 删除某个模块

#实例1: 加载cifs模块
modprobe cifs #不需要完整的模块文件名, 因为完整的模块文件名已记录到/lib/modules/$(uname -r)/modules.dep这个文件中, 若要删除, 执行如下命令:
modprobe -r cifs
#实例2: 加载vfat这个模块, 并查看该模块的相关模块是哪个?
modprobe vfat
lsmod | grep vfat
modprobe -r vfat

4. 内核模块的额外参数设置: /etc/modprobe.conf

假设我的网卡eth0使用ne, 但是eth1同样也使用ne, 为了避免同一个模块导致网卡的错乱, 因此先找到eth0与eth1的I/O与IRQ, 假设:

  • eth0: I/O (0x300)且IRQ=5
  • eth1: I/O (0x320)且IRQ=7
#则:
vi /etc/modprobe.conf
alias eth0 ne
alias eth1 ne
options eth0 io=0x300 irq=5
options eth1 io=0x320 irq=7
#如此一来, linux就不会捕获错网卡的对应了, 因为已经强制指定某个I/O了

Boot Loader: Grub

1. boot loader的两个stage

  • Stage1: 执行boot loader主程序

    主程序必须要被安装在启动区, 即MBR或boot sector(但因为MBR时整个硬盘的第一个sector内的一个块, 整个大小也才446bytes), 故MBR或boot sector通常仅安装boot loader的最小主程序, 不安装相关配置文件

  • Stage2: 主程序加载配置文件

    第二阶段为通过boot loader加载所有配置文件与相关的环境参数文件(包括文件系统定义与主要配置文件menu.lst), 配置文件都放在/boot/grub下

ls -l /boot/grub
-rw-r--r--. 1 root root     45 Sep 11 09:46 device.map #grub的设备对应文件
-rw-r--r--. 1 root root     63 Jul  4 15:49 device.map.backup
-rw-r--r--. 1 root root  13428 Sep 11 09:46 e2fs_stage1_5 #ext2/3文件系统的定义文件
-rw-r--r--. 1 root root  12636 Sep 11 09:46 fat_stage1_5
-rw-r--r--. 1 root root  11780 Sep 11 09:46 ffs_stage1_5
-rw-------. 1 root root   1717 Sep 11 16:55 grub.conf #grub在Red Hat中的配置文件
-rw-r--r--. 1 root root  11772 Sep 11 09:46 iso9660_stage1_5
-rw-r--r--. 1 root root  13284 Sep 11 09:46 jfs_stage1_5
lrwxrwxrwx. 1 root root     11 Jul  4 15:49 menu.lst -> ./grub.conf #此文件很重要!!!
-rw-r--r--. 1 root root  11972 Sep 11 09:46 minix_stage1_5
-rw-r--r--. 1 root root  14428 Sep 11 09:46 reiserfs_stage1_5
-rw-r--r--. 1 root root   1341 May  7  2010 splash.xpm.gz #启动时在grub下的后台图示
-rw-r--r--. 1 root root    512 Sep 11 09:46 stage1 #stage1的相关说明
-rw-r--r--. 1 root root 126148 Sep 11 09:46 stage2 #stage2的相关说明
-rw-r--r--. 1 root root  12040 Sep 11 09:46 ufs2_stage1_5
-rw-r--r--. 1 root root  11380 Sep 11 09:46 vstafs_stage1_5
-rw-r--r--. 1 root root  13980 Sep 11 09:46 xfs_stage1_5

我们的loader读取了这种文件系统定义数据后, 就能认识文件系统并读取该文件系统的内核文件

2. grub的配置文件/boot/grub/menu.lst与菜单类型

grub的优点:

  • 1.认识和支持较多的文件系统
  • 2.启动时可以自行编辑和修改设置选项
  • 3.动态查找配置文件, 而不需要在修改配置文件后重新安装grub, 我们只要修改/boot/grub/menu.lst里头的设置, 下次启动后就生效了

硬盘与分区在grub中的代号

  • grub到底是如何认识硬盘呢? 它对硬盘的识别使用如下代号:
  • (hd0,0)
  • 1.硬盘代号以小括号( )括起来
  • 2.任何硬盘均以hd表示, 后面接一组数字
  • 3.以“查找顺序”作为硬盘的编号, 而不是硬盘扁平电缆的排序(这个重要!)
  • 4.第一个查找的硬盘为0, 第二个为1, 以此类推
  • 5.每块硬盘的第一个分区为0, 依序类推
硬盘查找顺序 在Grub当中的代号
第一块 (hd0), (hd0,0), (hd0,1), (hd0,4) ...
第二块 (hd1), (hd1,0), (hd1,1), (hd1,4) ...
  • /boot/grub/menu.lst配置文件
vi /boot/grub/menu.lst
#先是整体设置:
[password --md5 经grub-md5-crypt加密后的密文]    #password放在此处不会被破解
default=0    #默认启动选项, 使用第一个菜单启动
timeout=5    #若5秒内未动键盘, 使用默认菜单启动
splashimage=(hd0,0)/grub/splash.xpm.gz    #后台图示所在的文件
hiddenmenu    #读秒期间是否显示出完整的菜单界面(默认隐藏)

#直接指定内核启动
title Red Hat Enterprise Linux 6 (2.6.32-642.el6.x86_64)
    [lock]    #多了死锁的功能
    [password --md5 经grub-md5-crypt加密后的密文]    #password放在此处可以被破解
    [rootnoverify (hd0,0)]    #不检验此分区
    root (hd0,0)    #代表内核文件放在哪个分区, 而不是根目录
    [hide (hd0,4)]    #隐藏(hd0,4)这个分区
    [makeactive]    #设置此分区为活动的(active)
    [chainloader +1]    #利用chainloader的方式转交控制权
    kernel /vmlinuz-2.6.32-642.el6.x86_64 ro root=/dev/mapper/vg_linuxofalex-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_LVM_LV=vg_linuxofalex/lv_root rd_NO_MD rd_LVM_LV=vg_linuxofalex/lv_swap SYSFONT=latarcyrheb-sun16  KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb vga=790 [single|1]
    #kernel后接的是内核的文件名, 而文件名后接的是内核的参数
    #由于启动过程中要挂载根目录, 因此kernel后面接的那个root=/dev/mapper/vg_linuxofalex-lv_root指的是linux的根目录在哪个分区, 可以使用LABEL来挂载根目录
    #至于rhgb为色彩显示而quiet则是安静模式(屏幕不会输出内核监测信息)
    initrd /initramfs-2.6.32-642.el6.x86_64.img
    #initrd: 就是前面提到的initrd制作出的RAM Disk的文件名
    
#实例1: 我的系统分区是/dev/hda1(/), /dev/hd2(swap), 且我的内核文件为/boot/vmlinuz, 请问grub的menu.lst内该如何编写内核文件位置?
title Linux $(uname -r)
    root (hd0,0)
    kernel (hd0,0)/boot/vmlinuz ro root=/dev/hda1/ rhgb quiet #root=LABEL=/1
    initrd (hd0,0)/boot/initrd.$(uname -r)
    #注: 此处的/boot为(hd0,0)内根目录下的一个目录
    
#实例2: 同上, 只是我的分区情况变成了/dev/sda1(/boot), /dev/sda5(/)时呢?
title Linux $(uname -r)
    root (hd0,0)
    kernel (hd0,0)/vmlinuz
    initrd (hd0,0)/initrd.$(uname -r)
    #注: 此处的/boot为在(hd0,0)内独立的一个分区
    
#如何重新读取MBR内的配置文件?
title Linux $(uname -r)
    root (hd0) #MBR为整块磁盘的第一个扇区, 故用整块磁盘的代号
    ...

3. initrd的重要性与创建新的initrd文件

initrd的目的: 提供启动过程中最需要的内核模块

需要initrd的时刻:

  • 1.根目录所在的磁盘为SATA, SCSI, USB等特殊接口
  • 2.根目录所在文件系统为LVM, RAID等特殊格式
  • 3.根目录所在的文件系统为非传统linux“认识”的文件系统
  • 4.其他必须在内核加载时提供的模块
#如果你有特殊需求而想重置initrd文件的话?
mkinitrd [-v] [--with=新加入的模块名称] init文件名 内核版本
-v : 显示mkinitrd的运行过程
--with=新加入的模块名称 : 模块名称指的是模块的名字而已, 不需要填写绝对路径的文件名, 例如: 目前内核版本的ext3文件系统模块下的文件名: /lib/modules/$(uname -r)/kernel/fs/ext3/ext3.ko 那你只要写成"--with=ext3"就好了, (省略.ko)
initrd文件名 : 你所需要创建的initrd文件的文件名
内核版本 : 某一个内核版本, 若是目前的内核版本则是"$(uname -r)"

#实例: 以mkinitrd的默认功能创建一个initrd的虚拟文件系统
mkinitrd -v initrd_$(uname -r) $(uname -r)
#实例二: 增加8139too这个模块的initrd文件
mkinitrd -v --with=8139too initrd_$(uname -r) $(uname -r)

initrd创建完成之后, 同时内核也处理完毕, 我们就可以使用grub新建菜单了

4. 测试与安装grub

若你的linux原来使用的并非grub, 现再你希望使用grub, 该如何安装它呢?

1. 利用grub-install安装配置文件

grub-install [--root-directory=DIR] INSTALL_DEVICE
--root-directory=DIR : 那个DIR为实际的绝对路劲目录, 使用grub-install默认将grub的所有文件都复制到/boot/grub/内, 如果想要复制到其他目录与设备中, 就需要指定
INSTALL_DEVICE : 安装的设备代号

#实例1: 将grub安装在目录系统的MBR下, 我的系统为/dev/sda
grub-install /dev/sda #默认安装路径/boot/grub下的所有目录的时间会被更新, 因为我们重装了

#实例2: 我的/home为独立的/dev/sdb3, 如何安装grub到/dev/sdb3 (boot sector)
grub-install --root-directory=/home /dev/sdb3
#会自动帮你生成/boot/grub/目录与文件, 但是要注意, 我们没有menu.lst这个配置文件, 这个文件需要自己手动创建

2. 将grub主程序安装到boot sector或MBR

想要将grub的主程序再次安装到/dev/sdb1的boot sector或MBR上, 需要使用grub shell

  • 1.用root (hdx,x)c选择含有grub目录的那个分区代号
  • 2.用find /boot/grub/stage1看看能否找到那个安装信息文件
  • 3.用find /boot/vmlinuz看看能否在到内核文件(不一定要成功)
  • 4.用setup (hdx,x)setup (hdx)将grub安装到boot sector或MBR中
  • 5.用quit离开grub shell
grub #进入grub shell
#1. 先设置一下那个含有grub目录的那个分区
grub>root (hd0,0)
Filesystem type is ext2fs, partition type 0x83 #此处可以发现grub能够识别文件系统

#2. 查找一下是否存在stage1这个配置文件
grub>find /boot/grub/stage1
(hd0,2)    
#怎么会只有一个, 我们明明有/boot/grub/与/home/boot/grub/啊?
#因为/boot是独立的, 因此找到该文件就得用一下的方式:
grub>find /grub/stage1
(hd0,0)
#要特别注意grub找到的不是目录树, 而是设备内的文件

#3. 查找是否可以找到内核文件/boot/vmlinuz-2.6.18-92.el5 (非必要)
grub>find /boot/vmlinuz-2.6.18-92.el5
Error 15: File not found
grub>find /vmlinuz-2.6.18-92.el5
(hd0,0)

#4. 将主程序安装到MBR
grub>setup (hd0)

#5. 重复安装到/dev/sda1的boot sector中
grub>setup (hd0,0)

grub>quit

启动过程的问题解决

1. init配置文件错误

单用户模式唯一无法挽救的情况: /etc/inittab这个文件设置错误导致无法启动

因为single mode(runlevel 1)也是要读取/etc/inittab来进行开机的

既然默认的init无法执行, 就告诉内核不要执行init, 改用bash, 在启动进入grub后, 在grub edit下这样做:

grubedit> kernel /vmlinuz-2.6.18-92.el15 ro root=LABEL=/1 rhgb quiet init=/bin/bash

2. BIOS磁盘对应问题

我可否将Windows安装在/dev/sda中而Linux安装在/dev/sdb中, 然后调整BIOS的启动设备顺序, 如此两套系统都安装在各自的MBR中, 这样做非常好, 问题是: grub对磁盘的设备代号使用的是检测到的顺序! 也就是说, 你调整了BIOS磁盘的启动顺序后, 你的menu.lst可能对应到了错误的磁盘上

我们可以通过/boot/grub/device.map这个文件来写死每个设备对grub磁盘代号的对应关系

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

如果你不清楚如何处理的话, 也可以利用grub-install的功能

grub-install --recheck /dev/sdb1    #这样device.map就会主动更新了

3. 因为文件系统错误而无法启动

  • 最容易出错的设置而导致无法顺利启动的步骤通常是/etc/fstab这个文件, 尤其是用户在实践quota时, 最容易写错参数, 又没有经过mount -a来测试挂载, 就立刻启动, 就会出现问题
  • 除了/etc/fstab编辑错误, 如果你曾经不正常关机, 也可能导致文件系统不一致(inconsistent), 也有可能会出现相同的问题, 此时你就应该用fsck检测对应出错的磁盘或分区, 等到系统发现错误, 并出现clear[Y/N]后, 输入Y

4. 利用chroot切换到另一块硬盘工作

chroot - change root directory, 这个命令可以暂时将根目录移到某个目录下, 然后去处理某个问题, 最后再离开该root而回到原本的系统中

chroot更换根目录时要注意以下几点:

  • 1.更换后的目录要有对应的shell

  • 2.要有对应shell的库文件例: ldd $(which bash), 其中库目录的名称也需要注意, lib或lib64

  • 3.其他命令在执行时同样有库的依赖关系

      本文基于<鸟哥的Linux私房菜>, 归纳整理, 在此致谢鸟哥.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,294评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,780评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,001评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,593评论 1 289
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,687评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,679评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,667评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,426评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,872评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,180评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,346评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,019评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,658评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,268评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,495评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,275评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,207评论 2 352

推荐阅读更多精彩内容