# Services, readiness, and shutdown [Documentation index](README.md) · [Native init and ARM VM](init.md) · [Cartridges](cartridges.md) **Implemented in M2:** native s6 PID 1, a compiled base service graph, console login, eudev, the Dasung controller, and a controllable test service. The [init walkthrough](init.md) explains how to boot the ARM VM and try the commands below. M6 adds the base cartridge service; M8 adds optional desktop/network profiles as described in the [desktop guide](desktop.md). ## Startup and service state ```text Linux → /sbin/init → s6-linux-init → s6-svscan (PID 1) └── rc.init → s6-rc-init → s6-rc change boot ``` The generated execline launcher immediately executes native init. Stage 1 prepares writable `/run`, starts the catch-all logger, and replaces itself with s6-svscan. Bash stage-2 scripts run as ordinary children. They initialize the live database and activate the `boot` bundle. No service compiler runs during boot. | Location in FDS | Purpose | | --- | --- | | `/etc/s6-rc/source` | Packaged, readable service definitions | | `/etc/s6-rc/compiled` | Dependency database compiled under ARM emulation during the build | | `/run/s6-rc` | Live service state on tmpfs | | `/run/service` | Supervision directories created at runtime | | `/run/uncaught-logs` | Native init catch-all log, also copied to the console | | `/run/log/dasungd` | Rotating monitor-controller log | These are guest paths, not instructions to start services on the Arch host. The Void build container never boots the FDS service graph. ## The base boot graph | Service | Function | Dependencies | | --- | --- | --- | | `runtime-fs` | Mount proc, sysfs, devpts and volatile temporary/log paths | Kernel or stage 0 supplies `/dev`; native stage 1 supplies `/run` | | `hostname` | Set the image's hostname | None | | `console` | Create volatile login accounting files | `runtime-fs` | | `getty` | Provide a console login | `console`, `hostname` | | `eudevd` | Process kernel device events | `runtime-fs`; readiness checked through its control channel | | `udev-trigger` | Request initial subsystem and device events | Ready `eudevd` | | `machine-config` | Validate internal NVMe settings and publish a fixed boot snapshot, or image defaults | `runtime-fs`; no console dependency | | `cartridged-runtime` | Prepare bounded cartridge log storage | `runtime-fs` | | `cartridged-log`, `cartridged` | USB events, bay inventory, validated mounts and IPC | Runtime paths and `machine-config`; no getty or eudev readiness dependency | | `dasungd-runtime` | Prepare private controller state and log paths | `runtime-fs` | | `dasungd-log`, `dasungd` | Supervise the monitor controller and its logger | Runtime paths and s6's logging pipeline | The bundle selects these services through their dependencies; it does not impose one serial list. Console startup does not wait for device enumeration, monitor reconnection, networking, or cartridge discovery. Dasung remains part of the base, independent of a GUI or an inserted ENVIRONMENT cartridge. See [Dasung](dasung.md). M6 includes the real static `cartridged` service and its logger. Network, DHCP, NTP, sshd, D-Bus, Xorg, WindowMaker, Bluetooth, and Wi-Fi are absent from the current boot bundle. ## Inspect and control services Inside the shell opened by `make vm`: ```sh s6-rc -l /run/s6-rc -a list s6-svstat /run/service/getty s6-svstat /run/service/eudevd s6-svstat /run/service/dasungd cat /run/log/dasungd/current s6-rc -l /run/s6-rc -u change test-echo s6-svstat -o up,ready,pid /run/service/test-echo printf 'hello\n' | s6-ipcclient /run/fds-test/echo.sock s6-ioconnect -t 3000 s6-rc -l /run/s6-rc -d change test-echo ``` `test-echo` is a root-only Unix-socket echo server. Its database entry ships in this development rootfs, but it is excluded from the normal boot bundle. Its `test-runtime` dependency creates `/run/fds-test` with mode 0700. The ARM boot test verifies replies, a supervised restart with a new PID, and stop/start state transitions. It also verifies that getty and Dasung are running without hardware. ## Readiness and failures A process existing does not always mean its service is usable. The echo server notifies s6 after it starts listening. Eudev has no native s6 notification, so `s6-notifyoncheck` checks its control channel within a bounded deadline. The initial device trigger does not wait for every unrelated device to settle. There is no global `udevadm settle` or sleep added to hide a boot race. A missing monitor leaves Dasung supervised and disconnected; it does not hold up getty. Service errors go to the runtime logs and console. Investigate the failed service and its dependencies instead of extending an arbitrary startup delay. ## Shutdown `poweroff`, `reboot`, `halt`, and `shutdown` are the native s6-linux-init wrappers. M10's `fds poweroff` and `fds reboot` first freeze new operations, stop optional sessions and managed jobs, then verify DATA and cartridge unmounts. A native shutdown hook also enforces this preparation for administrative use of the wrappers. Only successful preparation proceeds to the remaining s6 service stop and final kernel action. The two internal s6-rc helper services are marked essential and remain until native final cleanup; its diagnostic warnings about not stopping them are expected. The [shutdown guide](power.md) explains commands, failure recovery and the current M10 acceptance status. No physical Pi shutdown measurement is claimed. See [Performance](performance.md) for the hardware targets and measurement boundaries. M8 ENVIRONMENT profiles select OS-defined service bundles after console readiness. Profile metadata is declarative; a cartridge cannot inject a root shell script into startup. See [Cartridges](cartridges.md) for that trust boundary. ## Cartridge service M6 adds `cartridged` and its bounded volatile logger to the base boot bundle. It depends on runtime filesystem setup and M12 machine settings loading, independently of getty and eudev. See [Internal storage](internal-storage.md) for the read-only loading policy and explicit fallback diagnostics. Its readiness notification means the control socket exists, not that all cartridges have finished enumeration. Getty has no cartridge dependency. The service listens before scanning and reconciles kernel USB/block events with current sysfs state. See [Cartridges](cartridges.md) for configuration, controls, restart behavior and diagnostics. Dasung stays a separate mandatory base service. ## Optional desktop and network graph The `desktop` bundle selects `xserver` and `desktop-session`. Xorg's display-fd notification establishes server readiness; the static session helper subscribes to X11 property events before launching WindowMaker, then observes its EWMH supporting-window property. This avoids missing an event when the atom does not yet exist. Session processes run as fds in a root-owned cgroup. Their descendants are stopped before Xorg. Native service supervision handles unexpected exits. The `network` bundle selects `dhcp`. Its process readiness does not wait for a lease; DHCP remains asynchronous. Both bundles have bounded volatile loggers, and neither belongs to `boot`. Their runtime directories are prepared by separate oneshots. See [Desktop and Ethernet](desktop.md) for user commands. M10 places the DHCP client and its privilege-separated children in a root-owned cgroup. Network stop checks actual group exit as well as the supervised main process, then brings the managed interfaces down and clears volatile resolver state. It introduces no additional daemon or boot dependency.