# Using cartridges and configuring bays [Documentation index](README.md) · [Boot images](boot.md) · [Services](services.md) M6 adds the base `fds-cartridged` service, twelve bay states, USB hardware recognition, strict metadata inspection, read-only storage mounts and eject. Its [ARM VM acceptance checks passed](m6-validation.md). [Writable DATA integration](data.md) has passed M7 software acceptance; [desktop/program activation](desktop.md) passed M8 and [media creation tools](media-tools.md) passed M9 software acceptance. [M10 ordered shutdown](power.md) has passed software acceptance. ## Inspect the current machine At the FDS console: ```sh fds bays fds bay 3 fds cartridge 3 fds --json bays ``` The ordinary `fds` user can use these commands. `bays` shows all twelve bays, including empty and unconfigured ones. `cartridge` includes validated metadata and the current mount path. `--json` exposes a versioned machine-readable report. `fds rescan` explicitly refreshes inventory; normal insert/remove events trigger refresh automatically. The console does not wait for the inventory scan. | State | Meaning and next action | | --- | --- | | UNCONFIGURED | No measured controller/port mapping exists for this bay | | EMPTY | Configured bay with no detected USB device | | HARDWARE | USB device without storage; catalog name or VID/PID is shown | | UNRECOGNIZED STORAGE | Storage exists but no named FDS partition is available | | MOUNTED READ ONLY | Manifest validated; filesystem available at the displayed path | | MOUNTED READ WRITE | Active DATA is writable at `/data`; eject before removal | | PROTECTED | The active SYSTEM root; eject is refused | | AMBIGUOUS | Multiple devices or named partitions match; nothing is selected arbitrarily | | ERROR | Inspection, mounting or metadata validation failed; read the diagnostic | | SAFE | The requested unmount succeeded; remove the cartridge | An unrecognized storage state may briefly appear while the kernel discovers its partitions. It is not permission to remove a device being used elsewhere. Errors and ambiguous media never produce SAFE. An additional mount of the same filesystem also blocks managed eject until it is unmounted. ## Calibrate the physical bay map The shipped `/etc/fds/bays.toml` is deliberately empty: no Pi bay wiring has yet been measured. This produces UNCONFIGURED states, not invented assignments. 1. On the assembled machine, insert one known USB device into one physical bay. 2. Run `fds topology`. This diagnostic explicitly shows controller/port paths; ordinary bay commands omit those implementation details. 3. Record that path and repeat for each bay. Test both USB 2 and USB 3 devices, because their companion root hubs can have different logical port paths. 4. Put the measured map in your machine configuration directory and build the [internal image](internal-storage.md), or use `fds machine install DIRECTORY` from recovery and reboot. Machine settings persist independently of SYSTEM. The packaged `/etc/fds/` files are fallback defaults for missing/invalid internal storage; `fds machine status` shows which source is active. 5. Verify all twelve devices together, in different insertion orders and after reboot. That physical acceptance remains deferred. A **syntax example only**, using identities that must be replaced by observations: ```toml [front] hub = "platform/example-controller:usb2/1" [front.ports] 1 = 1 2 = 2 3 = 3 4 = 4 5 = 5 6 = 6 [front_superspeed] hub = "platform/example-controller:usb3/1" [front_superspeed.ports] 1 = 1 2 = 2 3 = 3 4 = 4 5 = 5 6 = 6 ``` `hub` names the controller and parent port chain. Its numbered `ports` map the next downstream port to a bay number from 1 through 12. Additional groups can map the rear hub. Explicit USB 2/3 aliases may refer to the same bay; duplicate ports, overlapping parent/child mappings, and duplicate bays within one hub are rejected. If two devices simultaneously match aliases for one bay, it becomes AMBIGUOUS. A hub inserted into a cartridge bay with multiple downstream devices also needs an explicit future composite-device policy; M6 refuses to guess. The identity excludes the Linux USB bus number and `/dev/sdX` enumeration order. It includes the controller's sysfs path, USB protocol generation and port chain. Moving a hub to another controller or changing wiring requires recalibration. ## Storage formats and metadata | Class | GPT partition name | Filesystem and current behavior | | --- | --- | --- | | SYSTEM | FDS_SYSTEM | EROFS; current root is protected, additional media read-only | | DATA | FDS_DATA | ext4; inspected read-only first, then activated at `/data` under the M7 policy | | PROGRAM | FDS_METADATA + FDS_PAYLOAD02… | Metadata and xz bundles in `1+m` EROFS partitions; see [software format](software-format.md) | | Legacy PROGRAM | FDS_PROGRAM | Existing single EROFS application tree; still readable | | ENVIRONMENT | FDS_ENVIRONMENT | EROFS; declarative selection of a trusted built-in profile | | UTILITY | FDS_UTILITY | EROFS; inspection only, no automatic actions | | HARDWARE | None required | VID/PID, optional serial, device/interface class and bay | Storage contains `/FDS/CARTRIDGE.TOML`. For example: ```toml format = 1 [cartridge] id = "fds.windowmaker" name = "WINDOW SYSTEM" class = "environment" version = "0.1" [media] writable = false [activation] profile = "windowmaker" ``` The manifest class must match the GPT partition name. SYSTEM, PROGRAM and ENVIRONMENT are read-only; DATA declares writable media during the initial read-only inspection. Unknown keys, root commands, unsafe identifiers, control characters, symlink metadata and nonregular metadata files are rejected. The parser accepts at most 64 KiB. No `/FDS/autorun.sh` is run. Inspect a standalone manifest with `fds inspect /path/to/CARTRIDGE.TOML`. For mounted storage, `fds cartridge N` reports the daemon's validated copy. Media is inspected in a root-only staging directory, then published at `/run/fds/media/NN` after validation, with nodev, nosuid and noexec. Device major/minor and kernel disk sequence are checked before mounting an opened block-device descriptor, preventing stale enumeration names from selecting a replacement disk. ## Eject a mounted cartridge ```sh fds eject 2 ``` Leave any shell working directory inside that cartridge and close files first. SAFE is emitted only after an ordinary unmount succeeds. Busy mounts return an error; forced or lazy unmount is never used to declare safe removal. Once SAFE, the daemon keeps that insertion unmounted until removal and reinsertion, including across a service restart. Its root-owned volatile marker is tied to the kernel disk sequence, so a replacement disk is not mistaken for ejected media. The active SYSTEM cannot be ejected. Swap SYSTEM only after shutting down. Pulling a mounted cartridge without eject is surprise removal. The daemon clears its inventory and detaches a vanished read-only mount where needed; that cleanup is not a successful eject. [M7 DATA handling](data.md) extends ejection to writable DATA, consumer tracking and syncfs. The temporary `/home/fds` remains usable without DATA and is lost at power-off. ## Hardware recognition Edit `packages/fds-cartridged/files/hardware-catalog.toml`, then rebuild SYSTEM. Entries name devices, never executable actions: ```toml [[device]] name = "MY SERIAL ADAPTER" vendor = "1234" product = "5678" # Optional exact restrictions: serial = "UNIT-1" class = "02" ``` Replace these example IDs with observed values. Device or interface class may match `class`. Multiple matching catalog entries produce an error; unknown hardware remains identified by VID/PID without being mistaken for empty media. Dasung control remains in the independent base monitor service. ## Implementation and diagnostics The daemon subscribes to kernel USB/block events before taking its first snapshot. A receive-buffer overflow causes a fresh snapshot. IPC uses a bounded Unix socket at `/run/fds/control.sock`, mode 0660 and group `fds`, with peer UID checks for root and the ordinary FDS user. Slow clients have individual deadlines and do not block other clients. No asynchronous runtime or new external Rust dependency is introduced: the existing std, libc, serde, serde_json and toml components suffice. Root diagnostics: `s6-svstat /run/service/cartridged` and `cat /run/log/cartridged/current`. Logs are bounded and volatile. Restart through `s6-rc -l /run/s6-rc -d change cartridged`, then the corresponding `-u` command. Close users of cartridge mounts first; restart cleanup refuses busy leftovers. On the build host, `make cartridge-test` runs fixtures and full virtual USB tests. These exercise actual kernel events and mounts but cannot establish physical wiring, USB power stability, or Pi port behavior. M11 expands to twelve-device stress, and physical calibration must be recorded separately.