# Writable DATA and managed programs [Documentation index](README.md) · [Cartridges](cartridges.md) · [Services](services.md) M7 implements writable DATA. Its sustained-write, safe-eject and surrounding image regression checks [passed in the ARM VM](m7-validation.md). A DATA cartridge uses a GPT partition named `FDS_DATA`, ext4, and a validated `/FDS/CARTRIDGE.TOML` declaring class `data` and `writable = true`. Use the [M9 media tools](media-tools.md) to create new DATA media. The virtual tests construct disposable image files and never format a workstation disk. ## Where your files live `/home/fds` remains a temporary home, whether DATA is present or absent. Its contents disappear at power-off. Persistent user files belong under `/data`. Separating these paths lets you eject DATA without hiding the active shell's home directory or substituting another cartridge underneath it. After inserting a DATA cartridge into a configured bay: ```sh fds bays fds cartridge 2 ls /data ``` If exactly one valid DATA candidate is available and none is active, the daemon activates it at `/data`. The filesystem must grant UID/GID 1000 the intended write permissions; insertion does not recursively change ownership of user files. M9's DATA formatter supplies that ownership for fresh media. An active DATA session stays attached to its current cartridge when another is inserted. If a discovery snapshot contains multiple candidates with none active, they remain read-only until you select one: ```sh fds data use 4 ``` Eject the existing active DATA before selecting a replacement. The daemon never changes `/data` underneath an active session. EMPTY, ERROR and SAFE states retain the meanings in the [cartridge guide](cartridges.md); MOUNTED READ WRITE means that the displayed DATA filesystem is available for user writes. ## Run a program that participates in eject Ordinary console commands work as usual. They are not automatically killed when you request eject: an open file or working directory may make eject fail as busy. For a background task that should stop when its DATA is ejected, use: ```sh fds run 2 -- /usr/bin/bash -c 'date > /data/managed-example.txt' ``` This starts a **background** managed program and prints its process ID. It has no interactive input. Output goes to the bounded, volatile cartridge service log: ```sh tail /run/log/cartridged/current fds cartridge 2 ``` The executable path must be absolute. The child starts with `/data` as its working directory, the ordinary FDS UID/GID, no supplementary groups, no effective capabilities, a small explicit environment, and `no_new_privs`. Programs cannot gain privileges through setuid executables. The limit is 256 managed processes per bay. This interface accepts healthy writable DATA; the [desktop guide](desktop.md) also explains M8's explicit PROGRAM-media launch interface. A root-owned Linux cgroup tracks the program and its descendants, including children that outlive their parent. Cgroups are kernel process tracking, not a new init system or runtime package. The configured kernel already includes the required cgroup v2 and process-limit support. The daemon sets up its hierarchy independently of the console. See the [kernel cgroup interface](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html). ## Eject and remove DATA ```sh cd "$HOME" fds eject 2 ``` Eject checks for additional mounts, stops managed consumers, flushes the DATA filesystem with `syncfs`, and performs a normal unmount. Only successful completion produces SAFE. A retained filesystem descriptor observes writeback errors during the session. M10 additionally makes the filesystem read-only and checks writeback again before closing that descriptor for unmount, preventing an error-reporting gap when a busy mount needs a later retry. Linux's [syncfs interface](https://man7.org/linux/man-pages/man2/syncfs.2.html) reports filesystem errors that must not be ignored. Managed programs receive TERM first. The daemon waits on actual cgroup exit notifications; programs that have not exited after a one-second deadline are killed as a group, including newly forked descendants. A further bounded exit check must succeed. These are failure deadlines, not delays imposed on a program that has already stopped. Requesting eject therefore ends those background jobs; it does not promise that unfinished application work is completed. An unmanaged busy shell/file, extra mount, failed flush or failed unmount prevents SAFE. Close the reported use and retry. A recorded DATA writeback fault requires investigation or recovery; a later successful call is not used to erase it and pretend the failed write succeeded. The daemon never uses lazy/forced unmount to claim successful eject. A successfully ejected insertion remains unmounted across a daemon restart until removal/reinsertion. M10 records writable sessions and faults outside the daemon process. If it crashes before verified unmount, the same insertion stays quarantined and read-only on restart. A later flush cannot reconstruct the lost error history. See [Shutdown and recovery records](power.md#data-recovery-records) for the current implementation and its acceptance status. Pulling DATA during writes is an error. The daemon stops its managed consumers, cleans up the vanished mount and logs that writes may have been lost. This path never produces SAFE and makes no filesystem-cleanliness promise. Use recovery inspection/repair before trusting media that was removed during I/O. ## Build and verify on the workstation After changing DATA code or image configuration, build fresh inputs in order: ```sh make rootfs PROFILE=cli make initramfs make system-card make data-test ``` The test boots disposable virtual media, writes continuously, verifies ordinary user privileges and descendant shutdown, checks busy and additional mounts, reopens persisted data, tests multiple candidates and simulates surprise removal. After safe eject it extracts the ext4 partition into an ordinary file, runs read-only `e2fsck -fn`, and compares the sustained-write payload byte-for-byte. No host mount or physical USB device is used. Run `make cartridge-test`, `make init-test`, `make boot-test` and `make console-test` for the surrounding regressions. Test logs and VM evidence are written under `out/`. Real flash-controller caches, battery loss, USB power and physical Pi eject/shutdown latency remain hardware acceptance work.