This commit is contained in:
zj
2026-02-12 04:07:53 +08:00
parent 19cff55298
commit 204e38b8d9

View File

@@ -1971,17 +1971,40 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str,
else:
grub_dir_name = "grub"
# 1. 清空 /boot/grub* 目录
# 1. 检查并恢复 GRUB 模块(从系统包中)
log_info("检查 GRUB EFI 模块...")
grub_modules_dir = os.path.join(mount_point, f"usr/lib/grub/x86_64-efi")
boot_grub_mods = os.path.join(mount_point, "boot", grub_dir_name, "x86_64-efi")
if os.path.exists(grub_modules_dir):
log_info(f"✓ 系统模块目录: {grub_modules_dir}")
# 确保 /boot/grub2/x86_64-efi 存在且包含模块
if not os.path.exists(boot_grub_mods) or len(os.listdir(boot_grub_mods)) < 10:
log_info("复制 GRUB 模块到 /boot...")
try:
import shutil
if os.path.exists(boot_grub_mods):
shutil.rmtree(boot_grub_mods)
shutil.copytree(grub_modules_dir, boot_grub_mods)
mod_count = len(os.listdir(boot_grub_mods))
log_success(f"✓ 复制 {mod_count} 个模块到 {boot_grub_mods}")
except Exception as e:
log_warning(f"复制模块失败: {e}")
# 2. 清空 /boot/grub* 目录中的配置和临时文件(保留模块和字体)
boot_grub_paths = [
os.path.join(mount_point, "boot", "grub"),
os.path.join(mount_point, "boot", "grub2"),
]
for grub_path in boot_grub_paths:
if os.path.exists(grub_path):
log_info(f"目录: {grub_path}")
log_info(f"目录: {grub_path}")
try:
# 删除目录内所有内容但保留目录本身
# 删除配置文件和临时文件,保留 x86_64-efi 目录和字体
preserve_dirs = {"x86_64-efi", "i386-pc", "fonts", "locale"}
for item in os.listdir(grub_path):
if item in preserve_dirs:
continue
item_path = os.path.join(grub_path, item)
if os.path.isfile(item_path) or os.path.islink(item_path):
os.unlink(item_path)
@@ -1990,9 +2013,9 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str,
import shutil
shutil.rmtree(item_path)
log_debug(f" 删除目录: {item}")
log_success(f"✓ 已清: {grub_path}")
log_success(f"✓ 已清: {grub_path}")
except Exception as e:
log_warning(f"失败: {e}")
log_warning(f"失败: {e}")
# 2. 清空 EFI 分区中的 GRUB 相关目录
efi_cleanup_dirs = ["GRUB", "grub", "Boot", "boot", "centos", "redhat", "fedora"]
@@ -2446,7 +2469,101 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str,
if not success:
log_error(f"GRUB 配置文件更新失败: {stderr}")
return False, f"GRUB配置文件更新失败: {stderr}"
# 备选方案:手动创建基本 grub.cfg
log_step("尝试手动创建基本 grub.cfg")
# 获取根分区信息
root_part = None
root_uuid = None
try:
# 从 /etc/fstab 获取根分区
fstab_path = os.path.join(mount_point, "etc/fstab")
if os.path.exists(fstab_path):
with open(fstab_path, 'r') as f:
for line in f:
if line.startswith('#') or not line.strip():
continue
parts = line.split()
if len(parts) >= 2 and parts[1] == '/':
root_part = parts[0]
break
# 获取 UUID
if root_part and root_part.startswith('UUID='):
root_uuid = root_part[5:].strip('"')
elif root_part and root_part.startswith('/dev/'):
success_uuid, uuid_out, _ = run_command(
["sudo", "blkid", "-s", "UUID", "-o", "value", root_part],
f"获取 {root_part} 的 UUID",
timeout=10
)
if success_uuid:
root_uuid = uuid_out.strip()
except Exception as e:
log_warning(f"获取根分区信息失败: {e}")
# 查找内核文件
boot_dir = os.path.join(mount_point, "boot")
kernel_files = []
initramfs_files = []
try:
for f in os.listdir(boot_dir):
if f.startswith('vmlinuz-'):
kernel_files.append(f)
elif f.startswith('initramfs-') and f.endswith('.img') and 'kdump' not in f:
initramfs_files.append(f)
kernel_files.sort(reverse=True)
initramfs_files.sort(reverse=True)
except Exception as e:
log_warning(f"查找内核文件失败: {e}")
if kernel_files and root_uuid:
# 创建基本 grub.cfg
grub_cfg_content = f"""# Minimal GRUB config generated by BootRepairTool
set timeout=5
set default=0
# Load necessary modules
insmod part_gpt
insmod xfs
insmod fat
# Search for the root partition by UUID
search --no-floppy --fs-uuid --set=root {root_uuid}
menuentry 'CentOS Linux (Auto)' {{
load_video
set gfxpayload=keep
insmod gzio
insmod part_gpt
insmod xfs
linux /{kernel_files[0]} root=UUID={root_uuid} ro
initrd /{initramfs_files[0] if initramfs_files else ''}
}}
menuentry 'CentOS Linux (Rescue)' {{
load_video
set gfxpayload=keep
insmod gzio
insmod part_gpt
insmod xfs
linux /{kernel_files[0]} root=UUID={root_uuid} ro rescue
initrd /{initramfs_files[0] if initramfs_files else ''}
}}
"""
try:
with open(full_config_path, 'w') as f:
f.write(grub_cfg_content)
log_success(f"✓ 手动创建 grub.cfg: {full_config_path}")
log_info(f" 内核: {kernel_files[0]}")
log_info(f" UUID: {root_uuid}")
success = True
except Exception as e:
log_error(f"手动创建 grub.cfg 失败: {e}")
return False, f"GRUB配置失败: {stderr}"
else:
return False, f"GRUB配置失败无法获取内核或UUID"
log_success("✓ GRUB 配置文件更新成功")