#!/bin/sh
# boot-slitaz.sh — boot a MÉTIER SliTaz ISO in QEMU from any OS.
#
# Why this exists: MÉTIER's x86_64 images are UEFI + USB-only (kernel/rootfs
# live on the FAT ESP, not the ISO9660), so a plain `-cdrom` run drops to a
# grub> prompt. This wraps the right incantation (OVMF pflash + usb-storage,
# or -cdrom for the i486 BIOS image) so anyone can boot without MÉTIER.
#
# Usage:  ./boot-slitaz.sh [options] <image.iso>
#   --vga MODEL   video card (default: cirrus for tisse, else std)
#   --mem MB      RAM in MB (default 1024, tisse 512)
#   --bios        force legacy BIOS / -cdrom (skip UEFI)
#   --headless    no window, serial to the terminal
#   -h, --help    this help
#
# Needs: qemu-system-x86_64 (and qemu-system-i386 for i486), plus OVMF for
# x86_64. Debian/Ubuntu: apt install qemu-system-x86 ovmf
set -eu

die()  { echo "boot-slitaz: $*" >&2; exit 1; }
info() { echo ">> $*" >&2; }

usage() { sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'; exit "${1:-0}"; }

# --- parse args -------------------------------------------------------------
ISO= ; VGA= ; MEM= ; FORCE_BIOS=0 ; HEADLESS=0
while [ $# -gt 0 ]; do
	case $1 in
		--vga)      VGA=$2; shift 2 ;;
		--vga=*)    VGA=${1#*=}; shift ;;
		--mem)      MEM=$2; shift 2 ;;
		--mem=*)    MEM=${1#*=}; shift ;;
		--bios)     FORCE_BIOS=1; shift ;;
		--headless) HEADLESS=1; shift ;;
		-h|--help)  usage 0 ;;
		-*)         die "unknown option: $1 (try --help)" ;;
		*)          ISO=$1; shift ;;
	esac
done
[ -n "$ISO" ] || usage 1
[ -f "$ISO" ] || die "no such file: $ISO"

# --- detect arch + flavor from the file name --------------------------------
base=$(basename "$ISO")
case $base in
	*x86_64*) ARCH=x86_64 ;;
	*i486*|*i386*) ARCH=i486 ;;
	*) ARCH=x86_64 ; info "arch not in name, assuming x86_64" ;;
esac

# tisse ships a stripped kernel whose only QEMU-usable DRM driver is cirrus;
# default to it so the Wayland compositor gets /dev/dri/card0.
if [ -z "$VGA" ]; then
	case $base in *tisse*) VGA=cirrus ;; *) VGA=std ;; esac
fi
[ -n "$MEM" ] || case $base in *tisse*) MEM=512 ;; *) MEM=1024 ;; esac

# --- pick the emulator ------------------------------------------------------
case $ARCH in
	x86_64) QEMU=qemu-system-x86_64 ;;
	i486)   QEMU=qemu-system-i386 ;;
esac
command -v "$QEMU" >/dev/null 2>&1 || \
	die "$QEMU not found (Debian/Ubuntu: apt install qemu-system-x86)"

# --- firmware: x86_64 is UEFI (OVMF), i486 is legacy BIOS -------------------
FW_ARGS= ; UEFI=0
if [ "$ARCH" = x86_64 ] && [ "$FORCE_BIOS" = 0 ]; then
	UEFI=1
	# Find an OVMF CODE image across distros + macOS/Homebrew.
	code=
	for c in \
		/usr/share/OVMF/OVMF_CODE_4M.fd \
		/usr/share/OVMF/OVMF_CODE.fd \
		/usr/share/edk2-ovmf/x64/OVMF_CODE.fd \
		/usr/share/edk2/ovmf/OVMF_CODE.fd \
		/usr/share/edk2/x64/OVMF_CODE.fd \
		/usr/share/ovmf/x64/OVMF_CODE.fd \
		/usr/share/qemu/edk2-x86_64-code.fd \
		/opt/homebrew/share/qemu/edk2-x86_64-code.fd \
		/usr/local/share/qemu/edk2-x86_64-code.fd ; do
		[ -f "$c" ] && { code=$c; break; }
	done
	if [ -n "$code" ]; then
		# Derive the matching writable VARS template.
		vars=${code%/*}/$(basename "$code" | sed 's/CODE/VARS/; s/code/vars/')
		[ -f "$vars" ] || vars=${code%/*}/OVMF_VARS_4M.fd
		[ -f "$vars" ] || vars=${code%/*}/OVMF_VARS.fd
		[ -f "$vars" ] || vars=/usr/share/qemu/edk2-i386-vars.fd
		[ -f "$vars" ] || die "found OVMF CODE ($code) but no VARS template"
		# VARS must be writable — copy per run.
		tmpvars=$(mktemp "${TMPDIR:-/tmp}/slitaz-ovmf-vars.XXXXXX")
		trap 'rm -f "$tmpvars"' EXIT INT TERM
		cp "$vars" "$tmpvars"
		FW_ARGS="-drive if=pflash,format=raw,unit=0,readonly=on,file=$code \
		         -drive if=pflash,format=raw,unit=1,file=$tmpvars"
	else
		# Single combined image fallback.
		for b in /usr/share/ovmf/OVMF.fd /usr/share/qemu/OVMF.fd; do
			[ -f "$b" ] && { FW_ARGS="-bios $b"; break; }
		done
		[ -n "$FW_ARGS" ] || die "UEFI run needs OVMF: apt install ovmf \
(or pass --bios if the image has a legacy bootloader)"
	fi
fi

# --- how to attach the image ------------------------------------------------
# UEFI x86_64: USB disk (boot files are on the FAT ESP, not the iso9660).
# i486 BIOS: optical -cdrom (isolinux boots fine that way).
if [ "$UEFI" = 1 ]; then
	MEDIA="-drive if=none,id=usbstick,format=raw,file=$ISO \
	       -device qemu-xhci -device usb-storage,drive=usbstick,bootindex=0"
else
	MEDIA="-cdrom $ISO"
fi

# --- accel: KVM on Linux/x86_64, HVF on macOS, else plain TCG ----------------
ACCEL=
if [ -w /dev/kvm ] && [ "$(uname -m)" = x86_64 ]; then
	ACCEL=-enable-kvm
elif [ "$(uname -s)" = Darwin ]; then
	ACCEL="-accel hvf"
fi

# --- display ----------------------------------------------------------------
DISP=
[ "$HEADLESS" = 1 ] && DISP="-display none -serial stdio -monitor none"

info "qemu=$QEMU arch=$ARCH fw=$([ $UEFI = 1 ] && echo uefi || echo bios) \
vga=$VGA mem=${MEM}M accel=$([ -n "$ACCEL" ] && echo on || echo off)"

# Intentional word-splitting of the arg groups below.
# shellcheck disable=SC2086
exec "$QEMU" $FW_ARGS -m "$MEM" -vga "$VGA" -no-reboot $ACCEL $MEDIA $DISP
