From 5021598d776f78c66905c57505670adb3630b4eb Mon Sep 17 00:00:00 2001 From: zj <1052308357@qq.com> Date: Thu, 12 Feb 2026 02:21:04 +0800 Subject: [PATCH] 6 --- AGENTS.md | 26 +++++++- __pycache__/backend.cpython-39.pyc | Bin 50636 -> 52538 bytes backend.py | 95 +++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 0b8a052..e22fe2b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -91,7 +91,30 @@ initrd /initramfs-4.18.0-348.el8.x86_64.img options root=/dev/mapper/cl-root ro crashkernel=auto rd.lvm.lv=cl/root rhgb quiet ``` -### 6. GRUB 修复 (`backend.py:chroot_and_repair_grub`) +### 6. UEFI 模块自动安装 (`backend.py:check_and_install_efi_modules`) + +**NEW v2.3**: 自动检测并安装 UEFI GRUB 模块 + +#### 问题场景 +在 UEFI 模式下,`grub-install` 需要 `/usr/lib/grub/x86_64-efi/` 目录下的 EFI 模块。如果缺少这些模块,会报错: +``` +/usr/lib/grub/x86_64-efi/modinfo.sh doesn't exist +``` + +这在以下场景常见: +- 最小化安装的系统 +- 从 BIOS 模式安装后切换到 UEFI 模式 +- `/usr` 被清空或损坏 + +#### 自动安装 +检测到缺少 EFI 模块时,自动安装相应的包: +| 发行版 | 包名 | +|--------|------| +| CentOS/RHEL/Rocky/Alma/Fedora | `grub2-efi-x64`, `grub2-efi-x64-modules` | +| Debian/Ubuntu | `grub-efi-amd64` | +| Arch/Manjaro | `grub` (已包含 EFI 支持) | + +### 7. GRUB 修复 (`backend.py:chroot_and_repair_grub`) #### BIOS 模式 - `grub-install --target=i386-pc --recheck --force /dev/sdX` @@ -99,6 +122,7 @@ options root=/dev/mapper/cl-root ro crashkernel=auto rd.lvm.lv=cl/root rhgb quie #### UEFI 模式 (参考 Calamares 实现) - 自动检测系统架构 (x86_64/i386/arm64/loongarch64) +- **NEW**: 自动检测并安装 UEFI GRUB 模块 - 获取正确的 EFI 参数 (target, grub_file, boot_file) - **多重安装策略**(自动回退): 1. 标准安装(带 NVRAM) diff --git a/__pycache__/backend.cpython-39.pyc b/__pycache__/backend.cpython-39.pyc index 1156655fe47161ccde3e7f6f5bd8f2d484917788..1fad2edf4c73361efc0d68df4db40833f1806228 100644 GIT binary patch delta 5542 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 oG79+K%=qZA`CGTqz8 return True, "" +def check_and_install_efi_modules(mount_point: str, distro_type: str, is_uefi: bool) -> Tuple[bool, str]: + """ + 检查并安装 UEFI GRUB 模块。 + 对于 UEFI 模式,需要检查 /usr/lib/grub/x86_64-efi/ 目录是否存在。 + 如果不存在,自动安装 grub2-efi 包。 + + 返回: (是否成功, 错误信息) + """ + if not is_uefi: + return True, "" + + log_step("检查 UEFI GRUB 模块") + + # 检测架构 + efi_params = get_grub_efi_parameters() + if not efi_params: + return False, "无法确定 EFI 架构" + + efi_target, _, _ = efi_params + # efi_target 格式: x86_64-efi, i386-efi, arm64-efi + arch_dir = efi_target # 如: x86_64-efi + + # 检查模块目录 + module_dir = os.path.join(mount_point, f"usr/lib/grub/{arch_dir}") + modinfo_file = os.path.join(module_dir, "modinfo.sh") + + if os.path.exists(modinfo_file): + log_success(f"✓ UEFI GRUB 模块已存在: {module_dir}") + return True, "" + + log_warning(f"UEFI GRUB 模块不存在: {module_dir}") + log_info("尝试安装 UEFI GRUB 模块包...") + + chroot_cmd_prefix = ["sudo", "chroot", mount_point] + + # 根据发行版选择正确的 EFI 包 + efi_packages_map = { + "centos": ["grub2-efi-x64", "grub2-efi-x64-modules"], + "rhel": ["grub2-efi-x64", "grub2-efi-x64-modules"], + "fedora": ["grub2-efi-x64", "grub2-efi-x64-modules"], + "rocky": ["grub2-efi-x64", "grub2-efi-x64-modules"], + "almalinux": ["grub2-efi-x64", "grub2-efi-x64-modules"], + "debian": ["grub-efi-amd64"], + "ubuntu": ["grub-efi-amd64"], + "arch": ["grub"], # Arch 的 grub 包包含 EFI 支持 + "manjaro": ["grub"], + } + + efi_packages = efi_packages_map.get(distro_type, []) + + if not efi_packages: + log_warning(f"未知的发行版 '{distro_type}',无法自动安装 EFI 模块") + return False, f"无法确定 {distro_type} 的 EFI 包名" + + # 安装 EFI 包 + if distro_type in ["centos", "rhel", "fedora", "rocky", "almalinux"]: + success, _, stderr = run_command( + chroot_cmd_prefix + ["yum", "install", "-y"] + efi_packages, + f"安装 UEFI GRUB 包", + timeout=300 + ) + elif distro_type in ["debian", "ubuntu"]: + success, _, stderr = run_command( + chroot_cmd_prefix + ["apt-get", "install", "-y"] + efi_packages, + f"安装 UEFI GRUB 包", + timeout=300 + ) + elif distro_type in ["arch", "manjaro"]: + success, _, stderr = run_command( + chroot_cmd_prefix + ["pacman", "-S", "--noconfirm"] + efi_packages, + f"安装 UEFI GRUB 包", + timeout=300 + ) + else: + return False, f"不支持的发行版: {distro_type}" + + if not success: + log_error(f"UEFI GRUB 包安装失败") + return False, f"无法安装 UEFI GRUB 包: {stderr}" + + # 重新检查模块 + if os.path.exists(modinfo_file): + log_success(f"✓ UEFI GRUB 模块安装成功") + return True, "" + else: + log_error("UEFI GRUB 模块安装后仍不存在") + return False, "UEFI 模块安装失败" + + def install_efi_fallback(mount_point: str, efi_target: str, efi_grub_file: str, efi_boot_file: str, bootloader_id: str = "GRUB") -> bool: """ @@ -1703,6 +1792,12 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, return False, "无法确定 EFI 架构参数" efi_target, efi_grub_file, efi_boot_file = efi_params log_info(f"EFI 参数: target={efi_target}, grub={efi_grub_file}, boot={efi_boot_file}") + + # 检查并安装 UEFI GRUB 模块 + efi_modules_ok, efi_modules_err = check_and_install_efi_modules(mount_point, distro_type, True) + if not efi_modules_ok: + log_error(f"UEFI 模块检查失败: {efi_modules_err}") + return False, f"UEFI 模块检查失败: {efi_modules_err}" grub_install_success = False install_errors = []