0c96485e914b2baff4405d422f5da65df9cc0827
[qemu-sanity-check.git] / src / qemu-sanity-check.in
1 #!/bin/bash
2 # -*- shell-script -*-
3 # qemu-sanity-check
4 # Copyright (C) 2013-2024 Red Hat Inc.
5 # @configure_input@
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License along
18 # with this program; if not, write to the Free Software Foundation, Inc.,
19 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 prefix="@prefix@"
22 exec_prefix="@exec_prefix@"
23 initrd="@libdir@/qemu-sanity-check/initrd"
24
25 arch="$(uname -m)"
26 canonical_arch="$(uname -m | sed 's/i[456]86/i386/')"
27
28 verbose=no
29 timeout=10m
30 accel=kvm:tcg
31 cpu=
32 memory=768
33 console=ttyS0
34 machine=
35
36 # Both libguestfs and virt-manager choose cpu=host when we think that
37 # KVM is available, and default otherwise.  Although testing for KVM
38 # is hairy, I found that on aarch64 it can fail unless we choose
39 # cpu=host for KVM.
40 if test -r /dev/kvm; then
41     cpu=host
42 fi
43
44 # Default machine and CPU type depends on arch.  You can override this
45 # using -m|--machine and --cpu options.
46 case "$canonical_arch" in
47     arm*)
48         console=ttyAMA0
49         machine=virt ;;
50     aarch*)
51         console=ttyAMA0
52         if [ "$cpu" = "" ]; then cpu=cortex-a57; fi
53         machine=virt ;;
54     s390*)
55         console=ttysclp0 ;;
56 esac
57
58 # Handle command line parsing.
59
60 function usage {
61     echo "qemu-sanity-check [options]"
62     echo "Options:"
63     echo "  --help               Display this help"
64     echo "  --accel=[kvm|tcg]    Force KVM or software emulation"
65     echo "  --cpu=cpu            Set CPU"
66     echo "  -i|--initrd=initrd   Set location of initramfs"
67     echo "  -k|--kernel=vmlinuz  Set location of kernel"
68     echo "  -m|--machine=machine Set machine type"
69     echo "  -q|--qemu=qemu       Set location of qemu/KVM binary"
70     echo "  -t|--timeout=timeout Set the timeout"
71     echo "  -v|--verbose         Verbose output"
72     echo "  -V|--version         Display version and exit"
73     exit 0
74 }
75
76 TEMP=$(getopt \
77     -o i:k:m:q:t:vV \
78     --long help \
79     --long accel: \
80     --long cpu: \
81     --long initrd: \
82     --long kernel: \
83     --long machine: \
84     --long qemu: \
85     --long timeout: \
86     --long verbose \
87     --long version \
88     -n 'qemu-sanity-check' -- "$@")
89 if [ $? != 0 ]; then exit 2; fi
90 eval set -- "$TEMP"
91
92 while true; do
93     case "$1" in
94         --help)
95             usage
96             ;;
97         --accel)
98             accel="$2"
99             shift 2
100             ;;
101         --cpu)
102             cpu="$2"
103             shift 2
104             ;;
105         -i|--initrd)
106             initrd="$2"
107             shift 2
108             ;;
109         -k|--kernel)
110             kernel="$2"
111             shift 2
112             ;;
113         -m|--machine)
114             machine="$2"
115             shift 2
116             ;;
117         -q|--qemu)
118             qemu="$2"
119             shift 2
120             ;;
121         -t|--timeout)
122             timeout="$2"
123             shift 2
124             ;;
125         -v|--verbose)
126             verbose=yes
127             shift
128             ;;
129         -V|--version)
130             echo "@PACKAGE_NAME@ @PACKAGE_VERSION@"
131             exit 0
132             ;;
133         --)
134             shift
135             break
136             ;;
137         *)
138             echo "$0: internal error parsing options: $1"
139             exit 2
140             ;;
141     esac
142 done
143
144 # Locate initrd.
145 if [ ! -r "$initrd" ]; then
146     echo "$0: cannot find 'initrd', try using --initrd=/path/to/initrd"
147     echo "If you are running qemu-sanity-check without installing, then do:"
148     echo "    $0 --initrd=./initrd $@"
149     echo "The default path is '@libdir@/initrd'."
150     exit 2
151 fi
152
153 # Locate kernel if not specified.
154 if [ -z "$kernel" ]; then
155     shopt -s nullglob
156     if [ "$verbose" = "yes" ]; then
157         echo "all kernels:"
158         ls -1dvr /lib/modules/*/vmlinuz /boot/vmlinuz-*.$arch*
159     fi
160     kernel="$(ls -1dvr /lib/modules/*/vmlinuz /boot/vmlinuz-*.$arch* 2>/dev/null | grep -v xen | head -1)"
161     if [ -z "$kernel" ]; then
162         echo "$0: cannot find a Linux kernel in /boot"
163         echo "Choose a kernel to test using --kernel=/path/to/vmlinuz"
164         exit 2
165     fi
166     shopt -u nullglob
167 fi
168 if [ ! -r "$kernel" ]; then
169     echo "$0: kernel $kernel is not readable"
170     exit 2
171 fi
172
173 # Locate qemu if not specified.
174 if [ -z "$qemu" ]; then
175     if [ "$verbose" = "yes" ]; then
176         echo "all qemus:" @QEMU_LIST@
177     fi
178     for q in @QEMU_LIST@; do
179         if "$q" --help >/dev/null 2>&1; then
180             qemu="$q"
181             break
182         fi
183     done
184     if [ -z "$qemu" ]; then
185         echo "$0: cannot find a qemu binary on the \$PATH"
186         echo "Choose a qemu binary to test using --qemu=/path/to/qemu"
187         exit 2
188     fi
189 fi
190
191 # Choose a temporary file for the output.
192 test_output="$(mktemp --suff=.out)"
193
194 # Generate the parameters for the qemu command.
195 declare -a argv
196 i=0
197 argv[$((i++))]="$qemu"
198 argv[$((i++))]="-display"
199 argv[$((i++))]="none"
200 argv[$((i++))]="-no-user-config"
201 argv[$((i++))]="-nodefaults"
202 argv[$((i++))]="-machine"
203 argv[$((i++))]="$machine${machine:+,}accel=$accel"
204 if [ "$cpu" != "" ]; then
205     argv[$((i++))]="-cpu"
206     argv[$((i++))]="$cpu"
207 fi
208 argv[$((i++))]="-m"
209 argv[$((i++))]="$memory"
210 argv[$((i++))]="-no-reboot"
211 argv[$((i++))]="-serial"
212 argv[$((i++))]="file:$test_output"
213 argv[$((i++))]="-kernel"
214 argv[$((i++))]="$kernel"
215 argv[$((i++))]="-initrd"
216 argv[$((i++))]="$initrd"
217 argv[$((i++))]="-append"
218 argv[$((i++))]="console=$console oops=panic panic=-1"
219
220 if [ "$verbose" = "yes" ]; then
221     echo "${argv[@]}"
222 fi
223
224 # Run the command.
225 timeout "$timeout" "${argv[@]}"
226 r="${PIPESTATUS[0]}"
227 if [ $r -eq 124 ]; then
228     cat "$test_output"
229     echo "$0: error: test $kernel on $qemu: timed out"
230     rm "$test_output"
231     exit 1
232 elif [ $r -ne 0 ]; then
233     cat "$test_output"
234     echo "$0: error: test $kernel on $qemu: failed"
235     rm "$test_output"
236     exit 1
237 fi
238
239 if [ "$verbose" = "yes" ]; then
240     cat "$test_output"
241 fi
242
243 # Check if there was a kernel panic.  Note that oops=panic is set
244 # which will force a reboot for any oops condition.
245 if grep -sq "Kernel panic - not syncing" "$test_output"; then
246     cat "$test_output"
247     echo "$0: error: test $kernel on $qemu: kernel panic seen"
248     rm "$test_output"
249     exit 1
250 fi
251
252 # Verify that userspace was reached.
253 if ! grep -sq "initrd started up OK" "$test_output"; then
254     cat "$test_output"
255     echo "$0: error: test $kernel on $qemu: init process did not start up"
256     rm "$test_output"
257     exit 1
258 fi
259
260 # Successful.
261 rm "$test_output"
262 exit 0