#!/usr/bin/env bash set -euo pipefail script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" if [[ -n "${VM_IMAGE_HELPER:-}" ]]; then image_downloader="$VM_IMAGE_HELPER" elif [[ -x "${script_dir}/vm-images/download-images.sh" ]]; then image_downloader="${script_dir}/vm-images/download-images.sh" else image_downloader="${script_dir}/../vm-images/download-images.sh" fi uses_shared_base_image=false if [[ -n "${FEDORA_VM_BASE_IMAGE:-}" ]]; then base_image="$FEDORA_VM_BASE_IMAGE" else [[ -x "$image_downloader" ]] || { printf 'Error: shared image helper is unavailable: %s\n' "$image_downloader" >&2; exit 1; } base_image="$("$image_downloader" --print-path fedora44)" uses_shared_base_image=true fi state_dir="${FEDORA_VM_STATE_DIR:-${script_dir}/.vm/fedora44}" disk_image="${FEDORA_VM_DISK_IMAGE:-${state_dir}/disk.qcow2}" seed_image="${FEDORA_VM_SEED_IMAGE:-$(dirname -- "$disk_image")/seed.iso}" disk_size="${FEDORA_VM_DISK_SIZE:-20G}" memory="${FEDORA_VM_MEMORY:-8G}" cpus="${FEDORA_VM_CPUS:-8}" ssh_port="${FEDORA_VM_SSH_PORT:-2224}" uefi_code="${FEDORA_VM_UEFI_CODE:-/usr/share/OVMF/OVMF_CODE_4M.fd}" uefi_vars_template="${FEDORA_VM_UEFI_VARS:-/usr/share/OVMF/OVMF_VARS_4M.fd}" uefi_vars="${state_dir}/OVMF_VARS_4M.fd" pid_file="${state_dir}/qemu.pid" log_file="${state_dir}/console.log" daemonize=false extra_args=() usage() { cat <&2; usage >&2; exit 2 ;; esac done for command_name in qemu-system-x86_64 qemu-img; do if ! command -v "$command_name" >/dev/null 2>&1; then printf 'Error: %s is not installed.\n' "$command_name" >&2 exit 1 fi done if [[ ! -f "$base_image" ]]; then if [[ "$uses_shared_base_image" == true ]]; then "$image_downloader" fedora44 else printf 'Error: Fedora base image was not found: %s\n' "$base_image" >&2 exit 1 fi fi [[ -f "$base_image" ]] || { printf 'Error: downloader did not create: %s\n' "$base_image" >&2; exit 1; } for firmware_file in "$uefi_code" "$uefi_vars_template"; do [[ -f "$firmware_file" ]] || { printf 'Error: required UEFI firmware was not found: %s\n' "$firmware_file" >&2; exit 1; } done if [[ ! -f "$seed_image" ]]; then seed_builder="${script_dir}/seediso/fedora44/build-seed.sh" if [[ ! -x "$seed_builder" ]]; then printf 'Error: seed image is missing and builder is unavailable: %s\n' "$seed_builder" >&2 exit 1 fi printf 'Seed image not found; building %s...\n' "$seed_image" "$seed_builder" "$seed_image" fi mkdir -p "$state_dir" [[ -f "$uefi_vars" ]] || cp -- "$uefi_vars_template" "$uefi_vars" if [[ -f "$pid_file" ]]; then old_pid="$(<"$pid_file")" if [[ "$old_pid" =~ ^[0-9]+$ ]] && kill -0 "$old_pid" 2>/dev/null; then printf 'Error: the Fedora virtual machine is already running (PID %s).\n' "$old_pid" >&2 exit 1 fi rm -f "$pid_file" fi if [[ ! -f "$disk_image" ]]; then qemu-img create -q -f qcow2 -F qcow2 -b "$base_image" "$disk_image" "$disk_size" printf 'Created writable disk overlay: %s\n' "$disk_image" fi qemu_args=( -name fedora44 -machine q35 -display gtk -m "$memory" -smp "$cpus" -drive "if=pflash,format=raw,readonly=on,file=${uefi_code}" -drive "if=pflash,format=raw,file=${uefi_vars}" -drive "file=${disk_image},if=virtio,format=qcow2" -drive "file=${seed_image},media=cdrom,readonly=on" -nic "user,model=virtio-net-pci,hostfwd=tcp::${ssh_port}-:22" ) if [[ -r /dev/kvm && -w /dev/kvm ]]; then qemu_args+=(-enable-kvm -cpu host) accelerator=KVM else qemu_args+=(-accel tcg -cpu max) accelerator=TCG fi printf 'Starting Fedora 44 with %s acceleration; SSH is forwarded to localhost:%s.\n' \ "$accelerator" "$ssh_port" if [[ "$daemonize" == true ]]; then : >"$log_file" qemu_args+=( -serial "file:${log_file}" -monitor none -daemonize -pidfile "$pid_file" ) qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}" printf 'VM started (PID %s); console log: %s\n' "$(<"$pid_file")" "$log_file" else exec qemu-system-x86_64 "${qemu_args[@]}" "${extra_args[@]}" fi