#!/bin/bash
# -*- shell-script -*-
# qemu-sanity-check
# Copyright (C) 2013 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

prefix="/usr"
exec_prefix="/usr"
initrd="/usr/lib/qemu-sanity-check/initrd"

arch="$(uname -m)"
canonical_arch="$(uname -m | sed 's/i[456]86/i386/')"

timeout=10m
accel=kvm:tcg

# Handle command line parsing.

function usage {
    echo "qemu-sanity-check [options]"
    echo "Options:"
    echo "  --help               Display this help"
    echo "  --accel=[kvm|tcg]    Force KVM or software emulation"
    echo "  -i|--initrd=initrd   Set location of initramfs"
    echo "  -k|--kernel=vmlinuz  Set location of kernel"
    echo "  -q|--qemu=qemu       Set location of qemu/KVM binary"
    echo "  -t|--timeout=timeout Set the timeout"
    echo "  -V|--version         Display version and exit"
    exit 0
}

TEMP=$(getopt \
    -o i:k:q:t:V \
    --long help \
    --long accel: \
    --long initrd: \
    --long kernel: \
    --long qemu: \
    --long timeout: \
    --long version \
    -n 'qemu-sanity-check' -- "$@")
if [ $? != 0 ]; then exit 2; fi
eval set -- "$TEMP"

while true; do
    case "$1" in
        --help)
            usage
            ;;
        --accel)
            accel="$2"
            shift 2
            ;;
        -i|--initrd)
            initrd="$2"
            shift 2
            ;;
        -k|--kernel)
            kernel="$2"
            shift 2
            ;;
        -q|--qemu)
            qemu="$2"
            shift 2
            ;;
        -t|--timeout)
            timeout="$2"
            shift 2
            ;;
        -V|--version)
            echo "qemu-sanity-check 1.1.5"
            exit 0
            ;;
        --)
            shift
            break
            ;;
        *)
            echo "$0: internal error parsing options: $1"
            exit 2
            ;;
    esac
done

# Locate initrd.
if [ ! -r "$initrd" ]; then
    echo "$0: cannot find 'initrd', try using --initrd=/path/to/initrd"
    echo "If you are running qemu-sanity-check without installing, then do:"
    echo "    $0 --initrd=./initrd $@"
    echo "The default path is '/usr/lib/initrd'."
    exit 2
fi

# Locate kernel if not specified.
if [ -z "$kernel" ]; then
    kernel="$(ls -1dvr /boot/vmlinuz-*.$arch* 2>/dev/null | grep -v xen | head -1)"
    if [ -z "$kernel" ]; then
        echo "$0: cannot find a Linux kernel in /boot"
        echo "Choose a kernel to test using --kernel=/path/to/vmlinuz"
        exit 2
    fi
fi
if [ ! -r "$kernel" ]; then
    echo "$0: kernel $kernel is not readable"
    exit 2
fi

# Locate qemu if not specified.
if [ -z "$qemu" ]; then
    for q in qemu-system-$canonical_arch; do
        if "$q" --help >/dev/null 2>&1; then
            qemu="$q"
            break
        fi
    done
    if [ -z "$qemu" ]; then
        echo "$0: cannot find a qemu binary on the \$PATH"
        echo "Choose a qemu binary to test using --qemu=/path/to/qemu"
        exit 2
    fi
fi

# Choose a temporary file for the output.
test_output="$(mktemp --suff=.out)"

# Generate the parameters for the qemu command.
declare -a argv
i=0
argv[$((i++))]="$qemu"
argv[$((i++))]="-nographic"
argv[$((i++))]="-nodefconfig"
argv[$((i++))]="-nodefaults"
argv[$((i++))]="-machine"
argv[$((i++))]="accel=$accel"
argv[$((i++))]="-no-reboot"
argv[$((i++))]="-serial"
argv[$((i++))]="file:$test_output"
argv[$((i++))]="-kernel"
argv[$((i++))]="$kernel"
argv[$((i++))]="-initrd"
argv[$((i++))]="$initrd"
argv[$((i++))]="-append"
argv[$((i++))]="console=ttyS0 oops=panic panic=-1"

#echo "${argv[@]}"

# Run the command.
timeout "$timeout" "${argv[@]}"
r="${PIPESTATUS[0]}"
if [ $r -eq 124 ]; then
    cat "$test_output"
    echo "$0: error: test $kernel on $qemu: timed out"
    rm "$test_output"
    exit 1
elif [ $r -ne 0 ]; then
    cat "$test_output"
    echo "$0: error: test $kernel on $qemu: failed"
    rm "$test_output"
    exit 1
fi

# Verify that userspace was reached.
if ! grep -sq "initrd started up OK" "$test_output"; then
    cat "$test_output"
    echo "$0: error: test $kernel on $qemu: init process did not start up"
    rm "$test_output"
    exit 1
fi

# Successful.
rm "$test_output"
exit 0
