本文所有操作全部基于VMware虚拟机,物理实体机器上的操作可能不同。
修复故障的通用操作
VMware虚拟机开机画面特殊按键
下图就是VMware虚拟机的开机画面:

在这个画面可以快速按以下三个键,功能如下:
F2
: SETUP(进入BIOS设置画面)F12
: Network Boot(从网络引导)ESC
: Boot Menu(选择从哪个设备引导系统,如下图所示)

进入光盘救援模式
- 开机画面按
ESC
键,进入Boot Menu - 选择
CD-ROM Drive
,从光盘启动(系统安装光盘必须提前挂载) - 选择
Rescue installed system

- 等待光盘文件被读入内存
-
设置救援模式的语言和键盘布局
-
选择是否设置网络(我选择
No
)- 稍后如果需要连接网络,可以通过
ifconfig eth0 192.168.0.7/24
这样的方式临时指定IP地址

- 稍后如果需要连接网络,可以通过
-
选择是否以读写模式挂载根分区(我选择
Continue
)Continue
:以读写模式挂载Read-Only
:以只读模式挂载Skip
:跳过挂载,直接进入shellAdvanced
:激活SAN设备

-
读写模式挂载成功,并提示如何切换到硬盘根目录

-
启动shell
- 所有救援操作完成之后,输入
exit
回到这个画面,选择reboot
重启系统

- 所有救援操作完成之后,输入
-
chroot /mnt/sysimage
切换到硬盘根目录
进入单用户模式
-
在GRUB画面按下任意键,显示GRUB菜单

-
在要启动的内核上按
a
键,修改内核启动参数
-
在启动参数末尾添加
single
,按下ENTER
键启动系统- 把
single
换成(s|S|1)
这三个字符的任何一个都是同样效果
- 把
- 系统启动到单用户模式,不需要密码就获取root权限
硬件故障
硬盘分区表被破坏
警告:如果分区表没有提前备份,破坏后将无法修复!
备份MBR分区表
$ dd if=/dev/sda of=/mbr-61 bs=1 count=64 skip=446
$ file /mbr-61
/mbr-61: 8086 relocatable (Microsoft)
# 必须把分区表备份到另一台主机,
# 如果保存在本机,破坏分区表之后将无法读取
$ scp /mbr-61 root@172.16.125.71:~
破坏MBR分区表
dd if=/dev/zero of=/dev/sda bs=1 count=64 seek=446
故障表现
黑屏上显示Error 22
:

修复方法
必须进入光盘救援模式修复。因为没有分区表,救援模式尝试挂载硬盘根分区会报错:

虽然没有分区表无法挂载文件系统,但操作系统可以识别连接的设备,通过fdisk -l
可以列出当前连接的硬盘设备,从下图可以看到,硬盘/dev/sda
确实没有分区信息:

此时可以从备份主机取回备份的分区表,然后用dd
命令写入硬盘:
# 指定IP地址,使本机可以连接其它主机
ifconfig eth0 172.16.125.61/24
# 从其它主机取回备份的分区表
scp root@172.16.125.71:~/mbr-61 .
# 把分区表写入硬盘
dd if=mbr-61 of=/dev/sda bs=1 seek=446
# 查看分区表写入结果
fdisk -l /dev/sda

从上图可以看到,分区信息已成功写入,修复完成。输入exit
退出救援模式,重启系统。
重启过程中禁用SELinux检查
由于修改了系统重要文件,SELinux会自动检查其管辖的文件,并重新打标签(relabeling),完成之后会自动重启。这个检查过程可能耗时良久,可以添加内核启动参数selinux=0
将其禁用:

这种方式只是临时禁用SELinux检查,下次重启依旧会检查,如果想彻底关闭,必须在/etc/selinux/config
文件中彻底禁用SELinux,然后重启系统生效:
sed -i.bak -r 's/^(SELINUX=).*/\1disabled/' /etc/selinux/config
Boot loader (GRUB Legacy) 故障
Stage 1 被破坏
破坏方式
执行破坏操作前,务必做好备份!
dd if=/dev/zero of=/dev/sda bs=1 count=446
故障表现
因为找不到Stage 1,BIOS认为硬盘不可引导,等同于没有安装操作系统,于是BIOS会尝试从可移动设备、光盘或网络引导,具体取决于引导设备的顺序。
修复方法
必须进入光盘救援模式修复。
# 必须chroot,否则系统找不到`grub-install`的路径
chroot /mnt/sysimage
grub-install /dev/sda
# 把内存数据写入到硬盘,可执行多次
sync
注意:grub-install
执行完之后,不要立即重启系统!否则内存中的数据可能没有完全写入硬盘,将导致修复失败。
修复过程实际上是重新写入了下图红色方框中的文件:

如果误操作破坏Stage 1之后,没有重启系统,而上图红色方框中的文件都完整保存在/boot/grub
目录,也可以使用grub
交互式命令来修复:

从上图可以看到,进入grub
的交互式命令行之后,
- 首先执行
root (hd0,0)
,设定/boot
目录的位置(在这里是第一块硬盘的第一个分区),grub
命令会自动检测分区的文件系统类型。如果不确定/boot
目录的位置,可以执行find /boot/grub/stage1
。 - 然后执行
setup (hd0)
:- 把GRUB Stage 1安装到第一块硬盘的MBR。
- 把文件系统驱动安装到MBR之后的扇区。
e2fs_stage1_5
驱动总共13428字节,因此占用27个扇区。
如果想把GRUB安装到分区的引导扇区而不是硬盘的MBR,就需要指定分区号
setup (hd0,0)
,但如此一来就需要链式载入(chain load)这个GRUB。
https://www.gnu.org/software/grub/manual/legacy/Installing-GRUB-natively.html
Stage 1.5 被破坏
破坏方式
执行破坏操作前,务必做好备份!
# Stage 1.5存储的文件系统驱动不同,具体需要破坏的扇区数不同,
# e2fs驱动总共占用27个扇区,因此这里破坏26个扇区,
# 如果破坏的扇区太少,系统仍然可能启动。
dd if=/dev/zero of=/dev/sda bs=512 count=26 seek=1
故障表现
系统可以从硬盘引导,但由于找不到/boot
所在分区的文件系统驱动,因此无法显示GRUB菜单,也无法进一步加载内核,只能显示一个黑屏,黑屏上没有任何信息。
修复方法
必须进入光盘救援模式修复。
# 必须`chroot`,否则系统找不到`grub-install`的路径
chroot /mnt/sysimage
grub-install /dev/sda
# 把内存数据写入到硬盘,可执行多次
sync
Stage 2 被破坏
破坏方式
Stage 1 和 1.5 的代码是以二进制的方式存储在硬盘上,因此只能通过dd
这种直接读写硬盘块(block)的工具来破坏和修复,而Stage 2代码是存储在/boot/grub/stage2
这个文件,只要将其移动或删除,就破坏了Stage 2。
故障表现
黑屏上显示Error 15
。
修复方法
必须进入光盘救援模式修复。
- 如果做过备份,把备份文件放回
/boot/grub/
目录即可,文件名必须是stage2
。 - 如果没有备份,仍然使用
grub-install
命令恢复。
实际上,grub-install
命令可以修复所有GRUB Legacy引导阶段的错误。
/boot/grub/grub.conf
被删除
故障表现
无法显示GRUB菜单,只能显示GRUB shell:

修复方法
临时指定引导参数:
# 指定`/boot`目录所在分区,
# 这里的 root 仅仅是GRUB的概念,不能与硬盘根分区混淆。
grub> root (hd0,0)
# 指定kernel路径,文件名可以用`<tab>`键补全,
# 必须用`root=`指定硬盘根分区,否则内核找不到根分区,将无法启动系统。
grub> kernel /vmlinuz-`uname -r` root=/dev/sda2
# 指定`initramfs`路径,文件名可以用`<tab>`键补全
grub> initrd /initramfs-`uname -r`.img
# 使用以上参数引导
grub> boot
系统启动成功之后,必须修复/boot/grub/grub.conf
文件:
vim /boot/grub/grub.conf
至少包含如下内容:
# 用户在5秒内没有操作,将使用默认内核启动
timeout=5
# 默认用第一个`title`指定的内核启动
default=0
# title后面的名字可以自定义
title CentOS 6.9 (2.6.32-696.el6.x86_64)
root (hd0,0)
# `ro root=`这个顺序很重要,`ro`必须在`root=`前面,
# 我第一次手写的时候,把顺序弄反了,结果重启后正确的用户名和密码无法登录,调整顺序立即恢复正常!
# `root=`后面也可以直接写`/dev/sda2`这样的分区名称。
kernel /vmlinuz-2.6.32-696.el6.x86_64 ro root=UUID=5561d4f2-d938-4bbd-98e9-d5a09a6731ec
initrd /initramfs-2.6.32-696.el6.x86_64.img
CentOS 6默认的其它内核引导参数:
KEYBOARDTYPE=pc
KEYTABLE=us
LANG=en_US.UTF-8
SYSFONT=latarcyrheb-sun16
crashkernel=auto
quiet
rd_NO_DM
rd_NO_LUKS
rd_NO_LVM
rd_NO_MD
rhgb
完整的内核引导参数列表可以通过man dracut
,然后搜索KERNEL COMMAND LINE
查看。
/boot
分区故障
initramfs
被删除
故障表现
系统可以从硬盘引导,可以显示GRUB菜单,但由于加载内核之后无法挂载根分区的文件系统,无法启动PID 1
进程,只能显示一个黑屏,黑屏上没有任何信息。
修复方法
initramfs
的完整路径是/boot/initramfs-$(uname -r).img
,删除后必须进入光盘救援模式修复。
# 必须chroot,否则mkinitrd会因为找不到文件报错
chroot /mnt/sysimage
cd /boot
mkinitrd initramfs-$(uname -r).img $(uname -r)
Kernel被删除
故障表现
黑屏上显示两行信息:
Error 15: File not found
Press any key to continue...

修复方法
必须进入光盘救援模式修复。
chroot /mnt/sysimage
# 挂载系统安装光盘
mount /dev/sr0 /mnt/cdrom
cd /mnt/cdrom/Packages
rpm -ivh --force kernel-$(uname -r).rpm
/boot
目录被删除
故障表现
黑屏上显示Error 15
。
修复方法
必须进入光盘救援模式修复。
第一步,恢复/boot
目录下的文件:
chroot /mnt/sysimage
mount /dev/sr0 /mnt/cdrom
cd /mnt/cdrom/Packages
rpm -ivh --force kernel-$(uname -r).rpm
第二步,恢复/boot/grub
目录下的文件:
# 不需要手工创建`/boot/grub`目录
grub-install /dev/sda
第三步,恢复/boot/grub/grub.conf
文件:
vim /boot/grub/grub.conf
timeout=5
default=0
title CentOS 6.9 Fixed
root (hd0,0)
kernel /vmlinuz-2.6.32-696.el6.x86_64 ro root=/dev/sda2
initrd /initramfs-2.6.32-696.el6.x86_64.img
/boot
目录和/etc/fstab
被删除
故障表现
黑屏上显示Error 15
。
注意:如果仅仅是删除了/etc/fstab
文件,系统仍然可以启动。
修复方法
必须进入光盘救援模式修复。
必须先修复/etc/fstab
文件,此时只能先列出硬盘分区,然后临时挂载每个分区,根据分区的文件来推测其正确的挂载点。
fdisk -l
mkdir /mnt/guess
mount /dev/sda2 /mnt/guess

从上图显示的文件可以推测/dev/sda2
正确的挂载点应该是/
,然后就可以修复/etc/fstab
文件:
umount /dev/sda2
mount /dev/sda2 /mnt/sysimage
cd /mnt/sysimage/etc
cat > fstab <<EOF
> /dev/sda2 / ext4 defaults 0 0
> /dev/sda1 /boot ext4 defaults 0 0
> /dev/sda3 /app ext4 defaults 0 0
> /dev/sda5 swap swap defaults 0 0
> EOF
修复完成后必须重启,让救援模式自动挂载文件系统,然后就可以执行上一小节的三步来恢复/boot
目录的所有文件。
救援模式挂载逻辑卷(LVM)分区
如果/
分区是逻辑卷,必须先激活卷组(Volume Group)才可以挂载:
vgchange -ay
启动文件故障
/sbin/init
被删除
/sbin/init
是内核挂载硬盘根分区之后启动的第一个进程,其它所有系统进程都是/sbin/init
的子进程,如果/sbin/init
被删除,系统将无法真正启动。
故障表现
shell报错cannot set terminal process group (-1)
,shell提示符后面无法输入任何字符,敲回车键就重复显示shell提示符本身:

修复方法
重启系统,在GRUB菜单添加内核启动参数init=/bin/bash
,然后按b
键,使用刚添加的参数引导内核,内核会把/bin/bash
作为第一个进程启动,启动成功后,执行如下操作:
# 必须用读写模式重新挂载根分区
mount -o remount,rw /
mount /dev/sr0 /mnt/cdrom
cd /mnt/cdrom/Packages
rpm -ivh --force `rpm -qf /sbin/init`.rpm
reboot
/etc/rc.d/rc.sysinit
被删除
这个脚本的用途很多,是系统启动必不可少的文件:
- 打印欢迎信息
- 设定主机名称
- 设定系统时间
- 初始化网络
- 挂载
/proc
文件系统 - 挂载
/etc/fstab
列出的文件系统 - 根据
/etc/sysctl.conf
文件设置内核参数 - 基于内核引导参数初始化硬件
- 初始化SELinux
- 清理
/var
等目录 - 激活LVM及Software RAID设备
- 加载额外设备的驱动程序
- ……
故障表现

备注:/etc/rc.sysinit
是指向/etc/rc.d/rc.sysinit
的软链接,若只是软链接被删除,系统仍然能够启动。
修复方法
必须进入光盘救援模式修复。
chroot /mnt/sysimage
mount /dev/sr0 /mnt/cdrom
rpm -ivh --force /mnt/cdrom/Packages/$(rpm -qf /etc/rc.d/rc.sysinit).rpm
reboot
Leave A Comment