162 lines
9.5 KiB
Markdown
162 lines
9.5 KiB
Markdown
# M9 media-tool validation
|
|
|
|
Development reference and historical context. For current operating instructions, use the [user manual](../README.md). Acceptance applies only to the source and artifacts identified in each record.
|
|
|
|
|
|
[Media-tool usage](media-tools.md) · [Implementation ledger](implementation-status.md)
|
|
|
|
M9 software acceptance passed on 2026-09-21. Both packaged profiles, ARM image
|
|
construction, confirmed virtual USB writes, SYSTEM creation/write/boot, and the
|
|
earlier-milestone regression checks passed. All devices in these tests are
|
|
disposable regular files exposed only to isolated ARM virtual machines. Physical
|
|
Pi, media-controller and display tests remain deferred.
|
|
|
|
## Verified behavior
|
|
|
|
`make media-image-test` created SYSTEM, DATA, PROGRAM and ENVIRONMENT images with
|
|
the actual static ARM `fds-burn`. Independent `sfdisk`, Python SHA-256,
|
|
`fsck.erofs` and `e2fsck` checked the outputs. Invalid GPT extents, extra partitions,
|
|
internal partition labels and inconsistent backups were rejected even when the
|
|
fixture recomputed valid CRCs. Existing output files and recursive source/output
|
|
layouts were refused. Evidence: `out/m9-images.zqojr8hc/`.
|
|
|
|
`make media-test` verified these cases through the ordinary FDS user's CLI:
|
|
|
|
- Inspection reports the bay's capacity, logical sector size, model, serial and
|
|
kernel insertion identity. The running SYSTEM and mounted media refuse writes.
|
|
- Preview and cancellation leave the target unchanged. A confirmation is bound
|
|
to its operation, bay, insertion and image hash; a wrong phrase cannot proceed.
|
|
- Changing source bytes after preview is detected before writing. Replacing the
|
|
device in the same bay invalidates the old confirmation and leaves the new
|
|
insertion untouched.
|
|
- A PROGRAM image is written, flushed, read back and marked SAFE. Its backup GPT
|
|
moves to the end of a larger device. SAFE survives a daemon restart; a new
|
|
insertion mounts normally and supports explicit unprivileged execution.
|
|
- PROGRAM, DATA and ENVIRONMENT images are created on the running ARM machine.
|
|
DATA permits ordinary-user writes, retains data across removal/reinsertion and
|
|
passes independent host `e2fsck` after safe eject.
|
|
- Cartridge status remains usable while a separate write worker is active.
|
|
Source DATA cannot be ejected while the worker holds its image, including
|
|
across the worker's private mount namespace.
|
|
- Killing the cartridge daemon during an awaiting-confirmation operation leaves
|
|
a failed record on restart. It never becomes SAFE or automatically remounts.
|
|
- A valid EROFS/GPT containing an approximately 60 KiB malformed manifest is
|
|
rejected before writing. Its diagnostic stays bounded and printable, the
|
|
daemon retains the same process ID, and subsequent status requests work.
|
|
|
|
The final virtual USB evidence is `out/m9-vm.cdlj6_r7/`. The crash case uses native s6
|
|
supervision controls; see the [upstream s6-svc interface](https://skarnet.org/software/s6/s6-svc.html).
|
|
|
|
## SYSTEM creation through boot
|
|
|
|
`tests/integration/m9-system.py` mounts a complete prepared SYSTEM after boot,
|
|
then runs the real ARM filesystem/image builder against that read-only tree.
|
|
The ordinary user previews and confirms a write to another virtual cartridge.
|
|
After device flush and readback verification, a fresh VM boots the written disk
|
|
through the actual Pi kernel, stage0 and native s6 to the ordinary FDS prompt.
|
|
The test verifies UID 1000, read-only SYSTEM behavior, Dasung, the preserved
|
|
`root:utmp` terminal-helper ownership, and packaged Terminus caches without a
|
|
new user cache. Final evidence: `out/m9-system.ej8oz_av/`.
|
|
|
|
This demonstrates creation and boot of a usable SYSTEM on ARM, not just a valid
|
|
partition header. It does not emulate Raspberry Pi firmware, physical NVMe/RP1,
|
|
USB power behavior or Dasung video output.
|
|
|
|
## Implementation and dependencies
|
|
|
|
`fds-burn` is static-musl Rust. `fds-inspect` and `fds-eject` are static aliases of
|
|
`fds`; the daemon starts a bounded worker for each media operation. The worker
|
|
opens the exact disk with exclusive access, checks live identity again before
|
|
writing, validates the image's filesystem and manifest, and verifies actual
|
|
readback after flushing and invalidating the device cache. A root-owned record
|
|
prevents interrupted operations from acquiring a false SAFE status after restart.
|
|
|
|
Protection checks cover mounts, swap, kernel holders and the three reserved
|
|
internal partition names. Existing primary and backup GPTs are also inspected
|
|
directly, so protection does not depend solely on partition uevent timing. Native
|
|
4 KiB logical-sector disks are explicitly unsupported by this writer.
|
|
|
|
The eight new locked Rust dependency entries are explained in the
|
|
[media guide](media-tools.md#dependencies-and-current-evidence). Filesystem tools
|
|
and GNU coreutils already belong to the base image; their package dependencies
|
|
are now declared explicitly. No init replacement, background network service,
|
|
new native library dependency of an FDS executable, or boot-time cache builder
|
|
was introduced. Void's tracked source files remain unchanged.
|
|
|
|
## Findings resolved during validation
|
|
|
|
A private checker device node initially failed to open because `/run` is mounted
|
|
with `nodev`. The final code creates an inaccessible private directory on
|
|
`devtmpfs`, opens its read-only device inode, and immediately unlinks it. The
|
|
filesystem checker receives that handle and runs as UID 1000; global `/dev/loopN`
|
|
permissions are unchanged. Image mounts exist only in the worker's private mount
|
|
namespace and disappear when it exits.
|
|
|
|
The namespace review also identified the need to block eject until the worker
|
|
exits: unmounting only the daemon's namespace could otherwise report a source
|
|
DATA cartridge SAFE while the worker retained its mount. The VM test now covers
|
|
that exact case.
|
|
|
|
Malformed TOML can include most of its source text in an error message. Worker
|
|
diagnostics are now limited to 2048 UTF-8 bytes plus a truncation suffix, with
|
|
control characters replaced by spaces. This prevents cartridge contents from
|
|
overflowing the daemon's status protocol or injecting terminal controls.
|
|
|
|
The sustained-write regression initially failed because kernel I/O diagnostics
|
|
interrupted CLI JSON in the middle of a serial line during deliberate removal.
|
|
The test now executes each command once, saves its stdout, and transfers it with
|
|
base64 and a SHA-256 checksum. A damaged transfer is retried without rerunning
|
|
the command. Kernel output remains in the serial log and a separate diagnostic
|
|
capture. The corrected test passed in `out/m7-vm.t5d5fd_4/`, including independent
|
|
ext4 checks and the exact 64 MiB write payload.
|
|
|
|
## Packaged artifacts and regressions
|
|
|
|
The rebuilt CLI rootfs contains 180 packages and 1393 AArch64 ELF files. All FDS
|
|
executables remain static-musl. Package archives, input hashes, ownership and
|
|
capability records are retained beside the rootfs.
|
|
|
|
| Artifact | Location | SHA-256 |
|
|
| --- | --- | --- |
|
|
| CLI rootfs, 498616320 bytes | `out/rootfs-build.gs9ZTA/rootfs-aarch64.tar` | `4abbc4e4e1823ef78acde2645d915160aa8e1c0f8b3173e8bc73f8d6b923d502` |
|
|
| CLI SYSTEM | `out/system-build.a74aryls/system.img` | `b7a71dad45c259c92ec5a5ac72b87356132f642df5c33d74d20e2e6ca564dee6` |
|
|
| FAT32 boot partition | `out/boot-build.oapz3fuf/boot.fat` | `ac3ee864c6293dd30a640fbbc0514b08acb92cda2d25d05128d234229308ac8f` |
|
|
|
|
The earlier-milestone regression run passed tooling, formatting/build checks,
|
|
rootfs rejection checks, native init, the stage0 boot matrix, console and
|
|
cartridge tests. Its logs are `out/logs/m9-final-*.log`; the corrected DATA run
|
|
is `out/logs/m9-data-retry3.log`. The final diagnostic change was then rebuilt
|
|
into the CLI archive and passed the complete media write/boot and archive checks
|
|
in `out/logs/m9-hardened-*.log`.
|
|
|
|
Native init evidence is `out/m2-vm.ijzHZC/`, the boot matrix is
|
|
`out/m4-vm.sxNb8D/`, console checks are `out/m5-vm.6suv4qjj/`, and cartridge
|
|
checks are `out/m6-vm.o5sjhatc/`. Kernel-to-console was 1854.858231 ms in this
|
|
VM run, compared with M8's 1854.724813 ms: **+0.133418 ms**. The actual static ARM
|
|
comparison passed without an exception; see `out/logs/m9-boot-comparison.log`.
|
|
This is below the 100 ms review threshold and is not a Pi performance result.
|
|
|
|
The development rootfs contains 191 packages and 1405 AArch64 ELF files.
|
|
`make rootfs-test`, `make desktop-test` and development SYSTEM construction passed,
|
|
followed by the final tooling and formatting/build checks. Evidence is
|
|
`out/m8-vm.498wsxsv/` and `out/logs/m9-hardened-*.log`. The screenshot was inspected
|
|
and retains the grayscale Terminus terminal. First desktop activation was
|
|
1111.300247 ms in this VM; physical display timing remains unmeasured.
|
|
|
|
| Artifact | Location | SHA-256 |
|
|
| --- | --- | --- |
|
|
| Development rootfs, 501882880 bytes | `out/rootfs-build.sQCq5V/rootfs-aarch64.tar` | `87e9a35829432f07e4a4bfa4c69eabd5ba0f30a25eadfed05ea9393bd1fb2afa` |
|
|
| Development SYSTEM | `out/system-build.l5e3j1pg/system.img` | `bcb8dfa7ec6e3207080f5c68074cc0c27d1bea63a0b51561c8ec628691e03611` |
|
|
|
|
The generic rootfs convenience links were restored to the CLI build after the
|
|
development checks. `out/rootfs-cli.tar` and `out/rootfs-development.tar` retain
|
|
explicit pointers to these two verified archives.
|
|
|
|
## Deferred and remaining acceptance
|
|
|
|
Physical media throughput, flash-controller write-cache behavior, USB brownouts,
|
|
power-loss durability and Pi boot remain deferred. No throughput or hardware
|
|
latency claim is made. Broader I/O failure injection and twelve-device stress
|
|
belong to M11; ordered power-off and persistent DATA error handling belong to M10;
|
|
signing, independent recovery and complete release inputs belong to M12.
|