orchestrator: always unwind bind mounts on exit

Bind mounts set up in run_chroot_finalizer used to be torn down in finish,
but finish doesn't run when a phase between the two raises. Move the unmount
loop into a dedicated cleanup_bind_mounts function and call it from main()'s
finally so it runs on success, failure, and KeyboardInterrupt.
This commit is contained in:
Ryan Hughes committed 2026-05-21 17:52:12 -04:00
1 parent 26f87f6789
commit 6d6b516221
2 files changed
+27 -14

No files matched your search

@@ -66,17 +66,22 @@ def main(argv=None) -> int:
info(f"Installing Omarchy for {ctx.username} → {ctx.target}")
try:
run(ctx, build_phases())
except PhaseError:
error("Installation halted.")
return 1
except KeyboardInterrupt:
error("Installation interrupted.")
return 130
from .phases_impl import cleanup_bind_mounts
info("Installation complete.")
return 0
try:
try:
run(ctx, build_phases())
except PhaseError:
error("Installation halted.")
return 1
except KeyboardInterrupt:
error("Installation interrupted.")
return 130
info("Installation complete.")
return 0
finally:
cleanup_bind_mounts(ctx)
if __name__ == "__main__":
@@ -359,13 +359,21 @@ def validate_boot(ctx: InstallContext) -> None:
# ─────────────────────────────────────────────────────────────────────────────
# finish: unwind bind mounts, prompt for reboot.
# cleanup_bind_mounts: invoked from main()'s finally so bind mounts get
# unwound on success, failure, or interrupt. Idempotent.
# ─────────────────────────────────────────────────────────────────────────────
def cleanup_bind_mounts(ctx: InstallContext) -> None:
for mount_point in ctx.state.get("bind_mounts", []):
subprocess.run(["umount", mount_point], check=False, capture_output=True)
ctx.state["bind_mounts"] = []
# ─────────────────────────────────────────────────────────────────────────────
# finish: prompt for reboot. Bind mounts are unwound in main()'s finally.
# ─────────────────────────────────────────────────────────────────────────────
def finish(ctx: InstallContext) -> None:
for mount_point in ctx.state.get("bind_mounts", []):
subprocess.run(["umount", mount_point], check=False, capture_output=True)
info("Installation finished. Reboot when ready.")
if confirm("Reboot now?", default=True):
os.system("reboot")