[PATCH v4 08/13] Use OS version to set partition labels and UKI name

Demi Marie Obenour
2025-11-26T19:37:31Z

systemd-sysupdate has strict requirements on the partition layout:

- The label of the active partition must match the template in the
.transfer file. For instance, the root filesystem of Spectrum 0.0.0
must be in a partition with label "Spectrum_0.0.0", and the verity
partition must have the label "Spectrum_0.0.0.verity".

- The label of the inactive partition must be that of the old version of
Spectrum, or "_empty" for freshly installed systems.

- The partition type UUID must conform to the Discoverable Partition
Specification.

Also, the UKI must have a name that includes the OS version. Otherwise,
it will not be deleted during updates.

Since the partition label includes the OS version, add an OS version
number. Use 0.0.0 to indicate that Spectrum OS is still in very early
development and should not be used. The version number can be
overridden in the build configuration file.

Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
Reviewed-by: Alyssa Ross <hi@alyssa.is>
---
Changes since v4:
- Rebase and address merge conflicts.
- Add missing "VERSION = config.version" in Nix files.
Changes since v2:
- Split off into separate commit.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
---
host/initramfs/Makefile | 4 ++--
host/initramfs/shell.nix | 2 ++
host/rootfs/Makefile | 4 ++--
host/rootfs/default.nix | 5 +++--
host/rootfs/shell.nix | 2 ++
lib/config.default.nix | 1 +
release/live/Makefile | 8 ++++----
release/live/default.nix | 3 +++
release/live/shell.nix | 3 ++-
9 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile
index c3d600ad5a55d81b8ca9c7a3e182ef5f4fd90f4b..a7f7bb22255b2cc3f845da7e85cadd7aab1efdb9 100644
--- a/host/initramfs/Makefile
+++ b/host/initramfs/Makefile
@@ -39,8 +39,8 @@ build/live.img: ../../scripts/format-uuid.awk ../../scripts/make-gpt.sh ../../sc
uuids=$$(awk -f ../../scripts/format-uuid.awk < $(ROOT_FS_VERITY_ROOTHASH)) && \
set -u -- $$uuids && \
bash ../../scripts/make-gpt.sh $@.tmp \
- $(ROOT_FS_VERITY):verity:$$2 \
- $(ROOT_FS_IMAGE):root:$$1
+ $(ROOT_FS_VERITY):verity:$$2:Spectrum_'$(VERSION).verity' \
+ $(ROOT_FS_IMAGE):root:$$1:Spectrum_'$(VERSION)'
mv $@.tmp $@

clean:
diff --git a/host/initramfs/shell.nix b/host/initramfs/shell.nix
index 8b47aa53bc19a818ebf563e281f22e82202a8ea5..44d4a985e969c1a57ad42d0666189c704aef9afd 100644
--- a/host/initramfs/shell.nix
+++ b/host/initramfs/shell.nix
@@ -4,6 +4,7 @@
import ../../lib/call-package.nix (
{ callSpectrumPackage, rootfs, pkgsStatic, stdenv
, cryptsetup, jq, qemu_kvm, tar2ext4, util-linux
+, config
}:

let
@@ -18,5 +19,6 @@ initramfs.overrideAttrs ({ nativeBuildInputs ? [], env ? {}, ... }: {
env = env // {
KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}";
ROOT_FS = rootfs;
+ VERSION = config.version;
};
})) (_: {})
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile
index ab24263c6f327e47cd1d012ca8d729b0ea5eb8f3..a6d9f23e9f5277b7c79a53105eb2dfe1bab1451e 100644
--- a/host/rootfs/Makefile
+++ b/host/rootfs/Makefile
@@ -96,8 +96,8 @@ build/live.img: ../../scripts/format-uuid.awk ../../scripts/make-gpt.sh ../../sc
uuids=$$(awk -f ../../scripts/format-uuid.awk < $(ROOT_FS_VERITY_ROOTHASH)) && \
set -u -- $$uuids && \
bash ../../scripts/make-gpt.sh $@.tmp \
- $(ROOT_FS_VERITY):verity:$$2 \
- $(ROOT_FS_IMAGE):root:$$1
+ $(ROOT_FS_VERITY):verity:$$2:Spectrum_'$(VERSION).verity' \
+ $(ROOT_FS_IMAGE):root:$$1:Spectrum_'$(VERSION)'
mv $@.tmp $@

debug:
diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix
index 941c04e619baa7652d1812f4eb50445c607d5884..16a151971715f9a9d987dc92a1d06eb169de1144 100644
--- a/host/rootfs/default.nix
+++ b/host/rootfs/default.nix
@@ -3,8 +3,8 @@
# SPDX-FileCopyrightText: 2022 Unikie

import ../../lib/call-package.nix (
-{ callSpectrumPackage, spectrum-build-tools, src
-, pkgsMusl, pkgsStatic, linux_latest
+{ callSpectrumPackage, config, spectrum-build-tools
+, src, pkgsMusl, pkgsStatic, linux_latest
}:
pkgsStatic.callPackage (

@@ -125,6 +125,7 @@ stdenvNoCC.mkDerivation {
printf "%s\n/\n" ${packagesSysroot} >$out
sed p ${writeClosure [ packagesSysroot] } >>$out
'';
+ VERSION = config.version;
};

# The Makefile uses $(ROOT_FS), not $(dest), so it can share code
diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix
index 6df2f575fdfc7cdf8067ccfdb5fecaad9f6ea5e6..27f93e05fce036257d27cf9992fee8c925073f80 100644
--- a/host/rootfs/shell.nix
+++ b/host/rootfs/shell.nix
@@ -5,6 +5,7 @@
import ../../lib/call-package.nix (
{ callSpectrumPackage, rootfs, pkgsStatic, srcOnly, stdenv
, btrfs-progs, cryptsetup, jq, netcat, qemu_kvm, reuse, util-linux
+, config
}:

rootfs.overrideAttrs (
@@ -20,5 +21,6 @@ rootfs.overrideAttrs (
KERNEL = "${passthru.kernel}/${stdenv.hostPlatform.linux-kernel.target}";
LINUX_SRC = srcOnly passthru.kernel.configfile;
VMLINUX = "${passthru.kernel.dev}/vmlinux";
+ VERSION = config.version;
};
})) (_: {})
diff --git a/lib/config.default.nix b/lib/config.default.nix
index a8422345cc00f9413bb19ec968fd89c82fed801b..489c231490a8b66aa01f50053b25646060f7f963 100644
--- a/lib/config.default.nix
+++ b/lib/config.default.nix
@@ -4,4 +4,5 @@
{
pkgsFun = import ./nixpkgs.default.nix;
pkgsArgs = {};
+ version = "0.0.0";
}
diff --git a/release/live/Makefile b/release/live/Makefile
index 5ab93451de109949af0e7ed7f70bf6827fefbf69..46628bdaa5b4a02aca3dd15be4477c3b2c194993 100644
--- a/release/live/Makefile
+++ b/release/live/Makefile
@@ -14,8 +14,8 @@ $(dest): ../../scripts/format-uuid.awk ../../scripts/make-gpt.sh ../../scripts/s
set -u -- $$uuids && \
bash ../../scripts/make-gpt.sh $@.tmp \
build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \
- $(ROOT_FS_VERITY):verity:$$2 \
- $(ROOT_FS_IMAGE):root:$$1
+ $(ROOT_FS_VERITY):verity:$$2:Spectrum_'$(VERSION).verity' \
+ $(ROOT_FS_IMAGE):root:$$1:Spectrum_'$(VERSION)'
mv $@.tmp $@

build/empty:
@@ -27,8 +27,8 @@ build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty
$(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux
# This symlink is necessary. Copying $(EFI_IMAGE) directly
# results in an unbootable image. TODO: figure out why.
- ln -s $(EFI_IMAGE) build/spectrum.efi
- $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux
+ ln -s $(EFI_IMAGE) 'build/Spectrum_$(VERSION).efi'
+ $(MCOPY) -i $@ 'build/Spectrum_$(VERSION).efi' ::/EFI/Linux
$(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME)

clean:
diff --git a/release/live/default.nix b/release/live/default.nix
index d1e2422e9f1ba666af7ad7a5cce1c80a242d0777..aa5c5869b9c82ce3722fc39029f6aabd7d8c874d 100644
--- a/release/live/default.nix
+++ b/release/live/default.nix
@@ -1,11 +1,13 @@
# SPDX-License-Identifier: MIT
# SPDX-FileCopyrightText: 2021-2023, 2025 Alyssa Ross <hi@alyssa.is>
# SPDX-FileCopyrightText: 2022 Unikie
+# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com>

import ../../lib/call-package.nix (
{ callSpectrumPackage, spectrum-build-tools, src
, lib, pkgsStatic, stdenvNoCC
, cryptsetup, dosfstools, jq, mtools, util-linux
+, config
}:

let
@@ -46,6 +48,7 @@ stdenv.mkDerivation {
SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
EFI_IMAGE = efi;
EFINAME = "BOOT${toUpper efiArch}.EFI";
+ VERSION = config.version;
};

buildFlags = [ "dest=$(out)" ];
diff --git a/release/live/shell.nix b/release/live/shell.nix
index b0bf957c085d1581a24d8916925611da0a60ec8b..e542793a66fb972cfde90f6be2204986442b7d4b 100644
--- a/release/live/shell.nix
+++ b/release/live/shell.nix
@@ -2,7 +2,7 @@
# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is>

import ../../lib/call-package.nix (
-{ callSpectrumPackage, stdenv, qemu_kvm }:
+{ callSpectrumPackage, config, stdenv, qemu_kvm }:

let
efi = callSpectrumPackage ../../host/efi.nix {};
@@ -17,6 +17,7 @@ in
OVMF_CODE = "${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd";
ROOT_FS = efi.rootfs;
EFI_IMAGE = efi;
+ VERSION = config.version;
};
}
)) (_: {})

--
2.52.0