FDS/OS 1.0
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
# M9 media-tool validation
|
||||
|
||||
[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.
|
||||
Reference in New Issue
Block a user