Table of Contents
include_toc
| include_toc |
|---|
| true |
Flash disk images with fds-flash
Home · Real hardware · Workstation tools · Release verification
fds-flash creates, inspects and installs FDS disk images from a Linux workstation. It has
an interactive guide and an unattended mode for scripts. It validates the image,
checks the destination, writes it, flushes it, reads the written bytes back, and
relocates the backup GPT automatically when the destination is larger.
You no longer need the manual dd, cmp and sfdisk installation sequence.
Cartridge images and the internal disk use the same flashing command. The
workstation image operations previously documented as fds-burn create and
fds-burn inspect are now available under fds-flash. The workstation package
does not install a separate fds-burn; the Pi retains that service worker and
its bay-control interface.
Install the tool
From the OS checkout on Arch Linux:
make workstation
make workstation-install
fds-flash --help
The fds-tools package includes fds-flash, fds-cartridge and fds-emulator.
For another Linux distribution, or to use the checkout without installing:
make workstation-binaries
out/workstation/fds-flash --help
Build as an ordinary user. Physical disk writes require root. The examples
below use the checkout binary; substitute fds-flash after package installation.
Inspection and flashing add no crates or external runtime utilities: they use the existing
Clap, serde/JSON, SHA-256 and libc dependencies plus Linux block-device APIs.
The Python commands in the scripting example only read saved JSON; Python is
not required by the installed flasher.
Image creation uses e2fsprogs for DATA and erofs-utils for ENVIRONMENT/SYSTEM.
These optional package dependencies supply the filesystem builders and checkers:
sudo pacman -S --needed e2fsprogs erofs-utils
fds-flash create calls those native utilities in /usr/bin; it does not use
fds-cartridge's optional Void tool runners. Creating DATA or ENVIRONMENT images
from your own files runs as an ordinary user. A prepared SYSTEM root can require
privileges to read protected files and preserve its intended ownership.
Choose the correct image
| Image | Destination |
|---|---|
out/fds-internal.img |
Whole microSD card through a reader; also usable for legacy NVMe |
out/fds-system-cli.img |
Whole USB SYSTEM cartridge |
out/fds-system-development.img |
Alternative SYSTEM cartridge with development tools |
A complete PROGRAM, DATA or ENVIRONMENT .img |
Its separate cartridge disk |
Versioned release filenames are supported too. First verify downloaded releases
with a separately trusted key as described in Release verification.
The flasher's SHA-256 check detects changed input; it does not authenticate a
publisher. PROGRAM images should also pass fds-cartridge inspect to check
software metadata and installed program trees before deployment.
Use an uncompressed, complete FDS GPT disk image. The raw fds-boot.img and
fds-recovery.img partition payloads, compressed archives, arbitrary operating
system images and 4 KiB logical-sector destinations are rejected. A disk must
have 512-byte logical sectors and enough space for the complete image. The
internal image is about 1.75 GiB and fits on a 32 GB SD card. The remaining
capacity stays unallocated. A reader may expose it as /dev/sdX; a native host
slot may use /dev/mmcblkN. Select the whole device, never a partition.
Flash a newly rebuilt SYSTEM too when migrating from NVMe: the settings loader
lives in SYSTEM as well as recovery. The older loader accepts NVMe only.
Use Raspberry Pi Imager, rather than fds-flash, for a separate Raspberry Pi OS
maintenance USB.
Create a cartridge image
Creation writes a new regular image file. It does not select or write a disk.
Start with a directory containing a valid FDS/CARTRIDGE.TOML manifest and the
files to include. For example, create a small DATA image:
mkdir -p out/my-data-tree/FDS
cat >out/my-data-tree/FDS/CARTRIDGE.TOML <<'EOF'
format = 1
[cartridge]
id = "my.data"
name = "My data"
class = "data"
version = "1.0"
[media]
writable = true
EOF
printf 'Hello from DATA\n' >out/my-data-tree/hello.txt
out/workstation/fds-flash create data out/my-data-tree out/my-data.img --size-mib 128
out/workstation/fds-flash inspect out/my-data.img
sudo ./out/workstation/fds-flash --image out/my-data.img
--size-mib sets the DATA filesystem size (default 128 MiB, minimum 32 MiB).
The complete image is slightly larger because it includes GPT metadata and
alignment. Its filesystem root belongs to FDS UID/GID 1000. The output must be
outside the source tree and must not already exist.
For other prepared trees:
out/workstation/fds-flash create environment environment-tree environment.img
out/workstation/fds-flash create system prepared-root system.img
The manifest class must match. ENVIRONMENT needs a read-only manifest with an
[activation] profile; see the manifest reference.
SYSTEM needs a complete prepared FDS root, including native init, cartridge
management and Dasung. Normal OS builds should use make rootfs PROFILE=cli
and make system-card PROFILE=cli; the creation command does not install packages.
Build new PROGRAM cartridges with fds-cartridge,
then inspect or flash the resulting complete image with fds-flash.
create program is intentionally unavailable: new software uses installed Void
package trees, while existing legacy images remain readable and flashable.
Append --json to any create command for a result with status: "created".
inspection contains the image path, geometry and SHA-256. Progress and utility
diagnostics go to stderr; creation failures return a nonzero exit status.
Interactive mode
Keep the Pi powered off while preparing its boot SD. Connect only the intended installation media, then launch the guide:
sudo ./out/workstation/fds-flash
- Enter the image's path.
- Select a disk by its model, serial and capacity. Mounted or otherwise occupied disks are marked BLOCKED. There is no default disk selection.
- Review the image type, partitions, SHA-256, destination and target ID.
- Type the exact
ERASE /dev/...phrase shown. Any other response cancels. - Wait for
VERIFIED. Errors or interruption return a nonzero exit status.
You can provide either path in advance. With both supplied, the command still shows the plan and requires terminal confirmation:
sudo ./out/workstation/fds-flash \
--image out/fds-internal.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_SD_DISK
Replace the destination with the verified whole-disk path, without a
-partN suffix. The confirmation uses the resolved kernel path shown in the
review. Repeat for SYSTEM with its image and a different disk:
sudo ./out/workstation/fds-flash \
--image out/fds-system-cli.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_SYSTEM_DISK
Every confirmed write replaces the destination's partition table and the image region. Reinstalling an internal disk also replaces its saved machine settings. The tool does not automatically unmount filesystems, disable swap or select an alternative disk. Release the intended disk yourself and rerun if it is blocked.
Inspect without writing
Inspect an image without a connected disk or root privileges:
out/workstation/fds-flash inspect out/fds-internal.img
out/workstation/fds-flash inspect out/my-data.img --json
This checks the same geometry and basic filesystem signatures as flashing and
reports the complete image's SHA-256. JSON uses status: "inspected" and the
same inspection object as creation. It accepts internal and all cartridge
image classes. For PROGRAM software contents, also use fds-cartridge inspect.
List physical disks and reasons they are unavailable:
out/workstation/fds-flash list
out/workstation/fds-flash list --json
To inspect an image and destination together, without opening the disk for writing:
out/workstation/fds-flash \
--image out/fds-internal.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_SD_DISK \
--dry-run --json >out/sd-plan.json
Read the saved plan. plan.target contains model, serial, capacity, logical-sector
size, canonical device path, host boot ID and kernel insertion identity. plan.target_id
binds those fields together. plan.sha256 identifies the complete source image.
After a host reboot, or if the device is reinserted, replaced, resized or otherwise changes identity,
obtain and review a new plan.
Unattended mode
Unattended writes require all of --image, --device, --expect-target and
--sha256. There is no bare --yes that can silently accept a newly discovered
disk. Obtain the expected values from a reviewed dry run or from your controlled
provisioning inventory, then pass them explicitly:
sudo -n ./out/workstation/fds-flash \
--image out/fds-internal.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_SD_DISK \
--unattended \
--expect-target TARGET_ID_FROM_THE_REVIEWED_PLAN \
--sha256 EXPECTED_IMAGE_SHA256 \
--json >out/sd-flash.json
Replace both hash placeholders with their full 64 hexadecimal characters.
sudo -n refuses to ask for a password, so privileges must already be available.
A script already running as root can invoke the binary directly. The flasher
never prompts or invokes sudo in unattended mode.
For an already reviewed out/sd-plan.json, this complete shell example loads
the bindings without adding a JSON utility dependency:
fds_target_id=$(python3 -c 'import json; print(json.load(open("out/sd-plan.json"))["plan"]["target_id"])')
fds_sha256=$(python3 -c 'import json; print(json.load(open("out/sd-plan.json"))["plan"]["sha256"])')
sudo -n ./out/workstation/fds-flash \
--image out/fds-internal.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_SD_DISK \
--unattended --expect-target "$fds_target_id" --sha256 "$fds_sha256" \
--json >out/sd-flash.json
A successful JSON response has status: "verified"; a dry run has
status: "dry_run". Progress and diagnostics go to stderr. Exit status 0 means
success for the requested operation; status 2 means an error, rejected input
or cancelled confirmation. Treat a killed/interrupted process as a failed flash
and reflash before using that disk. Check the process exit status before reading
an output file; failures may leave that redirected file empty.
What verification covers
Before writing, the tool checks GPT headers and tables, partition bounds, expected FDS labels/types, basic filesystem signatures, image size/hash and target identity. It rejects partitions, virtual/loop/device-mapper destinations, mounted disks or children, swap, kernel holders, read-only media and unsupported sector sizes. The destination is opened exclusively and checked again through block-device ioctls before the first write. A target replacement or changed source aborts.
Readback compares the written image region and relocated backup GPT, after flushing and invalidating the kernel block cache. Partition starts, sizes and filesystem contents stay unchanged. Unallocated capacity is not expanded or securely erased. Success also requires the kernel to reload the partition table.
After an internal installation, check FDS_BOOT, FDS_RECOVERY and FDS_INTERNAL
with lsblk -o NAME,PARTLABEL,FSTYPE,MOUNTPOINTS. If udev is still processing
partition events, run udevadm settle before checking labels. SYSTEM should show
FDS_SYSTEM.
Unmount any filesystems the desktop mounted after completion, safely disconnect
the media, and continue with first boot.
Disposable tests and hardware acceptance
--file-target is only for existing disposable regular files, as an ordinary user.
It is never inferred from a path, and root use of this test mode is rejected.
make flash-test requires e2fsprogs and covers DATA creation, independent filesystem
readback, inspection without a disk, the public CLI, interactive terminal confirmation,
unattended bindings, cancellation, changed inputs, corruption, and exact/larger
destinations. make flash-vm-test also exercises block-device writes and failures
on isolated virtual NVMe/USB disks. These tests do not write host block devices.
make clean recognizes these generated test directories and retains their latest
recorded results.
Physical acceptance remains separate: use a spare drive, record its model, serial and logical-sector size, retain the dry-run and verified JSON plus image hash, safely disconnect/reconnect it, and check its GPT and payloads independently. Then perform the real-hardware boot procedure. Drive firmware flush behavior, USB enclosure recovery and physical power-loss behavior remain unverified until measured on that hardware.
Software validation record
The 2026-09-24 run passed make flash-vm-test, including native CLI and transfer
unit tests, real pseudo-terminal interaction, disposable-file writes, inspection
of the current internal/SYSTEM build images, and isolated ARM NVMe/USB writes.
The VM checks covered the full wizard, unattended operation, kernel partition
refresh, reinstallation, mounted/partition/read-only/4 KiB rejection, USB
replacement, and injected write, flush and readback errors. These are software
and virtual-disk results; they do not establish physical durability.
The existing workstation software-image tests, twelve-bay emulator lifecycle
checks and make check also passed. Source and binary hashes, the latest test
record paths and package-validation evidence are recorded locally in
out/manifests/fds-flash-validation.json. Detailed logs are in
out/logs/flash-validation-final.log and
out/logs/flash-workstation-regression.log. The existing frozen 0.1.0 release
was not modified.
The subsequent workstation-command consolidation was checked with the actual
native fds-flash: DATA creation, inspection without a target, unattended file
flashing, independent ext4 content readback, and rejection of invalid or existing
outputs. ENVIRONMENT and prepared SYSTEM creation were checked with real EROFS
filesystems and independent extraction, using project-local filesystem utilities
inside a private namespace. The small SYSTEM source was an inert test fixture;
this check does not establish bootability. The ARM virtual NVMe/USB flashing and
failure checks also passed after the shared inspection refactor. Evidence for
this revision is recorded in out/manifests/fds-flash-consolidation-validation.json.
Linux interface reference: kernel block-device ABI.
FDS/OS
Start here
Use the computer
- Use cartridges and run programs
- DATA and persistent files
- WindowMaker and FDS Control
- Dasung Paperlike display
Install and maintain
- Flash disk images
- Internal storage and machine settings
- Pi 5 EEPROM configuration
- Recovery and rollback
- Verify a release
- Reclaim build space
- Troubleshooting
Build and contribute
Home · All pages · Edit the wiki · Source repository
Maintained directly in the fds-os.wiki repository. Historical acceptance applies only to the source and artifacts identified in each record.