#!/usr/bin/env bash # check_images.sh -- build the stick and the data stick and check them # (docs/v4.0.0/plans/2026-10-27-stick-3-images.md, Task 1; docs/v4.0.0/STICK.md 4). # # The stick: make boot_image TARGET=PC -> build/boards/pc/lithos-pc.img # The data stick: make -f kernel/Makefile ARCH=amd64 datastick -> build/amd64/kernel/datastick.img # # Prints PASS:/FAIL: per check and RESULT:; exits 0 only if every check passes. set -uo pipefail cd "$(dirname "$0")/.." PATH="$PATH:/usr/sbin:/sbin" STICK=build/boards/pc/lithos-pc.img DATA=build/amd64/kernel/datastick.img MKARTEMIS=build/amd64/kernel/tools/mkartemis ESP_T=C12A7328-F81F-11D2-BA4B-00A0C93EC93B IDENT_T=23BEBFE1-4817-4CF3-A537-9069BF159788 ART_T=BCD7B586-1C8E-4EEF-86A3-273A8D8EE624 ok=1 check() { # check "what" command... local what="$1"; shift if "$@" >/dev/null 2>&1; then echo "PASS: $what"; else echo "FAIL: $what"; ok=0; fi } # part IMG N FIELD -- a field (start, size, type) of partition N (1-based) from sfdisk --json part() { sfdisk --json "$1" 2>/dev/null | python3 -c " import json, sys p = json.load(sys.stdin)['partitiontable'] parts = p['partitions'] n = int(sys.argv[1]) if sys.argv[2] == 'count': print(len(parts)) elif sys.argv[2] == 'lastlba': print(p['lastlba']) elif n <= len(parts): print(str(parts[n - 1][sys.argv[2]]).upper()) " "$2" "$3" 2>/dev/null } eq() { [ "$1" = "$2" ]; } # geometry IMG -- every partition starts and ends on a whole MiB, the last one within a MiB of # the last usable LBA, and each starts where the one before it ends geometry() { local img="$1" n i prev=2048 s z last n=$(part "$img" 0 count); last=$(part "$img" 0 lastlba) for i in $(seq 1 "$n"); do s=$(part "$img" "$i" start); z=$(part "$img" "$i" size) [ "$s" = "$prev" ] && [ $((s % 2048)) -eq 0 ] && [ $((z % 2048)) -eq 0 ] || return 1 prev=$((s + z)) done [ $((prev - 1)) -le "$last" ] && [ $((last - (prev - 1))) -lt 2048 ] } zeros() { # zeros IMG N -- partition N is all zeros local s z s=$(part "$1" "$2" start); z=$(part "$1" "$2" size) [ -n "$s" ] && [ -n "$z" ] && cmp -s -i "$((s * 512)):0" -n "$((z * 512))" "$1" /dev/zero } artemis_check() { # artemis_check IMG N -- mkartemis --check on partition N "$MKARTEMIS" --check "$1" --first-lba "$(part "$1" "$2" start)" --sectors "$(part "$1" "$2" size)" } uuid() { artemis_check "$1" "$2" 2>/dev/null | sed -n 's/.*disk_uuid \([0-9a-f]*\).*/\1/p'; } echo "== building" make boot_image TARGET=PC >/dev/null 2>&1; echo "boot_image exit $?" make -f kernel/Makefile ARCH=amd64 datastick >/dev/null 2>&1; echo "datastick exit $?" echo "== the stick ($STICK)" check "it exists, 2048 MiB" eq "$(stat -c %s "$STICK" 2>/dev/null)" "$((2048 * 1048576))" check "three partitions" eq "$(part "$STICK" 0 count)" 3 check "1: EFI System, 64 MiB at LBA 2048" eq "$(part "$STICK" 1 type)/$(part "$STICK" 1 start)/$(part "$STICK" 1 size)" "$ESP_T/2048/131072" check "2: StarshipOS identity, 500 MiB" eq "$(part "$STICK" 2 type)/$(part "$STICK" 2 start)/$(part "$STICK" 2 size)" "$IDENT_T/133120/1024000" check "3: StarshipOS Artemis, the rest" eq "$(part "$STICK" 3 type)/$(part "$STICK" 3 start)" "$ART_T/1157120" check "whole MiB, contiguous, Artemis to the end" geometry "$STICK" check "sfdisk --verify: the GPT is clean" sfdisk --verify "$STICK" OFF=$((2048 * 512)) check "the ESP holds EFI/BOOT/BOOTX64.EFI" mdir -i "$STICK@@$OFF" ::/EFI/BOOT/BOOTX64.EFI check "the ESP holds startup.nsh" mdir -i "$STICK@@$OFF" ::/startup.nsh check "starforth.cfg's first word is system=v4" eq "$(mtype -i "$STICK@@$OFF" ::/starforth.cfg 2>/dev/null | awk '{print $1; exit}')" "system=v4" check "the identity partition is all zeros" zeros "$STICK" 2 check "Artemis: STFR v2, signature ok" artemis_check "$STICK" 3 echo "== the data stick ($DATA)" check "it exists, 1536 MiB" eq "$(stat -c %s "$DATA" 2>/dev/null)" "$((1536 * 1048576))" check "two partitions" eq "$(part "$DATA" 0 count)" 2 check "1: StarshipOS identity, 500 MiB at LBA 2048" eq "$(part "$DATA" 1 type)/$(part "$DATA" 1 start)/$(part "$DATA" 1 size)" "$IDENT_T/2048/1024000" check "2: StarshipOS Artemis, the rest" eq "$(part "$DATA" 2 type)/$(part "$DATA" 2 start)" "$ART_T/1026048" check "whole MiB, contiguous, Artemis to the end" geometry "$DATA" check "sfdisk --verify: the GPT is clean" sfdisk --verify "$DATA" check "the identity partition is all zeros" zeros "$DATA" 1 check "Artemis: STFR v2, signature ok" artemis_check "$DATA" 2 U1=$(uuid "$DATA" 2) make -f kernel/Makefile ARCH=amd64 datastick >/dev/null 2>&1 U2=$(uuid "$DATA" 2) check "made again, it is fresh: its own disk_uuid ($U1 / $U2)" test -n "$U1" -a -n "$U2" -a "$U1" != "$U2" # the builds regenerate these; put them back as committed (as qemu_session.py does) git checkout -q -- v3/include/version.h capsules/BLOCK_MAP.md sbom.spdx sbom.spdx.json echo "RESULT: $([ $ok = 1 ] && echo PASS || echo FAIL)" [ $ok = 1 ]