This commit is contained in:
zj
2026-02-11 02:38:52 +08:00
parent 70d8ac41b4
commit cdb32839d5
6 changed files with 525 additions and 151 deletions

View File

@@ -3,6 +3,8 @@
import tkinter as tk
from tkinter import ttk, messagebox
import threading
import os
import re
import backend # 导入后端逻辑
class GrubRepairApp:
@@ -153,18 +155,31 @@ class GrubRepairApp:
self.selected_root_partition_info = self.all_partitions_data.get(selected_display)
if self.selected_root_partition_info:
self.log_message(f"已选择根分区: {self.selected_root_partition_info['name']}", "info")
# 尝试根据根分区所在的磁盘自动选择目标磁盘
# /dev/sda1 -> /dev/sda
disk_name_from_root = "/".join(self.selected_root_partition_info['name'].split('/')[:3])
if disk_name_from_root in self.target_disk_combo['values']:
self.target_disk_combo.set(disk_name_from_root)
self.selected_target_disk_info = self.all_disks_data.get(disk_name_from_root)
self.log_message(f"自动选择目标磁盘: {self.selected_target_disk_info['name']}", "info")
else:
root_part_name = self.selected_root_partition_info['name']
self.log_message(f"已选择根分区: {root_part_name}", "info")
# 检查是否是 LVM 逻辑卷
is_lvm = self.selected_root_partition_info.get('is_lvm', False)
if is_lvm:
# LVM 逻辑卷无法直接从路径推断父磁盘,提示用户手动选择
self.target_disk_combo.set("")
self.selected_target_disk_info = None
self.log_message("无法自动选择目标磁盘,请手动选择", "warning")
self.log_message("检测到 LVM 逻辑卷,请手动选择 GRUB 安装的目标磁盘", "warning")
else:
# 尝试根据根分区所在的磁盘自动选择目标磁盘
# /dev/sda1 -> /dev/sda
# /dev/nvme0n1p1 -> /dev/nvme0n1
# /dev/mmcblk0p1 -> /dev/mmcblk0
disk_name_from_root = re.sub(r'(\d+)?p?\d+$', '', root_part_name)
if disk_name_from_root in self.target_disk_combo['values']:
self.target_disk_combo.set(disk_name_from_root)
self.selected_target_disk_info = self.all_disks_data.get(disk_name_from_root)
self.log_message(f"自动选择目标磁盘: {self.selected_target_disk_info['name']}", "info")
else:
self.target_disk_combo.set("")
self.selected_target_disk_info = None
self.log_message("无法自动选择目标磁盘,请手动选择。", "warning")
else:
self.selected_root_partition_info = None
self.target_disk_combo.set("")
@@ -215,71 +230,76 @@ class GrubRepairApp:
repair_thread.start()
def _run_repair_process(self):
root_part_path = self.selected_root_partition_info['name']
boot_part_path = self.selected_boot_partition_info['name'] if self.selected_boot_partition_info else None
efi_part_path = self.selected_efi_partition_info['name'] if self.selected_efi_partition_info else None
target_disk_path = self.selected_target_disk_info['name']
try:
root_part_path = self.selected_root_partition_info['name']
boot_part_path = self.selected_boot_partition_info['name'] if self.selected_boot_partition_info else None
efi_part_path = self.selected_efi_partition_info['name'] if self.selected_efi_partition_info else None
target_disk_path = self.selected_target_disk_info['name']
self.log_message(f"选择的根分区: {root_part_path}", "info")
self.log_message(f"选择的独立 /boot 分区: {boot_part_path if boot_part_path else ''}", "info")
self.log_message(f"选择的EFI分区: {efi_part_path if efi_part_path else ''}", "info")
self.log_message(f"GRUB安装目标磁盘: {target_disk_path}", "info")
self.log_message(f"UEFI模式: {'启用' if self.is_uefi_mode else '禁用'}", "info")
self.log_message(f"选择的根分区: {root_part_path}", "info")
self.log_message(f"选择的独立 /boot 分区: {boot_part_path if boot_part_path else ''}", "info")
self.log_message(f"选择的EFI分区: {efi_part_path if efi_part_path else ''}", "info")
self.log_message(f"GRUB安装目标磁盘: {target_disk_path}", "info")
self.log_message(f"UEFI模式: {'启用' if self.is_uefi_mode else '禁用'}", "info")
# 1. 挂载目标系统
self.log_message("正在挂载目标系统分区...", "info")
mount_ok, self.mount_point, mount_err = backend.mount_target_system(
root_part_path,
boot_part_path,
efi_part_path if self.is_uefi_mode else None # 只有UEFI模式才挂载EFI分区
)
if not mount_ok:
self.log_message(f"挂载失败,修复中止: {mount_err}", "error")
messagebox.showerror("修复失败", f"无法挂载目标系统分区。请检查分区选择和权限。\n错误: {mount_err}")
self.start_button.config(state="normal")
return
# 1. 挂载目标系统
self.log_message("正在挂载目标系统分区...", "info")
mount_ok, self.mount_point, mount_err = backend.mount_target_system(
root_part_path,
boot_part_path,
efi_part_path if self.is_uefi_mode else None # 只有UEFI模式才挂载EFI分区
)
if not mount_ok:
self.log_message(f"挂载失败,修复中止: {mount_err}", "error")
self.master.after(0, lambda: messagebox.showerror("修复失败", f"无法挂载目标系统分区。请检查分区选择和权限。\n错误: {mount_err}"))
return
# 2. 尝试识别发行版类型
self.log_message("正在检测目标系统发行版...", "info")
distro_type = backend.detect_distro_type(self.mount_point)
self.log_message(f"检测到目标系统发行版: {distro_type}", "info")
# 2. 尝试识别发行版类型
self.log_message("正在检测目标系统发行版...", "info")
distro_type = backend.detect_distro_type(self.mount_point)
self.log_message(f"检测到目标系统发行版: {distro_type}", "info")
# 3. Chroot并修复GRUB
self.log_message("正在进入Chroot环境并修复GRUB...", "info")
repair_ok, repair_err = backend.chroot_and_repair_grub(
self.mount_point,
target_disk_path,
self.is_uefi_mode,
distro_type
)
if not repair_ok:
self.log_message(f"GRUB修复失败: {repair_err}", "error")
messagebox.showerror("修复失败", f"GRUB修复过程中发生错误。\n错误: {repair_err}")
# 即使失败,也要尝试卸载
else:
self.log_message("GRUB修复命令执行成功", "success")
# 3. Chroot并修复GRUB
self.log_message("正在进入Chroot环境并修复GRUB...", "info")
repair_ok, repair_err = backend.chroot_and_repair_grub(
self.mount_point,
target_disk_path,
self.is_uefi_mode,
distro_type
)
if not repair_ok:
self.log_message(f"GRUB修复失败: {repair_err}", "error")
self.master.after(0, lambda: messagebox.showerror("修复失败", f"GRUB修复过程中发生错误。\n错误: {repair_err}"))
# 即使失败,也要尝试卸载
else:
self.log_message("GRUB修复命令执行成功", "success")
# 4. 卸载分区
self.log_message("正在卸载目标系统分区...", "info")
unmount_ok, unmount_err = backend.unmount_target_system(self.mount_point)
if not unmount_ok:
self.log_message(f"卸载分区失败: {unmount_err}", "error")
messagebox.showwarning("卸载警告", f"部分分区可能未能正确卸载。请手动检查并卸载。\n错误: {unmount_err}")
else:
self.log_message("所有分区已成功卸载。", "success")
# 4. 卸载分区
self.log_message("正在卸载目标系统分区...", "info")
unmount_ok, unmount_err = backend.unmount_target_system(self.mount_point)
if not unmount_ok:
self.log_message(f"卸载分区失败: {unmount_err}", "error")
self.master.after(0, lambda: messagebox.showwarning("卸载警告", f"部分分区可能未能正确卸载。请手动检查并卸载。\n错误: {unmount_err}"))
else:
self.log_message("所有分区已成功卸载。", "success")
self.log_message("--- GRUB 修复过程结束 ---", "info")
# 最终结果提示
if repair_ok and unmount_ok:
self.master.after(0, lambda: messagebox.showinfo("修复成功", "GRUB引导修复已完成请重启系统以验证。"))
elif repair_ok and not unmount_ok:
self.master.after(0, lambda: messagebox.showwarning("修复完成,但有警告", "GRUB引导修复已完成但部分分区卸载失败。请重启系统以验证。"))
else:
self.master.after(0, lambda: messagebox.showerror("修复失败", "GRUB引导修复过程中发生错误。请检查日志并尝试手动修复。"))
self.log_message("--- GRUB 修复过程结束 ---", "info")
# 最终结果提示
if repair_ok and unmount_ok:
messagebox.showinfo("修复成功", "GRUB引导修复已完成请重启系统以验证。")
elif repair_ok and not unmount_ok:
messagebox.showwarning("修复完成,但有警告", "GRUB引导修复已完成但部分分区卸载失败。请重启系统以验证。")
else:
messagebox.showerror("修复失败", "GRUB引导修复过程中发生错误。请检查日志并尝试手动修复。")
self.start_button.config(state="normal")
except Exception as e:
self.log_message(f"发生未预期的错误: {str(e)}", "error")
self.master.after(0, lambda err=str(e): messagebox.showerror("错误", f"修复过程中发生错误:\n{err}"))
finally:
# 确保按钮状态被恢复
self.master.after(0, lambda: self.start_button.config(state="normal"))
if __name__ == "__main__":