# Fedora 42 Custom Live ISO Builder # Requires: lorax, lorax-lmc-novirt, anaconda (for kickstart validation) # Must run with sudo for livemedia-creator SHELL := /bin/bash .ONESHELL: .SHELLFLAGS := -eu -o pipefail -c # ============================================================================ # Configuration # ============================================================================ FEDORA_VERSION := 42 ARCH := x86_64 VARIANT ?= minimal BUILD_DIR := $(CURDIR)/build CACHE_DIR := $(CURDIR)/cache OUTPUT_DIR := $(CURDIR)/output KICKSTART_DIR := $(CURDIR)/kickstarts OVERLAY_DIR := $(CURDIR)/overlays SCRIPTS_DIR := $(CURDIR)/scripts TMP_DIR := /var/tmp/lorax-build ISO_LABEL := FEDORA-CUSTOM ISO_NAME := fedora-$(FEDORA_VERSION)-custom-$(VARIANT)-$(ARCH) ISO_FILE := $(OUTPUT_DIR)/$(ISO_NAME).iso LORAX_OPTS := --nomacboot --noverifyssl KICKSTART ?= $(KICKSTART_DIR)/$(VARIANT).ks # ============================================================================ # Colors # ============================================================================ CLR_RED := \033[0;31m CLR_GREEN := \033[0;32m CLR_YELLOW := \033[0;33m CLR_BLUE := \033[0;34m CLR_RESET := \033[0m # ============================================================================ # Default target # ============================================================================ .PHONY: all all: help # ============================================================================ # Help # ============================================================================ .PHONY: help help: @printf "Fedora $(FEDORA_VERSION) Custom Live ISO Builder\n" @printf "==============================================\n\n" @printf "Usage: sudo make [VARIANT=]\n\n" @printf "Build targets:\n" @printf " iso Build the live ISO (requires sudo)\n" @printf " iso-novirt Build without KVM (slower, works in containers)\n\n" @printf "Variants (VARIANT=):\n" @printf " minimal Bare minimum bootable system (~400MB)\n" @printf " kiosk Single-app kiosk/PoS system\n" @printf " workstation Lightweight workstation with Sway\n" @printf " security Security/forensics toolkit\n\n" @printf "Setup targets:\n" @printf " deps Install build dependencies\n" @printf " init-kickstarts Generate kickstart templates\n\n" @printf "Utility targets:\n" @printf " validate Validate kickstart syntax\n" @printf " test-qemu Boot ISO in QEMU\n" @printf " checksum Generate SHA256/MD5 checksums\n" @printf " clean Remove build artifacts\n" @printf " distclean Remove everything including output\n\n" @printf "Examples:\n" @printf " make init-kickstarts\n" @printf " sudo make iso VARIANT=minimal\n" @printf " sudo make iso VARIANT=kiosk\n" @printf " sudo make iso KICKSTART=./custom.ks\n" # ============================================================================ # Dependencies # ============================================================================ .PHONY: deps deps: @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Installing build dependencies...\n" @if ! command -v dnf &>/dev/null; then \ printf "$(CLR_RED)[ERROR]$(CLR_RESET) Requires Fedora/RHEL with dnf\n"; \ exit 1; \ fi dnf install -y \ lorax \ lorax-lmc-novirt \ anaconda \ pykickstart \ qemu-kvm \ libvirt \ virt-install \ syslinux \ isomd5sum \ squashfs-tools \ xorriso \ grub2-tools-extra @printf "$(CLR_GREEN)[OK]$(CLR_RESET) Dependencies installed\n" # ============================================================================ # Directory setup # ============================================================================ .PHONY: dirs dirs: @mkdir -p $(BUILD_DIR) $(CACHE_DIR) $(OUTPUT_DIR) $(KICKSTART_DIR) $(OVERLAY_DIR) $(SCRIPTS_DIR) $(TMP_DIR) # ============================================================================ # Kickstart generation (via external script) # ============================================================================ .PHONY: init-kickstarts init-kickstarts: dirs @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Generating kickstart templates...\n" @chmod +x $(SCRIPTS_DIR)/gen-kickstarts.sh @$(SCRIPTS_DIR)/gen-kickstarts.sh $(KICKSTART_DIR) @printf "$(CLR_GREEN)[OK]$(CLR_RESET) Kickstarts created in $(KICKSTART_DIR)/\n" # ============================================================================ # Validation # ============================================================================ .PHONY: validate validate: $(KICKSTART) @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Validating: $(KICKSTART)\n" @ksvalidator $(KICKSTART) @printf "$(CLR_GREEN)[OK]$(CLR_RESET) Kickstart is valid\n" # ============================================================================ # Root check # ============================================================================ .PHONY: check-root check-root: @if [ "$$(id -u)" -ne 0 ]; then \ printf "$(CLR_RED)[ERROR]$(CLR_RESET) Must run as root (use sudo)\n"; \ exit 1; \ fi # ============================================================================ # ISO Build # ============================================================================ .PHONY: iso iso: dirs validate check-root @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Building: $(ISO_NAME)\n" @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Kickstart: $(KICKSTART)\n" @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) This may take 10-30 minutes...\n" @rm -rf $(BUILD_DIR)/result livemedia-creator \ --ks $(KICKSTART) \ --no-virt \ --resultdir $(BUILD_DIR)/result \ --project "Fedora Custom" \ --releasever $(FEDORA_VERSION) \ --volid $(ISO_LABEL) \ --iso-only \ --iso-name $(ISO_NAME).iso \ --tmp $(TMP_DIR) \ --logfile $(BUILD_DIR)/livemedia.log \ $(LORAX_OPTS) @mv $(BUILD_DIR)/result/$(ISO_NAME).iso $(ISO_FILE) 2>/dev/null || \ mv $(BUILD_DIR)/result/images/$(ISO_NAME).iso $(ISO_FILE) 2>/dev/null || \ find $(BUILD_DIR) -name "*.iso" -exec mv {} $(ISO_FILE) \; @printf "$(CLR_GREEN)[OK]$(CLR_RESET) ISO created: $(ISO_FILE)\n" @$(MAKE) -s checksum .PHONY: iso-novirt iso-novirt: iso # ============================================================================ # Testing # ============================================================================ .PHONY: test-qemu test-qemu: $(ISO_FILE) @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Booting ISO in QEMU...\n" qemu-system-x86_64 \ -enable-kvm \ -m 2048 \ -cpu host \ -smp 2 \ -cdrom $(ISO_FILE) \ -boot d \ -vga virtio \ -display gtk .PHONY: test-qemu-serial test-qemu-serial: $(ISO_FILE) @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Booting ISO (serial console)...\n" qemu-system-x86_64 \ -enable-kvm \ -m 2048 \ -cpu host \ -smp 2 \ -cdrom $(ISO_FILE) \ -boot d \ -nographic \ -serial mon:stdio # ============================================================================ # Checksums # ============================================================================ .PHONY: checksum checksum: $(ISO_FILE) @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Generating checksums...\n" @cd $(OUTPUT_DIR) && sha256sum $(notdir $(ISO_FILE)) > $(notdir $(ISO_FILE)).sha256 @cd $(OUTPUT_DIR) && md5sum $(notdir $(ISO_FILE)) > $(notdir $(ISO_FILE)).md5 @printf "$(CLR_GREEN)[OK]$(CLR_RESET) Checksums:\n" @cat $(ISO_FILE).sha256 .PHONY: implant-md5 implant-md5: $(ISO_FILE) @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Implanting MD5 into ISO...\n" implantisomd5 $(ISO_FILE) @printf "$(CLR_GREEN)[OK]$(CLR_RESET) Verify with: checkisomd5 $(ISO_FILE)\n" # ============================================================================ # Cleanup # ============================================================================ .PHONY: clean clean: @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Cleaning build artifacts...\n" rm -rf $(BUILD_DIR) rm -rf $(TMP_DIR) @printf "$(CLR_GREEN)[OK]$(CLR_RESET) Clean complete\n" .PHONY: distclean distclean: clean @printf "$(CLR_BLUE)[INFO]$(CLR_RESET) Removing all generated files...\n" rm -rf $(OUTPUT_DIR) rm -rf $(CACHE_DIR) @printf "$(CLR_GREEN)[OK]$(CLR_RESET) Distclean complete\n" # ============================================================================ # Info # ============================================================================ .PHONY: info info: @printf "Configuration:\n" @printf " FEDORA_VERSION: $(FEDORA_VERSION)\n" @printf " ARCH: $(ARCH)\n" @printf " VARIANT: $(VARIANT)\n" @printf " KICKSTART: $(KICKSTART)\n" @printf " ISO_FILE: $(ISO_FILE)\n" @printf " BUILD_DIR: $(BUILD_DIR)\n" @printf " TMP_DIR: $(TMP_DIR)\n" .PHONY: list-isos list-isos: @printf "Built ISOs:\n" @ls -lh $(OUTPUT_DIR)/*.iso 2>/dev/null || printf " (none)\n" # ============================================================================ # Kickstart prerequisite # ============================================================================ $(KICKSTART): @printf "$(CLR_RED)[ERROR]$(CLR_RESET) Kickstart not found: $(KICKSTART)\n" @printf "$(CLR_YELLOW)[HINT]$(CLR_RESET) Run: make init-kickstarts\n" @exit 1