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 1156655..1fad2ed 100644 Binary files a/__pycache__/backend.cpython-39.pyc and b/__pycache__/backend.cpython-39.pyc differ diff --git a/backend.py b/backend.py index faa8b51..3485fec 100644 --- a/backend.py +++ b/backend.py @@ -1140,6 +1140,95 @@ def check_chroot_environment(mount_point: str, distro_type: str = "unknown") -> 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 = []