diff --git a/__pycache__/backend.cpython-39.pyc b/__pycache__/backend.cpython-39.pyc index 3242a64..3da93ce 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 f88d111..4dae880 100644 --- a/backend.py +++ b/backend.py @@ -881,23 +881,116 @@ def detect_distro_type(mount_point: str) -> str: return "unknown" -def _get_grub_package_install_cmd(distro_type: str) -> str: - """获取安装 GRUB 包的命令提示""" - package_commands = { - "centos": "yum install grub2-tools grub2-pc", - "fedora": "dnf install grub2-tools grub2-pc", - "debian": "apt-get install grub-pc", - "ubuntu": "apt-get install grub-pc", - "arch": "pacman -S grub", - "opensuse": "zypper install grub2", +def _get_grub_packages(distro_type: str) -> Tuple[List[str], str]: + """ + 获取安装 GRUB 包所需的包列表和包管理器命令。 + 返回: (包列表, 包管理器基命令) + """ + package_map = { + "centos": (["grub2-tools", "grub2-pc"], "yum install -y"), + "fedora": (["grub2-tools", "grub2-pc"], "dnf install -y"), + "rhel": (["grub2-tools", "grub2-pc"], "yum install -y"), + "rocky": (["grub2-tools", "grub2-pc"], "dnf install -y"), + "almalinux": (["grub2-tools", "grub2-pc"], "dnf install -y"), + "debian": (["grub-pc"], "apt-get install -y"), + "ubuntu": (["grub-pc"], "apt-get install -y"), + "arch": (["grub"], "pacman -S --noconfirm"), + "manjaro": (["grub"], "pacman -S --noconfirm"), + "opensuse": (["grub2"], "zypper install -y"), + "void": (["grub"], "xbps-install -y"), + "gentoo": (["sys-boot/grub"], "emerge"), } - return package_commands.get(distro_type, "安装 GRUB 包(请查阅发行版文档)") + return package_map.get(distro_type, (["grub"], "包管理器安装")) + + +def _auto_install_grub(mount_point: str, distro_type: str) -> bool: + """ + 自动在 chroot 环境中安装 GRUB 包。 + 返回是否成功。 + """ + log_step("自动安装 GRUB 包", f"发行版: {distro_type}") + + packages, pkg_cmd = _get_grub_packages(distro_type) + + if not packages: + log_warning(f"未知的发行版 '{distro_type}',无法自动安装 GRUB") + return False + + chroot_cmd_prefix = ["sudo", "chroot", mount_point] + + # 1. 首先检查网络连接(通过 ping) + log_info("检查网络连接...") + success, _, _ = run_command( + chroot_cmd_prefix + ["ping", "-c", "1", "8.8.8.8"], + "检查网络连接", + timeout=10 + ) + if not success: + # 尝试使用主机的网络配置 + log_warning("chroot 环境无网络,尝试从 Live 环境复制 DNS 配置...") + + # 复制 /etc/resolv.conf + resolv_source = "/etc/resolv.conf" + resolv_target = os.path.join(mount_point, "etc/resolv.conf") + if os.path.exists(resolv_source): + try: + shutil.copy2(resolv_source, resolv_target) + log_info("已复制 DNS 配置") + except Exception as e: + log_warning(f"复制 DNS 配置失败: {e}") + + # 再次检查网络 + success, _, _ = run_command( + chroot_cmd_prefix + ["ping", "-c", "1", "8.8.8.8"], + "再次检查网络连接", + timeout=10 + ) + if not success: + log_error("chroot 环境无法连接网络,无法自动安装 GRUB") + log_info("请手动安装 GRUB 包后再运行此工具") + return False + + log_success("网络连接正常") + + # 2. 更新包列表(某些发行版需要) + update_cmds = { + "debian": ["apt-get", "update"], + "ubuntu": ["apt-get", "update"], + "arch": ["pacman", "-Sy"], + "manjaro": ["pacman", "-Sy"], + } + + if distro_type in update_cmds: + log_info(f"更新 {distro_type} 包列表...") + run_command( + chroot_cmd_prefix + update_cmds[distro_type], + f"更新 {distro_type} 包列表", + timeout=120 + ) + + # 3. 安装 GRUB 包 + log_info(f"安装 GRUB 包: {', '.join(packages)}") + + install_cmd = chroot_cmd_prefix + pkg_cmd.split() + packages + success, stdout, stderr = run_command( + install_cmd, + f"安装 GRUB 包 ({' '.join(packages)})", + timeout=300 + ) + + if success: + log_success(f"✓ GRUB 包安装成功") + return True + else: + log_error(f"✗ GRUB 包安装失败: {stderr}") + return False def check_chroot_environment(mount_point: str, distro_type: str = "unknown") -> Tuple[bool, str]: """ 检查 chroot 环境是否可用。 检测可用的 GRUB 命令及其版本。 + 如果缺少 GRUB 命令,尝试自动安装。 """ log_step("检查 chroot 环境", f"挂载点: {mount_point}") @@ -915,27 +1008,36 @@ def check_chroot_environment(mount_point: str, distro_type: str = "unknown") -> log_debug(f" ✗ 未找到命令: {cmd}") if not found_commands: - log_error(f"=" * 60) - log_error(f"chroot 环境中未找到关键的 GRUB 命令!") - log_error(f"") - log_error(f"目标系统缺少 GRUB 引导加载器。") - log_error(f"") - log_error(f"解决方案:") - log_error(f"1. 进入目标系统的 chroot 环境") - log_error(f"2. 安装 GRUB 包:") - install_cmd = _get_grub_package_install_cmd(distro_type) - log_error(f" {install_cmd}") - log_error(f"") - log_error(f"3. 然后重新运行此工具") - log_error(f"=" * 60) + log_warning(f"chroot 环境中未找到关键的 GRUB 命令") + log_info(f"尝试自动安装 GRUB 包...") - error_msg = ( - f"目标系统缺少 GRUB 工具。\n" - f"请先安装 GRUB 包:\n" - f"{install_cmd}\n" - f"然后重新运行修复工具。" - ) - return False, error_msg + # 尝试自动安装 + 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: + log_success("✓ 自动安装成功,GRUB 命令已可用") + else: + log_error("✗ 自动安装后仍未找到 GRUB 命令") + return False, "自动安装 GRUB 失败,请手动安装" + else: + log_error("=" * 60) + log_error(f"无法自动安装 GRUB 包") + log_error(f"") + log_error(f"请手动安装 GRUB 包:") + packages, pkg_cmd = _get_grub_packages(distro_type) + log_error(f" chroot {mount_point}") + log_error(f" {pkg_cmd} {' '.join(packages)}") + log_error(f" exit") + log_error(f"=" * 60) + return False, "自动安装 GRUB 失败" # 检查 grub-install 版本(优先使用 grub2-install 如果存在) grub_cmd = "grub2-install" if "grub2-install" in found_commands else "grub-install"