common.qemu (12836B)
1#!/usr/bin/env bash 2# 3# This allows for launching of multiple QEMU instances, with independent 4# communication possible to each instance. 5# 6# Each instance can choose, at launch, to use either the QMP or the 7# HMP (monitor) interface. 8# 9# All instances are cleaned up via _cleanup_qemu, including killing the 10# running qemu instance. 11# 12# Copyright (C) 2014 Red Hat, Inc. 13# 14# This program is free software; you can redistribute it and/or modify 15# it under the terms of the GNU General Public License as published by 16# the Free Software Foundation; either version 2 of the License, or 17# (at your option) any later version. 18# 19# This program is distributed in the hope that it will be useful, 20# but WITHOUT ANY WARRANTY; without even the implied warranty of 21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22# GNU General Public License for more details. 23# 24# You should have received a copy of the GNU General Public License 25# along with this program. If not, see <http://www.gnu.org/licenses/>. 26# 27 28QEMU_COMM_TIMEOUT=10 29 30QEMU_FIFO_IN="${QEMU_TEST_DIR}/qmp-in-$$" 31QEMU_FIFO_OUT="${QEMU_TEST_DIR}/qmp-out-$$" 32 33QEMU_HANDLE=0 34export _QEMU_HANDLE=0 35 36# If bash version is >= 4.1, these will be overwritten and dynamic 37# file descriptor values assigned. 38_out_fd=3 39_in_fd=4 40 41# Wait for expected QMP response from QEMU. Will time out 42# after 10 seconds, which counts as failure. 43# 44# Override QEMU_COMM_TIMEOUT for a timeout different than the 45# default 10 seconds 46# 47# $1: The handle to use 48# $2+ All remaining arguments comprise the string to search for 49# in the response. 50# 51# If $silent is set to anything but an empty string, then 52# response is not echoed out. 53# If $mismatch_only is set, only non-matching responses will 54# be echoed. 55# 56# If $capture_events is non-empty, then any QMP event names it lists 57# will not be echoed out, but instead collected in the $QEMU_EVENTS 58# variable. The _wait_event function can later be used to receive 59# the cached events. 60# 61# If $only_capture_events is set to anything but an empty string, 62# then an error will be raised if a QMP message is seen which is 63# not an event listed in $capture_events. 64# 65# If $success_or_failure is set, the meaning of the arguments is 66# changed as follows: 67# $2: A string to search for in the response; if found, this indicates 68# success and ${QEMU_STATUS[$1]} is set to 0. 69# $3: A string to search for in the response; if found, this indicates 70# failure and the test is either aborted (if $qemu_error_no_exit 71# is not set) or ${QEMU_STATUS[$1]} is set to -1 (otherwise). 72_timed_wait_for() 73{ 74 local h=${1} 75 shift 76 77 if [ -z "${success_or_failure}" ]; then 78 success_match=${*} 79 failure_match= 80 else 81 success_match=${1} 82 failure_match=${2} 83 fi 84 85 timeout=yes 86 87 QEMU_STATUS[$h]=0 88 read_timeout="-t ${QEMU_COMM_TIMEOUT}" 89 if [ -n "${GDB_OPTIONS}" ]; then 90 read_timeout= 91 fi 92 93 while IFS= read ${read_timeout} resp <&${QEMU_OUT[$h]} 94 do 95 if [ -n "$capture_events" ]; then 96 capture=0 97 local evname 98 for evname in $capture_events 99 do 100 case ${resp} in 101 *\"event\":\ \"${evname}\"* ) capture=1 ;; 102 esac 103 done 104 if [ $capture = 1 ]; 105 then 106 ev=$(echo "${resp}" | tr -d '\r' | tr % .) 107 QEMU_EVENTS="${QEMU_EVENTS:+${QEMU_EVENTS}%}${ev}" 108 if [ -n "$only_capture_events" ]; then 109 return 110 else 111 continue 112 fi 113 fi 114 fi 115 if [ -n "$only_capture_events" ]; then 116 echo "Only expected $capture_events but got ${resp}" 117 exit 1 118 fi 119 120 if [ -z "${silent}" ] && [ -z "${mismatch_only}" ]; then 121 echo "${resp}" | _filter_testdir | _filter_qemu \ 122 | _filter_qemu_io | _filter_qmp | _filter_hmp 123 fi 124 if [ -n "${failure_match}" ]; then 125 grep -q "${failure_match}" < <(echo "${resp}") 126 if [ $? -eq 0 ]; then 127 timeout= 128 break 129 fi 130 fi 131 grep -q "${success_match}" < <(echo "${resp}") 132 if [ $? -eq 0 ]; then 133 return 134 fi 135 if [ -z "${silent}" ] && [ -n "${mismatch_only}" ]; then 136 echo "${resp}" | _filter_testdir | _filter_qemu \ 137 | _filter_qemu_io | _filter_qmp | _filter_hmp 138 fi 139 140 done 141 QEMU_STATUS[$h]=-1 142 if [ -z "${qemu_error_no_exit}" ]; then 143 if [ -n "${timeout}" ]; then 144 echo "Timeout waiting for ${success_match} on handle ${h}" 145 else 146 echo "Wrong response matching ${failure_match} on handle ${h}" 147 fi 148 exit 1 # Timeout or wrong match mean the test failed 149 fi 150} 151 152 153# Sends QMP or HMP command to QEMU, and waits for the expected response 154# 155# $1: QEMU handle to use 156# $2: String of the QMP command to send 157# ${@: -1} (Last string passed) 158# String that the QEMU response should contain. If it is a null 159# string, do not wait for a response 160# 161# Set qemu_cmd_repeat to the number of times to repeat the cmd 162# until either timeout, or a response. If it is not set, or <=0, 163# then the command is only sent once. 164# 165# If neither $silent nor $mismatch_only is set, and $cmd begins with '{', 166# echo the command before sending it the first time. 167# 168# If $qemu_error_no_exit is set, then even if the expected response 169# is not seen, we will not exit. $QEMU_STATUS[$1] will be set it -1 in 170# that case. 171# 172# If $success_or_failure is set, then the last two strings are the 173# strings the response will be scanned for. The first of the two 174# indicates success, the latter indicates failure. Failure is handled 175# like a timeout. 176_send_qemu_cmd() 177{ 178 local h=${1} 179 local count=1 180 local cmd= 181 local use_error=${qemu_error_no_exit} 182 shift 183 184 if [ ${qemu_cmd_repeat} -gt 0 ] 2>/dev/null; then 185 count=${qemu_cmd_repeat} 186 use_error="no" 187 fi 188 189 cmd=$1 190 shift 191 192 # Display QMP being sent, but not HMP (since HMP already echoes its 193 # input back to output); decide based on leading '{' 194 if [ -z "$silent" ] && [ -z "$mismatch_only" ] && 195 [ "$cmd" != "${cmd#\{}" ]; then 196 echo "${cmd}" | _filter_testdir | _filter_imgfmt 197 fi 198 while [ ${count} -gt 0 ] 199 do 200 echo "${cmd}" >&${QEMU_IN[${h}]} 201 if [ -n "${1}" ]; then 202 if [ -z "${success_or_failure}" ]; then 203 qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" 204 else 205 qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" "${2}" 206 fi 207 if [ ${QEMU_STATUS[$h]} -eq 0 ]; then 208 return 209 fi 210 fi 211 let count--; 212 done 213 if [ ${QEMU_STATUS[$h]} -ne 0 ] && [ -z "${qemu_error_no_exit}" ]; then 214 echo "Timeout waiting for command ${1} response on handle ${h}" 215 exit 1 #Timeout means the test failed 216 fi 217} 218 219 220# Check event cache for a named QMP event 221# 222# Input parameters: 223# $1: Name of the QMP event to check for 224# 225# Checks if the named QMP event that was previously captured 226# into $QEMU_EVENTS. When matched, the QMP event will be echoed 227# and the $matched variable set to 1. 228# 229# _wait_event is more suitable for test usage in most cases 230_check_cached_events() 231{ 232 local evname=${1} 233 234 local match="\"event\": \"$evname\"" 235 236 matched=0 237 if [ -n "$QEMU_EVENTS" ]; then 238 CURRENT_QEMU_EVENTS=$QEMU_EVENTS 239 QEMU_EVENTS= 240 old_IFS=$IFS 241 IFS="%" 242 for ev in $CURRENT_QEMU_EVENTS 243 do 244 grep -q "$match" < <(echo "${ev}") 245 if [ $? -eq 0 ] && [ $matched = 0 ]; then 246 echo "${ev}" | _filter_testdir | _filter_qemu \ 247 | _filter_qemu_io | _filter_qmp | _filter_hmp 248 matched=1 249 else 250 QEMU_EVENTS="${QEMU_EVENTS:+${QEMU_EVENTS}%}${ev}" 251 fi 252 done 253 IFS=$old_IFS 254 fi 255} 256 257# Wait for a named QMP event 258# 259# Input parameters: 260# $1: QEMU handle to use 261# $2: Name of the QMP event to wait for 262# 263# Checks if the named QMP even was previously captured 264# into $QEMU_EVENTS. If none are present, then waits for the 265# event to arrive on the QMP channel. When matched, the QMP 266# event will be echoed 267_wait_event() 268{ 269 local h=${1} 270 local evname=${2} 271 272 while true 273 do 274 _check_cached_events $evname 275 276 if [ $matched = 1 ]; 277 then 278 return 279 fi 280 281 only_capture_events=1 qemu_error_no_exit=1 _timed_wait_for ${h} 282 283 if [ ${QEMU_STATUS[$h]} -ne 0 ] ; then 284 echo "Timeout waiting for event ${evname} on handle ${h}" 285 exit 1 #Timeout means the test failed 286 fi 287 done 288} 289 290# Launch a QEMU process. 291# 292# Input parameters: 293# $qemu_comm_method: set this variable to 'monitor' (case insensitive) 294# to use the QEMU HMP monitor for communication. 295# Otherwise, the default of QMP is used. 296# $qmp_pretty: Set this variable to 'y' to enable QMP pretty printing. 297# $keep_stderr: Set this variable to 'y' to keep QEMU's stderr output on stderr. 298# If this variable is empty, stderr will be redirected to stdout. 299# Returns: 300# $QEMU_HANDLE: set to a handle value to communicate with this QEMU instance. 301# 302_launch_qemu() 303{ 304 local comm= 305 local fifo_out= 306 local fifo_in= 307 308 if (shopt -s nocasematch; [[ "${qemu_comm_method}" == "monitor" ]]) 309 then 310 comm="-monitor stdio" 311 else 312 local qemu_comm_method="qmp" 313 if [ "$qmp_pretty" = "y" ]; then 314 comm="-monitor none -qmp-pretty stdio" 315 else 316 comm="-monitor none -qmp stdio" 317 fi 318 fi 319 320 fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE} 321 fifo_in=${QEMU_FIFO_IN}_${_QEMU_HANDLE} 322 mkfifo "${fifo_out}" 323 mkfifo "${fifo_in}" 324 325 object_options= 326 if [ -n "$IMGKEYSECRET" ]; then 327 object_options="--object secret,id=keysec0,data=$IMGKEYSECRET" 328 fi 329 330 if [ -z "$keep_stderr" ]; then 331 QEMU_NEED_PID='y'\ 332 ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ 333 2>&1 \ 334 <"${fifo_in}" & 335 elif [ "$keep_stderr" = "y" ]; then 336 QEMU_NEED_PID='y'\ 337 ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ 338 <"${fifo_in}" & 339 else 340 exit 1 341 fi 342 343 if [[ "${BASH_VERSINFO[0]}" -ge "5" || 344 ("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]] 345 then 346 # bash >= 4.1 required for automatic fd 347 exec {_out_fd}<"${fifo_out}" 348 exec {_in_fd}>"${fifo_in}" 349 else 350 let _out_fd++ 351 let _in_fd++ 352 eval "exec ${_out_fd}<'${fifo_out}'" 353 eval "exec ${_in_fd}>'${fifo_in}'" 354 fi 355 356 QEMU_OUT[${_QEMU_HANDLE}]=${_out_fd} 357 QEMU_IN[${_QEMU_HANDLE}]=${_in_fd} 358 QEMU_STATUS[${_QEMU_HANDLE}]=0 359 360 if [ "${qemu_comm_method}" == "qmp" ] 361 then 362 # Don't print response, since it has version information in it 363 silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities" 364 if [ "$qmp_pretty" = "y" ]; then 365 silent=yes _timed_wait_for ${_QEMU_HANDLE} "^}" 366 fi 367 fi 368 QEMU_HANDLE=${_QEMU_HANDLE} 369 let _QEMU_HANDLE++ 370} 371 372 373# Silently kills the QEMU process 374# 375# If $wait is set to anything other than the empty string, the process will not 376# be killed but only waited for, and any output will be forwarded to stdout. If 377# $wait is empty, the process will be killed and all output will be suppressed. 378_cleanup_qemu() 379{ 380 # QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices 381 for i in "${!QEMU_OUT[@]}" 382 do 383 local QEMU_PID 384 if [ -f "${QEMU_TEST_DIR}/qemu-${i}.pid" ]; then 385 read QEMU_PID < "${QEMU_TEST_DIR}/qemu-${i}.pid" 386 rm -f "${QEMU_TEST_DIR}/qemu-${i}.pid" 387 if [ -z "${wait}" ] && [ -n "${QEMU_PID}" ]; then 388 kill -KILL ${QEMU_PID} 2>/dev/null 389 fi 390 if [ -n "${QEMU_PID}" ]; then 391 wait ${QEMU_PID} 2>/dev/null # silent kill 392 fi 393 fi 394 395 if [ -n "${wait}" ]; then 396 cat <&${QEMU_OUT[$i]} | _filter_testdir | _filter_qemu \ 397 | _filter_qemu_io | _filter_qmp | _filter_hmp 398 fi 399 rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}" 400 eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors 401 eval "exec ${QEMU_OUT[$i]}<&-" 402 403 unset QEMU_IN[$i] 404 unset QEMU_OUT[$i] 405 done 406}