update docs

This commit is contained in:
2026-09-22 13:23:34 +08:00
parent 99bc3d15c5
commit 8a4788fca8
126 changed files with 7198 additions and 2425 deletions
+88 -98
View File
@@ -1,117 +1,107 @@
# Software cartridge format 1
# Software cartridge format
[Build and use a cartridge](workstation.md) · [Original cartridge classes](cartridges.md)
A PROGRAM cartridge is a complete GPT disk image with one EROFS metadata partition
and one or more EROFS payload partitions. New media uses catalogue format 2 and
stores installed Void package trees. Source recipes and build tools remain on
the workstation; FDS executes the installed files directly.
A software cartridge is a complete GPT disk image with **1 + m** partitions,
where `m` is 1–32. Partition 1 describes every software package in all payload
partitions. All partitions use read-only EROFS. This format is the current
PROGRAM creation format; existing single-partition PROGRAM media remain readable.
SYSTEM, DATA and ENVIRONMENT layouts retain their existing meanings.
## Disk and filesystem layout
```text
GPT protective MBR + primary GPT
1 FDS_METADATA
FDS/CARTRIDGE.TOML
FDS/SOFTWARE.TOML
2 FDS_PAYLOAD02
bundles/demo.hello.tar.xz
bundles/demo.editor.tar.xz
3 FDS_PAYLOAD03
bundles/demo.report.tar.xz
...
backup GPT
```
Partition entries are consecutive, use Linux filesystem type GUIDs, unique
nonzero partition UUIDs, no GPT attributes, and nonoverlapping MiB-aligned
extents. Partition 1 starts at LBA 2048. Both GPT copies, their headers and CRCs
must agree. A full-drive write to a larger USB device relocates the backup table
and header. The existing on-target image parser and the workstation writer
share these checks.
`FDS/CARTRIDGE.TOML` uses the existing format-1 identity with `class = "program"`
and `media.writable = false`. It contains no startup command. A sample catalogue:
## Software source recipe
```toml
format = 1
[[software]]
id = "demo.hello"
name = "AArch64 hello"
format = 2
id = "example.hello"
name = "Hello"
version = "1.0"
architecture = "aarch64"
partition = 2
archive_bytes = 2308
unpacked_bytes = 70504
entries = 2
sha256 = "REPLACE_WITH_THE_64_CHARACTER_LOWERCASE_SHA256"
[software.commands]
hello = "bin/hello"
[commands]
hello = "usr/bin/hello"
[source]
package = "hello"
```
Those lengths and the digest are illustrative. The builder generates actual
values. IDs and command names use the existing restricted FDS identifier syntax.
IDs are unique per cartridge. Every declared payload partition must contain
exactly the catalogue's `bundles/<id>.tar.xz` archive names, and every payload
partition must be represented. Multiple software entries may share a partition.
The catalogue contains 1–128 software entries and at most 64 KiB of TOML.
`package` names a source package in the selected `void-packages` checkout. For a
custom package, also set `template = "void"`: that directory must contain a
normal Void `template` and any `files/` or `patches/` directories it uses. Paths
are relative to this recipe. The [included hello package](../examples/software/hello/void/template)
is a complete example.
## Archive contract
Custom sources are copied into an untracked `srcpkgs/PACKAGE` directory. Existing
tracked Void sources are never overwritten. If a generated source copy differs,
inspect it, preserve any independent edits, then remove that generated copy and
retry. An unchanged copy can be reused.
Bundles are deterministic USTAR archives compressed with single-threaded xz.
Entries are sorted, timestamps/UID/GID are zero, and permissions normalize to
0755 for directories/executables or 0644 for ordinary data. Host source symlinks
to regular files inside the root are flattened into regular files. Directory or
escaping symlinks are rejected; the archive itself never contains links.
`fds-cartridge` builds with `xbps-src -a aarch64`, installs the resulting package
and runtime dependencies into a fresh tree, and records installed XBPS versions.
Use package dependency declarations to request runtime libraries and utilities.
Each software tree is self-contained with respect to its installed dependencies;
there is no cross-cartridge package resolver.
The reader rejects:
Software IDs and public command names use lowercase ASCII letters, digits,
periods, hyphens and underscores, with a maximum length of 64. Command paths are
relative to the installed root and must resolve to executable files within it.
- Absolute, parent-traversing, repeated-separator, non-UTF-8 or control-character paths.
- Duplicate entries, file-as-parent conflicts, links, devices, sockets, FIFOs,
privileged permissions, and GNU/PAX extension entries.
- Incorrect SHA-256, compressed length, unpacked length, entry count, or command
paths that do not name executable regular files.
- ELF files that are not little-endian 64-bit AArch64, or any ELF in a bundle
declared `architecture = "any"`.
- Invalid xz data, nonzero material after the tar end marker, and resource-limit
violations. Each archive is at most 512 MiB compressed, 1 GiB unpacked and
65,536 entries. Xz decompression has a 256 MiB memory limit.
## Cartridge recipe
A source path must fit USTAR's path fields. Packaging reports paths that cannot
be represented rather than emitting an unsupported extension header.
```toml
format = 2
id = "example.tools"
name = "Example tools"
version = "1.0"
## Guest lifecycle
[[payload]]
sources = ["hello/software.toml", "report/software.toml"]
```
On insertion the daemon validates the complete GPT against kernel partition
geometry and the current USB disk identity. It reads metadata without following
symlinks, mounts every payload read-only/noexec/nosuid/nodev, and checks the
archive inventory and lengths. `fds bay BAY` reports the full catalogue;
`fds bays` stays compact. No archive command runs automatically on insertion.
Each payload section creates one partition. Sources may be recipe paths or
previously built directories containing `software.toml` and `root/`. The metadata
partition records which software belongs to which partition. Software IDs and
cartridge identity must satisfy the metadata validation rules.
`fds run BAY -- SOFTWARE-ID:COMMAND [ARGUMENT...]` verifies and extracts that
package on first use. It creates a private temporary filesystem, applies the
archive contract, then makes the finished tree read-only and accessible for
execution. The runtime cache has a stricter **256 MiB per software tree** limit,
including reserved inode overhead; a host-valid larger bundle may therefore
need splitting before running. Caches live under `/run/fds/software/<bay>/` and
vanish after eject, unplug, restart cleanup, or shutdown.
## On-disk contents
Managed consumers run as UID/GID 1000 with no new privileges in the bay's cgroup.
`FDS_APP`, `PATH`, `LD_LIBRARY_PATH` and `XDG_DATA_DIRS` point to that software
root. DISPLAY/XAUTHORITY retain the established optional desktop integration.
The xz utility is already an explicit dependency of the mandatory `fds-base`
package; runtime extraction adds no target package.
```text
Partition 1: FDS_METADATA
FDS/CARTRIDGE.TOML
FDS/SOFTWARE.TOML
Partition 2: FDS_PAYLOAD02
programs/example.hello/usr/bin/hello
programs/example.hello/usr/lib/...
programs/example.hello/var/db/xbps/...
programs/example.report/...
```
Build recipes, compilers, installation hooks and privileged archive scripts are
never part of this runtime path.
The software catalogue records identity, architecture, commands, partition,
installed package versions, entry count, byte count and SHA-256. `installed=true`
selects the direct-tree contract. The retained `unpacked_bytes` field records
installed file bytes; it does not imply an archive or guest extraction.
Safe eject stops consumers, rejects unexpected mount aliases, unmounts caches,
payloads and metadata, then reports SAFE. Confirmed surprise removal permits
lazy detachment after stopping consumers. Service restart removes stale mounts
before rescanning. SYSTEM stays immutable throughout.
The tree digest covers sorted paths, entry types, modes, contents and symlink
targets. Root-relative package symlinks are relocated to relative in-tree links
when building. Escaping links, special files, privileged/writeable executable
trees, wrong-architecture ELF files and inconsistent metadata are rejected.
Current per-tree bounds are 1 GiB of file data and 65,536 entries.
SHA-256 detects corruption and binds an archive to its catalogue; it does not
establish a publisher's identity. Only run software you trust. Release signature
verification remains the separate [release workflow](releases.md).
## Runtime behavior
FDS verifies the cartridge's geometry, identity, inventory and tree integrity
on insertion. Payloads are mounted read-only with `nosuid,nodev`. No software
command runs automatically. Published command aliases appear in `/run/fds/bin`.
Programs run as UID/GID 1000 in the bay's managed process group. `FDS_APP` names
the installed tree; PATH, library paths and data search paths include its
`usr/bin`, `usr/lib` and `usr/share`. Dynamically linked ELF entry points use the
package tree's own loader. Programs that hard-code unrelated system paths still
need to be compatible with FDS; the tree is not a container or a writable root.
Safe eject stops consumers and releases every payload before reporting SAFE.
A digest detects corruption, not publisher identity: choose software sources
you trust. Distribution signatures are covered by [release verification](releases.md).
## Older media
The reader retains support for catalogue format 1 with xz payloads and legacy
single-partition PROGRAM cartridges containing `app/`. Old xz payloads retain
their temporary extraction behavior and limits. Creation commands produce only
the installed-tree format. Rebuild old software from its Void source recipe to
use direct execution.