Skip to content

Disk layout and updates

GurtOS keeps two complete systems on disk, slots A and B, and runs from one. An update is written to the other slot, started once on trial, and kept only if the box comes up healthy. Everything that must outlive an update lives on a separate data partition. For the reasoning, read System updates. To run an update, see Update and roll back.

Disk layout and how an update is applied The disk has five partitions: BIOS boot (1 MB), the EFI system partition (512 MB), system slot A (6 GB), system slot B (6 GB) and the data partition (the rest). The box runs from one slot. An update checks its signature and hash, writes the other slot, and starts it once. The box must report healthy within 5 minutes. If it does, the new slot becomes the default. If not, the box restarts into the old slot. The disk (not to scale) BIOS 1 MB ESP 512 MB Slot A 6 GB, running Slot B 6 GB, the update Data: the rest log, workspaces, vault An update box-update apply checks signature, hash Writes the other slot the running one stays Starts it once next_entry Health check within 5 minutes Healthy the new slot becomes default Not healthy back to the old slot
The installer's five partitions. An update fills the slot that is not running, which starts once on trial and becomes the default only after a health check passes.

The installer erases the disk and makes these partitions, in this order:

Partition Size Partition name Mounted at Holds
BIOS boot 1 MB box-bios GRUB for machines that start with BIOS. x86 only.
EFI system partition 512 MB box-esp (FAT label BOX-ESP) /boot/efi GRUB, its menu, and grubenv, which says which slot starts
System slot A 6 GB, 12 GB on GurtOS Personal box-a / when running A whole system: kernel, Ubuntu base, the box service, and the desktop on Personal
System slot B the same as slot A box-b / when running The other system. Empty until the first update.
Data the rest box-data /data Everything that must outlive an update
Edition Both slots Smallest disk Use in practice
GurtOS Server 12 GB about 17 GB 25 GB or more
GurtOS Personal 24 GB about 29 GB 48 GB or more

The installer refuses a disk too small for both slots, the EFI system partition and 4 GB of data.

The installer uses a blank disk straight away. It erases a disk that has anything on it only after someone types erase on the box's screen.

The data partition is mounted at /data, and these paths are bind-mounted from it, so both slots see the same files:

Path What
/var/lib/box The action log, workspaces and tasks (BOX_HOME)
/etc/box The vault and the box's identity key
/var/lib/spacetimedb SpacetimeDB's data
/root/.config/spacetime The identity that owns the box's SpacetimeDB database
/var/log/journal System logs, so a failed update's logs are still there after the rollback

GurtOS Personal also keeps these on the data partition, and will not start its desktop without them:

Path What
/home People's home folders
Network connections Saved Wi-Fi and wired connections (NetworkManager)
AccountsService Account pictures and account types
Bluetooth Paired devices

/data/update holds trial and last: the update in progress and the last result.

An update also copies into the new slot: /etc/machine-id, SSH host keys (debug builds), and the task users the core made (uids 30000 to 39999), so a resumed task keeps its uid. On GurtOS Personal it also carries people's accounts (uids 1000 to 29999), their groups, including sudo, the time zone, language, computer name and login settings.

On GurtOS Personal, software someone installs with apt, and any other change outside their home folder and the settings above, is gone after the next system update, because the update replaces the whole system.

GRUB reads grubenv on the EFI system partition:

Variable Meaning
saved_entry The default slot, a or b
next_entry A slot to start once. GRUB clears it as it uses it.

The running slot is on the kernel command line as box.slot=a or box.slot=b. The kernel starts with panic=10, so a kernel that panics restarts by itself after 10 seconds.

  1. box-update apply <file or URL> fetches gurtos-<edition>-<arch>.sqfs with its .sha256 and .sig.
  2. It checks the signature on the hash against /etc/box-os/update.pub, then checks the hash against the file. Either failing stops the update.
  3. It formats the other slot, unpacks the image into it, and checks it holds a kernel and the box service, and that it is the same edition as the running system. A GurtOS Server image never replaces GurtOS Personal, which would lose its desktop.
  4. It copies the machine's identity and task users across, as above.
  5. It sets next_entry to the new slot, writes /data/update/trial, and restarts.
  6. At every start, box-confirm.service waits up to 5 minutes for GET /health on the box's API to answer ok.
    • Healthy on trial: the new slot becomes saved_entry, the default. The update is kept.
    • Not healthy: the box restarts. saved_entry never changed, so GRUB starts the old slot.
    • The new slot did not start at all: the box is already on the old slot, and the result is recorded.

Each result is written to /data/update/last and printed on the serial console.

image/build makes these, and the same .sqfs is both on the install disc and the update file:

File What
gurtos-<edition>-<arch>.iso The install disc. Starts with BIOS and UEFI. Also runs as a live system.
gurtos-<edition>-<arch>.sqfs The whole system as one compressed image
gurtos-<edition>-<arch>.sqfs.sha256 Its SHA-256 hash
gurtos-<edition>-<arch>.sqfs.sig The hash, signed with the build machine's ed25519 update key

<edition> is server or personal, and <arch> is x86_64 or arm64: for example gurtos-server-x86_64.iso or gurtos-personal-x86_64.iso. Debug builds end in -debug, such as gurtos-server-x86_64-debug.iso.

Run as root on the box. Release builds have no shell, so today this needs a debug build with SSH.

box-update status # the running slot, the other slot, the default, the last result
box-update apply https://updates.example/gurtos-server-x86_64.sqfs
box-update apply /tmp/gurtos-server-x86_64.sqfs --no-reboot # write the slot now, restart later
box-update rollback # make the other slot the default and restart into it
box-update confirm # what box-confirm.service runs at every start

apply with a local file expects the .sha256 and .sig files beside it.

  • The slots are plain writable ext4. They are not read-only and not verified at boot (no dm-verity). Changes made by hand inside a running slot are lost at the next update, by design.
  • A system that hangs, instead of panicking or failing its health check, stays hung until someone restarts it. A hardware watchdog would cover that; not every machine or VM has one.
  • The GRUB menu on the EFI system partition is written once at install and never updated. A change to the boot menu itself needs a reinstall.
  • Updates are signed with one ed25519 key held on one build machine. There is no key rotation and no rollback protection: an older signed image installs fine.
  • The boot loader is not signed, so Secure Boot must be off.

GurtOS is open source under the Apache License 2.0.Source code on GitHub.