# single-user-shell — Interactive root shell on /dev/console for # single-user (recovery) mode. Activated only when g_runlevel == SINGLE, # either via -s in kernel boot args or `zygctl single` at runtime. # # Phase A: spawns /sbin/sh with no authentication. Physical console # access == root in this mode. This is intentional — the primary use # case is recovering from forgotten root passwords / borked configs, # which can't gate on the very things we're trying to fix. # # Phase B (future): swap start.sh to invoke /sbin/sulogin which # prompts for the root password and falls through to a root shell on # success. Single TOML edit; the architecture stays the same. [service] name = "single-user-shell" description = "Single-user-mode interactive root shell on /dev/console" type = "daemon" [exec] start = "/etc/zyginit/services/single-user-shell/start.sh" [runlevel] mode = "single" [dependencies] # Filesystem needs to be mounted so /var/log etc. are readable for # diagnosis. Everything beyond filesystem (network, ipmgmtd, dlmgmtd, # etc.) is multi-user only and not started in single-user. requires = ["root-fs", "filesystem"] [restart] # When the user types `exit`, supervisor respawns the shell — that's # the expected single-user UX. To leave single-user, run # `zygctl multi` (or `init 3`) which transitions runlevels and stops # this service before starting multi-user services. on = "always" delay = 0 [contract] # The shell forks children freely; don't let stray exits kill the # contract. We rely on `restart=always` to bring the shell back if # the immediate process dies. param = ["inherit", "noorphan"] fatal = ["hwerr"] #!/bin/sh # single-user-shell/start.sh — replace fd 0/1/2 with /dev/console and # exec the root shell. Supervisor sets up fd 1/2 to point at the per- # service log file by default; for an interactive recovery shell we # need the user's actual console terminal. The redirect happens BEFORE # exec so the shell inherits a controlling tty (zyginit's PID-1 holds # /dev/console with O_NOCTTY, leaving it available to claim). exec /dev/console 2>/dev/console exec /sbin/sh