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 while IFS= read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]} 89 do 90 if [ -n "$capture_events" ]; then 91 capture=0 92 local evname 93 for evname in $capture_events 94 do 95 case ${resp} in 96 *\"event\":\ \"${evname}\"* ) capture=1 ;; 97 esac 98 done 99 if [ $capture = 1 ]; 100 then 101 ev=$(echo "${resp}" | tr -d '\r' | tr % .) 102 QEMU_EVENTS="${QEMU_EVENTS:+${QEMU_EVENTS}%}${ev}" 103 if [ -n "$only_capture_events" ]; then 104 return 105 else 106 continue 107 fi 108 fi 109 fi 110 if [ -n "$only_capture_events" ]; then 111 echo "Only expected $capture_events but got ${resp}" 112 exit 1 113 fi 114 115 if [ -z "${silent}" ] && [ -z "${mismatch_only}" ]; then 116 echo "${resp}" | _filter_testdir | _filter_qemu \ 117 | _filter_qemu_io | _filter_qmp | _filter_hmp 118 fi 119 if [ -n "${failure_match}" ]; then 120 grep -q "${failure_match}" < <(echo "${resp}") 121 if [ $? -eq 0 ]; then 122 timeout= 123 break 124 fi 125 fi 126 grep -q "${success_match}" < <(echo "${resp}") 127 if [ $? -eq 0 ]; then 128 return 129 fi 130 if [ -z "${silent}" ] && [ -n "${mismatch_only}" ]; then 131 echo "${resp}" | _filter_testdir | _filter_qemu \ 132 | _filter_qemu_io | _filter_qmp | _filter_hmp 133 fi 134 135 done 136 QEMU_STATUS[$h]=-1 137 if [ -z "${qemu_error_no_exit}" ]; then 138 if [ -n "${timeout}" ]; then 139 echo "Timeout waiting for ${success_match} on handle ${h}" 140 else 141 echo "Wrong response matching ${failure_match} on handle ${h}" 142 fi 143 exit 1 # Timeout or wrong match mean the test failed 144 fi 145} 146 147 148# Sends QMP or HMP command to QEMU, and waits for the expected response 149# 150# $1: QEMU handle to use 151# $2: String of the QMP command to send 152# ${@: -1} (Last string passed) 153# String that the QEMU response should contain. If it is a null 154# string, do not wait for a response 155# 156# Set qemu_cmd_repeat to the number of times to repeat the cmd 157# until either timeout, or a response. If it is not set, or <=0, 158# then the command is only sent once. 159# 160# If neither $silent nor $mismatch_only is set, and $cmd begins with '{', 161# echo the command before sending it the first time. 162# 163# If $qemu_error_no_exit is set, then even if the expected response 164# is not seen, we will not exit. $QEMU_STATUS[$1] will be set it -1 in 165# that case. 166# 167# If $success_or_failure is set, then the last two strings are the 168# strings the response will be scanned for. The first of the two 169# indicates success, the latter indicates failure. Failure is handled 170# like a timeout. 171_send_qemu_cmd() 172{ 173 local h=${1} 174 local count=1 175 local cmd= 176 local use_error=${qemu_error_no_exit} 177 shift 178 179 if [ ${qemu_cmd_repeat} -gt 0 ] 2>/dev/null; then 180 count=${qemu_cmd_repeat} 181 use_error="no" 182 fi 183 184 cmd=$1 185 shift 186 187 # Display QMP being sent, but not HMP (since HMP already echoes its 188 # input back to output); decide based on leading '{' 189 if [ -z "$silent" ] && [ -z "$mismatch_only" ] && 190 [ "$cmd" != "${cmd#\{}" ]; then 191 echo "${cmd}" | _filter_testdir | _filter_imgfmt 192 fi 193 while [ ${count} -gt 0 ] 194 do 195 echo "${cmd}" >&${QEMU_IN[${h}]} 196 if [ -n "${1}" ]; then 197 if [ -z "${success_or_failure}" ]; then 198 qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" 199 else 200 qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" "${2}" 201 fi 202 if [ ${QEMU_STATUS[$h]} -eq 0 ]; then 203 return 204 fi 205 fi 206 let count--; 207 done 208 if [ ${QEMU_STATUS[$h]} -ne 0 ] && [ -z "${qemu_error_no_exit}" ]; then 209 echo "Timeout waiting for command ${1} response on handle ${h}" 210 exit 1 #Timeout means the test failed 211 fi 212} 213 214 215# Check event cache for a named QMP event 216# 217# Input parameters: 218# $1: Name of the QMP event to check for 219# 220# Checks if the named QMP event that was previously captured 221# into $QEMU_EVENTS. When matched, the QMP event will be echoed 222# and the $matched variable set to 1. 223# 224# _wait_event is more suitable for test usage in most cases 225_check_cached_events() 226{ 227 local evname=${1} 228 229 local match="\"event\": \"$evname\"" 230 231 matched=0 232 if [ -n "$QEMU_EVENTS" ]; then 233 CURRENT_QEMU_EVENTS=$QEMU_EVENTS 234 QEMU_EVENTS= 235 old_IFS=$IFS 236 IFS="%" 237 for ev in $CURRENT_QEMU_EVENTS 238 do 239 grep -q "$match" < <(echo "${ev}") 240 if [ $? -eq 0 ] && [ $matched = 0 ]; then 241 echo "${ev}" | _filter_testdir | _filter_qemu \ 242 | _filter_qemu_io | _filter_qmp | _filter_hmp 243 matched=1 244 else 245 QEMU_EVENTS="${QEMU_EVENTS:+${QEMU_EVENTS}%}${ev}" 246 fi 247 done 248 IFS=$old_IFS 249 fi 250} 251 252# Wait for a named QMP event 253# 254# Input parameters: 255# $1: QEMU handle to use 256# $2: Name of the QMP event to wait for 257# 258# Checks if the named QMP even was previously captured 259# into $QEMU_EVENTS. If none are present, then waits for the 260# event to arrive on the QMP channel. When matched, the QMP 261# event will be echoed 262_wait_event() 263{ 264 local h=${1} 265 local evname=${2} 266 267 while true 268 do 269 _check_cached_events $evname 270 271 if [ $matched = 1 ]; 272 then 273 return 274 fi 275 276 only_capture_events=1 qemu_error_no_exit=1 _timed_wait_for ${h} 277 278 if [ ${QEMU_STATUS[$h]} -ne 0 ] ; then 279 echo "Timeout waiting for event ${evname} on handle ${h}" 280 exit 1 #Timeout means the test failed 281 fi 282 done 283} 284 285# Launch a QEMU process. 286# 287# Input parameters: 288# $qemu_comm_method: set this variable to 'monitor' (case insensitive) 289# to use the QEMU HMP monitor for communication. 290# Otherwise, the default of QMP is used. 291# $qmp_pretty: Set this variable to 'y' to enable QMP pretty printing. 292# $keep_stderr: Set this variable to 'y' to keep QEMU's stderr output on stderr. 293# If this variable is empty, stderr will be redirected to stdout. 294# Returns: 295# $QEMU_HANDLE: set to a handle value to communicate with this QEMU instance. 296# 297_launch_qemu() 298{ 299 local comm= 300 local fifo_out= 301 local fifo_in= 302 303 if (shopt -s nocasematch; [[ "${qemu_comm_method}" == "monitor" ]]) 304 then 305 comm="-monitor stdio" 306 else 307 local qemu_comm_method="qmp" 308 if [ "$qmp_pretty" = "y" ]; then 309 comm="-monitor none -qmp-pretty stdio" 310 else 311 comm="-monitor none -qmp stdio" 312 fi 313 fi 314 315 fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE} 316 fifo_in=${QEMU_FIFO_IN}_${_QEMU_HANDLE} 317 mkfifo "${fifo_out}" 318 mkfifo "${fifo_in}" 319 320 object_options= 321 if [ -n "$IMGKEYSECRET" ]; then 322 object_options="--object secret,id=keysec0,data=$IMGKEYSECRET" 323 fi 324 325 if [ -z "$keep_stderr" ]; then 326 QEMU_NEED_PID='y'\ 327 ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ 328 2>&1 \ 329 <"${fifo_in}" & 330 elif [ "$keep_stderr" = "y" ]; then 331 QEMU_NEED_PID='y'\ 332 ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ 333 <"${fifo_in}" & 334 else 335 exit 1 336 fi 337 338 if [[ "${BASH_VERSINFO[0]}" -ge "5" || 339 ("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]] 340 then 341 # bash >= 4.1 required for automatic fd 342 exec {_out_fd}<"${fifo_out}" 343 exec {_in_fd}>"${fifo_in}" 344 else 345 let _out_fd++ 346 let _in_fd++ 347 eval "exec ${_out_fd}<'${fifo_out}'" 348 eval "exec ${_in_fd}>'${fifo_in}'" 349 fi 350 351 QEMU_OUT[${_QEMU_HANDLE}]=${_out_fd} 352 QEMU_IN[${_QEMU_HANDLE}]=${_in_fd} 353 QEMU_STATUS[${_QEMU_HANDLE}]=0 354 355 if [ "${qemu_comm_method}" == "qmp" ] 356 then 357 # Don't print response, since it has version information in it 358 silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities" 359 if [ "$qmp_pretty" = "y" ]; then 360 silent=yes _timed_wait_for ${_QEMU_HANDLE} "^}" 361 fi 362 fi 363 QEMU_HANDLE=${_QEMU_HANDLE} 364 let _QEMU_HANDLE++ 365} 366 367 368# Silently kills the QEMU process 369# 370# If $wait is set to anything other than the empty string, the process will not 371# be killed but only waited for, and any output will be forwarded to stdout. If 372# $wait is empty, the process will be killed and all output will be suppressed. 373_cleanup_qemu() 374{ 375 # QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices 376 for i in "${!QEMU_OUT[@]}" 377 do 378 local QEMU_PID 379 if [ -f "${QEMU_TEST_DIR}/qemu-${i}.pid" ]; then 380 read QEMU_PID < "${QEMU_TEST_DIR}/qemu-${i}.pid" 381 rm -f "${QEMU_TEST_DIR}/qemu-${i}.pid" 382 if [ -z "${wait}" ] && [ -n "${QEMU_PID}" ]; then 383 kill -KILL ${QEMU_PID} 2>/dev/null 384 fi 385 if [ -n "${QEMU_PID}" ]; then 386 wait ${QEMU_PID} 2>/dev/null # silent kill 387 fi 388 fi 389 390 if [ -n "${wait}" ]; then 391 cat <&${QEMU_OUT[$i]} | _filter_testdir | _filter_qemu \ 392 | _filter_qemu_io | _filter_qmp | _filter_hmp 393 fi 394 rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}" 395 eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors 396 eval "exec ${QEMU_OUT[$i]}<&-" 397 398 unset QEMU_IN[$i] 399 unset QEMU_OUT[$i] 400 done 401} 402