Document interactive and unattended disk installation with fds-flash

2026-09-24 14:41:41 +08:00
parent ddae6bf6a6
commit ef88914454
15 changed files with 317 additions and 204 deletions
+2 -2
@@ -51,8 +51,8 @@ indexing also explicitly sets `XBPS_ARCH=aarch64`.
## Generic Linux workstation tools and desktop additions
`make workstation` builds the Arch `fds-tools` package; `make workstation-install`
installs it with pacman. `make workstation-binaries` builds native `fds-cartridge`
and `fds-emulator` on generic Linux. Python 3 and Git resolve build versions;
installs it with pacman. `make workstation-binaries` builds native `fds-cartridge`,
`fds-emulator` and `fds-flash` on generic Linux. Python 3 and Git resolve build versions;
Dasung builds install these tools in the project-local Void container as well. Runtime
requirements are QEMU, erofs-utils, bubblewrap and native XBPS with a prepared
Void source checkout for software creation. `fds-cartridge` invokes xbps-src,
+1
@@ -14,6 +14,7 @@ the inputs named in those reports; a changed source tree needs fresh checks.
## Design and build references
- [Workstation disk flashing](Flashing)
- [Editing the Gitea wiki](Gitea-Wiki)
- [Clean upstream and writable Void workspace](Developer-Void-Workspace)
+6 -5
@@ -28,11 +28,12 @@ own strict format parsers; they are not process argument parsers.
## Workstation software and emulator extension
Current sources extend the frozen 0.1.0 checkpoint with native Linux
`fds-cartridge` and `fds-emulator` tools. The software format uses metadata plus
`m` payload partitions containing xz tarballs. Software builds and complete
image creation run on the workstation; the guest verifies, extracts and runs
selected commands as UID 1000. See [usage](Developer-Workstation),
[format](Developer-Software-Format), and [current acceptance](Developer-Workstation-Validation).
`fds-cartridge`, `fds-emulator` and `fds-flash` tools. The current software format
uses metadata plus `m` EROFS payload partitions containing installed Void package
trees. Software builds and image creation run on the workstation; the guest
verifies and executes those trees directly as UID 1000. Legacy archive readers
remain available. See [usage](Workstation), [format](Software-Format),
[disk installation](Flashing), and [cartridge/desktop acceptance](Developer-Current-Revision).
Historical M0–M12 and Clap reports describe their recorded artifacts; they do
not by themselves validate these new sources.
+6 -90
@@ -54,97 +54,13 @@ empty. The builder accepts ordinary image files, never a host block-device
output. Final hardware provisioning and identity checks belong to the physical
acceptance procedure; do not confuse a partition payload with the complete disk.
## Install the internal disk when hardware is available
## Install the internal disk
This is a **deferred physical procedure**. The image and virtual NVMe workflow
are software-tested; writing and booting the user's actual NVMe still require
the hardware. Installation erases the selected disk, including any existing
machine settings. Retain backups before replacing an existing installation.
Use an NVMe enclosure or another Linux machine that can access the target drive
while the Pi is off. First verify a downloaded release using a separately trusted
public key as described in [Release signatures](Developer-Releases). Its complete disk
is named `fds-internal-0.1.0.img`; a local build uses `out/fds-internal.img`.
Use the complete disk image, not the separate BOOT or RECOVERY payload.
List disks before and after connecting the intended drive:
```sh
lsblk -d -o NAME,PATH,MODEL,SERIAL,SIZE,TRAN,LOG-SEC
ls -l /dev/disk/by-id/
```
Match the physical model, serial and capacity. Choose a persistent **whole-disk**
`/dev/disk/by-id/` path without a `-partN` suffix; never guess a `/dev/sdX` name.
Unmount every target partition and disable any swap on it. Do not select the
workstation's system disk. The current images require 512-byte logical sectors
and a disk at least as large as the image; 4 KiB logical-sector media is not
supported by this layout.
Open Bash (`bash`), replace both paths below, then run the block. It checks the
selected disk again, requires a typed confirmation, writes and reads back the
complete image, and relocates the backup GPT when the disk is larger than the
image. It does not expand any partition or filesystem.
```bash
(
set -euo pipefail
fds_image="$PWD/out/fds-internal.img"
fds_disk=/dev/disk/by-id/REPLACE_WITH_THE_TARGET_DISK
[[ -f "$fds_image" && -s "$fds_image" && -b "$fds_disk" ]]
[[ $(lsblk -dnro TYPE "$fds_disk") == disk ]]
[[ $(sudo blockdev --getss "$fds_disk") == 512 ]]
fds_bytes=$(stat -Lc %s "$fds_image")
(( $(sudo blockdev --getsize64 "$fds_disk") >= fds_bytes ))
lsblk -p -o NAME,TYPE,MODEL,SERIAL,SIZE,MOUNTPOINTS "$fds_disk"
if lsblk -nrpo MOUNTPOINTS "$fds_disk" | grep '[^[:space:]]' >/dev/null; then
echo 'Target has mounted filesystems or swap; stop and release them first.' >&2
exit 1
fi
if lsblk -nrpo TYPE "$fds_disk" | grep -Ev '^(disk|part)$' >/dev/null; then
echo 'Target has device-mapper or other active descendants; stop.' >&2
exit 1
fi
read -r -p "Type ERASE $fds_disk to erase this disk: " fds_confirmation
[[ "$fds_confirmation" == "ERASE $fds_disk" ]]
sudo dd if="$fds_image" of="$fds_disk" bs=4M conv=fsync status=progress
sudo blockdev --flushbufs "$fds_disk"
sudo cmp -n "$fds_bytes" "$fds_image" "$fds_disk"
sudo sfdisk --lock=yes --relocate gpt-bak-std "$fds_disk"
sudo sfdisk --verify "$fds_disk"
sudo blockdev --flushbufs "$fds_disk"
)
```
Every command must succeed. The byte comparison occurs before relocating GPT,
because relocation intentionally changes disk-table headers. GNU `dd`'s `fsync`
flushes output before it returns; `sfdisk`'s `gpt-bak-std` moves the backup header
to the end of the target. See the [GNU dd manual](https://www.gnu.org/s/coreutils/manual/html_node/dd-invocation.html)
and [sfdisk manual](https://man7.org/linux/man-pages/man8/sfdisk.8.html).
These commands use the already documented coreutils, diffutils and util-linux
host tools; they do not add a target daemon.
Confirm that the disk shows `FDS_BOOT`, `FDS_RECOVERY` and `FDS_INTERNAL` in that
order using `lsblk -o NAME,PARTLABEL,FSTYPE,MOUNTPOINTS`. Unmount anything the
desktop automatically mounted, then safely disconnect the enclosure and install
the NVMe in the powered-off Pi. Follow [EEPROM preparation](Developer-EEPROM) for the
separately reviewed NVMe boot settings.
Prepare the **first SYSTEM cartridge on the workstation** using the same guarded
write block, with its two path assignments changed to the chosen SYSTEM image
and a different, empty USB cartridge disk. For a local build select
`out/fds-system-cli.img` or `out/fds-system-development.img`; release files are
`fds-system-cli-0.1.0.img` and `fds-system-development-0.1.0.img`. They are
alternative complete GPT images, each containing one `FDS_SYSTEM` partition.
Readback and backup-GPT relocation apply to this disk too. Check its partition
label, safely disconnect it, and insert exactly one SYSTEM cartridge in the Pi
before normal boot. Subsequent cartridge creation and updates can use FDS's
confirmed [media workflow](Developer-Media-Tools) after bay calibration.
On the first physical boot, check `fds info`, `fds machine status`, and
`fds bays`. The supplied bay map is empty until calibration. Follow
[physical acceptance](Developer-Stress-Testing) to measure ports, test the Dasung
display, and record actual boot/shutdown behavior before relying on the machine.
Current workstation installation uses [fds-flash](Flashing), with guided or
unattended operation, image/target validation, readback and backup-GPT relocation.
Follow [the installation commands](Internal-Storage#install-the-internal-disk).
Historical M12 acceptance describes the artifacts and procedures recorded then;
it does not validate this new workstation tool.
## Configure the machine before building
+1 -1
@@ -73,7 +73,7 @@ checks. `make workstation-test` exercises the installed-tree cartridge creator;
`make emulator-test` covers stopping and starting the same directory, preserved
logs/overlays/mappings, and rejecting a restart of a live VM.
`make workstation-package-test` installs the real Arch package with pacman in a
disposable root and executes both installed commands. After building matching
disposable root and executes all three installed commands. After building matching
images, `python3 tests/integration/version-images.py` reads the identity and
metadata directly from the GPT/EROFS image and executes its twelve FDS commands
under ARM emulation to compare their versions. Image acceptance
+11 -2
@@ -5,8 +5,8 @@ include_toc: true
# Workstation tooling plan
The current source of requirements is [the active revision](Developer-Current-Revision).
The public tools remain native Linux Clap applications: `fds-cartridge` and
`fds-emulator`. Full OS cross builds keep their separate pinned Void environment.
The public tools remain native Linux Clap applications: `fds-cartridge`, `fds-emulator` and
`fds-flash`. Full OS cross builds keep their separate pinned Void environment.
New software creation uses Void source templates and `xbps-src`. The image builder
installs packages and dependencies on the workstation, verifies installed trees,
@@ -31,3 +31,12 @@ The Arch distribution package is `fds-tools`, built by `make workstation` and
installed by `make workstation-install`. `make workstation-binaries` preserves
the generic Linux build. Stopped emulator directories support a fresh boot while
retaining logs, DATA overlays and archived cartridge mappings.
`fds-flash` installs complete internal and cartridge GPT images. Its interactive
mode requires terminal confirmation; unattended mode binds a specific image
SHA-256 and target identity. Installation includes exclusive block access,
readback, backup-GPT relocation and kernel partition refresh. The tool reuses
existing Rust dependencies; it does not invoke shell disk-writing commands.
See [flashing](Flashing) and validate with `make flash-test`,
`make flash-vm-test`, `make workstation-test`, `make emulator-test` and
`make workstation-package-test`. Physical-drive behavior remains a separate gate.
+2 -1
@@ -16,7 +16,8 @@ source software to a cartridge disk image, runs that image in FDS, and explains
how to write the same complete image to USB. All commands run from the checkout
root unless marked as guest commands.
The two native host tools are `fds-cartridge` and `fds-emulator`. They use typed
The original native host tools are `fds-cartridge` and `fds-emulator`. The current
workstation package also includes [fds-flash](Flashing) for complete disk installation. All use typed
Clap interfaces; append `--help` to any command or subcommand. The target's `fds`
command remains a static AArch64 executable. The new host tools are never part
of the Pi base image. Dasung support remains in the base boot bundle.
+223
@@ -0,0 +1,223 @@
---
include_toc: true
---
# Flash disk images with fds-flash
[Home](Home) · [Real hardware](Hardware-Setup) · [Workstation tools](Workstation) · [Release verification](Releases)
`fds-flash` installs a complete FDS disk image 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.
## Install the tool
From the OS checkout on Arch Linux:
```sh
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:
```sh
make workstation-binaries
out/workstation/fds-flash --help
```
Build as an ordinary user. Only physical disk writes require root. The examples
below use the checkout binary; substitute `fds-flash` after package installation.
The flasher adds no crates or external runtime utilities: it uses 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.
## Choose the correct image
| Image | Destination |
| --- | --- |
| `out/fds-internal.img` | Whole NVMe disk, normally connected through an enclosure |
| `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](Releases).
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.
## Interactive mode
Keep the Pi powered off while preparing its NVMe. Connect only the intended
installation media, then launch the guide:
```sh
sudo ./out/workstation/fds-flash
```
1. Enter the image's path.
2. Select a disk by its model, serial and capacity. Mounted or otherwise occupied
disks are marked **BLOCKED**. There is no default disk selection.
3. Review the image type, partitions, SHA-256, destination and target ID.
4. Type the exact `ERASE /dev/...` phrase shown. Any other response cancels.
5. 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:
```sh
sudo ./out/workstation/fds-flash \
--image out/fds-internal.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_NVME_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:
```sh
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
List physical disks and reasons they are unavailable:
```sh
out/workstation/fds-flash list
out/workstation/fds-flash list --json
```
To inspect an image and destination together, without opening the disk for writing:
```sh
out/workstation/fds-flash \
--image out/fds-internal.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_NVME_DISK \
--dry-run --json >out/nvme-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:
```sh
sudo -n ./out/workstation/fds-flash \
--image out/fds-internal.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_NVME_DISK \
--unattended \
--expect-target TARGET_ID_FROM_THE_REVIEWED_PLAN \
--sha256 EXPECTED_IMAGE_SHA256 \
--json >out/nvme-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/nvme-plan.json`, this complete shell example loads
the bindings without adding a JSON utility dependency:
```sh
fds_target_id=$(python3 -c 'import json; print(json.load(open("out/nvme-plan.json"))["plan"]["target_id"])')
fds_sha256=$(python3 -c 'import json; print(json.load(open("out/nvme-plan.json"))["plan"]["sha256"])')
sudo -n ./out/workstation/fds-flash \
--image out/fds-internal.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_NVME_DISK \
--unattended --expect-target "$fds_target_id" --sha256 "$fds_sha256" \
--json >out/nvme-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](Hardware-Setup#6-power-on-and-reach-the-console).
## 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` covers 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](Hardware-Setup). 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.
Linux interface reference: [kernel block-device ABI](https://www.kernel.org/doc/html/latest/admin-guide/abi-stable.html).
+20 -14
@@ -184,24 +184,30 @@ boot order until the rescue and normal boot paths have been checked.
## 5. Write the two disks
On the **workstation**, follow the complete
[guarded disk-writing procedure](Internal-Storage#install-the-internal-disk).
It includes disk identification by model/serial, an explicit erase confirmation,
readback, and backup-GPT relocation. Run it separately for these assignments:
On the **workstation**, build the native tools and run `fds-flash` once per disk:
| Pass | `fds_image` | `fds_disk` |
| --- | --- | --- |
| Internal disk | `$PWD/out/fds-internal.img` | The verified NVMe enclosure's whole-disk `/dev/disk/by-id/…` path |
| SYSTEM | `$PWD/out/fds-system-cli.img` | A different, verified USB cartridge's whole-disk `/dev/disk/by-id/…` path |
```sh
make workstation-binaries
sudo ./out/workstation/fds-flash --image out/fds-internal.img
sudo ./out/workstation/fds-flash --image out/fds-system-cli.img
```
Both writes erase the selected disk. Follow all checks in that procedure; a
`-part1` path is not a whole-disk destination. The disks must use 512-byte logical
sectors and be at least as large as their respective images.
Each invocation lists disks by model, serial and capacity. Select the NVMe
enclosure for the internal image and a different USB disk for SYSTEM, review the
plan, and enter the displayed erase phrase. Both writes replace the selected
media. The tool refuses mounted/occupied disks and non-512-byte logical sectors;
it writes, flushes, verifies readback and relocates the backup GPT automatically.
Wait for `VERIFIED` before proceeding.
Use `--device /dev/disk/by-id/...` to preselect a whole disk while retaining
interactive confirmation. The [flashing guide](Flashing) covers dry runs and
unattended mode with explicit image checksum and target identity.
Confirm the three internal partition labels and the USB's single `FDS_SYSTEM`
label after writing. Safely disconnect the disks, install NVMe on the powered-off
Pi, and connect exactly one SYSTEM. Do not leave the NVMe enclosure connected as
a duplicate source of FDS partitions.
label with `lsblk -o NAME,PARTLABEL,FSTYPE,MOUNTPOINTS`. Unmount any automatic
desktop mounts after flashing, safely disconnect the disks, install NVMe on the
powered-off Pi, and connect exactly one SYSTEM. Do not leave the NVMe enclosure
connected as a duplicate source of FDS partitions.
## 6. Power on and reach the console
+1
@@ -17,6 +17,7 @@ Use the sidebar or [all pages](Page-Index) to find a guide.
| --- | --- |
| [Overview](Overview) | How the computer, internal storage and cartridges fit together |
| [Run on a Raspberry Pi 5](Hardware-Setup) | Wire HDMI/USB/power, prepare NVMe and SYSTEM, reach the first console, calibrate bays and diagnose hardware |
| [Flash disk images](Flashing) | Install NVMe and cartridges interactively or unattended with verification |
| [Build and start FDS](Getting-Started) | Prepare the OS build workstation, create images and boot the emulator |
| [Software and emulator walkthrough](Workstation) | Build Void source packages, assemble cartridges, insert them and write USB media |
| [Using cartridges](Cartridges) | Inspect bays, run applications, resolve command names and eject safely |
+26 -64
@@ -57,79 +57,41 @@ public key as described in [Release signatures](Releases). Its complete disk
is named `fds-internal-0.1.0.img`; a local build uses `out/fds-internal.img`.
Use the complete disk image, not the separate BOOT or RECOVERY payload.
List disks before and after connecting the intended drive:
Install the workstation `fds-tools` package or run `make workstation-binaries`,
then use [fds-flash](Flashing) for interactive or unattended installation:
```sh
lsblk -d -o NAME,PATH,MODEL,SERIAL,SIZE,TRAN,LOG-SEC
ls -l /dev/disk/by-id/
sudo ./out/workstation/fds-flash \
--image out/fds-internal.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_NVME_DISK
```
Match the physical model, serial and capacity. Choose a persistent **whole-disk**
`/dev/disk/by-id/` path without a `-partN` suffix; never guess a `/dev/sdX` name.
Unmount every target partition and disable any swap on it. Do not select the
workstation's system disk. The current images require 512-byte logical sectors
and a disk at least as large as the image; 4 KiB logical-sector media is not
supported by this layout.
Replace the destination with the verified whole-disk path. The tool shows model,
serial, capacity, partitions and image hash, then requires an exact erase phrase.
It refuses mounted or occupied disks and handles flushing, readback, backup-GPT
relocation and kernel partition-table refresh. Partitions and filesystems retain
their image sizes. The [flashing guide](Flashing) covers dry runs, JSON output,
unattended identity/checksum bindings and failure handling.
Open Bash (`bash`), replace both paths below, then run the block. It checks the
selected disk again, requires a typed confirmation, writes and reads back the
complete image, and relocates the backup GPT when the disk is larger than the
image. It does not expand any partition or filesystem.
Prepare the first SYSTEM cartridge separately:
```bash
(
set -euo pipefail
fds_image="$PWD/out/fds-internal.img"
fds_disk=/dev/disk/by-id/REPLACE_WITH_THE_TARGET_DISK
[[ -f "$fds_image" && -s "$fds_image" && -b "$fds_disk" ]]
[[ $(lsblk -dnro TYPE "$fds_disk") == disk ]]
[[ $(sudo blockdev --getss "$fds_disk") == 512 ]]
fds_bytes=$(stat -Lc %s "$fds_image")
(( $(sudo blockdev --getsize64 "$fds_disk") >= fds_bytes ))
lsblk -p -o NAME,TYPE,MODEL,SERIAL,SIZE,MOUNTPOINTS "$fds_disk"
if lsblk -nrpo MOUNTPOINTS "$fds_disk" | grep '[^[:space:]]' >/dev/null; then
echo 'Target has mounted filesystems or swap; stop and release them first.' >&2
exit 1
fi
if lsblk -nrpo TYPE "$fds_disk" | grep -Ev '^(disk|part)$' >/dev/null; then
echo 'Target has device-mapper or other active descendants; stop.' >&2
exit 1
fi
read -r -p "Type ERASE $fds_disk to erase this disk: " fds_confirmation
[[ "$fds_confirmation" == "ERASE $fds_disk" ]]
sudo dd if="$fds_image" of="$fds_disk" bs=4M conv=fsync status=progress
sudo blockdev --flushbufs "$fds_disk"
sudo cmp -n "$fds_bytes" "$fds_image" "$fds_disk"
sudo sfdisk --lock=yes --relocate gpt-bak-std "$fds_disk"
sudo sfdisk --verify "$fds_disk"
sudo blockdev --flushbufs "$fds_disk"
)
```sh
sudo ./out/workstation/fds-flash \
--image out/fds-system-cli.img \
--device /dev/disk/by-id/REPLACE_WITH_THE_SYSTEM_DISK
```
Every command must succeed. The byte comparison occurs before relocating GPT,
because relocation intentionally changes disk-table headers. GNU `dd`'s `fsync`
flushes output before it returns; `sfdisk`'s `gpt-bak-std` moves the backup header
to the end of the target. See the [GNU dd manual](https://www.gnu.org/s/coreutils/manual/html_node/dd-invocation.html)
and [sfdisk manual](https://man7.org/linux/man-pages/man8/sfdisk.8.html).
These commands use the already documented coreutils, diffutils and util-linux
host tools; they do not add a target daemon.
Use a different disk for SYSTEM. Both confirmed writes replace the selected
media's contents; the internal image also replaces stored machine settings.
The alternative development image is `out/fds-system-development.img`.
Versioned release images use the same commands.
Confirm that the disk shows `FDS_BOOT`, `FDS_RECOVERY` and `FDS_INTERNAL` in that
order using `lsblk -o NAME,PARTLABEL,FSTYPE,MOUNTPOINTS`. Unmount anything the
desktop automatically mounted, then safely disconnect the enclosure and install
the NVMe in the powered-off Pi. Follow [EEPROM preparation](EEPROM) for the
separately reviewed NVMe boot settings.
Prepare the **first SYSTEM cartridge on the workstation** using the same guarded
write block, with its two path assignments changed to the chosen SYSTEM image
and a different, empty USB cartridge disk. For a local build select
`out/fds-system-cli.img` or `out/fds-system-development.img`; release files are
`fds-system-cli-0.1.0.img` and `fds-system-development-0.1.0.img`. They are
alternative complete GPT images, each containing one `FDS_SYSTEM` partition.
Readback and backup-GPT relocation apply to this disk too. Check its partition
label, safely disconnect it, and insert exactly one SYSTEM cartridge in the Pi
before normal boot. Subsequent cartridge creation and updates can use FDS's
confirmed [media workflow](Developer-Media-Tools) after bay calibration.
Confirm `FDS_BOOT`, `FDS_RECOVERY`, `FDS_INTERNAL` on NVMe and `FDS_SYSTEM` on
SYSTEM with `lsblk -o NAME,PARTLABEL,FSTYPE,MOUNTPOINTS`. Unmount any automatic
desktop mounts after flashing, safely disconnect the media, and install NVMe in
the powered-off Pi. Insert exactly one SYSTEM cartridge before normal boot.
Continue with [real-hardware setup](Hardware-Setup) and the separately reviewed
[EEPROM configuration](EEPROM).
## Configure the machine before building
+2 -2
@@ -62,7 +62,7 @@ Run these from the repository root:
| Command | Result |
| --- | --- |
| `make wiki-check` | Check the documentation in `fds-os.wiki` |
| `make workstation` | Arch `fds-tools` package containing both workstation commands |
| `make workstation` | Arch `fds-tools` package containing all three workstation commands |
| `make workstation-install` | Install that package using pacman |
| `make workstation-binaries` | Native commands for other Linux distributions |
| `make bootstrap` | Prepares the complete OS build environment on x86_64 Arch Linux |
@@ -78,7 +78,7 @@ programs and dependencies directly. FDS does not extract those programs at launc
The workstation walkthrough includes prerequisites, complete example commands,
expected outputs, emulator lifecycle and the confirmed USB-writing workflow.
Append `--help` to either native tool for its command reference; run `make help`
Append `--help` to any native tool for its command reference; run `make help`
for the complete build target list.
Build identities come from Git release tags. See [versioning](Developer-Versioning) for release, development and source-export behavior.
+1
@@ -6,6 +6,7 @@ include_toc: true
## User manual
- [Flash disk images with fds-flash](Flashing)
- [Build and start FDS](Getting-Started)
- [Build software cartridges and use the emulator](Workstation)
- [Dasung Paperlike display](Dasung)
+14 -23
@@ -11,7 +11,7 @@ as guest commands.
## Prepare the tools
The native tools are `fds-cartridge` and `fds-emulator`. On Arch Linux, build
The native tools are `fds-cartridge`, `fds-emulator` and `fds-flash`. On Arch Linux, build
and install their `fds-tools` package from the checkout:
```sh
@@ -21,7 +21,7 @@ make workstation-install
```
`make workstation` produces `out/workstation/fds-tools-VERSION-1-ARCH.pkg.tar.zst`
with both commands, documentation, examples and license notices. It does not
with all three commands, documentation, examples and license notices. It does not
install packages. `make workstation-install` builds that package and invokes
`sudo pacman -U` to install it into `/usr/bin`. Pacman tracks upgrades and removal;
remove it later with `sudo pacman -R fds-tools`. The exact latest package path is
@@ -246,33 +246,24 @@ preserved by `make clean`; keep them under your own names, such as `my-emulator`
## Write a cartridge to USB
Identify the intended whole USB drive, unmount its partitions, then preview:
Use `fds-flash` to write the complete cartridge image interactively:
```sh
fds-cartridge preview out/demo-tools.img /dev/sdX out/usb-preview.json
sudo fds-flash --image out/demo-tools.img
```
Replace `/dev/sdX` with the actual destination. The JSON identifies the drive,
capacity, image hash and exact confirmation phrase. Check those values before
writing: this replaces the selected drive's contents.
Choose the intended whole USB disk, review its model, serial and capacity, and
type the displayed erase phrase. The tool writes, flushes and verifies the disk,
including backup-GPT relocation on a larger destination. For a checkout build,
use `sudo ./out/workstation/fds-flash` instead of the installed command.
```sh
sudo /absolute/path/to/fds-cartridge write out/usb-preview.json \
--confirm 'COPY THE EXACT confirmation VALUE FROM THE PREVIEW'
```
The [flashing guide](Flashing) covers explicit device paths, dry-run JSON,
unattended writes and disposable-file testing. It also covers the internal
NVMe and first SYSTEM disk; `fds-flash` accepts those complete disk images too.
The writer rechecks identity, writes the entire disk image, flushes it and verifies
readback. On a larger drive it moves the backup GPT to the end. A changed image
or reinserted drive requires a fresh preview. Use the image-tool runner for
preview and inspection if your EROFS utilities are in the local container.
To rehearse with a disposable regular file:
```sh
truncate -s "$(stat -c %s out/demo-tools.img)" out/disposable-usb.img
fds-cartridge preview out/demo-tools.img out/disposable-usb.img out/file-preview.json --file-target
fds-cartridge write out/file-preview.json --confirm 'COPY THE EXACT confirmation VALUE'
```
The older `fds-cartridge preview` / `write --confirm` interface remains supported
for USB cartridge workflows. It performs deeper cartridge content inspection and
retains its protection against overwriting internal FDS partitions.
See [troubleshooting](Troubleshooting) for failed builds, namespace errors,
busy consoles, invalid media and blocked ejects.
+1
@@ -17,6 +17,7 @@
**Install and maintain**
- [Flash disk images](Flashing)
- [Internal storage and machine settings](Internal-Storage)
- [Pi 5 EEPROM configuration](EEPROM)
- [Recovery and rollback](Recovery)