# live-image/Makefile — builds the Debian live image that PXE-booted
# hosts land in. Requires a Linux host (or WSL) with mkosi installed.
# On native Windows this Makefile short-circuits with a clear message.

ifeq ($(OS),Windows_NT)
UNAME_S := Windows
else
UNAME_S := $(shell uname -s)
endif

REPO_ROOT := $(abspath ..)
AGENT_BIN := $(REPO_ROOT)/bin/vetting-agent.linux-amd64
MKOSI_EXTRA_AGENT := mkosi.extra/usr/local/sbin/vetting-agent

.PHONY: all check-linux check-initrd repack-initrd agent clean
all: check-linux $(MKOSI_EXTRA_AGENT)
	mkosi --force build
	$(MAKE) repack-initrd
	$(MAKE) check-initrd

# mkosi + initramfs-tools produce a *boot stub* initrd (~50 MB) that
# expects to mount a separate rootfs (squashfs / disk / NFS). Our PXE
# channel only delivers vmlinuz+initrd.img, so there's nothing for the
# stub to pivot to and boot wedges right after the kernel hands off.
#
# Fix: pack the entire rootfs as the initrd. Kernel unpacks the cpio.zst
# into tmpfs and runs /init from it — no pivot, no live-boot, no rootfs
# param. Size balloons to a few hundred MB but that's the real cost of
# shipping firmware + modules + userspace in a diskless boot.
repack-initrd:
	@# Materialize symlinked kernel/initrd into real files so downstream
	@# copies (release tarball) don't have to follow links.
	@cp -fL build/vmlinuz build/vmlinuz.real && mv build/vmlinuz.real build/vmlinuz
	@rm -f build/initrd.img build/initrd.img.old build/vmlinuz.old
	@# Kernel execs /init from the unpacked initramfs. systemd-sysv puts
	@# init at /sbin/init; add the top-level symlink the kernel looks for.
	@[ -e build/init ] || ln -sf sbin/init build/init
	@# Skip /boot: holds the old kernel + stub initrd, both superseded.
	@# Write to a sibling temp path so find doesn't race with the
	@# archive being written into the dir it's walking.
	@cd build && \
	 find . -path ./boot -prune -o -print0 \
	 | cpio --null --create --format=newc --quiet \
	 | zstd -T0 -10 -q > ../build.initrd.img.tmp
	@mv build.initrd.img.tmp build/initrd.img

# Fail the build if the repacked initrd doesn't actually contain the
# firmware we need. Two failure modes:
#   1. Packages didn't install (apt/bootstrap misconfigured) → size check.
#   2. Packages installed but repack-initrd missed /lib/firmware → blob
#      presence check.
# cpio -t lists the archive; zstd -dc streams it without extracting.
check-initrd:
	@# With repack-initrd the initrd is the full rootfs (cpio.zst), so
	@# 200 MB is the floor — anything smaller means firmware/userspace
	@# is missing or the repack step silently produced a stub.
	@size=$$(wc -c < build/initrd.img); \
	 min=$$((200 * 1024 * 1024)); \
	 if [ "$$size" -lt "$$min" ]; then \
	   echo "ERROR: initrd.img is $$size bytes (< $$min) — firmware/rootfs almost certainly missing."; \
	   echo "       Check mkosi build log and repack-initrd output."; \
	   exit 1; \
	 fi
	@if ! zstd -dc build/initrd.img | cpio -t --quiet 2>/dev/null | grep -q 'lib/firmware/i915/tgl_guc'; then \
	   echo "ERROR: i915/tgl_guc firmware missing from initrd."; \
	   echo "       firmware-misc-nonfree likely didn't install during bootstrap."; \
	   exit 1; \
	 fi
	@echo "initrd.img OK ($$(du -hL build/initrd.img | cut -f1), i915 firmware present)"

agent: $(AGENT_BIN)

$(AGENT_BIN):
	cd $(REPO_ROOT) && GOOS=linux GOARCH=amd64 go build -o $(AGENT_BIN) ./cmd/vetting-agent

# Stage the prebuilt agent into mkosi.extra/ so mkosi copies it into the
# image root without the postinst needing to reach outside the source tree.
$(MKOSI_EXTRA_AGENT): $(AGENT_BIN)
	install -D -m 0755 $< $@

check-linux:
ifneq ($(UNAME_S),Linux)
	@echo "ERROR: live-image must be built on Linux (you're on $(UNAME_S))."
	@echo "Run 'wsl make -C live-image all' from Windows instead."
	@exit 1
endif
	@command -v mkosi >/dev/null 2>&1 || { echo "ERROR: mkosi not installed. Try: apt install mkosi"; exit 1; }

clean:
	rm -rf build mkosi.output mkosi.cache
	rm -f $(MKOSI_EXTRA_AGENT)
