Files
fds-os/docs/software-format.md
T
2026-09-21 22:29:23 +08:00

118 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Software cartridge format 1
[Build and use a cartridge](workstation.md) · [Original cartridge classes](cartridges.md)
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:
```toml
format = 1
[[software]]
id = "demo.hello"
name = "AArch64 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"
```
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.
## Archive contract
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.
The reader rejects:
- 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.
A source path must fit USTAR's path fields. Packaging reports paths that cannot
be represented rather than emitting an unsupported extension header.
## Guest lifecycle
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.
`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.
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.
Build recipes, compilers, installation hooks and privileged archive scripts are
never part of this runtime path.
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.
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).