xref: /kvm-unit-tests/scripts/arch-run.bash (revision 3b4b978a27f6f7df37875f97470d19d647b2c179)
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
31b16df9eeSAndrew Jones	initrd_create || return $?
32d76bf076SAndrew Jones	echo -n "$@"
33b16df9eeSAndrew Jones	[ "$ENVIRON_DEFAULT" = "yes" ] && echo -n " #"
348b13a5b5SRadim Krčmář	echo " $INITRD"
358b13a5b5SRadim Krčmář
36f0ca153cSRadim Krčmář	# stdout to {stdout}, stderr to $errors and stderr
37b2a2aa5dSAndrew Jones	exec {stdout}>&1
388b13a5b5SRadim Krčmář	errors=$("${@}" $INITRD </dev/null 2> >(tee /dev/stderr) > /dev/fd/$stdout)
39b2a2aa5dSAndrew Jones	ret=$?
40b2a2aa5dSAndrew Jones	exec {stdout}>&-
418727c886SAndrew Jones
428727c886SAndrew Jones	[ $ret -eq 134 ] && echo "QEMU Aborted" >&2
43b2a2aa5dSAndrew Jones
44b2a2aa5dSAndrew Jones	if [ "$errors" ]; then
45b2a2aa5dSAndrew Jones		sig=$(grep 'terminating on signal' <<<"$errors")
46b2a2aa5dSAndrew Jones		if [ "$sig" ]; then
47*3df129a6SNicholas Piggin			# This is too complex for ${var/search/replace}
48*3df129a6SNicholas Piggin			# shellcheck disable=SC2001
49b2a2aa5dSAndrew Jones			sig=$(sed 's/.*terminating on signal \([0-9][0-9]*\).*/\1/' <<<"$sig")
50b2a2aa5dSAndrew Jones		fi
51b2a2aa5dSAndrew Jones	fi
52b2a2aa5dSAndrew Jones
53b2a2aa5dSAndrew Jones	if [ $ret -eq 0 ]; then
54b2a2aa5dSAndrew Jones		# Some signals result in a zero return status, but the
55b2a2aa5dSAndrew Jones		# error log tells the truth.
56b2a2aa5dSAndrew Jones		if [ "$sig" ]; then
57b2a2aa5dSAndrew Jones			((ret=sig+128))
58b2a2aa5dSAndrew Jones		else
59b2a2aa5dSAndrew Jones			# Exiting with zero (non-debugexit) is an error
60b2a2aa5dSAndrew Jones			ret=1
61b2a2aa5dSAndrew Jones		fi
62b2a2aa5dSAndrew Jones	elif [ $ret -eq 1 ]; then
63b2a2aa5dSAndrew Jones		# Even when ret==1 (unittest success) if we also got stderr
64b2a2aa5dSAndrew Jones		# logs, then we assume a QEMU failure. Otherwise we translate
65b2a2aa5dSAndrew Jones		# status of 1 to 0 (SUCCESS)
665bf124ffSNicholas Piggin	        if [ "$errors" ]; then
675bf124ffSNicholas Piggin			if ! grep -qvi warning <<<"$errors" ; then
685bf124ffSNicholas Piggin				ret=0
695bf124ffSNicholas Piggin			fi
705bf124ffSNicholas Piggin		else
71b2a2aa5dSAndrew Jones			ret=0
72b2a2aa5dSAndrew Jones		fi
73b2a2aa5dSAndrew Jones	fi
74b2a2aa5dSAndrew Jones
75b2a2aa5dSAndrew Jones	return $ret
76b2a2aa5dSAndrew Jones}
77fd149358SAndrew Jones
78e0a8391eSRadim Krčmářrun_qemu_status ()
79e0a8391eSRadim Krčmář{
80e0a8391eSRadim Krčmář	local stdout ret
81e0a8391eSRadim Krčmář
82e0a8391eSRadim Krčmář	exec {stdout}>&1
83e0a8391eSRadim Krčmář	lines=$(run_qemu "$@" > >(tee /dev/fd/$stdout))
84e0a8391eSRadim Krčmář	ret=$?
85e0a8391eSRadim Krčmář	exec {stdout}>&-
86e0a8391eSRadim Krčmář
87e0a8391eSRadim Krčmář	if [ $ret -eq 1 ]; then
88a6e2b9e6SNicholas Piggin		testret=$(grep '^EXIT: ' <<<"$lines" | head -n1 | sed 's/.*STATUS=\([0-9][0-9]*\).*/\1/')
89e0a8391eSRadim Krčmář		if [ "$testret" ]; then
90e0a8391eSRadim Krčmář			if [ $testret -eq 1 ]; then
91e0a8391eSRadim Krčmář				ret=0
92e0a8391eSRadim Krčmář			else
93e0a8391eSRadim Krčmář				ret=$testret
94e0a8391eSRadim Krčmář			fi
95e0a8391eSRadim Krčmář		fi
96e0a8391eSRadim Krčmář	fi
97e0a8391eSRadim Krčmář
98e0a8391eSRadim Krčmář	return $ret
99e0a8391eSRadim Krčmář}
100e0a8391eSRadim Krčmář
101fd149358SAndrew Jonestimeout_cmd ()
102fd149358SAndrew Jones{
10315a12650SAndrew Jones	local s
10415a12650SAndrew Jones
105fd149358SAndrew Jones	if [ "$TIMEOUT" ] && [ "$TIMEOUT" != "0" ]; then
10615a12650SAndrew Jones		if [ "$CONFIG_EFI" = 'y' ]; then
10715a12650SAndrew Jones			s=${TIMEOUT: -1}
10815a12650SAndrew Jones			if [ "$s" = 's' ]; then
10915a12650SAndrew Jones				TIMEOUT=${TIMEOUT:0:-1}
11015a12650SAndrew Jones				((TIMEOUT += 10)) # Add 10 seconds for booting UEFI
11115a12650SAndrew Jones				TIMEOUT="${TIMEOUT}s"
11215a12650SAndrew Jones			fi
11315a12650SAndrew Jones		fi
114fd149358SAndrew Jones		echo "timeout -k 1s --foreground $TIMEOUT"
115fd149358SAndrew Jones	fi
116fd149358SAndrew Jones}
11737abdda9SThomas Huth
11837abdda9SThomas Huthqmp ()
11937abdda9SThomas Huth{
120b508e114SJamie Iles	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | ncat -U $1
12137abdda9SThomas Huth}
12237abdda9SThomas Huth
1235f65d6f4SNico Boehrqmp_events ()
1245f65d6f4SNico Boehr{
1255f65d6f4SNico Boehr	while ! test -S "$1"; do sleep 0.1; done
1265f65d6f4SNico Boehr	echo '{ "execute": "qmp_capabilities" }{ "execute": "cont" }' |
1275f65d6f4SNico Boehr		ncat --no-shutdown -U $1 |
1285f65d6f4SNico Boehr		jq -c 'select(has("event"))'
1295f65d6f4SNico Boehr}
1305f65d6f4SNico Boehr
1314aadd216SNicholas Pigginfilter_quiet_msgs ()
1324aadd216SNicholas Piggin{
133fa8914bcSNicholas Piggin	grep -v "Now migrate the VM (quiet)" |
134956004acSNicholas Piggin	grep -v "Begin continuous migration (quiet)" |
135956004acSNicholas Piggin	grep -v "End continuous migration (quiet)" |
136fa8914bcSNicholas Piggin	grep -v "Skipped VM migration (quiet)"
1374aadd216SNicholas Piggin}
1384aadd216SNicholas Piggin
1394aadd216SNicholas Pigginseen_migrate_msg ()
1404aadd216SNicholas Piggin{
141fa8914bcSNicholas Piggin	if [ $skip_migration -eq 1 ]; then
142956004acSNicholas Piggin	        grep -q -e "Now migrate the VM" -e "Begin continuous migration" < $1
143fa8914bcSNicholas Piggin	else
144956004acSNicholas Piggin	        grep -q -e "Now migrate the VM" -e "Begin continuous migration" -e "Skipped VM migration" < $1
145fa8914bcSNicholas Piggin	fi
1464aadd216SNicholas Piggin}
1474aadd216SNicholas Piggin
14837abdda9SThomas Huthrun_migration ()
14937abdda9SThomas Huth{
150b508e114SJamie Iles	if ! command -v ncat >/dev/null 2>&1; then
151b508e114SJamie Iles		echo "${FUNCNAME[0]} needs ncat (netcat)" >&2
1522176d963SThomas Huth		return 77
15337abdda9SThomas Huth	fi
15437abdda9SThomas Huth
155a8d9d8dcSNicholas Piggin	migcmdline=("$@")
15614ea7bdaSNicholas Piggin
157af3484fcSNicholas Piggin	trap 'trap - TERM ; kill 0 ; exit 2' INT TERM
158fa8914bcSNicholas Piggin	trap 'rm -f ${src_out} ${dst_out} ${src_outfifo} ${dst_outfifo} ${dst_incoming} ${src_qmp} ${dst_qmp} ${src_infifo} ${dst_infifo}' RETURN EXIT
159af3484fcSNicholas Piggin
160cd45aeb7SNicholas Piggin	dst_incoming=$(mktemp -u -t mig-helper-socket-incoming.XXXXXXXXXX)
161cd45aeb7SNicholas Piggin	src_out=$(mktemp -t mig-helper-stdout1.XXXXXXXXXX)
162cd45aeb7SNicholas Piggin	src_outfifo=$(mktemp -u -t mig-helper-fifo-stdout1.XXXXXXXXXX)
163cd45aeb7SNicholas Piggin	dst_out=$(mktemp -t mig-helper-stdout2.XXXXXXXXXX)
164cd45aeb7SNicholas Piggin	dst_outfifo=$(mktemp -u -t mig-helper-fifo-stdout2.XXXXXXXXXX)
165cd45aeb7SNicholas Piggin	src_qmp=$(mktemp -u -t mig-helper-qmp1.XXXXXXXXXX)
166cd45aeb7SNicholas Piggin	dst_qmp=$(mktemp -u -t mig-helper-qmp2.XXXXXXXXXX)
167fa8914bcSNicholas Piggin	src_infifo=$(mktemp -u -t mig-helper-fifo-stdin1.XXXXXXXXXX)
168fa8914bcSNicholas Piggin	dst_infifo=$(mktemp -u -t mig-helper-fifo-stdin2.XXXXXXXXXX)
169cd45aeb7SNicholas Piggin	src_qmpout=/dev/null
170cd45aeb7SNicholas Piggin	dst_qmpout=/dev/null
171fa8914bcSNicholas Piggin	skip_migration=0
172956004acSNicholas Piggin	continuous_migration=0
17337abdda9SThomas Huth
174cd45aeb7SNicholas Piggin	mkfifo ${src_outfifo}
175cd45aeb7SNicholas Piggin	mkfifo ${dst_outfifo}
17614ea7bdaSNicholas Piggin
17749bbfc65SNicholas Piggin	# Holding both ends of the input fifo open prevents opens from
17849bbfc65SNicholas Piggin	# blocking and readers getting EOF when a writer closes it.
179*3df129a6SNicholas Piggin	# These fds appear to be unused to shellcheck so quieten the warning.
180fa8914bcSNicholas Piggin	mkfifo ${src_infifo}
18149bbfc65SNicholas Piggin	mkfifo ${dst_infifo}
182*3df129a6SNicholas Piggin	# shellcheck disable=SC2034
183fa8914bcSNicholas Piggin	exec {src_infifo_fd}<>${src_infifo}
184*3df129a6SNicholas Piggin	# shellcheck disable=SC2034
18549bbfc65SNicholas Piggin	exec {dst_infifo_fd}<>${dst_infifo}
18649bbfc65SNicholas Piggin
187b3a1827eSNicholas Piggin	"${migcmdline[@]}" \
188cd45aeb7SNicholas Piggin		-chardev socket,id=mon,path=${src_qmp},server=on,wait=off \
189fa8914bcSNicholas Piggin		-mon chardev=mon,mode=control \
190fa8914bcSNicholas Piggin		< ${src_infifo} > ${src_outfifo} &
191659557c0SNicholas Piggin	live_pid=$!
192*3df129a6SNicholas Piggin	# Shellcheck complains about useless cat but it is clearer than a
193*3df129a6SNicholas Piggin	# redirect in this case.
194*3df129a6SNicholas Piggin	# shellcheck disable=SC2002
1954aadd216SNicholas Piggin	cat ${src_outfifo} | tee ${src_out} | filter_quiet_msgs &
19637abdda9SThomas Huth
19714ea7bdaSNicholas Piggin	# Start the first destination QEMU machine in advance of the test
19814ea7bdaSNicholas Piggin	# reaching the migration point, since we expect at least one migration.
19914ea7bdaSNicholas Piggin	# Then destination machines are started after the test outputs
20014ea7bdaSNicholas Piggin	# subsequent "Now migrate the VM" messages.
20114ea7bdaSNicholas Piggin	do_migration || return $?
20237abdda9SThomas Huth
20314ea7bdaSNicholas Piggin	while ps -p ${live_pid} > /dev/null ; do
204956004acSNicholas Piggin		if [ ${continuous_migration} -eq 1 ] ; then
205956004acSNicholas Piggin			do_migration || return $?
206956004acSNicholas Piggin		elif ! seen_migrate_msg ${src_out} ;  then
20714ea7bdaSNicholas Piggin			sleep 0.1
208956004acSNicholas Piggin		elif grep -q "Begin continuous migration" < ${src_out} ; then
209956004acSNicholas Piggin			do_migration || return $?
210fa8914bcSNicholas Piggin		elif grep -q "Now migrate the VM" < ${src_out} ; then
21114ea7bdaSNicholas Piggin			do_migration || return $?
212fa8914bcSNicholas Piggin		elif [ $skip_migration -eq 0 ] && grep -q "Skipped VM migration" < ${src_out} ; then
213fa8914bcSNicholas Piggin			echo > ${src_infifo} # Resume src and carry on.
214fa8914bcSNicholas Piggin			break;
21514ea7bdaSNicholas Piggin		fi
21614ea7bdaSNicholas Piggin	done
21714ea7bdaSNicholas Piggin
21814ea7bdaSNicholas Piggin	wait ${live_pid}
21914ea7bdaSNicholas Piggin	ret=$?
22014ea7bdaSNicholas Piggin
22114ea7bdaSNicholas Piggin	while (( $(jobs -r | wc -l) > 0 )); do
22214ea7bdaSNicholas Piggin		sleep 0.1
22314ea7bdaSNicholas Piggin	done
22414ea7bdaSNicholas Piggin
22514ea7bdaSNicholas Piggin	return $ret
22614ea7bdaSNicholas Piggin}
22714ea7bdaSNicholas Piggin
22814ea7bdaSNicholas Piggindo_migration ()
22914ea7bdaSNicholas Piggin{
230b3a1827eSNicholas Piggin	"${migcmdline[@]}" \
231cd45aeb7SNicholas Piggin		-chardev socket,id=mon,path=${dst_qmp},server=on,wait=off \
232cd45aeb7SNicholas Piggin		-mon chardev=mon,mode=control -incoming unix:${dst_incoming} \
23349bbfc65SNicholas Piggin		< ${dst_infifo} > ${dst_outfifo} &
23414ea7bdaSNicholas Piggin	incoming_pid=$!
235*3df129a6SNicholas Piggin	# Shellcheck complains about useless cat but it is clearer than a
236*3df129a6SNicholas Piggin	# redirect in this case.
237*3df129a6SNicholas Piggin	# shellcheck disable=SC2002
2384aadd216SNicholas Piggin	cat ${dst_outfifo} | tee ${dst_out} | filter_quiet_msgs &
23914ea7bdaSNicholas Piggin
24014ea7bdaSNicholas Piggin	# The test must prompt the user to migrate, so wait for the
2414aadd216SNicholas Piggin	# "Now migrate VM" or similar console message.
242956004acSNicholas Piggin	while [ ${continuous_migration} -eq 0 ] && ! seen_migrate_msg ${src_out} ; do
243bfe5d7d0SNicholas Piggin		if ! ps -p ${live_pid} > /dev/null ; then
244cd45aeb7SNicholas Piggin			echo > ${dst_infifo}
245cd45aeb7SNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
246fa8914bcSNicholas Piggin			echo "ERROR: Test exit before migration point." >&2
247fa8914bcSNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
248bfe5d7d0SNicholas Piggin			return 3
249bfe5d7d0SNicholas Piggin		fi
25014ea7bdaSNicholas Piggin		sleep 0.1
25137abdda9SThomas Huth	done
25237abdda9SThomas Huth
253956004acSNicholas Piggin	if grep -q "Begin continuous migration" < ${src_out} ; then
254956004acSNicholas Piggin		if [ ${continuous_migration} -eq 1 ] ; then
255956004acSNicholas Piggin			echo > ${dst_infifo}
256956004acSNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
257956004acSNicholas Piggin			echo "ERROR: Continuous migration already begun." >&2
258956004acSNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
259956004acSNicholas Piggin			return 3
260956004acSNicholas Piggin		fi
261956004acSNicholas Piggin		continuous_migration=1
262956004acSNicholas Piggin		echo > ${src_infifo}
263956004acSNicholas Piggin	fi
264956004acSNicholas Piggin
265659557c0SNicholas Piggin	# Wait until the destination has created the incoming and qmp sockets
266cd45aeb7SNicholas Piggin	while ! [ -S ${dst_incoming} ] ; do sleep 0.1 ; done
267cd45aeb7SNicholas Piggin	while ! [ -S ${dst_qmp} ] ; do sleep 0.1 ; done
268659557c0SNicholas Piggin
269fa8914bcSNicholas Piggin	if [ $skip_migration -eq 0 ] && grep -q "Skipped VM migration" < ${src_out} ; then
270fa8914bcSNicholas Piggin		# May not get any migrations, exit to main loop for now...
271956004acSNicholas Piggin		# No migrations today, shut down dst in an orderly manner...
272956004acSNicholas Piggin		if [ ${continuous_migration} -eq 1 ] ; then
273956004acSNicholas Piggin			echo > ${dst_infifo}
274956004acSNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
275956004acSNicholas Piggin			echo "ERROR: Can't skip in continuous migration." >&2
276956004acSNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
277956004acSNicholas Piggin			return 3
278956004acSNicholas Piggin		fi
279fa8914bcSNicholas Piggin		echo > ${dst_infifo}
280fa8914bcSNicholas Piggin		qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
281fa8914bcSNicholas Piggin		echo > ${src_infifo} # Resume src and carry on.
282fa8914bcSNicholas Piggin		skip_migration=1
283fa8914bcSNicholas Piggin		return 0
284fa8914bcSNicholas Piggin	fi
285fa8914bcSNicholas Piggin
286cd45aeb7SNicholas Piggin	qmp ${src_qmp} '"migrate", "arguments": { "uri": "unix:'${dst_incoming}'" }' > ${src_qmpout}
28737abdda9SThomas Huth
28837abdda9SThomas Huth	# Wait for the migration to complete
28909e55926SNicholas Piggin	migstatus=$(qmp ${src_qmp} '"query-migrate"' | grep return)
29037abdda9SThomas Huth	while ! grep -q '"completed"' <<<"$migstatus" ; do
29114ea7bdaSNicholas Piggin		sleep 0.1
29209e55926SNicholas Piggin		if ! migstatus=$(qmp ${src_qmp} '"query-migrate"'); then
29309e8c119SNico Boehr			echo "ERROR: Querying migration state failed." >&2
294cd45aeb7SNicholas Piggin			echo > ${dst_infifo}
295cd45aeb7SNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
29609e8c119SNico Boehr			return 2
29709e8c119SNico Boehr		fi
29809e55926SNicholas Piggin		migstatus=$(grep return <<<"$migstatus")
29937abdda9SThomas Huth		if grep -q '"failed"' <<<"$migstatus"; then
30037abdda9SThomas Huth			echo "ERROR: Migration failed." >&2
301cd45aeb7SNicholas Piggin			echo > ${dst_infifo}
302cd45aeb7SNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
303cd45aeb7SNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
3049806f62dSAndrew Jones			return 2
30537abdda9SThomas Huth		fi
30637abdda9SThomas Huth	done
30714ea7bdaSNicholas Piggin
308cd45aeb7SNicholas Piggin	qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
30914ea7bdaSNicholas Piggin
310956004acSNicholas Piggin	# Should we end continuous migration?
311956004acSNicholas Piggin	if grep -q "End continuous migration" < ${src_out} ; then
312956004acSNicholas Piggin		if [ ${continuous_migration} -eq 0 ] ; then
313956004acSNicholas Piggin			echo "ERROR: Can't end continuous migration when not started." >&2
314956004acSNicholas Piggin			echo > ${dst_infifo}
315956004acSNicholas Piggin			qmp ${dst_qmp} '"quit"'> ${dst_qmpout} 2>/dev/null
316956004acSNicholas Piggin			qmp ${src_qmp} '"quit"'> ${src_qmpout} 2>/dev/null
317956004acSNicholas Piggin			return 3
318956004acSNicholas Piggin		fi
319956004acSNicholas Piggin		continuous_migration=0
320956004acSNicholas Piggin		echo > ${src_infifo}
321956004acSNicholas Piggin	fi
322956004acSNicholas Piggin
323956004acSNicholas Piggin	if [ ${continuous_migration} -eq 0 ]; then
32414ea7bdaSNicholas Piggin		# keypress to dst so getchar completes and test continues
325cd45aeb7SNicholas Piggin		echo > ${dst_infifo}
326956004acSNicholas Piggin	fi
32714ea7bdaSNicholas Piggin
3284b54f4faSNico Boehr	# Wait for the incoming socket being removed, ready for next destination
3294b54f4faSNico Boehr	while [ -S ${dst_incoming} ] ; do sleep 0.1 ; done
33014ea7bdaSNicholas Piggin
33114ea7bdaSNicholas Piggin	wait ${live_pid}
3329806f62dSAndrew Jones	ret=$?
333394d1421SAndrew Jones
334cd45aeb7SNicholas Piggin	# Now flip the variables because destination machine becomes source
335cd45aeb7SNicholas Piggin	# for the next migration.
33614ea7bdaSNicholas Piggin	live_pid=${incoming_pid}
337cd45aeb7SNicholas Piggin	tmp=${src_out}
338cd45aeb7SNicholas Piggin	src_out=${dst_out}
339cd45aeb7SNicholas Piggin	dst_out=${tmp}
340fa8914bcSNicholas Piggin	tmp=${src_infifo}
341fa8914bcSNicholas Piggin	src_infifo=${dst_infifo}
342fa8914bcSNicholas Piggin	dst_infifo=${tmp}
343cd45aeb7SNicholas Piggin	tmp=${src_outfifo}
344cd45aeb7SNicholas Piggin	src_outfifo=${dst_outfifo}
345cd45aeb7SNicholas Piggin	dst_outfifo=${tmp}
346cd45aeb7SNicholas Piggin	tmp=${src_qmp}
347cd45aeb7SNicholas Piggin	src_qmp=${dst_qmp}
348cd45aeb7SNicholas Piggin	dst_qmp=${tmp}
349394d1421SAndrew Jones
3509806f62dSAndrew Jones	return $ret
35137abdda9SThomas Huth}
35237abdda9SThomas Huth
3535f65d6f4SNico Boehrrun_panic ()
3545f65d6f4SNico Boehr{
3555f65d6f4SNico Boehr	if ! command -v ncat >/dev/null 2>&1; then
3565f65d6f4SNico Boehr		echo "${FUNCNAME[0]} needs ncat (netcat)" >&2
3575f65d6f4SNico Boehr		return 77
3585f65d6f4SNico Boehr	fi
3595f65d6f4SNico Boehr
3605f65d6f4SNico Boehr	if ! command -v jq >/dev/null 2>&1; then
3615f65d6f4SNico Boehr		echo "${FUNCNAME[0]} needs jq" >&2
3625f65d6f4SNico Boehr		return 77
3635f65d6f4SNico Boehr	fi
3645f65d6f4SNico Boehr
365af3484fcSNicholas Piggin	trap 'trap - TERM ; kill 0 ; exit 2' INT TERM
3665f65d6f4SNico Boehr	trap 'rm -f ${qmp}' RETURN EXIT
3675f65d6f4SNico Boehr
368af3484fcSNicholas Piggin	qmp=$(mktemp -u -t panic-qmp.XXXXXXXXXX)
369af3484fcSNicholas Piggin
3705f65d6f4SNico Boehr	# start VM stopped so we don't miss any events
371b3a1827eSNicholas Piggin	"$@" -chardev socket,id=mon,path=${qmp},server=on,wait=off \
372cd45aeb7SNicholas Piggin		-mon chardev=mon,mode=control -S &
3735f65d6f4SNico Boehr
3745f65d6f4SNico Boehr	panic_event_count=$(qmp_events ${qmp} | jq -c 'select(.event == "GUEST_PANICKED")' | wc -l)
3755f65d6f4SNico Boehr	if [ "$panic_event_count" -lt 1 ]; then
3765f65d6f4SNico Boehr		echo "FAIL: guest did not panic"
3775f65d6f4SNico Boehr		ret=3
3785f65d6f4SNico Boehr	else
3795f65d6f4SNico Boehr		# some QEMU versions report multiple panic events
3805f65d6f4SNico Boehr		echo "PASS: guest panicked"
3815f65d6f4SNico Boehr		ret=1
3825f65d6f4SNico Boehr	fi
3835f65d6f4SNico Boehr
3845f65d6f4SNico Boehr	return $ret
3855f65d6f4SNico Boehr}
3865f65d6f4SNico Boehr
38737abdda9SThomas Huthmigration_cmd ()
38837abdda9SThomas Huth{
38937abdda9SThomas Huth	if [ "$MIGRATION" = "yes" ]; then
39037abdda9SThomas Huth		echo "run_migration"
39137abdda9SThomas Huth	fi
39237abdda9SThomas Huth}
393531326aeSBalamuruhan S
3945f65d6f4SNico Boehrpanic_cmd ()
3955f65d6f4SNico Boehr{
3965f65d6f4SNico Boehr	if [ "$PANIC" = "yes" ]; then
3975f65d6f4SNico Boehr		echo "run_panic"
3985f65d6f4SNico Boehr	fi
3995f65d6f4SNico Boehr}
4005f65d6f4SNico Boehr
401531326aeSBalamuruhan Ssearch_qemu_binary ()
402531326aeSBalamuruhan S{
403531326aeSBalamuruhan S	local save_path=$PATH
404232f404aSAndrew Jones	local qemucmd qemu
405232f404aSAndrew Jones
406ee5a8a1aSAndrew Jones	: "${QEMU_ARCH:=$ARCH_NAME}"
407ee5a8a1aSAndrew Jones
408531326aeSBalamuruhan S	export PATH=$PATH:/usr/libexec
409ee5a8a1aSAndrew Jones	for qemucmd in ${QEMU:-qemu-system-$QEMU_ARCH qemu-kvm}; do
410232f404aSAndrew Jones		if $qemucmd --help 2>/dev/null | grep -q 'QEMU'; then
411232f404aSAndrew Jones			qemu="$qemucmd"
412531326aeSBalamuruhan S			break
413531326aeSBalamuruhan S		fi
414531326aeSBalamuruhan S	done
415531326aeSBalamuruhan S
416232f404aSAndrew Jones	if [ -z "$qemu" ]; then
417fcf4e0d9SRadim Krčmář		echo "A QEMU binary was not found." >&2
418fcf4e0d9SRadim Krčmář		echo "You can set a custom location by using the QEMU=<path> environment variable." >&2
419fcf4e0d9SRadim Krčmář		return 2
420531326aeSBalamuruhan S	fi
421232f404aSAndrew Jones	command -v $qemu
422531326aeSBalamuruhan S	export PATH=$save_path
423531326aeSBalamuruhan S}
4244da0bc9aSAndrew Jones
425c8764266SNicholas Piggininitrd_cleanup ()
426c8764266SNicholas Piggin{
427c8764266SNicholas Piggin	rm -f $KVM_UNIT_TESTS_ENV
428c8764266SNicholas Piggin	if [ "$KVM_UNIT_TESTS_ENV_OLD" ]; then
429b7e5dfd3SNicholas Piggin		export KVM_UNIT_TESTS_ENV
430b7e5dfd3SNicholas Piggin		KVM_UNIT_TESTS_ENV="$KVM_UNIT_TESTS_ENV_OLD"
431c8764266SNicholas Piggin	else
432c8764266SNicholas Piggin		unset KVM_UNIT_TESTS_ENV
433c8764266SNicholas Piggin	fi
434c8764266SNicholas Piggin	unset KVM_UNIT_TESTS_ENV_OLD
435c8764266SNicholas Piggin}
436c8764266SNicholas Piggin
4374da0bc9aSAndrew Jonesinitrd_create ()
4384da0bc9aSAndrew Jones{
439b16df9eeSAndrew Jones	if [ "$ENVIRON_DEFAULT" = "yes" ]; then
440c8764266SNicholas Piggin		trap_exit_push 'initrd_cleanup'
441b16df9eeSAndrew Jones		[ -f "$KVM_UNIT_TESTS_ENV" ] && export KVM_UNIT_TESTS_ENV_OLD="$KVM_UNIT_TESTS_ENV"
442b7e5dfd3SNicholas Piggin		export KVM_UNIT_TESTS_ENV
443b7e5dfd3SNicholas Piggin		KVM_UNIT_TESTS_ENV=$(mktemp)
444b16df9eeSAndrew Jones		env_params
445b16df9eeSAndrew Jones		env_file
446b16df9eeSAndrew Jones		env_errata || return $?
447b16df9eeSAndrew Jones	fi
4488b13a5b5SRadim Krčmář
4494da0bc9aSAndrew Jones	unset INITRD
45063dd93ecSAndrew Jones	[ -f "$KVM_UNIT_TESTS_ENV" ] && INITRD="-initrd $KVM_UNIT_TESTS_ENV"
4518b13a5b5SRadim Krčmář
452b16df9eeSAndrew Jones	return 0
4534da0bc9aSAndrew Jones}
4548ec99569SAndrew Jones
455b16df9eeSAndrew Jonesenv_add_params ()
4568ec99569SAndrew Jones{
457b16df9eeSAndrew Jones	local p
4588ec99569SAndrew Jones
459b16df9eeSAndrew Jones	for p in "$@"; do
460b16df9eeSAndrew Jones		if eval test -v $p; then
461b16df9eeSAndrew Jones			eval export "$p"
462b16df9eeSAndrew Jones		else
463b16df9eeSAndrew Jones			eval export "$p="
464b16df9eeSAndrew Jones		fi
465b16df9eeSAndrew Jones		grep "^$p=" <(env) >>$KVM_UNIT_TESTS_ENV
4668ec99569SAndrew Jones	done
467b16df9eeSAndrew Jones}
468b16df9eeSAndrew Jones
469b16df9eeSAndrew Jonesenv_params ()
470b16df9eeSAndrew Jones{
471b16df9eeSAndrew Jones	local qemu have_qemu
472b16df9eeSAndrew Jones	local _ rest
473b16df9eeSAndrew Jones
474b16df9eeSAndrew Jones	qemu=$(search_qemu_binary) && have_qemu=1
475b16df9eeSAndrew Jones
476b16df9eeSAndrew Jones	if [ "$have_qemu" ]; then
477b16df9eeSAndrew Jones		if [ -n "$ACCEL" ] || [ -n "$QEMU_ACCEL" ]; then
478b16df9eeSAndrew Jones			[ -n "$ACCEL" ] && QEMU_ACCEL=$ACCEL
479b16df9eeSAndrew Jones		fi
480b16df9eeSAndrew Jones		QEMU_VERSION_STRING="$($qemu -h | head -1)"
481*3df129a6SNicholas Piggin		# Shellcheck does not see QEMU_MAJOR|MINOR|MICRO are used
482*3df129a6SNicholas Piggin		# shellcheck disable=SC2034
483b16df9eeSAndrew Jones		IFS='[ .]' read -r _ _ _ QEMU_MAJOR QEMU_MINOR QEMU_MICRO rest <<<"$QEMU_VERSION_STRING"
484b16df9eeSAndrew Jones	fi
485b16df9eeSAndrew Jones	env_add_params QEMU_ACCEL QEMU_VERSION_STRING QEMU_MAJOR QEMU_MINOR QEMU_MICRO
486b16df9eeSAndrew Jones
487b16df9eeSAndrew Jones	KERNEL_VERSION_STRING=$(uname -r)
488b16df9eeSAndrew Jones	IFS=. read -r KERNEL_VERSION KERNEL_PATCHLEVEL rest <<<"$KERNEL_VERSION_STRING"
489b16df9eeSAndrew Jones	IFS=- read -r KERNEL_SUBLEVEL KERNEL_EXTRAVERSION <<<"$rest"
490b16df9eeSAndrew Jones	KERNEL_SUBLEVEL=${KERNEL_SUBLEVEL%%[!0-9]*}
491b16df9eeSAndrew Jones	KERNEL_EXTRAVERSION=${KERNEL_EXTRAVERSION%%[!0-9]*}
492b16df9eeSAndrew Jones	! [[ $KERNEL_SUBLEVEL =~ ^[0-9]+$ ]] && unset $KERNEL_SUBLEVEL
493b16df9eeSAndrew Jones	! [[ $KERNEL_EXTRAVERSION =~ ^[0-9]+$ ]] && unset $KERNEL_EXTRAVERSION
494b16df9eeSAndrew Jones	env_add_params KERNEL_VERSION_STRING KERNEL_VERSION KERNEL_PATCHLEVEL KERNEL_SUBLEVEL KERNEL_EXTRAVERSION
495b16df9eeSAndrew Jones}
496b16df9eeSAndrew Jones
497b16df9eeSAndrew Jonesenv_file ()
498b16df9eeSAndrew Jones{
499b16df9eeSAndrew Jones	local line var
500b16df9eeSAndrew Jones
501b16df9eeSAndrew Jones	[ ! -f "$KVM_UNIT_TESTS_ENV_OLD" ] && return
502b16df9eeSAndrew Jones
503ec11048dSNicholas Piggin	grep -E '^[[:blank:]]*[[:alpha:]_][[:alnum:]_]*=' "$KVM_UNIT_TESTS_ENV_OLD" | while IFS= read -r line ; do
504b16df9eeSAndrew Jones		var=${line%%=*}
505b16df9eeSAndrew Jones		if ! grep -q "^$var=" $KVM_UNIT_TESTS_ENV; then
506b16df9eeSAndrew Jones			eval export "$line"
507b16df9eeSAndrew Jones			grep "^$var=" <(env) >>$KVM_UNIT_TESTS_ENV
508b16df9eeSAndrew Jones		fi
509b16df9eeSAndrew Jones	done
510b16df9eeSAndrew Jones}
511b16df9eeSAndrew Jones
512b16df9eeSAndrew Jonesenv_errata ()
513b16df9eeSAndrew Jones{
514d50fa5a8SNicholas Piggin	local new_env
515d50fa5a8SNicholas Piggin
516ec2f5147SAlex Bennée	if [ "$ACCEL" = "tcg" ]; then
517ec2f5147SAlex Bennée		export "ERRATA_FORCE=y"
518ec2f5147SAlex Bennée	elif [ "$ERRATATXT" ] && [ ! -f "$ERRATATXT" ]; then
519b16df9eeSAndrew Jones		echo "$ERRATATXT not found. (ERRATATXT=$ERRATATXT)" >&2
520b16df9eeSAndrew Jones		return 2
521b16df9eeSAndrew Jones	elif [ "$ERRATATXT" ]; then
52270fcb64bSAndrew Jones		env_generate_errata
5238ec99569SAndrew Jones	fi
524d50fa5a8SNicholas Piggin	new_env=$(sort <(env | grep '^ERRATA_') <(grep '^ERRATA_' $KVM_UNIT_TESTS_ENV) | uniq -u)
525d50fa5a8SNicholas Piggin	echo "$new_env" >>$KVM_UNIT_TESTS_ENV
5268ec99569SAndrew Jones}
5278ec99569SAndrew Jones
52870fcb64bSAndrew Jonesenv_generate_errata ()
52970fcb64bSAndrew Jones{
53012a4328eSAndrew Jones	local line commit minver errata rest v p s x have
53170fcb64bSAndrew Jones
5321ea4709cSAndrew Jones	for line in $(grep -v '^#' "$ERRATATXT" | tr -d '[:blank:]' | cut -d: -f1,2); do
53370fcb64bSAndrew Jones		commit=${line%:*}
53470fcb64bSAndrew Jones		minver=${line#*:}
53570fcb64bSAndrew Jones
536171aa3a2SPeter Shier		test -z "$commit" && continue
53770fcb64bSAndrew Jones		errata="ERRATA_$commit"
538d1bc9395SAndrew Jones		[ -n "${!errata}" ] && continue
53970fcb64bSAndrew Jones
540d38b111bSJim Mattson		IFS=. read -r v p rest <<<"$minver"
541d38b111bSJim Mattson		IFS=- read -r s x <<<"$rest"
54270fcb64bSAndrew Jones		s=${s%%[!0-9]*}
54312a4328eSAndrew Jones		x=${x%%[!0-9]*}
54412a4328eSAndrew Jones
54512a4328eSAndrew Jones		if ! [[ $v =~ ^[0-9]+$ ]] || ! [[ $p =~ ^[0-9]+$ ]]; then
54612a4328eSAndrew Jones			echo "Bad minimum kernel version in $ERRATATXT, $minver"
5479806f62dSAndrew Jones			return 2
54812a4328eSAndrew Jones		fi
54912a4328eSAndrew Jones		! [[ $s =~ ^[0-9]+$ ]] && unset $s
55012a4328eSAndrew Jones		! [[ $x =~ ^[0-9]+$ ]] && unset $x
55170fcb64bSAndrew Jones
552b16df9eeSAndrew Jones		if (( $KERNEL_VERSION > $v ||
553b16df9eeSAndrew Jones		      ($KERNEL_VERSION == $v && $KERNEL_PATCHLEVEL > $p) )); then
55470fcb64bSAndrew Jones			have=y
555b16df9eeSAndrew Jones		elif (( $KERNEL_VERSION == $v && $KERNEL_PATCHLEVEL == $p )); then
556b16df9eeSAndrew Jones			if [ "$KERNEL_SUBLEVEL" ] && [ "$s" ]; then
557b16df9eeSAndrew Jones				if (( $KERNEL_SUBLEVEL > $s )); then
55870fcb64bSAndrew Jones					have=y
559b16df9eeSAndrew Jones				elif (( $KERNEL_SUBLEVEL == $s )); then
560b16df9eeSAndrew Jones					if [ "$KERNEL_EXTRAVERSION" ] && [ "$x" ]; then
561b16df9eeSAndrew Jones						if (( $KERNEL_EXTRAVERSION >= $x )); then
56212a4328eSAndrew Jones							have=y
56312a4328eSAndrew Jones						else
56412a4328eSAndrew Jones							have=n
56512a4328eSAndrew Jones						fi
56612a4328eSAndrew Jones					elif [ "$x" ] && (( $x != 0 )); then
56712a4328eSAndrew Jones						have=n
56812a4328eSAndrew Jones					else
56912a4328eSAndrew Jones						have=y
57012a4328eSAndrew Jones					fi
57170fcb64bSAndrew Jones				else
57270fcb64bSAndrew Jones					have=n
57370fcb64bSAndrew Jones				fi
57470fcb64bSAndrew Jones			elif [ "$s" ] && (( $s != 0 )); then
57570fcb64bSAndrew Jones				have=n
57670fcb64bSAndrew Jones			else
57770fcb64bSAndrew Jones				have=y
57870fcb64bSAndrew Jones			fi
57970fcb64bSAndrew Jones		else
58070fcb64bSAndrew Jones			have=n
58170fcb64bSAndrew Jones		fi
58270fcb64bSAndrew Jones		eval export "$errata=$have"
58370fcb64bSAndrew Jones	done
58470fcb64bSAndrew Jones}
58570fcb64bSAndrew Jones
5868ec99569SAndrew Jonestrap_exit_push ()
5878ec99569SAndrew Jones{
588b7e5dfd3SNicholas Piggin	local old_exit
589b7e5dfd3SNicholas Piggin
590b7e5dfd3SNicholas Piggin	old_exit=$(trap -p EXIT | sed "s/^[^']*'//;s/'[^']*$//")
5918ec99569SAndrew Jones	trap -- "$1; $old_exit" EXIT
5928ec99569SAndrew Jones}
593f4d99928SRadim Krčmář
594f4d99928SRadim Krčmářkvm_available ()
595f4d99928SRadim Krčmář{
596f4d99928SRadim Krčmář	[ -c /dev/kvm ] ||
597f4d99928SRadim Krčmář		return 1
598f4d99928SRadim Krčmář
599f4d99928SRadim Krčmář	[ "$HOST" = "$ARCH_NAME" ] ||
600d76bf076SAndrew Jones		( [ "$HOST" = aarch64 ] && [ "$ARCH" = arm ] ) ||
601d76bf076SAndrew Jones		( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] )
602f4d99928SRadim Krčmář}
603f4d99928SRadim Krčmář
6047edd698eSRoman Bolshakovhvf_available ()
6057edd698eSRoman Bolshakov{
6067edd698eSRoman Bolshakov	[ "$(sysctl -n kern.hv_support 2>/dev/null)" = "1" ] || return 1
6077edd698eSRoman Bolshakov	[ "$HOST" = "$ARCH_NAME" ] ||
6087edd698eSRoman Bolshakov		( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] )
6097edd698eSRoman Bolshakov}
6107edd698eSRoman Bolshakov
61101e047d0SGavin Shanset_qemu_accelerator ()
612f4d99928SRadim Krčmář{
613*3df129a6SNicholas Piggin	# Shellcheck does not see ACCEL_PROPS is used
614*3df129a6SNicholas Piggin	# shellcheck disable=SC2034
61501e047d0SGavin Shan	ACCEL_PROPS=${ACCEL#"${ACCEL%%,*}"}
61601e047d0SGavin Shan	ACCEL=${ACCEL%%,*}
61701e047d0SGavin Shan
618f4d99928SRadim Krčmář	if [ "$ACCEL" = "kvm" ] && ! kvm_available; then
619f4d99928SRadim Krčmář		echo "KVM is needed, but not available on this host" >&2
620f4d99928SRadim Krčmář		return 2
621f4d99928SRadim Krčmář	fi
6227edd698eSRoman Bolshakov	if [ "$ACCEL" = "hvf" ] && ! hvf_available; then
6237edd698eSRoman Bolshakov		echo "HVF is needed, but not available on this host" >&2
6247edd698eSRoman Bolshakov		return 2
6257edd698eSRoman Bolshakov	fi
626f4d99928SRadim Krčmář
62701e047d0SGavin Shan	if [ -z "$ACCEL" ]; then
62801e047d0SGavin Shan		if kvm_available; then
62901e047d0SGavin Shan			ACCEL="kvm"
6307edd698eSRoman Bolshakov		elif hvf_available; then
63101e047d0SGavin Shan			ACCEL="hvf"
632f4d99928SRadim Krčmář		else
63301e047d0SGavin Shan			ACCEL="tcg"
634f4d99928SRadim Krčmář		fi
63501e047d0SGavin Shan	fi
63601e047d0SGavin Shan
63701e047d0SGavin Shan	return 0
638f4d99928SRadim Krčmář}
639