一、系统引导流程与 GRUB2
引导链路
BIOS → MBR(启动代码)→ GRUB/GRUB2(bootloader)→ 内核 vmlinuz + initramfs → init/systemd
MBR 中的启动程序加载 GRUB,GRUB 负责加载内核(并向内核传递参数),内核挂载临时根文件系统 initramfs,最后交给 systemd 启动各类服务。
MBR 结构
硬盘的第一个逻辑块(扇区)用于存储 MBR 信息,共 512 字节:
MBR(512) = 启动代码(446) + 分区表(64) + 结束标志(2)
各发行版使用的引导程序
| 发行版 | 引导程序 |
|---|---|
| CentOS 7 | GRUB2 |
| Ubuntu | GRUB |
| Windows | GRUB4DOS |
GRUB 配置文件位置
- CentOS 7(BIOS):
/boot/grub2/grub.cfg - CentOS 7(UEFI):
/boot/efi/EFI/centos/grub.cfg - Ubuntu:
/boot/grub/grub.cfg
GRUB 设备命名
| 表示法 | 含义 |
|---|---|
hd0 |
第一块硬盘 |
hd0,1 |
第一块硬盘的第一个分区(分区号从 1 开始) |
hd0,msdos1 |
第一块硬盘的第一个 MBR 分区 |
hd1,gpt2 |
第二块硬盘的第二个 GPT 分区 |
示例:第一块硬盘第三个分区中 /boot/vmlinuz 的 GRUB 路径为:
(hd0,msdos3)/boot/vmlinuz
常用 GRUB 命令
| 命令 | 作用 |
|---|---|
set |
设置 GRUB 环境变量 |
menuentry |
创建菜单项 |
insmod |
加载 GRUB 模块(如 ntfs、ext2、lvm) |
linux |
指定启动的内核 |
initrd |
指定启动的临时文件系统 |
chainloader |
链式加载其它引导程序 |
boot |
在 GRUB 命令行中启动系统 |
# 设置菜单显示风格
set timeout_style=menu
# 设置等待时间(秒)
set timeout=30
# 设置 GRUB 根分区
set root='hd0,msdos1'
# 设置默认启动项
set default=2
# 创建菜单项
menuentry 'My Menu Options' {
...
}
启动 Linux 的菜单项示例
menuentry 'Ubuntu 16.04.4' {
set root='hd0,msdos1'
linux /boot/vmlinuz-4.4.0-116-generic root=/dev/sda1
initrd /boot/initrd.img-4.4.0-116-generic
}
等价写法(把设备写在路径里):
menuentry 'Ubuntu16.04.4' {
linux (hd0,msdos1)/boot/vmlinuz-4.4.0-116-generic root=/dev/sda1
initrd (hd0,msdos1)/boot/initrd.img-4.4.0-116-generic
}
/boot 分区与关键文件
/boot目录建议放在独立分区中;- 该分区必须是主分区,并且建议使用 ext2 文件系统。
| 文件/目录 | 说明 |
|---|---|
/boot/grub/grub.cfg |
GRUB 配置文件,丢失会进入 grub> 命令行 |
/boot/grub/i386-pc |
GRUB 模块目录,丢失会进入 grub rescue> 命令行 |
/boot/vmlinuz-* |
Linux 内核文件 |
/boot/initrd.img-*、/boot/initramfs-* |
临时文件系统(initramfs) |
二、grub.cfg 与 grub2-mkconfig
自动生成配置
# Ubuntu:自动生成 grub.cfg
sudo update-grub
# CentOS 7(BIOS):自动生成 grub.cfg
grub2-mkconfig -o /boot/grub2/grub.cfg
自定义菜单的持久化(关键注意事项)
直接编辑 /boot/grub2/grub.cfg 虽然立即可用,但运行 grub2-mkconfig(或内核升级触发的自动重建)会重新生成该文件,覆盖所有手动添加的 menuentry 块。
自定义菜单项应写入 /etc/grub.d/40_custom:
# 编辑自定义菜单文件
sudo vim /etc/grub.d/40_custom
在该文件中添加自定义 menuentry 块,每行格式与 grub.cfg 完全一致,例如:
menuentry "Windows 7" {
insmod ntfs
set root=(hd0,1)
chainloader +1
}
- 文件必须保持可执行权限(
-rwxr-xr-x),否则grub2-mkconfig会忽略它; - 修改后执行
grub2-mkconfig -o /boot/grub2/grub.cfg重新生成即可保留自定义菜单。
默认启动项
# 将默认启动项设为菜单中的某个条目(按名称匹配)
grub2-set-default "Windows 7"
# 查看当前保存的默认项
grub2-editenv list
# 查看 GRUB 环境变量文件
cat /boot/grub2/grubenv
需要在 /etc/default/grub 中设置 GRUB_DEFAULT=saved,使系统记住并使用 grub2-set-default 设定的值:
# 编辑 /etc/default/grub,确保包含以下行
GRUB_DEFAULT=saved
/boot/grub2/grubenv 中记录了 saved_entry 等下次启动相关的变量,一般通过 grub2-set-default、grub2-reboot 等命令维护,不建议直接手工编辑:
vim /boot/grub2/grubenv
BIOS 与 UEFI 的路径差异
| 启动模式 | GRUB 配置文件路径 | 对应命令 |
|---|---|---|
| BIOS | /boot/grub2/grub.cfg |
grub2-mkconfig -o /boot/grub2/grub.cfg |
| UEFI | /boot/efi/EFI/centos/grub.cfg |
grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg |
执行
grub2-mkconfig时务必指定正确的输出路径,UEFI 系统下若误写入/boot/grub2/grub.cfg,配置不会生效。
三、CentOS 7 下添加 Windows 7 双系统引导
CentOS 7 使用 GRUB2 作为引导程序。当先安装 Windows 7、再安装 CentOS 7 时,GRUB2 通常会自动识别 Windows;若未识别,可手工添加引导菜单。适用于 CentOS 7 + GRUB2 + Windows 7 双系统环境。
1. 编辑 GRUB2 配置文件
vim /boot/grub2/grub.cfg
在合适位置添加如下菜单项:
menuentry "Windows 7" {
insmod ntfs
set root=(hd0,1)
chainloader +1
}
参数说明:
insmod ntfs:加载 NTFS 模块,使 GRUB 能识别 Windows 分区;hd0代表第一块硬盘;1代表 Windows 7 所在的分区号,根据实际情况修改,例如 Windows 装在第二分区则为(hd0,2);chainloader +1表示将引导权链式转交给该分区的引导扇区(第一个扇区)。
保存退出。
注意:在较新的 GRUB2 实践中,更推荐将自定义菜单写到
/etc/grub.d/40_custom后执行grub2-mkconfig -o /boot/grub2/grub.cfg,避免内核升级或重新生成配置时grub.cfg被覆盖。原教程是直接修改grub.cfg,此处保留作记录。
2. 将 Windows 7 设为默认启动项
grub2-set-default "Windows 7"
3. 检验默认项是否设置成功
grub2-editenv list
输出中 saved_entry 应显示为 Windows 7。
4. 查看/编辑 GRUB2 环境文件
vim /boot/grub2/grubenv
5. 在 GRUB 命令行临时引导 Windows
在 GRUB 菜单界面按 c 进入命令行,手工链式引导 Windows(假设 Windows 在 /dev/sda2):
set root=(hd0,2)
chainloader +1
boot
6. 多系统菜单完整示例
将 Ubuntu/Mint/CentOS 的启动文件统一放在 boot 分区(如 /dev/sda3),通过 GRUB 配置多系统菜单:
- Ubuntu/Mint 使用 GRUB,配置在
(hd0,3)/grub/grub.cfg; - CentOS 7 使用 GRUB2,配置在
(hd0,3)/grub2/grub.cfg。
| 系统 | 配置文件 | 内核文件 |
|---|---|---|
| Ubuntu/Mint | (hd0,3)/grub/grub.cfg |
vmlinuz-4.4.0-116-generic |
| CentOS 7 | (hd0,3)/grub2/grub.cfg |
vmlinuz-3.10.0-862.el7.x86_64 |
在 GRUB 命令行分别启动各系统:
# Ubuntu
linux (hd0,3)/vmlinuz-4.4.0-116-generic root=/dev/sda1 quiet splash
initrd (hd0,3)/initrd.img-4.4.0-116-generic
boot
# Mint
linux (hd0,3)/vmlinuz-4.15.0-20-generic root=/dev/mapper/up-mint quiet splash
initrd (hd0,3)/initrd.img-4.15.0-20-generic
boot
# CentOS 7
linux (hd0,3)/vmlinuz-3.10.0-862.el7.x86_64 root=/dev/mapper/up-centos quiet splash
initrd (hd0,3)/initramfs-3.10.0-862.el7.x86_64.img
boot
完整的多系统 grub.cfg 示例:
insmod all_video
insmod gfxterm
insmod gettext
insmod lvm
insmod part_msdos
insmod ext2
insmod exfat
insmod iso9660
insmod loopback
insmod jpeg
insmod png
insmod cryptodisk
set gfxmode=auto
set locale_dir=$prefix/locale
set lang=zh_CN
set timeout_style=menu
set timeout=5
set default=0
background_image /boot/grub/bg.jpg
menuentry 'Ubuntu 16.04' {
linux (hd0,3)/vmlinuz-4.4.0-116-generic root=/dev/sda1 quiet splash
initrd (hd0,3)/initrd.img-4.4.0-116-generic
}
menuentry 'Mint 19' {
linux (hd0,3)/vmlinuz-4.15.0-20-generic root=/dev/mapper/up-mint quiet splash
initrd (hd0,3)/initrd.img-4.15.0-20-generic
}
menuentry 'CentOS 7' {
linux (hd0,3)/vmlinuz-3.10.0-862.el7.x86_64 root=/dev/mapper/up-centos quiet splash
initrd (hd0,3)/initramfs-3.10.0-862.el7.x86_64.img
}
menuentry 'Windows 7' {
set root=(hd0,2)
chainloader +1
}
menuentry 'CentOS 7 Install' {
set root=(hd0,6)
linux /vmlinuz linux repo=hd:/dev/sda6:/
initrd /initrd.img
}
menuentry 'Mint 19 Install' {
set root=(hd0,6)
loopback loop /mint19.iso
set root=(loop)
linux /casper/vmlinuz boot=casper iso-scan/filename=/mint19.iso quiet splash --
initrd /initrd.img
}
menuentry 'Ghost' {
set root=(hd0,6)
linux16 /memdisk c=2000 h=4 s=36 floppy
initrd /ghost.img
}
menuentry '重启' {
reboot
}
menuentry '关机' {
halt --no-apm
}
四、单用户模式、救援模式与 root 密码重置
运行级别与目标
| 运行级别 | 名称 | 说明 |
|---|---|---|
1 |
Single user mode | 单用户模式,用于系统维护,只启动最少服务,不启动网络 |
3 |
Multi-user | 多用户命令行模式 |
5 |
Graphical | 图形界面模式 |
CentOS 7 已用 systemd target 取代运行级别,与单用户/救援相关的目标是:
| target | 对应说明 |
|---|---|
rescue.target |
救援模式,等价于传统单用户模式,挂载本地文件系统、启动极少服务 |
emergency.target |
紧急模式,只以只读方式挂载根文件系统,不启动任何服务,用于 fstab 写错等严重故障 |
在 GRUB 菜单中按 e 编辑目标菜单项,在 linux16/linux 内核行末尾追加参数即可临时进入:
systemd.unit=rescue.target
# 或
systemd.unit=emergency.target
编辑完成后按 Ctrl + x 启动。
忘记 root 密码的处理思路
思路一(推荐,CentOS 7 通用):在 GRUB 菜单按 e 编辑启动项,在内核行末尾追加 rd.break,按 Ctrl + x 启动,进入 initramfs 的紧急 shell 后:
# 此时真实根文件系统以只读方式挂载在 /sysroot
mount -o remount,rw /sysroot
chroot /sysroot
# 修改 root 密码
passwd root
# 若启用了 SELinux,必须创建自动重新打标记的标志文件
touch /.autorelabel
exit
exit # 系统继续启动并自动重新打标记(耗时较长),完成后自动重启
思路二:在内核行末尾追加 init=/bin/bash(或 CentOS 6 及更早的 single)进入 shell,再 mount -o remount,rw / 后执行 passwd root。
思路三:使用光盘/U 盘启动进入救援模式(安装介质菜单中的 Rescue installed system),挂载并 chroot 到原系统后改密码(步骤见下一节的 chroot 修复流程)。
安全提示:可以给 GRUB 加密码,防止他人在启动时修改 GRUB 参数进入单用户模式修改 root 密码。但 GRUB 密码并不绝对安全,攻击者仍可通过外部介质的 rescue 模式进入系统,物理访问控制才是根本。
五、MBR 与引导故障修复
1. MBR 与分区表的备份与恢复
以下两种备份方式任选其一:
# 1. 连同启动加载程序(MBR 全部 512 字节)一起备份
head -c 512 /dev/sda > /some/where/boot_sector.bin
# 2. 仅备份分区表(MBR 中偏移 446 开始的 64 字节)
head -c 510 /dev/sda | tail -c 64 > /some/where/partition_table.bin
恢复(慎用,会覆盖目标盘的 MBR):
dd if=./mbr.txt of=/dev/sda bs=1 count=512
只恢复分区表时应写回 64 字节到偏移 446 处(
dd ... bs=1 seek=446 count=64),不要整体覆盖 512 字节,避免破坏正常的启动代码。
2. 情况一:进入 grub> 命令行
当 grub.cfg 配置文件错误或丢失,开机会进入 grub> 命令行,此时可手工引导系统:
set root=(hd0,1)
linux /boot/vmlinuz-4.4.0-130-generic root=/dev/sda1
# 输入 linux /boot/vmlinuz- 后可按 Tab 补全内核文件名
initrd /boot/initrd.img-4.4.0-130-generic
boot
进入系统后重新生成配置文件(update-grub 或 grub2-mkconfig -o /boot/grub2/grub.cfg)即可恢复菜单。
3. 情况二:进入 grub-rescue> 命令行
当 GRUB 模块目录(i386-pc)丢失时,会进入 grub-rescue> 命令行。前提是已知 GRUB 目录所在分区(例如第一块硬盘的第一个分区):
set prefix=(hd0,1)/grub # 设置 grub 程序(模块)根目录
set root=(hd0,1) # 设置默认根分区
insmod normal # 导入 normal 核心模块
normal # 运行 normal 模块,进入 grub 菜单
4. 直接重装 GRUB 引导程序(BIOS + MBR)
# 将 GRUB 引导程序写入 MBR,并生成 /boot 下相关文件
sudo grub-install /dev/sda
# Ubuntu 自动生成 grub.cfg
sudo update-grub
grub-install /dev/sda 会自动将 GRUB 引导程序写入 MBR,并在 /boot 下生成 GRUB 相关文件。CentOS 7 下对应的配置生成命令是 grub2-mkconfig -o /boot/grub2/grub.cfg(注意该命令会重新生成并覆盖 grub.cfg,手工添加的 menuentry 会丢失,自定义菜单请写入 /etc/grub.d/40_custom)。
5. 借助第三方 Linux 系统修复(chroot 流程)
适用于根分区完整、只是引导程序或相关文件丢失导致无法启动的情况。可借助 U 盘、光盘或网络启动的 Linux 系统修复:
# 1. 挂载待修复系统的根分区
sudo mount /dev/sda1 /mnt
# 2. 挂载 boot 分区到 /mnt/boot
sudo mount /dev/sda3 /mnt/boot/
# 3. 绑定挂载内核相关目录(proc、sys、dev、tmp)
sudo mount -o bind /proc /mnt/proc/
sudo mount -o bind /sys /mnt/sys/
sudo mount -o bind /dev /mnt/dev/
sudo mount -o bind /tmp /mnt/tmp/
# 4. 切换到待修复系统
sudo chroot /mnt
# 5. 重装 GRUB
sudo grub-install /dev/sda
在 chroot 环境中同样可以执行 passwd root 重置密码、修正 /etc/fstab 等操作,完成后 exit 退出并重启。
练习
练习 1:分区方案(含 Swap)
按照以下方案使用 fdisk 完成分区,并通过 t 修改分区类型:
| 分区 | 大小 | 用途 | 分区类型 ID |
|---|---|---|---|
| 第一个分区 | 50G | CentOS 根分区 | 20(不要动) |
| 第二个分区 | 4G | swap | 19(不要动) |
| 第三个分区 | 4G | boot 分区 | 4 |
| 第四个分区 | 扩展分区 | — | — |
| └ 第二个逻辑分区 | 50G | /home |
20 |
| └ 第三个逻辑分区 | 30G | ubuntu | 20 |
| └ 第四个逻辑分区 | 20G | mint | 20 |
| └ 最后一个逻辑分区 | 剩余空间 | Windows D 盘 | 7 |
注意:第一个/第二个分区已存在时不要动;分区结束后用 partprobe 刷新设备文件,再按需格式化、挂载。
练习 4:添加 Windows 引导项
- 在
/etc/grub.d/40_custom中添加Windows 7的menuentry,确认文件具有可执行权限; - 执行
grub2-mkconfig -o /boot/grub2/grub.cfg重新生成配置; - 用
grub2-set-default "Windows 7"设为默认项,grub2-editenv list验证saved_entry; - 确认
/etc/default/grub中GRUB_DEFAULT=saved。
练习 5:引导故障修复演练
- 备份 MBR(512 字节)和分区表(64 字节)到安全位置;
- 重命名
/boot/grub2/grub.cfg,重启观察进入grub>命令行; - 在
grub>下用set root、linux、initrd、boot手工引导进入系统; - 用
grub2-mkconfig恢复配置文件; - 演练在 GRUB 菜单追加
rd.break,通过chroot /sysroot重置 root 密码(记得touch /.autorelabel)。
此处评论已关闭