恢复策略
当机器无法启动或行为异常时,遵循由外而内的原则:先获取 Shell,再查看磁盘,然后修复最小的故障点。大多数恢复流程遵循相同的弧线:从救援介质启动,挂载或 chroot 进入已安装的系统,修复引导加载程序、文件系统或配置,然后重启。| 症状 | 使用工具 |
|---|
| 无引导加载程序 | grub-install |
| 内核找不到根设备 | update-initramfs |
| 启动进入紧急模式 | findmnt |
| 丢失 root 密码 | passwd |
| 文件系统脏数据 | fsck |
| 软件包损坏 | dpkg |
| 磁盘故障 | smartctl |
| 文件误删 | testdisk |
在故障磁盘上做任何修改之前,先对其做镜像。详见备份与镜像基础页面中的 ddrescue 和 dd 用法。从救援介质启动
几乎所有修复都需要从第二个环境开始,这样损坏的系统不会在修复过程中继续运行。从 Live USB 启动(任何发行版的安装介质都可以)或你发行版的专用救援镜像,然后进入终端。dd if=linux.iso of=/dev/sdc bs=4M status=progress conv=fsync
许多发行版在 GRUB 中也自带rescue条目,systemd 还提供了内置的恢复 Shell,可以在启动菜单中调用(详见下方的救援与紧急模式)。当引导加载程序本身丢失时,使用 Live USB。Live 系统的架构应尽可能与损坏的系统匹配,工具集也应一致。Arch Live USB 包含 mkinitcpio;Debian Live USB 包含 update-initramfs。查看磁盘
在挂载任何内容之前,先识别分区。lsblk 显示块设备树,blkid 打印文件系统类型和 UUID,确保你挂载的是正确的分区。findmnt 显示已挂载的内容,在 Live 系统自动挂载磁盘时很有用。| 命令 | 显示内容 |
|---|
lsblk -f | 设备、文件系统、标签、挂载点 |
blkid | 每个分区的 UUID 和类型 |
fdisk -l | 分区表和大小 |
findmnt | 当前挂载树 |
激活 LVM 和加密卷
如果根文件系统位于 LVM 或 LUKS 上,Live 系统默认不会识别它,需要手动激活。先解锁加密分区,再扫描卷组。cryptsetup open /dev/sda2 cryptrootvgscanvgchange -aylvscan
之后,逻辑卷会出现在 /dev/mapper/ 下,解锁的 LUKS 设备出现在 /dev/mapper/cryptroot 下,即可挂载。挂载损坏的系统
将根分区挂载到某个位置,然后将 /boot(以及 EFI 分区)叠加挂载,使路径与真实系统一致。mount /dev/sda2 /mntmount /dev/sda1 /mnt/boot/efi
如果你只需要复制数据,到这里就可以停止并提取文件。如果根文件系统无法干净挂载,先运行检查(详见文件系统修复)。当只想从可疑磁盘中抢救数据时,使用 mount -o ro 只读挂载,这样不会进一步破坏数据。chroot 进入系统
要运行损坏系统自身的工具(它的 grub、它的包管理器、它的 passwd),需要 chroot 进入该系统。首先绑定挂载内核的伪文件系统,使这些工具正常工作,包括用于修复 UEFI 引导加载程序的 EFI 变量。mount --rbind /dev /mnt/devmount --rbind /proc /mnt/procmount --rbind /sys /mnt/sysmount --rbind /run /mnt/runchroot /mnt /bin/bash
在 Arch 及其衍生发行版上,arch-chroot 可以一步完成上述所有操作。完成后,先 exit 退出 chroot,然后反向递归卸载所有挂载点。绑定挂载不是可选的。如果没有挂载 /dev、/proc 和 /sys,grub-install 和 update-initramfs 等工具会以令人困惑的方式失败。每次 --rbind 后,运行 mount --make-rslave /mnt/dev(其他同理),这样后续的 umount -R /mnt 不会回传并卸载 Live 系统自身的 /dev 和 /sys。修复引导加载程序
缺失或损坏的引导加载程序会让你停留在 grub> 提示符或完全没有菜单。在 chroot 内部,重新将 GRUB 安装到磁盘,然后重新生成配置。对于传统 BIOS 系统,安装到整个磁盘(而非某个分区)。对于 UEFI 系统,安装到 EFI 分区并指定 EFI 目标:grub-install--target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB
然后重建菜单,使其列出已安装的内核。Debian 和 Ubuntu 将此封装为 update-grub。grub-mkconfig -o /boot/grub/grub.cfgupdate-grub
当固件引导了错误的条目时,使用 efibootmgr 检查或清理 UEFI 启动条目。重建 initramfs
如果内核更新中断或早期启动镜像损坏(启动时出现 "cannot find root device" 或内核恐慌),在 chroot 内部重新生成 initramfs。具体命令取决于发行版。| 发行版 | 重建命令 |
|---|
| Debian / Ubuntu | update-initramfs -u -k all |
| Arch | mkinitcpio -P |
| Fedora / RHEL | dracut -f --regenerate-all |
update-initramfs -u-k allmkinitcpio -Pdracut -f--regenerate-all
救援与紧急模式
并非总是需要 Live USB。systemd 自带两个恢复目标,可以在 GRUB 菜单中调用:rescue(单用户模式,大多数服务已停止)和emergency(裸 Shell,根分区只读挂载,几乎无其他服务)。在菜单中,高亮条目,按 e 编辑,追加到 linux 行,然后按 Ctrl-X(或 F10)启动:systemd.unit=rescue.targetsystemd.unit=emergency.target
要完全绕过 init 并获取无需密码的 root Shell,改为追加以下内容,然后将根文件系统重新挂载为可写:init=/bin/bashmount -o remount,rw /
在已运行的系统中,也可以直接切换到这些模式,修复完成后恢复正常启动。systemctl rescuesystemctl emergencysystemctl default
注意:使用 init=/bin/bash 后,正常的关机路径已不可用。运行 sync 并使用魔法 SysRq 键重启,或在硬重置前执行 mount -o remount,ro /,以免损坏文件系统。重置遗忘的 root 密码
最简单的方式是通过 chroot:挂载系统,chroot 进入,直接设置密码。chroot /mnt /bin/bashpasswd root
没有救援介质时,使用上述 init=/bin/bash 技巧,将根分区重新挂载为可写,修改密码后重启。mount -o remount,rw /passwd rootexec /sbin/init
在 SELinux 系统上(Fedora、RHEL):以这种方式修改密码后,运行 touch /.autorelabel。否则重写的 /etc/shadow 会保留错误的安全标签,下次启动时可能再次将你锁定。文件系统修复
脏数据或损坏的文件系统可能阻止启动。始终在未挂载的文件系统上检查,绝不要在 Live 系统的根分区上检查。从救援介质启动,保持分区未挂载,然后运行对应的检查工具。对于 ext2/3/4,fsck(或 e2fsck)会重放日志并修复结构。-f 强制完整检查,-y 对所有提示回答 yes。fsck -f /dev/sda2e2fsck -fy /dev/sda2
XFS 使用自己的修复工具,需要文件系统处于未挂载状态。Btrfs 默认只读检查;--repair 是真正的最后手段,可能使损坏更严重。btrfs check /dev/sda2btrfs check --repair /dev/sda2
| 文件系统 | 检查 / 修复 |
|---|
| ext2/3/4 | fsck -f, e2fsck -fy |
| XFS | xfs_repair |
| Btrfs | btrfs check, --repair(最后手段) |
| FAT / exFAT | fsck.vfat -a, fsck.exfat |
注意:在已挂载、可写的文件系统上运行 fsck 会破坏它。如果必须检查根设备,从救援介质执行,或在重新挂载为可写之前进行。修复损坏的 /etc/fstab
/etc/fstab 中的拼写错误或缺失设备会导致启动进入紧急模式。在紧急 Shell 中,将根分区重新挂载为可写,修复或注释掉错误的行。编辑 /etc/fstab,注释掉有问题的挂载项,或添加 nofail 选项,使缺失的设备不再阻塞启动。UUID=... /data ext4 defaults,nofail 02
重启前验证文件解析是否正确;mount -a 会尝试每个条目并报告失败。使用 UUID(来自blkid)匹配设备,而非 /dev/sdX,后者可能在不同启动间变化,是 fstab 启动失败的常见原因。修复损坏的软件包状态
中断的升级可能导致软件包处于半配置状态,使系统无法启动或无法使用。如果系统无法启动,在 chroot 中运行这些命令;如果能勉强进入 Shell,直接运行即可。在 Debian 和 Ubuntu 上,完成待处理的配置并解决损坏的依赖:dpkg --configure-aapt --fix-broken install
在 Fedora 和 RHEL 上,检查并重新同步软件包集合:如果 rpm 本身报错,重建损坏的 RPM 数据库:通过日志诊断
在猜测之前,先查看系统记录的内容。journalctl 显示启动日志;-x 添加解释,-b 选择某次启动,-b -1 显示上一次(失败的)启动。journalctl -xbjournalctl -b-1-p err
从 Live USB 启动时,将 journalctl 指向损坏系统的日志,而非 Live 系统的日志。journalctl -D /mnt/var/log/journal -xb
内核环形缓冲区会捕获硬件和驱动错误,这些错误可能导致早期崩溃。检查磁盘健康
如果相同的错误反复出现,磁盘可能正在损坏。smartctl 读取磁盘自身的 SMART 数据,是确认硬件故障的最快方式。smartctl -H /dev/sdasmartctl -a /dev/sdasmartctl -t short /dev/sda
badblocks 扫描表面以查找不可读的扇区。在有数据的磁盘上使用只读模式。smartctl -a 中的Reallocated_Sector_Ct或Current_Pending_Sector数值异常意味着:停止操作,用 ddrescue 对磁盘做镜像,然后更换磁盘。在濒死硬件上做修复只能争取几分钟时间。恢复误删的文件和分区
当问题是数据丢失而非启动损坏时,在磁盘的副本上操作,绝不要在原始磁盘上操作。testdisk 可以重建损坏的分区表并恢复整个分区。photorec 忽略文件系统,通过文件签名来恢复文件,即使在重新格式化的磁盘上也能工作。对于 ext3/ext4,extundelete 可以利用日志恢复最近删除的文件。extundelete /dev/sda2 --restore-all
一旦发现文件被删除,立即卸载文件系统或关机。持续的写入会覆盖你试图恢复的数据块。最后手段:救援,然后重建
如果系统损坏到无法修复,抢救能抢救的数据,然后重新安装。在磁盘进一步恶化之前先对其做镜像,然后挂载镜像以自己的节奏提取文件。ddrescue /dev/sda rescue.img rescue.map
整盘镜像包含分区表而非单个文件系统,因此使用 losetup -P 以只读方式附加镜像以暴露其分区,然后挂载你需要的分区。mount -o ro /dev/loop0p2 /mnt
复制你需要的数据,重新安装操作系统,然后从备份恢复。干净的重新安装通常比追踪深度损坏的系统更快、更安全。每次恢复都会提醒你:拥有最新备份和经过测试的恢复方案是多么重要。你在这里所做的一切工作,都是因为没有备份的代价:详见备份与镜像页面。