Files
fds-os/docs/developer/services.md
T
2026-09-22 13:23:34 +08:00

7.7 KiB

Services, readiness, and shutdown

Development reference and historical context. For current operating instructions, use the user manual. Acceptance applies only to the source and artifacts identified in each record.

Documentation index · Native init and ARM VM · Cartridges

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 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.

Startup and service state

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.

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:

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 explains commands, failure recovery and the current M10 acceptance status. No physical Pi shutdown measurement is claimed. See Performance 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 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 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 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 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.