Initial version of qemu-sanity-check.
authorRichard W.M. Jones <rjones@redhat.com>
Tue, 20 Aug 2013 12:59:59 +0000 (13:59 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Tue, 20 Aug 2013 15:30:40 +0000 (16:30 +0100)
.gitignore [new file with mode: 0644]
Makefile.am
README
configure.ac
init.c [new file with mode: 0644]
qemu-sanity-check.in
qemu-sanity-check.pod.in [new file with mode: 0644]
run-qemu-sanity-check [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..c07535f
--- /dev/null
@@ -0,0 +1,28 @@
+*~
+*.log
+*.o
+*.trs
+
+.deps
+Makefile
+Makefile.in
+
+/aclocal.m4
+/autom4te.cache
+/compile
+/config.cache
+/config.h
+/config.h.in
+/config.log
+/config.status
+/configure
+/depcomp
+/init
+/initrd
+/install-sh
+/missing
+/qemu-sanity-check
+/qemu-sanity-check.1
+/qemu-sanity-check.pod
+/stamp-h1
+/test-driver
index 8450892..caf4011 100644 (file)
@@ -22,6 +22,25 @@ EXTRA_DIST = \
 CLEANFILES = qemu-sanity-check
 
 bin_SCRIPTS = qemu-sanity-check
+initrddir = $(libdir)/qemu-sanity-check
+initrd_DATA = initrd
+
+# Build the initramfs.
+initrd: init
+       echo $< | cpio --quiet -o -H newc > $@-t
+       mv $@-t $@
+
+noinst_PROGRAMS = init
+init_SOURCES = init.c
+init_CFLAGS = -static
+init_LDFLAGS = -static
+
+# Build the man pages.
+qemu-sanity-check.pod: qemu-sanity-check.pod.in Makefile
+       rm -f $@ $@-t
+       $(SED) -e 's,@libdir\@,$(libdir),g' < $< > $@-t
+       mv $@-t $@
+       chmod 0555 $@
 
 if HAVE_POD2MAN
 
@@ -35,4 +54,5 @@ qemu-sanity-check.1: qemu-sanity-check.pod
 
 endif
 
-TESTS = qemu-sanity-check
+# Tests.
+TESTS = run-qemu-sanity-check
diff --git a/README b/README
index 7ce7518..3e67291 100644 (file)
--- a/README
+++ b/README
@@ -33,6 +33,12 @@ Requirements:
 
   bash - to run the script
 
+  gcc - to compile the helper program
+
+  static libc - to link the helper program statically
+
+  cpio - to build the initramfs
+
   qemu and/or Linux kernel - something to test
 
   pod2man (from Perl) - if you want to build the manual page
index 1807999..664f47b 100644 (file)
 AC_INIT([qemu-sanity-check],[1.1.1])
 AM_INIT_AUTOMAKE([foreign])
 
+dnl Check for basic C environment.
+AC_PROG_CC_STDC
+AC_PROG_INSTALL
+AC_PROG_CPP
+
+AC_C_PROTOTYPES
+test "x$U" != "x" && AC_MSG_ERROR([Compiler not ANSI compliant])
+
+AM_PROG_CC_C_O
+
+AC_PROG_SED
+
+AC_MSG_CHECKING([that a static binary can be built])
+old_CFLAGS="$CFLAGS"
+old_LDFLAGS="$LDFLAGS"
+CFLAGS="$CFLAGS -static"
+LDFLAGS="$LDFLAGS -static"
+AC_LINK_IFELSE([
+    #include <stdio.h>
+    #include <stdlib.h>
+    int main () { exit (0); }
+],[
+    AC_MSG_RESULT([yes])
+],[
+    AC_MSG_RESULT([no])
+    AC_MSG_ERROR([Building a static binary failed.  Make sure you have static libc installed.])
+])
+
 AC_CHECK_PROG([POD2MAN], [pod2man], [pod2man], [no])
 if test "x$POD2MAN" = "xno"; then
     AC_MSG_WARN([pod2man was not found.  This is needed to build man pages.])
@@ -26,7 +54,7 @@ AM_CONDITIONAL([HAVE_POD2MAN], [test "x$POD2MAN" != "xno"])
 
 dnl Produce output files.
 AC_CONFIG_HEADERS([config.h])
-AC_CONFIG_FILES([qemu-sanity-check],[chmod +x qemu-sanity-check])
+AC_CONFIG_FILES([qemu-sanity-check],[chmod 0555 qemu-sanity-check])
 AC_CONFIG_FILES([Makefile])
 
 AC_OUTPUT
diff --git a/init.c b/init.c
new file mode 100644 (file)
index 0000000..17bfa2a
--- /dev/null
+++ b/init.c
@@ -0,0 +1,41 @@
+/* init
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main (int argc, char *argv[])
+{
+  fprintf (stderr, "\n");
+  fprintf (stderr, "***** initrd started up OK *****\n");
+  fprintf (stderr, "\n");
+  fprintf (stderr, "\n");
+  fprintf (stderr, "expect to see a kernel panic below, that is normal\n");
+  fprintf (stderr, "\n");
+  fprintf (stderr, "\n");
+
+  /* This process is init, PID 1, so when it exits the kernel will
+   * panic and reboot, but because we use qemu -no-reboot that will
+   * cause qemu to exit.
+   */
+  exit (0);
+}
index 50b50ef..da4f59a 100644 (file)
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+initrd="@libdir@/initrd"
+
+arch="$(uname -m)"
+canonical_arch="$(uname -m | sed 's/i[456]86/i386/')"
+
+#timeout=10m
+
 # Handle command line parsing.
 
 function usage {
     echo "qemu-sanity-check [options]"
     echo "Options:"
-    echo "  --help          Display this help"
-    echo "  --version       Display version and exit"
+    echo "  --help               Display this help"
+    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 v \
+    -o i:k:q:V \
     --long help \
+    --long initrd: \
+    --long kernel: \
+    --long qemu: \
     --long version \
     -n 'qemu-sanity-check' -- "$@")
-if [ $? != 0 ]; then exit 1; fi
+if [ $? != 0 ]; then exit 2; fi
 eval set -- "$TEMP"
 
 while true; do
     case "$1" in
-        --help) usage ;;
-        -v|--version) echo "@PACKAGE_NAME@ @PACKAGE_VERSION@"; exit 0 ;;
-        --) shift; break ;;
-        *) fail "internal error ($1)" ;;
+        --help)
+            usage
+            ;;
+        -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 "@PACKAGE_NAME@ @PACKAGE_VERSION@"
+            exit 0
+            ;;
+        --)
+            shift
+            break
+            ;;
+        *)
+            echo "$0: internal error parsing options: $1"
+            exit 2
+            ;;
     esac
 done
+
+# Locate initrd.
+if [ ! -f "$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 '@libdir@/initrd'."
+    exit 2
+fi
+
+# Locate kernel if not specified.
+if [ -z "$kernel" ]; then
+    kernel="$(ls -vr /boot/vmlinuz-*.$arch | 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
+
+# Locate qemu if not specified.
+if [ -z "$qemu" ]; then
+    for q in qemu-kvm qemu-system-$canonical_arch qemu kvm; 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)"
+
+# Run the command
+set -x
+#timeout "$timeout"
+"$qemu" \
+    -nographic -nodefconfig -nodefaults \
+    -no-reboot \
+    -serial stdio \
+    -kernel "$kernel" \
+    -initrd "$initrd" \
+    -append "console=ttyS0 panic=1" 2>&1 | tee "$test_output"
+r="${PIPESTATUS[0]}"
+set +x
+#if [ $r -eq 124 ]; then
+#    cat "$test_output"
+#    echo "$0: error: test $kernel on $qemu: timed out"
+#    rm "$test_output"
+#    exit 1
+if [ $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
diff --git a/qemu-sanity-check.pod.in b/qemu-sanity-check.pod.in
new file mode 100644 (file)
index 0000000..836fb1f
--- /dev/null
@@ -0,0 +1,138 @@
+=encoding utf8
+
+=head1 NAME
+
+qemu-sanity-check - run a simple sanity check on qemu and the Linux kernel
+
+=head1 SUMMARY
+
+qemu-sanity-check [options]
+
+=head1 DESCRIPTION
+
+B<qemu-sanity-check> is a short shell script that test-boots a Linux
+kernel under qemu, making sure it boots up to userspace.  The idea is
+to test the Linux kernel and/or qemu to make sure they are working.
+
+You can use the command on its own:
+
+ qemu-sanity-check
+
+In this case, the script will look for a suitable qemu binary on the
+C<$PATH> and the latest Linux kernel in C</boot> and try to boot that
+kernel on that qemu.
+
+You can also specify a qemu binary or a Linux kernel (either or both
+options can be omitted):
+
+ qemu-sanity-check --qemu=/path/to/qemu --kernel=/path/to/vmlinuz
+
+=head2 KVM
+
+KVM (C<kvm> or C<qemu-kvm>) can be used in place of qemu.
+
+=head2 KERNEL DRIVERS
+
+No kernel modules or special drivers are required except as noted
+below.  The test uses an initramfs containing a static binary, so the
+kernel is B<not> required to locate block devices, use virtio, mount
+filesystems, etc.
+
+The kernel B<must> support only the following, compiled in (not as
+modules):
+
+=over 4
+
+=item *
+
+A serial port (usually: C<CONFIG_SERIAL_8250=y>)
+
+=item *
+
+Initrd/initramfs (C<CONFIG_BLK_DEV_INITRD=y>)
+
+=back
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<--help>
+
+Display short help message and exit.
+
+=item B<-i> INITRD
+
+=item B<--initrd>=INITRD
+
+Use the initramfs image named C<INITRD> instead of the default.
+
+=item B<-k> VMLINUZ
+
+=item B<--kernel>=VMLINUZ
+
+Use the kernel image C<VMLINUZ> instead of searching for the latest
+kernel installed in C</boot>.
+
+=item B<-q> QEMU
+
+=item B<--qemu>=QEMU
+
+Use the qemu (or KVM) binary C<QEMU> instead of searching C<$PATH> for
+a suitable binary.
+
+=item B<-V>
+
+=item B<--version>
+
+Display version and exit.
+
+=back
+
+=head1 EXIT STATUS
+
+The exit status is 0 if the Linux kernel booted as far as userspace
+under qemu; or if the I<--help> or I<--version> options were used.
+
+The exit status is 1 if the kernel boot failed under qemu.
+
+The exit status is 2 if the script itself failed (eg. incorrect
+command line options were used, a suitable kernel could not be found).
+
+=head1 FILES
+
+=over 4
+
+=item B<@libdir@/qemu-sanity-check/initrd>
+
+The default location for the small initramfs image that is used to
+test that userspace has been reached.
+
+=back
+
+=head1 SEE ALSO
+
+L<http://qemu.org>,
+L<http://kernel.org>
+
+=head1 AUTHORS
+
+Richard W.M. Jones <rjones@redhat.com>
+
+=head1 COPYRIGHT
+
+(C) Copyright 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., 675 Mass Ave, Cambridge, MA 02139, USA.
diff --git a/run-qemu-sanity-check b/run-qemu-sanity-check
new file mode 100755 (executable)
index 0000000..4553653
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+# -*- shell-script -*-
+# run-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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+./qemu-sanity-check --initrd=./initrd