9.2 KiB
Build software cartridges and use the emulator
This walkthrough runs on a Linux workstation. It builds applications from Void source packages, creates a complete cartridge image, runs it in FDS, and explains how to write it to USB. Commands run from the FDS checkout root unless marked as guest commands.
Prepare the tools
The native tools are fds-cartridge and fds-emulator. Build them with Rust,
a C linker and Make; the repository selects its pinned Rust toolchain:
make workstation
mkdir -p out
export PATH="$PWD/out/workstation:$PATH"
| Prerequisite | Used for |
|---|---|
Prepared Void void-packages checkout and native XBPS utilities |
Build source packages and install their AArch64 runtime dependencies |
mkfs.erofs, fsck.erofs |
Create and inspect read-only payload filesystems |
bwrap |
Inspect filesystems and install package trees in a user namespace |
xz |
Read older software cartridges and package/source archives |
qemu-system-aarch64, qemu-img |
Run the emulator and create writable DATA overlays |
Install tools through your Linux distribution's package manager. Enable unprivileged user namespaces for bubblewrap. Software builds run as an ordinary user and execute trusted Void build templates on the workstation. Run source builds sequentially when they share the same Void checkout.
Prepare a Void source checkout using its upstream instructions.
Complete xbps-src binary-bootstrap for the workstation architecture before
using it. The workstation itself need not run Void. Select that checkout with
--void-packages /path/to/void-packages; native xbps-* tools must be in PATH,
or selected with --xbps-bin /path/to/bin. Builds target AArch64/glibc.
For the complete FDS build workstation, bootstrap already
prepares vendor/void-packages and .host/xbps/usr/bin. Reuse its local tools:
./tools/prepare-image-tools
./tools/in-void xbps-install -y qemu-img
fds-cartridge --image-tool-runner tools/in-image-tools doctor
fds-emulator doctor --qemu-runner tools/in-void
An optional runner receives a utility name followed by its arguments. Image runners select EROFS utilities; XBPS runners provide the package-installation namespace. Without runners, the tools use native utilities and bubblewrap.
Build the example cartridge
The repository includes hello and system-report Void source packages. Each software recipe names a package, its source-template directory and its public commands. A cartridge recipe groups those software recipes into payloads.
With native tools and a prepared checkout:
fds-cartridge --void-packages /path/to/void-packages \
create examples/software/cartridge.toml out/demo-tools.img
fds-cartridge inspect out/demo-tools.img
With the project-local Void and image tools, use this equivalent command:
fds-cartridge --image-tool-runner tools/in-image-tools \
--xbps-tool-runner tools/in-void --xbps-bin "$PWD/.host/xbps/usr/bin" \
create examples/software/cartridge.toml out/demo-tools.img
fds-cartridge --image-tool-runner tools/in-image-tools inspect out/demo-tools.img
Choose one route. Output paths must be new. The command builds each package
with xbps-src, installs the package and runtime dependencies into private
staging trees, verifies their architecture and integrity, and writes the complete
image. Source build logs go to standard error; the final result is JSON.
The example image contains:
| Partition | Contents |
|---|---|
1: FDS_METADATA |
Cartridge identity and software catalogue |
2: FDS_PAYLOAD02 |
programs/demo.hello/, including usr/bin/hello and libraries |
3: FDS_PAYLOAD03 |
programs/demo.report/, including usr/bin/report and dependencies |
There are no new xz software bundles. Programs are ready to run directly from EROFS. Inspection validates both GPT tables, filesystem contents and software hashes, then prints partition and command details as JSON.
Build a reusable installed-software directory
To separate package compilation from cartridge assembly:
fds-cartridge --xbps-tool-runner tools/in-void \
--xbps-bin "$PWD/.host/xbps/usr/bin" \
software build examples/software/hello/software.toml out/demo-hello
fds-cartridge software inspect out/demo-hello
The output contains software.toml and root/. A cartridge's sources list can
name this directory instead of a source recipe. For example:
format = 2
id = "my.tools"
name = "My tools"
version = "1.0"
[[payload]]
sources = ["../out/demo-hello"]
Paths are relative to the cartridge recipe. Put several sources in one list to
share a partition, or add [[payload]] sections for separate partitions. See
the format reference for complete source metadata and limits.
Start FDS
Build matching boot inputs using Build and start FDS, or copy a kernel, initramfs and SYSTEM image from an FDS build machine.
fds-emulator --session out/my-emulator start --qemu-runner tools/in-void
Omit --qemu-runner when QEMU is installed directly on the workstation. To use
copied boot images:
fds-emulator --session out/my-emulator start \
--kernel /path/to/kernel_2712.img \
--initramfs /path/to/fds-initramfs.img \
--system /path/to/fds-system-cli.img
The session directory must be new and private. Keep its absolute path short
(under 90 bytes) for Unix sockets. Start waits for the FDS prompt and uses two
emulated CPUs and 1024 MiB RAM; --memory-mib 2048 increases memory. SYSTEM and
PROGRAM images are read-only. The session holds logs and any DATA overlays.
Insert and run software
From the workstation:
fds-emulator --session out/my-emulator insert 01 out/demo-tools.img
fds-emulator --session out/my-emulator guest -- fds bay 01
fds-emulator --session out/my-emulator guest -- hello 'Hello from the emulator'
fds-emulator --session out/my-emulator guest -- fds run 01 -- demo.report:report
Discovery is asynchronous. Wait until the bay reports MOUNTED READ ONLY before
running commands. Direct commands return their output and exit status to the
caller. fds run starts a background job; read its output with:
fds-emulator --session out/my-emulator guest -- tail -20 /run/log/cartridged/current
Open an interactive shell with fds-emulator --session out/my-emulator console.
At FDS>, use hello, report, fds bays or other guest commands. Ctrl-]
detaches without stopping the VM. Detach before using guest, eject or ordinary
stop, since they also need the serial console.
All twelve virtual bays accept images. Simultaneously inserted PROGRAM cartridges must have distinct cartridge IDs. Duplicate identities produce a guest error. Command-name collisions are resolved as described in Using cartridges.
Eject and stop
fds-emulator --session out/my-emulator eject 01
fds-emulator --session out/my-emulator status
fds-emulator --session out/my-emulator stop
Eject asks FDS to stop programs and release storage before removing the virtual
USB device. If FDS refuses, the cartridge stays attached. stop performs native
FDS shutdown. Session logs remain available; create a new session to boot again.
unplug BAY simulates a physical pull, and stop --force cuts virtual power.
Use these only for deliberate failure simulation; DATA writes can be lost.
Save emulator DATA
Inserting a DATA image creates a writable data-<bay>-<id>.qcow2 overlay in the
session directory. Eject retains it. Reinserting the original image creates a
fresh overlay. To export the changed contents after eject or shutdown:
qemu-img convert -f qcow2 -O raw /path/to/session/data-02-ID.qcow2 out/saved-data.img
Keep its backing image at the recorded path until export completes. Never convert
an overlay while a running VM is using it. Personal session directories are
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:
fds-cartridge preview out/demo-tools.img /dev/sdX out/usb-preview.json
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.
sudo /absolute/path/to/fds-cartridge write out/usb-preview.json \
--confirm 'COPY THE EXACT confirmation VALUE FROM THE PREVIEW'
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:
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'
See troubleshooting for failed builds, namespace errors, busy consoles, invalid media and blocked ejects.