"""Chroot environment preparation.""" import shutil from pathlib import Path from .utils import info, success, warn, run, is_mounted def prepare_chroot(mount_root: Path | None = None) -> None: """Prepare chroot environment with bind mounts.""" if mount_root is None: mount_root = Path("/mnt/gentoo") info("=== Preparing Chroot Environment ===") # Check if already prepared (idempotency) if is_mounted(mount_root / "proc"): info("Chroot already prepared (skipping)") return # Copy DNS configuration info("Copying DNS configuration...") resolv_src = Path("/etc/resolv.conf") resolv_dst = mount_root / "etc/resolv.conf" if resolv_src.exists(): # Use --dereference to copy the actual file if it's a symlink shutil.copy2(resolv_src.resolve(), resolv_dst) success("Copied resolv.conf") # Bind mount pseudo-filesystems mounts = [ ("proc", "/proc", ["--rbind"]), ("sys", "/sys", ["--rbind"]), ("dev", "/dev", ["--rbind"]), ("run", "/run", ["--rbind"]), ] for name, source, flags in mounts: target = mount_root / name.lstrip("/") target.mkdir(parents=True, exist_ok=True) run("mount", *flags, source, str(target)) run("mount", "--make-rslave", str(target)) success(f"Mounted {source}") print() success("=== Chroot environment ready ===") print() info("To enter chroot:") print(f" chroot {mount_root} /bin/bash") print(" source /etc/profile") print(" export PS1=\"(chroot) $PS1\"") def enter_chroot(mount_root: Path | None = None) -> None: """Enter the chroot environment.""" if mount_root is None: mount_root = Path("/mnt/gentoo") import os os.execvp("chroot", ["chroot", str(mount_root), "/bin/bash", "--login"]) def cleanup_chroot(mount_root: Path | None = None) -> None: """Unmount chroot bind mounts.""" if mount_root is None: mount_root = Path("/mnt/gentoo") info("Cleaning up chroot mounts...") # Unmount in reverse order for name in ["run", "dev", "sys", "proc"]: target = mount_root / name result = run("umount", "-R", str(target), check=False) if not result.ok: # Try lazy unmount as fallback warn(f"Normal unmount failed for {target}, trying lazy unmount...") run("umount", "-Rl", str(target), check=False) success("Chroot mounts cleaned up.")