2
This commit is contained in:
129
backend.py
129
backend.py
@@ -1971,17 +1971,40 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str,
|
|||||||
else:
|
else:
|
||||||
grub_dir_name = "grub"
|
grub_dir_name = "grub"
|
||||||
|
|
||||||
# 1. 清空 /boot/grub* 目录
|
# 1. 检查并恢复 GRUB 模块(从系统包中)
|
||||||
|
log_info("检查 GRUB EFI 模块...")
|
||||||
|
grub_modules_dir = os.path.join(mount_point, f"usr/lib/grub/x86_64-efi")
|
||||||
|
boot_grub_mods = os.path.join(mount_point, "boot", grub_dir_name, "x86_64-efi")
|
||||||
|
|
||||||
|
if os.path.exists(grub_modules_dir):
|
||||||
|
log_info(f"✓ 系统模块目录: {grub_modules_dir}")
|
||||||
|
# 确保 /boot/grub2/x86_64-efi 存在且包含模块
|
||||||
|
if not os.path.exists(boot_grub_mods) or len(os.listdir(boot_grub_mods)) < 10:
|
||||||
|
log_info("复制 GRUB 模块到 /boot...")
|
||||||
|
try:
|
||||||
|
import shutil
|
||||||
|
if os.path.exists(boot_grub_mods):
|
||||||
|
shutil.rmtree(boot_grub_mods)
|
||||||
|
shutil.copytree(grub_modules_dir, boot_grub_mods)
|
||||||
|
mod_count = len(os.listdir(boot_grub_mods))
|
||||||
|
log_success(f"✓ 复制 {mod_count} 个模块到 {boot_grub_mods}")
|
||||||
|
except Exception as e:
|
||||||
|
log_warning(f"复制模块失败: {e}")
|
||||||
|
|
||||||
|
# 2. 清空 /boot/grub* 目录中的配置和临时文件(保留模块和字体)
|
||||||
boot_grub_paths = [
|
boot_grub_paths = [
|
||||||
os.path.join(mount_point, "boot", "grub"),
|
os.path.join(mount_point, "boot", "grub"),
|
||||||
os.path.join(mount_point, "boot", "grub2"),
|
os.path.join(mount_point, "boot", "grub2"),
|
||||||
]
|
]
|
||||||
for grub_path in boot_grub_paths:
|
for grub_path in boot_grub_paths:
|
||||||
if os.path.exists(grub_path):
|
if os.path.exists(grub_path):
|
||||||
log_info(f"清空目录: {grub_path}")
|
log_info(f"清理目录: {grub_path}")
|
||||||
try:
|
try:
|
||||||
# 删除目录内所有内容但保留目录本身
|
# 只删除配置文件和临时文件,保留 x86_64-efi 目录和字体
|
||||||
|
preserve_dirs = {"x86_64-efi", "i386-pc", "fonts", "locale"}
|
||||||
for item in os.listdir(grub_path):
|
for item in os.listdir(grub_path):
|
||||||
|
if item in preserve_dirs:
|
||||||
|
continue
|
||||||
item_path = os.path.join(grub_path, item)
|
item_path = os.path.join(grub_path, item)
|
||||||
if os.path.isfile(item_path) or os.path.islink(item_path):
|
if os.path.isfile(item_path) or os.path.islink(item_path):
|
||||||
os.unlink(item_path)
|
os.unlink(item_path)
|
||||||
@@ -1990,9 +2013,9 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str,
|
|||||||
import shutil
|
import shutil
|
||||||
shutil.rmtree(item_path)
|
shutil.rmtree(item_path)
|
||||||
log_debug(f" 删除目录: {item}")
|
log_debug(f" 删除目录: {item}")
|
||||||
log_success(f"✓ 已清空: {grub_path}")
|
log_success(f"✓ 已清理: {grub_path}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log_warning(f"清空失败: {e}")
|
log_warning(f"清理失败: {e}")
|
||||||
|
|
||||||
# 2. 清空 EFI 分区中的 GRUB 相关目录
|
# 2. 清空 EFI 分区中的 GRUB 相关目录
|
||||||
efi_cleanup_dirs = ["GRUB", "grub", "Boot", "boot", "centos", "redhat", "fedora"]
|
efi_cleanup_dirs = ["GRUB", "grub", "Boot", "boot", "centos", "redhat", "fedora"]
|
||||||
@@ -2446,7 +2469,101 @@ def chroot_and_repair_grub(mount_point: str, target_disk: str,
|
|||||||
|
|
||||||
if not success:
|
if not success:
|
||||||
log_error(f"GRUB 配置文件更新失败: {stderr}")
|
log_error(f"GRUB 配置文件更新失败: {stderr}")
|
||||||
return False, f"GRUB配置文件更新失败: {stderr}"
|
|
||||||
|
# 备选方案:手动创建基本 grub.cfg
|
||||||
|
log_step("尝试手动创建基本 grub.cfg")
|
||||||
|
|
||||||
|
# 获取根分区信息
|
||||||
|
root_part = None
|
||||||
|
root_uuid = None
|
||||||
|
try:
|
||||||
|
# 从 /etc/fstab 获取根分区
|
||||||
|
fstab_path = os.path.join(mount_point, "etc/fstab")
|
||||||
|
if os.path.exists(fstab_path):
|
||||||
|
with open(fstab_path, 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith('#') or not line.strip():
|
||||||
|
continue
|
||||||
|
parts = line.split()
|
||||||
|
if len(parts) >= 2 and parts[1] == '/':
|
||||||
|
root_part = parts[0]
|
||||||
|
break
|
||||||
|
|
||||||
|
# 获取 UUID
|
||||||
|
if root_part and root_part.startswith('UUID='):
|
||||||
|
root_uuid = root_part[5:].strip('"')
|
||||||
|
elif root_part and root_part.startswith('/dev/'):
|
||||||
|
success_uuid, uuid_out, _ = run_command(
|
||||||
|
["sudo", "blkid", "-s", "UUID", "-o", "value", root_part],
|
||||||
|
f"获取 {root_part} 的 UUID",
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
if success_uuid:
|
||||||
|
root_uuid = uuid_out.strip()
|
||||||
|
except Exception as e:
|
||||||
|
log_warning(f"获取根分区信息失败: {e}")
|
||||||
|
|
||||||
|
# 查找内核文件
|
||||||
|
boot_dir = os.path.join(mount_point, "boot")
|
||||||
|
kernel_files = []
|
||||||
|
initramfs_files = []
|
||||||
|
try:
|
||||||
|
for f in os.listdir(boot_dir):
|
||||||
|
if f.startswith('vmlinuz-'):
|
||||||
|
kernel_files.append(f)
|
||||||
|
elif f.startswith('initramfs-') and f.endswith('.img') and 'kdump' not in f:
|
||||||
|
initramfs_files.append(f)
|
||||||
|
kernel_files.sort(reverse=True)
|
||||||
|
initramfs_files.sort(reverse=True)
|
||||||
|
except Exception as e:
|
||||||
|
log_warning(f"查找内核文件失败: {e}")
|
||||||
|
|
||||||
|
if kernel_files and root_uuid:
|
||||||
|
# 创建基本 grub.cfg
|
||||||
|
grub_cfg_content = f"""# Minimal GRUB config generated by BootRepairTool
|
||||||
|
set timeout=5
|
||||||
|
set default=0
|
||||||
|
|
||||||
|
# Load necessary modules
|
||||||
|
insmod part_gpt
|
||||||
|
insmod xfs
|
||||||
|
insmod fat
|
||||||
|
|
||||||
|
# Search for the root partition by UUID
|
||||||
|
search --no-floppy --fs-uuid --set=root {root_uuid}
|
||||||
|
|
||||||
|
menuentry 'CentOS Linux (Auto)' {{
|
||||||
|
load_video
|
||||||
|
set gfxpayload=keep
|
||||||
|
insmod gzio
|
||||||
|
insmod part_gpt
|
||||||
|
insmod xfs
|
||||||
|
linux /{kernel_files[0]} root=UUID={root_uuid} ro
|
||||||
|
initrd /{initramfs_files[0] if initramfs_files else ''}
|
||||||
|
}}
|
||||||
|
|
||||||
|
menuentry 'CentOS Linux (Rescue)' {{
|
||||||
|
load_video
|
||||||
|
set gfxpayload=keep
|
||||||
|
insmod gzio
|
||||||
|
insmod part_gpt
|
||||||
|
insmod xfs
|
||||||
|
linux /{kernel_files[0]} root=UUID={root_uuid} ro rescue
|
||||||
|
initrd /{initramfs_files[0] if initramfs_files else ''}
|
||||||
|
}}
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
with open(full_config_path, 'w') as f:
|
||||||
|
f.write(grub_cfg_content)
|
||||||
|
log_success(f"✓ 手动创建 grub.cfg: {full_config_path}")
|
||||||
|
log_info(f" 内核: {kernel_files[0]}")
|
||||||
|
log_info(f" UUID: {root_uuid}")
|
||||||
|
success = True
|
||||||
|
except Exception as e:
|
||||||
|
log_error(f"手动创建 grub.cfg 失败: {e}")
|
||||||
|
return False, f"GRUB配置失败: {stderr}"
|
||||||
|
else:
|
||||||
|
return False, f"GRUB配置失败,无法获取内核或UUID"
|
||||||
|
|
||||||
log_success("✓ GRUB 配置文件更新成功")
|
log_success("✓ GRUB 配置文件更新成功")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user