From 9f86574eceb2cd1c31af36ab35c49a865246dd1c Mon Sep 17 00:00:00 2001 From: zj <1052308357@qq.com> Date: Wed, 11 Feb 2026 15:33:41 +0800 Subject: [PATCH] 2 --- __pycache__/backend.cpython-39.pyc | Bin 41382 -> 41562 bytes backend.py | 149 +++++++++++++++-------------- 2 files changed, 78 insertions(+), 71 deletions(-) diff --git a/__pycache__/backend.cpython-39.pyc b/__pycache__/backend.cpython-39.pyc index 2319b42bac4dd01e2a30bfa6f87e3e06762a5765..117495d0f8786b04b22940995aa7773efabdad1e 100644 GIT binary patch delta 5027 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 eU_J3K`_x|RRbf(2t`+eu$4GYe6O6Gp& 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 W@4PefvRoPE!3#Cyem?s`^M3*Kq9YOj diff --git a/backend.py b/backend.py index 6fe8d39..77f7389 100644 --- a/backend.py +++ b/backend.py @@ -1026,63 +1026,76 @@ def _auto_install_grub(mount_point: str, distro_type: str) -> bool: return False +def _get_grub_cmd_path(mount_point: str, distro_type: str) -> Tuple[Optional[str], Optional[str]]: + """ + 查找 GRUB 命令的完整路径。 + 返回: (grub_install_path, grub_mkconfig_path) 或 (None, None) + """ + # 可能的命令名 + install_names = ["grub2-install", "grub-install"] + mkconfig_names = ["grub2-mkconfig", "grub-mkconfig"] + + # 可能的目录 + dirs = ["/usr/sbin", "/sbin", "/usr/bin", "/bin"] + + install_path = None + mkconfig_path = None + + for name in install_names: + for dir_path in dirs: + full_path = os.path.join(mount_point, dir_path.lstrip('/'), name) + if os.path.exists(full_path): + install_path = os.path.join(dir_path, name) + break + if install_path: + break + + for name in mkconfig_names: + for dir_path in dirs: + full_path = os.path.join(mount_point, dir_path.lstrip('/'), name) + if os.path.exists(full_path): + mkconfig_path = os.path.join(dir_path, name) + break + if mkconfig_path: + break + + return install_path, mkconfig_path + + +# 全局变量存储找到的命令路径 +_grub_install_cmd: Optional[str] = None +_grub_mkconfig_cmd: Optional[str] = None + + def check_chroot_environment(mount_point: str, distro_type: str = "unknown") -> Tuple[bool, str]: """ 检查 chroot 环境是否可用。 检测可用的 GRUB 命令及其版本。 如果缺少 GRUB 命令,尝试自动安装。 """ + global _grub_install_cmd, _grub_mkconfig_cmd + log_step("检查 chroot 环境", f"挂载点: {mount_point}") - # 检查关键命令是否存在(在 PATH 中) - critical_commands = ["grub-install", "grub-mkconfig", "update-grub", "grub2-install", "grub2-mkconfig"] - found_commands = [] + # 首先尝试找到命令路径 + install_path, mkconfig_path = _get_grub_cmd_path(mount_point, distro_type) - for cmd in critical_commands: - success, _, _ = run_command(["sudo", "chroot", mount_point, "which", cmd], - f"检查命令 {cmd}", timeout=10) - if success: - found_commands.append(cmd) - log_info(f" ✓ 找到命令: {cmd}") - else: - log_debug(f" ✗ 未找到命令: {cmd}") - - # 如果在 PATH 中未找到,检查常见的sbin路径(某些发行版sbin不在默认PATH中) - if not found_commands: - log_info("在 PATH 中未找到命令,检查 sbin 目录...") - sbin_paths = [ - "/usr/sbin/grub2-install", - "/usr/sbin/grub2-mkconfig", - "/usr/sbin/grub-install", - "/usr/sbin/grub-mkconfig", - "/sbin/grub2-install", - "/sbin/grub2-mkconfig", - ] - - for sbin_path in sbin_paths: - full_path = mount_point + sbin_path - if os.path.exists(full_path): - cmd_name = os.path.basename(sbin_path) - found_commands.append(cmd_name) - log_info(f" ✓ 找到命令: {sbin_path}") - - if not found_commands: - log_warning(f"chroot 环境中未找到关键的 GRUB 命令") - log_info(f"尝试自动安装 GRUB 包...") + if install_path and mkconfig_path: + log_info(f" ✓ 找到 grub-install: {install_path}") + log_info(f" ✓ 找到 grub-mkconfig: {mkconfig_path}") + _grub_install_cmd = install_path + _grub_mkconfig_cmd = mkconfig_path + else: + log_warning("未找到 GRUB 命令,尝试自动安装...") # 尝试自动安装 if _auto_install_grub(mount_point, distro_type): - # 重新检查命令 - log_info("重新检查 GRUB 命令...") - for cmd in critical_commands: - success, _, _ = run_command(["sudo", "chroot", mount_point, "which", cmd], - f"检查命令 {cmd}", timeout=10) - if success: - found_commands.append(cmd) - log_info(f" ✓ 找到命令: {cmd}") - - if found_commands: + # 重新查找 + install_path, mkconfig_path = _get_grub_cmd_path(mount_point, distro_type) + if install_path and mkconfig_path: log_success("✓ 自动安装成功,GRUB 命令已可用") + _grub_install_cmd = install_path + _grub_mkconfig_cmd = mkconfig_path else: log_error("✗ 自动安装后仍未找到 GRUB 命令") return False, "自动安装 GRUB 失败,请手动安装" @@ -1098,9 +1111,8 @@ def check_chroot_environment(mount_point: str, distro_type: str = "unknown") -> log_error(f"=" * 60) return False, "自动安装 GRUB 失败" - # 检查 grub-install 版本(优先使用 grub2-install 如果存在) - grub_cmd = "grub2-install" if "grub2-install" in found_commands else "grub-install" - success, stdout, _ = run_command(["sudo", "chroot", mount_point, grub_cmd, "--version"], + # 检查 grub-install 版本 + success, stdout, _ = run_command(["sudo", "chroot", mount_point, _grub_install_cmd, "--version"], "检查 grub-install 版本", timeout=10) if success: log_info(f"grub-install 版本: {stdout.strip()}") @@ -1234,17 +1246,26 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, use_fallback: 是否安装 EFI fallback 文件 efi_bootloader_id: EFI 启动项名称 """ + global _grub_install_cmd, _grub_mkconfig_cmd + log_step("修复 GRUB", f"目标磁盘: {target_disk}, UEFI: {is_uefi}, 发行版: {distro_type}") if not is_uefi and not validate_device_path(target_disk): log_error(f"无效的目标磁盘路径: {target_disk}") return False, f"无效的目标磁盘路径: {target_disk}" - # 检查 chroot 环境 + # 检查 chroot 环境(这会设置 _grub_install_cmd 和 _grub_mkconfig_cmd) ok, err = check_chroot_environment(mount_point, distro_type) if not ok: return False, err + # 确保命令路径已设置 + if not _grub_install_cmd or not _grub_mkconfig_cmd: + return False, "无法确定 GRUB 命令路径" + + log_info(f"使用 grub-install: {_grub_install_cmd}") + log_info(f"使用 grub-mkconfig: {_grub_mkconfig_cmd}") + chroot_cmd_prefix = ["sudo", "chroot", mount_point] # 检测 Live 环境 @@ -1281,7 +1302,7 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, log_warning(f"✗ EFI 目录不存在: {efi_check_path}") grub_install_cmd = chroot_cmd_prefix + [ - "grub-install" if distro_type != "centos" else "grub2-install", + _grub_install_cmd, f"--target={efi_target}", "--efi-directory=/boot/efi", f"--bootloader-id={efi_bootloader_id}", @@ -1292,7 +1313,7 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, if is_live_env: log_info("Live 环境: 优先使用 --removable 模式") removable_cmd = chroot_cmd_prefix + [ - "grub-install" if distro_type != "centos" else "grub2-install", + _grub_install_cmd, f"--target={efi_target}", "--efi-directory=/boot/efi", "--removable", @@ -1312,6 +1333,7 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, else: log_warning(f"removable 模式失败,尝试标准模式") + install_errors.append(f"removable 模式: {stderr}") if not grub_install_success: @@ -1333,7 +1355,7 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, # 第二次尝试: removable 模式 log_info("尝试 2/3: Live环境/可移动模式(--removable)...") removable_cmd = chroot_cmd_prefix + [ - "grub-install" if distro_type != "centos" else "grub2-install", + _grub_install_cmd, f"--target={efi_target}", "--efi-directory=/boot/efi", "--removable", @@ -1376,7 +1398,7 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, log_step("安装 BIOS GRUB") bios_cmd = chroot_cmd_prefix + [ - "grub-install" if distro_type != "centos" else "grub2-install", + _grub_install_cmd, "--target=i386-pc", "--recheck", "--force", @@ -1436,28 +1458,13 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, # ===== 更新 GRUB 配置 ===== log_step("更新 GRUB 配置文件") - # 确定正确的命令和路径 - grub_update_cmd = [] - config_path = "" - - # 根据发行版确定命令 - grub_install_bin = "grub-install" - grub_mkconfig_bin = "grub-mkconfig" - - if distro_type == "centos": - grub_install_bin = "grub2-install" - grub_mkconfig_bin = "grub2-mkconfig" - elif distro_type == "fedora": - grub_mkconfig_bin = "grub2-mkconfig" - elif distro_type == "opensuse": - grub_mkconfig_bin = "grub2-mkconfig" - - # 检测配置文件路径 + # 确定配置文件路径 possible_config_paths = [ "/boot/grub/grub.cfg", "/boot/grub2/grub.cfg", ] + config_path = "" for cfg_path in possible_config_paths: full_path = os.path.join(mount_point, cfg_path.lstrip('/')) if os.path.exists(os.path.dirname(full_path)): @@ -1474,9 +1481,9 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str, if success: grub_update_cmd = ["update-grub"] else: - grub_update_cmd = [grub_mkconfig_bin, "-o", config_path] + grub_update_cmd = [_grub_mkconfig_cmd, "-o", config_path] else: - grub_update_cmd = [grub_mkconfig_bin, "-o", config_path] + grub_update_cmd = [_grub_mkconfig_cmd, "-o", config_path] log_info(f"使用命令: {' '.join(grub_update_cmd)}") log_info(f"配置文件路径: {config_path}")