xref: /kvm-unit-tests/scripts/arch-run.bash (revision 70fcb64b7d548240f6f08680ccbe94f9c16104fb)
1b2a2aa5dSAndrew Jones##############################################################################
2b2a2aa5dSAndrew Jones# run_qemu translates the ambiguous exit status in Table1 to that in Table2.
3b2a2aa5dSAndrew Jones# Table3 simply documents the complete status table.
4b2a2aa5dSAndrew Jones#
5b2a2aa5dSAndrew Jones# Table1: Before fixup
6b2a2aa5dSAndrew Jones# --------------------
7b2a2aa5dSAndrew Jones# 0      - Unexpected exit from QEMU (possible signal), or the unittest did
8b2a2aa5dSAndrew Jones#          not use debug-exit
9b2a2aa5dSAndrew Jones# 1      - most likely unittest succeeded, or QEMU failed
10b2a2aa5dSAndrew Jones#
11b2a2aa5dSAndrew Jones# Table2: After fixup
12b2a2aa5dSAndrew Jones# -------------------
13b2a2aa5dSAndrew Jones# 0      - Everything succeeded
14b2a2aa5dSAndrew Jones# 1      - most likely QEMU failed
15b2a2aa5dSAndrew Jones#
16b2a2aa5dSAndrew Jones# Table3: Complete table
17b2a2aa5dSAndrew Jones# ----------------------
18b2a2aa5dSAndrew Jones# 0      - SUCCESS
19b2a2aa5dSAndrew Jones# 1      - most likely QEMU failed
20b2a2aa5dSAndrew Jones# 2      - most likely a run script failed
21b2a2aa5dSAndrew Jones# 3      - most likely the unittest failed
22fd149358SAndrew Jones# 124    - most likely the unittest timed out
23b2a2aa5dSAndrew Jones# 127    - most likely the unittest called abort()
24b2a2aa5dSAndrew Jones# 1..127 - FAILURE (could be QEMU, a run script, or the unittest)
25b2a2aa5dSAndrew Jones# >= 128 - Signal (signum = status - 128)
26b2a2aa5dSAndrew Jones##############################################################################
27b2a2aa5dSAndrew Jonesrun_qemu ()
28b2a2aa5dSAndrew Jones{
298c3f0d96SAndrew Jones	local stdout errors ret sig
30b2a2aa5dSAndrew Jones
31f0ca153cSRadim Krčmář	# stdout to {stdout}, stderr to $errors and stderr
32b2a2aa5dSAndrew Jones	exec {stdout}>&1
338c3f0d96SAndrew Jones	errors=$("${@}" </dev/null 2> >(tee /dev/stderr) > /dev/fd/$stdout)
34b2a2aa5dSAndrew Jones	ret=$?
35b2a2aa5dSAndrew Jones	exec {stdout}>&-
368727c886SAndrew Jones
378727c886SAndrew Jones	[ $ret -eq 134 ] && echo "QEMU Aborted" >&2
38b2a2aa5dSAndrew Jones
39b2a2aa5dSAndrew Jones	if [ "$errors" ]; then
40b2a2aa5dSAndrew Jones		sig=$(grep 'terminating on signal' <<<"$errors")
41b2a2aa5dSAndrew Jones		if [ "$sig" ]; then
42b2a2aa5dSAndrew Jones			sig=$(sed 's/.*terminating on signal \([0-9][0-9]*\).*/\1/' <<<"$sig")
43b2a2aa5dSAndrew Jones		fi
44b2a2aa5dSAndrew Jones	fi
45b2a2aa5dSAndrew Jones
46b2a2aa5dSAndrew Jones	if [ $ret -eq 0 ]; then
47b2a2aa5dSAndrew Jones		# Some signals result in a zero return status, but the
48b2a2aa5dSAndrew Jones		# error log tells the truth.
49b2a2aa5dSAndrew Jones		if [ "$sig" ]; then
50b2a2aa5dSAndrew Jones			((ret=sig+128))
51b2a2aa5dSAndrew Jones		else
52b2a2aa5dSAndrew Jones			# Exiting with zero (non-debugexit) is an error
53b2a2aa5dSAndrew Jones			ret=1
54b2a2aa5dSAndrew Jones		fi
55b2a2aa5dSAndrew Jones	elif [ $ret -eq 1 ]; then
56b2a2aa5dSAndrew Jones		# Even when ret==1 (unittest success) if we also got stderr
57b2a2aa5dSAndrew Jones		# logs, then we assume a QEMU failure. Otherwise we translate
58b2a2aa5dSAndrew Jones		# status of 1 to 0 (SUCCESS)
59a51bab13SRadim Krčmář		if [ -z "$(echo "$errors" | grep -vi warning)" ]; then
60b2a2aa5dSAndrew Jones			ret=0
61b2a2aa5dSAndrew Jones		fi
62b2a2aa5dSAndrew Jones	fi
63b2a2aa5dSAndrew Jones
64b2a2aa5dSAndrew Jones	return $ret
65b2a2aa5dSAndrew Jones}
66fd149358SAndrew Jones
67fd149358SAndrew Jonestimeout_cmd ()
68fd149358SAndrew Jones{
69fd149358SAndrew Jones	if [ "$TIMEOUT" ] && [ "$TIMEOUT" != "0" ]; then
70fd149358SAndrew Jones		echo "timeout -k 1s --foreground $TIMEOUT"
71fd149358SAndrew Jones	fi
72fd149358SAndrew Jones}
7337abdda9SThomas Huth
7437abdda9SThomas Huthqmp ()
7537abdda9SThomas Huth{
7637abdda9SThomas Huth	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1
7737abdda9SThomas Huth}
7837abdda9SThomas Huth
7937abdda9SThomas Huthrun_migration ()
8037abdda9SThomas Huth{
8137abdda9SThomas Huth	if ! command -v nc >/dev/null 2>&1; then
8237abdda9SThomas Huth		echo "$FUNCNAME needs nc (netcat)" >&2
8337abdda9SThomas Huth		exit 2
8437abdda9SThomas Huth	fi
8537abdda9SThomas Huth
8637abdda9SThomas Huth	qemu=$1
8737abdda9SThomas Huth	shift
8837abdda9SThomas Huth
8937abdda9SThomas Huth	migsock=`mktemp -u -t mig-helper-socket.XXXXXXXXXX`
9037abdda9SThomas Huth	migout1=`mktemp -t mig-helper-stdout1.XXXXXXXXXX`
9137abdda9SThomas Huth	qmp1=`mktemp -u -t mig-helper-qmp1.XXXXXXXXXX`
9237abdda9SThomas Huth	qmp2=`mktemp -u -t mig-helper-qmp2.XXXXXXXXXX`
9337abdda9SThomas Huth	qmpout1=/dev/null
9437abdda9SThomas Huth	qmpout2=/dev/null
9537abdda9SThomas Huth
9637abdda9SThomas Huth	trap 'rm -f ${migout1} ${migsock} ${qmp1} ${qmp2}' EXIT
9737abdda9SThomas Huth
9837abdda9SThomas Huth	$qemu "$@" -chardev socket,id=mon1,path=${qmp1},server,nowait \
9937abdda9SThomas Huth		 -mon chardev=mon1,mode=control | tee ${migout1} &
10037abdda9SThomas Huth
10137abdda9SThomas Huth	$qemu "$@" -chardev socket,id=mon2,path=${qmp2},server,nowait \
10237abdda9SThomas Huth		 -mon chardev=mon2,mode=control -incoming unix:${migsock} &
10337abdda9SThomas Huth
10437abdda9SThomas Huth	# The test must prompt the user to migrate, so wait for the "migrate" keyword
10537abdda9SThomas Huth	while ! grep -q -i "migrate" < ${migout1} ; do
10637abdda9SThomas Huth		sleep 1
10737abdda9SThomas Huth	done
10837abdda9SThomas Huth
10937abdda9SThomas Huth	qmp ${qmp1} '"migrate", "arguments": { "uri": "unix:'${migsock}'" }' > ${qmpout1}
11037abdda9SThomas Huth
11137abdda9SThomas Huth	# Wait for the migration to complete
11237abdda9SThomas Huth	migstatus=`qmp ${qmp1} '"query-migrate"' | grep return`
11337abdda9SThomas Huth	while ! grep -q '"completed"' <<<"$migstatus" ; do
11437abdda9SThomas Huth		sleep 1
11537abdda9SThomas Huth		migstatus=`qmp ${qmp1} '"query-migrate"' | grep return`
11637abdda9SThomas Huth		if grep -q '"failed"' <<<"$migstatus" ; then
11737abdda9SThomas Huth			echo "ERROR: Migration failed." >&2
11837abdda9SThomas Huth			qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null
11937abdda9SThomas Huth			qmp ${qmp2} '"quit"'> ${qmpout2} 2>/dev/null
12037abdda9SThomas Huth			exit 2
12137abdda9SThomas Huth		fi
12237abdda9SThomas Huth	done
12337abdda9SThomas Huth	qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null
12437abdda9SThomas Huth
12537abdda9SThomas Huth	qmp ${qmp2} '"inject-nmi"'> ${qmpout2}
12637abdda9SThomas Huth
12737abdda9SThomas Huth	wait
12837abdda9SThomas Huth}
12937abdda9SThomas Huth
13037abdda9SThomas Huthmigration_cmd ()
13137abdda9SThomas Huth{
13237abdda9SThomas Huth	if [ "$MIGRATION" = "yes" ]; then
13337abdda9SThomas Huth		echo "run_migration"
13437abdda9SThomas Huth	fi
13537abdda9SThomas Huth}
136531326aeSBalamuruhan S
137531326aeSBalamuruhan Ssearch_qemu_binary ()
138531326aeSBalamuruhan S{
139531326aeSBalamuruhan S	local save_path=$PATH
140232f404aSAndrew Jones	local qemucmd qemu
141232f404aSAndrew Jones
142531326aeSBalamuruhan S	export PATH=$PATH:/usr/libexec
143232f404aSAndrew Jones	for qemucmd in ${QEMU:-qemu-system-$ARCH_NAME qemu-kvm}; do
144232f404aSAndrew Jones		if $qemucmd --help 2>/dev/null | grep -q 'QEMU'; then
145232f404aSAndrew Jones			qemu="$qemucmd"
146531326aeSBalamuruhan S			break
147531326aeSBalamuruhan S		fi
148531326aeSBalamuruhan S	done
149531326aeSBalamuruhan S
150232f404aSAndrew Jones	if [ -z "$qemu" ]; then
151232f404aSAndrew Jones		echo "A QEMU binary was not found."
152232f404aSAndrew Jones		echo "You can set a custom location by using the QEMU=<path> environment variable."
153531326aeSBalamuruhan S		exit 2
154531326aeSBalamuruhan S	fi
155232f404aSAndrew Jones	command -v $qemu
156531326aeSBalamuruhan S	export PATH=$save_path
157531326aeSBalamuruhan S}
1584da0bc9aSAndrew Jones
1594da0bc9aSAndrew Jonesinitrd_create ()
1604da0bc9aSAndrew Jones{
1618ec99569SAndrew Jones	env_add_errata
1624da0bc9aSAndrew Jones	unset INITRD
1634da0bc9aSAndrew Jones	[ -f "$ENV" ] && INITRD="-initrd $ENV"
1644da0bc9aSAndrew Jones}
1658ec99569SAndrew Jones
1668ec99569SAndrew Jonesenv_add_errata ()
1678ec99569SAndrew Jones{
1688ec99569SAndrew Jones	local line errata
1698ec99569SAndrew Jones
1708ec99569SAndrew Jones	if [ -f "$ENV" ] && grep -q '^ERRATA_' <(env); then
1718ec99569SAndrew Jones		for line in $(grep '^ERRATA_' "$ENV"); do
1728ec99569SAndrew Jones			errata=${line%%=*}
1738ec99569SAndrew Jones			test -v $errata && continue
1748ec99569SAndrew Jones			eval export "$line"
1758ec99569SAndrew Jones		done
176*70fcb64bSAndrew Jones	elif [ ! -f "$ENV" ]; then
177*70fcb64bSAndrew Jones		env_generate_errata
1788ec99569SAndrew Jones	fi
1798ec99569SAndrew Jones
1808ec99569SAndrew Jones	if grep -q '^ERRATA_' <(env); then
1818ec99569SAndrew Jones		export ENV_OLD="$ENV"
1828ec99569SAndrew Jones		export ENV=$(mktemp)
1838ec99569SAndrew Jones		trap_exit_push 'rm -f $ENV; [ "$ENV_OLD" ] && export ENV="$ENV_OLD" || unset ENV; unset ENV_OLD'
1848ec99569SAndrew Jones		[ -f "$ENV_OLD" ] && grep -v '^ERRATA_' "$ENV_OLD" > $ENV
1858ec99569SAndrew Jones		grep '^ERRATA_' <(env) >> $ENV
1868ec99569SAndrew Jones	fi
1878ec99569SAndrew Jones}
1888ec99569SAndrew Jones
189*70fcb64bSAndrew Jonesenv_generate_errata ()
190*70fcb64bSAndrew Jones{
191*70fcb64bSAndrew Jones	local kernel_version_string=$(uname -r)
192*70fcb64bSAndrew Jones	local kernel_version kernel_patchlevel kernel_sublevel
193*70fcb64bSAndrew Jones	local line commit minver errata v p s have
194*70fcb64bSAndrew Jones
195*70fcb64bSAndrew Jones	IFS=. read kernel_version kernel_patchlevel kernel_sublevel <<<$kernel_version_string
196*70fcb64bSAndrew Jones	kernel_sublevel=${kernel_sublevel%%[!0-9]*}
197*70fcb64bSAndrew Jones
198*70fcb64bSAndrew Jones	[ "$ENVIRON_DEFAULT" != "yes" ] && return
199*70fcb64bSAndrew Jones	[ ! -f errata.txt ] && return
200*70fcb64bSAndrew Jones
201*70fcb64bSAndrew Jones	for line in $(grep -v '^#' errata.txt | tr -d '[:blank:]' | cut -d: -f1,2); do
202*70fcb64bSAndrew Jones		commit=${line%:*}
203*70fcb64bSAndrew Jones		minver=${line#*:}
204*70fcb64bSAndrew Jones
205*70fcb64bSAndrew Jones		errata="ERRATA_$commit"
206*70fcb64bSAndrew Jones		test -v $errata && continue
207*70fcb64bSAndrew Jones
208*70fcb64bSAndrew Jones		IFS=. read v p s <<<$minver
209*70fcb64bSAndrew Jones		s=${s%%[!0-9]*}
210*70fcb64bSAndrew Jones
211*70fcb64bSAndrew Jones		if (( $kernel_version > $v ||
212*70fcb64bSAndrew Jones		      ($kernel_version == $v && $kernel_patchlevel > $p) )); then
213*70fcb64bSAndrew Jones			have=y
214*70fcb64bSAndrew Jones		elif (( $kernel_version == $v && $kernel_patchlevel == $p )); then
215*70fcb64bSAndrew Jones			if [ "$kernel_sublevel" ] && [ "$s" ]; then
216*70fcb64bSAndrew Jones				if (( $kernel_sublevel >= $s )); then
217*70fcb64bSAndrew Jones					have=y
218*70fcb64bSAndrew Jones				else
219*70fcb64bSAndrew Jones					have=n
220*70fcb64bSAndrew Jones				fi
221*70fcb64bSAndrew Jones			elif [ "$s" ] && (( $s != 0 )); then
222*70fcb64bSAndrew Jones				have=n
223*70fcb64bSAndrew Jones			else
224*70fcb64bSAndrew Jones				have=y
225*70fcb64bSAndrew Jones			fi
226*70fcb64bSAndrew Jones		else
227*70fcb64bSAndrew Jones			have=n
228*70fcb64bSAndrew Jones		fi
229*70fcb64bSAndrew Jones		eval export "$errata=$have"
230*70fcb64bSAndrew Jones	done
231*70fcb64bSAndrew Jones}
232*70fcb64bSAndrew Jones
2338ec99569SAndrew Jonestrap_exit_push ()
2348ec99569SAndrew Jones{
2358ec99569SAndrew Jones	local old_exit=$(trap -p EXIT | sed "s/^[^']*'//;s/'[^']*$//")
2368ec99569SAndrew Jones	trap -- "$1; $old_exit" EXIT
2378ec99569SAndrew Jones}
238