#!/bin/sh
# launch: boot /disk/disk.img, a Linux computer's disk form, under QEMU until it powers off, on a copy-on-write overlay
# so the disk stays as it is: with KVM when /dev/kvm is here and the disk is this machine's arch, else with TCG, from
# UEFI firmware. The guest's console is this container's output.
#   VM_ENV_<NAME>  the computer's variable NAME, its value base64'd, for its NoCloud seed (CIDATA; see seed)
#   VM_PORTS       guest TCP ports, each forwarded from the same port here
#   VM_ARCH        the disk's arch, amd64 or arm64; this machine's by default
#   VM_CPUS, VM_MEMORY_MB   its size: 2 and 4096 by default
set -eu
here=$(dpkg --print-architecture)
arch=${VM_ARCH:-$here}
work=/run/vm
rm -rf "$work"
mkdir -p "$work"
qemu-img create -q -f qcow2 -b /disk/disk.img -F qcow2 "$work/disk.qcow2"
seed "$work"
mkfs.vfat -C -n CIDATA "$work/seed.img" 2048 >/dev/null
mcopy -i "$work/seed.img" "$work/user-data" "$work/meta-data" ::/
forwards=""
for port in ${VM_PORTS:-}; do
    forwards="$forwards,hostfwd=tcp::$port-:$port"
done
accel=tcg cpu=max
if [ -w /dev/kvm ] && [ "$arch" = "$here" ]; then
    accel=kvm cpu=host
fi
case "$arch" in
    amd64)
        cp /usr/share/OVMF/OVMF_VARS_4M.fd "$work/vars.fd"
        set -- qemu-system-x86_64 -machine "q35,accel=$accel" \
            -drive if=pflash,format=raw,readonly=on,file=/usr/share/OVMF/OVMF_CODE_4M.fd ;;
    arm64)
        cp /usr/share/AAVMF/AAVMF_CODE.fd "$work/code.fd"
        truncate -s 64M "$work/code.fd" "$work/vars.fd"
        set -- qemu-system-aarch64 -machine "virt,accel=$accel" \
            -drive if=pflash,format=raw,readonly=on,file="$work/code.fd" ;;
    *)
        echo "launch: no architecture $arch" >&2
        exit 2 ;;
esac
exec "$@" -cpu "$cpu" -smp "${VM_CPUS:-2}" -m "${VM_MEMORY_MB:-4096}" \
    -drive if=pflash,format=raw,file="$work/vars.fd" \
    -drive file="$work/disk.qcow2",format=qcow2,if=virtio \
    -drive file="$work/seed.img",format=raw,if=virtio,readonly=on \
    -netdev "user,id=net$forwards" -device virtio-net-pci,netdev=net -device virtio-rng-pci \
    -display none -serial stdio -no-reboot
