From 204e38b8d9e50a4c03ebbe4b397c65e7d02cd3c4 Mon Sep 17 00:00:00 2001 From: zj <1052308357@qq.com> Date: Thu, 12 Feb 2026 04:07:53 +0800 Subject: [PATCH] 2 --- backend.py | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 123 insertions(+), 6 deletions(-) diff --git a/backend.py b/backend.py index b37ca05..ad07a4e 100644 --- a/backend.py +++ b/backend.py @@ -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 配置文件更新成功")