228 lines
6.5 KiB
Python
228 lines
6.5 KiB
Python
"""GRUB bootloader installation and configuration."""
|
|
|
|
import re
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
from .utils import info, success, error, warn, run, emerge
|
|
|
|
|
|
def emerge_grub() -> None:
|
|
"""Install GRUB bootloader."""
|
|
info("=== Installing GRUB ===")
|
|
|
|
emerge("sys-boot/grub")
|
|
|
|
success("GRUB installed.")
|
|
|
|
|
|
def install_grub_efi() -> None:
|
|
"""Install GRUB to EFI system partition."""
|
|
info("=== Installing GRUB to EFI ===")
|
|
|
|
run(
|
|
"grub-install",
|
|
"--target=x86_64-efi",
|
|
"--efi-directory=/boot",
|
|
"--bootloader-id=Gentoo",
|
|
)
|
|
|
|
success("GRUB installed to EFI partition.")
|
|
|
|
|
|
def configure_grub() -> None:
|
|
"""Configure GRUB for LUKS + NVIDIA."""
|
|
info("=== Configuring GRUB ===")
|
|
|
|
grub_default = Path("/etc/default/grub")
|
|
|
|
if not grub_default.exists():
|
|
error("/etc/default/grub not found")
|
|
return
|
|
|
|
content = grub_default.read_text()
|
|
changes_made = False
|
|
|
|
# Settings to apply (use regex for robust matching of commented/uncommented lines)
|
|
settings = {
|
|
"GRUB_CMDLINE_LINUX_DEFAULT": '"nvidia_drm.modeset=1 acpi_backlight=native"',
|
|
"GRUB_ENABLE_CRYPTODISK": "y",
|
|
"GRUB_GFXMODE": "1920x1080",
|
|
}
|
|
|
|
for key, value in settings.items():
|
|
full_setting = f'{key}={value}'
|
|
pattern = rf'^#?\s*{key}=.*$'
|
|
|
|
if re.search(pattern, content, re.MULTILINE):
|
|
# Replace existing line (commented or not)
|
|
new_content = re.sub(pattern, full_setting, content, flags=re.MULTILINE)
|
|
if new_content != content:
|
|
content = new_content
|
|
changes_made = True
|
|
else:
|
|
# Append if not found at all
|
|
content += f"\n{full_setting}"
|
|
changes_made = True
|
|
|
|
if changes_made:
|
|
grub_default.write_text(content)
|
|
success("GRUB configured for LUKS + NVIDIA + HiDPI")
|
|
print(" - GRUB_CMDLINE_LINUX_DEFAULT: nvidia_drm.modeset=1 acpi_backlight=native")
|
|
print(" - GRUB_ENABLE_CRYPTODISK: y")
|
|
print(" - GRUB_GFXMODE: 1920x1080")
|
|
else:
|
|
info("GRUB already configured")
|
|
|
|
|
|
def generate_grub_config() -> None:
|
|
"""Generate GRUB configuration."""
|
|
info("=== Generating GRUB Config ===")
|
|
|
|
run("grub-mkconfig", "-o", "/boot/grub/grub.cfg")
|
|
|
|
success("GRUB config generated.")
|
|
|
|
|
|
def copy_dracut_crypt_config(source_dir: Path) -> None:
|
|
"""Copy LUKS dracut configuration."""
|
|
info("=== Copying Dracut Crypt Config ===")
|
|
|
|
dracut_src = source_dir / "dracut.conf.d" / "crypt.conf"
|
|
dracut_dst = Path("/etc/dracut.conf.d")
|
|
dracut_dst.mkdir(parents=True, exist_ok=True)
|
|
|
|
if dracut_src.exists():
|
|
shutil.copy2(dracut_src, dracut_dst / "crypt.conf")
|
|
success("Copied crypt.conf to /etc/dracut.conf.d/")
|
|
else:
|
|
# Create default if not in source
|
|
crypt_conf = dracut_dst / "crypt.conf"
|
|
crypt_conf.write_text(
|
|
"# LUKS support for encrypted root\n"
|
|
'add_dracutmodules+=" crypt "\n'
|
|
)
|
|
success("Created default /etc/dracut.conf.d/crypt.conf")
|
|
|
|
|
|
def verify_initramfs() -> None:
|
|
"""Verify initramfs has required modules for boot."""
|
|
info("=== Verifying Initramfs ===")
|
|
|
|
# Find latest initramfs
|
|
boot = Path("/boot")
|
|
initramfs_files = sorted(boot.glob("initramfs-*.img"), reverse=True)
|
|
|
|
if not initramfs_files:
|
|
error("No initramfs found in /boot")
|
|
return
|
|
|
|
initramfs = initramfs_files[0]
|
|
info(f"Checking {initramfs.name}...")
|
|
|
|
result = run("lsinitrd", str(initramfs), capture=True, check=False)
|
|
|
|
if not result.ok or not result.stdout:
|
|
error("Could not inspect initramfs")
|
|
return
|
|
|
|
output = result.stdout
|
|
|
|
# Check for crypt/LUKS modules
|
|
print()
|
|
info("LUKS/Crypt modules:")
|
|
crypt_found = False
|
|
for keyword in ["crypt", "luks", "dm-crypt"]:
|
|
matches = [line for line in output.split("\n") if keyword in line.lower()]
|
|
if matches:
|
|
crypt_found = True
|
|
for match in matches[:5]:
|
|
print(f" {match}")
|
|
|
|
if crypt_found:
|
|
success("LUKS support found in initramfs")
|
|
else:
|
|
error("WARNING: No LUKS/crypt modules found!")
|
|
print(" Boot from encrypted root may fail.")
|
|
|
|
# Check for NVIDIA modules
|
|
print()
|
|
info("NVIDIA modules:")
|
|
nvidia_found = False
|
|
nvidia_modules = [line for line in output.split("\n") if "nvidia" in line.lower()]
|
|
|
|
if nvidia_modules:
|
|
nvidia_found = True
|
|
for module in nvidia_modules[:5]:
|
|
print(f" {module}")
|
|
success("NVIDIA modules found in initramfs")
|
|
else:
|
|
warn("No NVIDIA modules in initramfs (may be OK if not using early KMS)")
|
|
|
|
# Summary
|
|
print()
|
|
if crypt_found and nvidia_found:
|
|
success("Initramfs verification PASSED - LUKS and NVIDIA modules present")
|
|
elif crypt_found:
|
|
success("Initramfs verification PASSED - system should boot (NVIDIA optional)")
|
|
else:
|
|
error("Initramfs verification FAILED - fix before rebooting!")
|
|
|
|
|
|
def rebuild_initramfs() -> None:
|
|
"""Rebuild initramfs with current configuration."""
|
|
info("=== Rebuilding Initramfs ===")
|
|
|
|
# Find installed kernel version
|
|
modules_dir = Path("/lib/modules")
|
|
if not modules_dir.exists():
|
|
error("No kernel modules found. Install kernel first.")
|
|
return
|
|
|
|
kernels = sorted(modules_dir.iterdir(), reverse=True)
|
|
if not kernels:
|
|
error("No kernel versions found in /lib/modules")
|
|
return
|
|
|
|
kernel_version = kernels[0].name
|
|
info(f"Rebuilding initramfs for kernel {kernel_version}")
|
|
|
|
run("dracut", "--force", f"/boot/initramfs-{kernel_version}.img", kernel_version)
|
|
|
|
success("Initramfs rebuilt.")
|
|
|
|
|
|
def setup_bootloader(source_dir: Path | None = None) -> None:
|
|
"""Full bootloader setup workflow."""
|
|
if source_dir is None:
|
|
source_dir = Path("/root/gentoo")
|
|
|
|
# Ensure dracut crypt config is in place
|
|
copy_dracut_crypt_config(source_dir)
|
|
print()
|
|
|
|
emerge_grub()
|
|
print()
|
|
install_grub_efi()
|
|
print()
|
|
configure_grub()
|
|
print()
|
|
generate_grub_config()
|
|
print()
|
|
|
|
# Verify initramfs
|
|
verify_initramfs()
|
|
|
|
print()
|
|
success("=== Bootloader Setup Complete ===")
|
|
print()
|
|
info("Pre-reboot checklist:")
|
|
print(" 1. Verify /etc/fstab is correct")
|
|
print(" 2. Verify /etc/conf.d/dmcrypt has swap configured")
|
|
print(" 3. Ensure root password is set")
|
|
print(" 4. Ensure user account exists")
|
|
print()
|
|
info("Ready to reboot!")
|
|
print(" exit # Leave chroot")
|
|
print(" reboot # Restart system")
|