From aee03601ac923906391b438bc4040c4a4265112d Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 20 Aug 2013 13:59:59 +0100 Subject: [PATCH 1/1] Initial version of qemu-sanity-check. --- .gitignore | 28 ++++++++++ Makefile.am | 22 +++++++- README | 6 +++ configure.ac | 30 ++++++++++- init.c | 41 ++++++++++++++ qemu-sanity-check.in | 132 ++++++++++++++++++++++++++++++++++++++++++--- qemu-sanity-check.pod.in | 138 +++++++++++++++++++++++++++++++++++++++++++++++ run-qemu-sanity-check | 20 +++++++ 8 files changed, 407 insertions(+), 10 deletions(-) create mode 100644 .gitignore create mode 100644 init.c create mode 100644 qemu-sanity-check.pod.in create mode 100755 run-qemu-sanity-check diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c07535f --- /dev/null +++ b/.gitignore @@ -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 diff --git a/Makefile.am b/Makefile.am index 8450892..caf4011 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 --- 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 diff --git a/configure.ac b/configure.ac index 1807999..664f47b 100644 --- a/configure.ac +++ b/configure.ac @@ -18,6 +18,34 @@ 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 + #include + 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 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 + +#include +#include +#include + +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); +} diff --git a/qemu-sanity-check.in b/qemu-sanity-check.in index 50b50ef..da4f59a 100644 --- a/qemu-sanity-check.in +++ b/qemu-sanity-check.in @@ -17,29 +17,145 @@ # 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 index 0000000..836fb1f --- /dev/null +++ b/qemu-sanity-check.pod.in @@ -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 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 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 or C) 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 required to locate block devices, use virtio, mount +filesystems, etc. + +The kernel B support only the following, compiled in (not as +modules): + +=over 4 + +=item * + +A serial port (usually: C) + +=item * + +Initrd/initramfs (C) + +=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 instead of the default. + +=item B<-k> VMLINUZ + +=item B<--kernel>=VMLINUZ + +Use the kernel image C instead of searching for the latest +kernel installed in C. + +=item B<-q> QEMU + +=item B<--qemu>=QEMU + +Use the qemu (or KVM) binary C 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, +L + +=head1 AUTHORS + +Richard W.M. Jones + +=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 index 0000000..4553653 --- /dev/null +++ b/run-qemu-sanity-check @@ -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 -- 1.8.3.1