#!/bin/sh set -eu PRE15_LIB_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/lib" && pwd -P) PRE15_QEMU_SCRIPT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P)/run-qemu.sh export PRE15_LIB_DIR PRE15_QEMU_SCRIPT . "$PRE15_LIB_DIR/runner.sh" . "$PRE15_LIB_DIR/manifest.sh" pre15_pick_port() { python3 - <<'PY' import socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: sock.bind(("127.0.0.1", 0)) print(sock.getsockname()[1]) PY } pre15_wait_for_ssh() { pre15_ssh_wait=0 while test "$pre15_ssh_wait" -lt "${PRE15_QEMU_BOOT_TIMEOUT:-180}"; do if ! kill -0 "$PRE15_QEMU_PID" 2>/dev/null; then pre15_infra_blocked 'QEMU exited before SSH became ready' fi if pre15_guest_ssh true >/dev/null 2>&1; then return 0 fi sleep 1 pre15_ssh_wait=$((pre15_ssh_wait + 1)) done pre15_infra_blocked 'guest SSH did not become ready before the boot deadline' } pre15_qemu_worker() { pre15_qemu_case=$1 pre15_require_paths pre15_qemu_case_script=$(pre15_find_case "$pre15_qemu_case") : "${PRE15_QEMU_BASE_IMAGE:?PRE15_QEMU_BASE_IMAGE is required}" : "${PRE15_QEMU_SSH_KEY:?PRE15_QEMU_SSH_KEY is required}" PRE15_QEMU_SSH_USER=${PRE15_QEMU_SSH_USER:-root} PRE15_QEMU_BASE_FORMAT=${PRE15_QEMU_BASE_FORMAT:-qcow2} export PRE15_QEMU_SSH_USER PRE15_QEMU_BASE_FORMAT for pre15_qemu_tool in qemu-img qemu-system-x86_64 ssh; do command -v "$pre15_qemu_tool" >/dev/null 2>&1 || \ pre15_infra_blocked "missing QEMU runner tool: $pre15_qemu_tool" done test -f "$PRE15_QEMU_SSH_KEY" || \ pre15_infra_blocked "SSH key is absent: $PRE15_QEMU_SSH_KEY" pre15_own_base_image "$PRE15_QEMU_BASE_IMAGE" pre15_qemu_overlay=$PRE15_RUN_DIR/guest-overlay.qcow2 qemu-img create -f qcow2 -F "$PRE15_QEMU_BASE_FORMAT" \ -b "$PRE15_QEMU_BASE_IMAGE" "$pre15_qemu_overlay" pre15_own_path "$pre15_qemu_overlay" 'QEMU overlay' PRE15_QEMU_SSH_PORT=$(pre15_pick_port) export PRE15_QEMU_SSH_PORT pre15_own_port "$PRE15_QEMU_SSH_PORT" 'QEMU SSH forwarding' PRE15_QEMU_CONTROL_PATH=$PRE15_RUN_DIR/ssh-control PRE15_QEMU_SERIAL=$PRE15_RUN_DIR/serial.log PRE15_QEMU_DEBUG=$PRE15_RUN_DIR/qemu.log export PRE15_QEMU_CONTROL_PATH PRE15_QEMU_SERIAL PRE15_QEMU_DEBUG pre15_write_argv_json "$PRE15_RUN_DIR/qemu-argv.json" \ qemu-system-x86_64 -accel tcg,thread=multi -cpu qemu64 \ -m "${PRE15_QEMU_MEMORY_MB:-6144}" -smp "${PRE15_QEMU_CPUS:-4}" \ -drive "file=$pre15_qemu_overlay,if=virtio,format=qcow2" \ -netdev "user,id=net0,hostfwd=tcp:127.0.0.1:$PRE15_QEMU_SSH_PORT-:22" \ -device virtio-net-pci,netdev=net0 -display none \ -serial "file:$PRE15_QEMU_SERIAL" -monitor none qemu-system-x86_64 -accel tcg,thread=multi -cpu qemu64 \ -m "${PRE15_QEMU_MEMORY_MB:-6144}" -smp "${PRE15_QEMU_CPUS:-4}" \ -drive "file=$pre15_qemu_overlay,if=virtio,format=qcow2" \ -netdev "user,id=net0,hostfwd=tcp:127.0.0.1:$PRE15_QEMU_SSH_PORT-:22" \ -device virtio-net-pci,netdev=net0 -display none \ -serial "file:$PRE15_QEMU_SERIAL" -monitor none & PRE15_QEMU_PID=$! export PRE15_QEMU_PID pre15_own_pid "$PRE15_QEMU_PID" QEMU pre15_wait_for_ssh if ssh -MNf -o BatchMode=yes -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null -o ConnectTimeout=5 \ -o ControlMaster=yes -o "ControlPath=$PRE15_QEMU_CONTROL_PATH" \ -i "$PRE15_QEMU_SSH_KEY" -p "$PRE15_QEMU_SSH_PORT" \ "$PRE15_QEMU_SSH_USER@127.0.0.1"; then pre15_own_ssh_control "$PRE15_QEMU_CONTROL_PATH" 'QEMU SSH ControlMaster' else pre15_infra_blocked 'could not establish SSH ControlMaster' fi pre15_guest_ssh_bounded uname -a > "$PRE15_RUN_DIR/guest-uname.txt" pre15_guest_ssh_bounded kldstat > "$PRE15_RUN_DIR/guest-kldstat-before.txt" pre15_guest_ssh_bounded dmesg > "$PRE15_RUN_DIR/guest-dmesg-before.txt" /bin/sh "$pre15_qemu_case_script" pre15_guest_ssh_bounded dmesg > "$PRE15_RUN_DIR/guest-dmesg-after.txt" } if test "${1:-}" = --worker; then shift test "$#" -eq 1 || pre15_fail_usage 'internal QEMU worker requires one case' pre15_qemu_worker "$1" exit 0 fi test "$#" -eq 1 || pre15_fail_usage 'usage: run-qemu.sh CASE' pre15_require_paths pre15_find_case "$1" >/dev/null pre15_run_command qemu "$1" "${PRE15_QEMU_TIMEOUT:-1200}" \ "$PRE15_QEMU_SCRIPT" --worker "$1"