diff --git a/backend.py b/backend.py index aa42279..8d58886 100644 --- a/backend.py +++ b/backend.py @@ -2060,6 +2060,80 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, grub_install_success = False install_errors = [] + # ===== 清空并重建 GRUB 环境(针对严重损坏的系统)===== + # 这个步骤在 UEFI 和 BIOS 模式下都需要 + log_step("清空并重建 GRUB 环境") + + # 确定正确的 GRUB 目录名 + if distro_type in ["centos", "rhel", "fedora", "rocky", "almalinux", "opensuse"]: + grub_dir_name = "grub2" + else: + grub_dir_name = "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}") + 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) + log_debug(f" 删除文件: {item}") + elif os.path.isdir(item_path): + import shutil + shutil.rmtree(item_path) + log_debug(f" 删除目录: {item}") + log_success(f"✓ 已清理: {grub_path}") + except Exception as e: + log_warning(f"清理失败: {e}") + + # 3. 创建 grubenv 文件(普通文件,不是符号链接) + # GRUB2 要求环境块精确为 4096 字节(一个扇区) + grubenv_path = os.path.join(mount_point, "boot", grub_dir_name, "grubenv") + try: + # 构建 4096 字节的 grubenv 内容 + header = "# GRUB Environment Block\n" + saved_entry = "saved_entry=\n" + # 计算需要填充的字节数(4096 - header - saved_entry - 结尾的 #) + padding_size = 4096 - len(header) - len(saved_entry) - 1 + content = header + saved_entry + "#" * padding_size + with open(grubenv_path, 'w') as f: + f.write(content) + log_success(f"✓ 创建 grubenv ({os.path.getsize(grubenv_path)} 字节): {grubenv_path}") + except Exception as e: + log_warning(f"创建 grubenv 失败: {e}") + + log_success("✓ GRUB 环境重建完成") + # ===== UEFI 安装 ===== if is_uefi or install_hybrid: log_step("安装 UEFI GRUB") @@ -2076,62 +2150,10 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, else: log_warning(f"✗ EFI 目录不存在: {efi_check_path}") - # ===== 清空并重建 GRUB 环境(针对严重损坏的系统)===== - log_step("清空并重建 GRUB 环境") + # ===== 清空 EFI 分区并重建(UEFI 模式特有)===== + log_step("清空 EFI 分区并重建") - # 确定正确的 GRUB 目录名 - if distro_type in ["centos", "rhel", "fedora", "rocky", "almalinux", "opensuse"]: - grub_dir_name = "grub2" - else: - grub_dir_name = "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}") - 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) - log_debug(f" 删除文件: {item}") - elif os.path.isdir(item_path): - import shutil - shutil.rmtree(item_path) - log_debug(f" 删除目录: {item}") - log_success(f"✓ 已清理: {grub_path}") - except Exception as e: - log_warning(f"清理失败: {e}") - - # 2. 清空 EFI 分区中的 GRUB 相关目录 + # 1. 清空 EFI 分区中的 GRUB 相关目录 efi_cleanup_dirs = ["GRUB", "grub", "Boot", "boot", "centos", "redhat", "fedora"] for efi_dir in efi_cleanup_dirs: efi_dir_path = os.path.join(mount_point, "boot/efi/EFI", efi_dir) @@ -2144,10 +2166,9 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, except Exception as e: log_warning(f"删除失败: {e}") - # 3. 重建目录结构 - log_info("重建 GRUB 目录结构...") + # 2. 重建 EFI 目录结构 + log_info("重建 EFI 目录结构...") dirs_to_create = [ - os.path.join(mount_point, "boot", grub_dir_name), os.path.join(mount_point, "boot/efi/EFI", efi_bootloader_id), os.path.join(mount_point, "boot/efi/EFI", "Boot"), ] @@ -2158,22 +2179,6 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, except Exception as e: log_warning(f"创建目录失败: {e}") - # 4. 创建 grubenv 文件(普通文件,不是符号链接) - # GRUB2 要求环境块精确为 4096 字节(一个扇区) - grubenv_path = os.path.join(mount_point, "boot", grub_dir_name, "grubenv") - try: - # 构建 4096 字节的 grubenv 内容 - header = "# GRUB Environment Block\n" - saved_entry = "saved_entry=\n" - # 计算需要填充的字节数(4096 - header - saved_entry - 结尾的 #) - padding_size = 4096 - len(header) - len(saved_entry) - 1 - content = header + saved_entry + "#" * padding_size - with open(grubenv_path, 'w') as f: - f.write(content) - log_success(f"✓ 创建 grubenv ({os.path.getsize(grubenv_path)} 字节): {grubenv_path}") - except Exception as e: - log_warning(f"创建 grubenv 失败: {e}") - log_success("✓ GRUB 环境重建完成") # 5. 为独立 /boot 分区创建 EFI 辅助 grub.cfg