]>
Commit | Line | Data |
---|---|---|
11a82d14 | 1 | #!/usr/bin/env bash |
e940bc13 JC |
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 | ||
28 | QEMU_COMM_TIMEOUT=10 | |
29 | ||
846a1d11 JC |
30 | QEMU_FIFO_IN="${QEMU_TEST_DIR}/qmp-in-$$" |
31 | QEMU_FIFO_OUT="${QEMU_TEST_DIR}/qmp-out-$$" | |
e940bc13 | 32 | |
e940bc13 | 33 | QEMU_HANDLE=0 |
cce293a2 | 34 | export _QEMU_HANDLE=0 |
e940bc13 JC |
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. | |
a2339699 JC |
53 | # If $mismatch_only is set, only non-matching responses will |
54 | # be echoed. | |
81c6ddf4 HR |
55 | # |
56 | # If $success_or_failure is set, the meaning of the arguments is | |
57 | # changed as follows: | |
58 | # $2: A string to search for in the response; if found, this indicates | |
59 | # success and ${QEMU_STATUS[$1]} is set to 0. | |
60 | # $3: A string to search for in the response; if found, this indicates | |
61 | # failure and the test is either aborted (if $qemu_error_no_exit | |
62 | # is not set) or ${QEMU_STATUS[$1]} is set to -1 (otherwise). | |
8cedcffd | 63 | _timed_wait_for() |
e940bc13 JC |
64 | { |
65 | local h=${1} | |
66 | shift | |
67 | ||
81c6ddf4 HR |
68 | if [ -z "${success_or_failure}" ]; then |
69 | success_match=${*} | |
70 | failure_match= | |
71 | else | |
72 | success_match=${1} | |
73 | failure_match=${2} | |
74 | fi | |
75 | ||
76 | timeout=yes | |
77 | ||
e940bc13 | 78 | QEMU_STATUS[$h]=0 |
72538537 | 79 | while IFS= read -t ${QEMU_COMM_TIMEOUT} resp <&${QEMU_OUT[$h]} |
e940bc13 | 80 | do |
a2339699 | 81 | if [ -z "${silent}" ] && [ -z "${mismatch_only}" ]; then |
e940bc13 | 82 | echo "${resp}" | _filter_testdir | _filter_qemu \ |
69404d9e | 83 | | _filter_qemu_io | _filter_qmp | _filter_hmp |
e940bc13 | 84 | fi |
81c6ddf4 HR |
85 | if [ -n "${failure_match}" ]; then |
86 | grep -q "${failure_match}" < <(echo "${resp}") | |
87 | if [ $? -eq 0 ]; then | |
88 | timeout= | |
89 | break | |
90 | fi | |
91 | fi | |
92 | grep -q "${success_match}" < <(echo "${resp}") | |
e940bc13 JC |
93 | if [ $? -eq 0 ]; then |
94 | return | |
81c6ddf4 HR |
95 | fi |
96 | if [ -z "${silent}" ] && [ -n "${mismatch_only}" ]; then | |
a2339699 JC |
97 | echo "${resp}" | _filter_testdir | _filter_qemu \ |
98 | | _filter_qemu_io | _filter_qmp | _filter_hmp | |
e940bc13 | 99 | fi |
a2339699 | 100 | |
e940bc13 JC |
101 | done |
102 | QEMU_STATUS[$h]=-1 | |
103 | if [ -z "${qemu_error_no_exit}" ]; then | |
81c6ddf4 HR |
104 | if [ -n "${timeout}" ]; then |
105 | echo "Timeout waiting for ${success_match} on handle ${h}" | |
106 | else | |
107 | echo "Wrong response matching ${failure_match} on handle ${h}" | |
108 | fi | |
109 | exit 1 # Timeout or wrong match mean the test failed | |
e940bc13 JC |
110 | fi |
111 | } | |
112 | ||
113 | ||
114 | # Sends QMP or HMP command to QEMU, and waits for the expected response | |
115 | # | |
116 | # $1: QEMU handle to use | |
117 | # $2: String of the QMP command to send | |
118 | # ${@: -1} (Last string passed) | |
119 | # String that the QEMU response should contain. If it is a null | |
120 | # string, do not wait for a response | |
121 | # | |
122 | # Set qemu_cmd_repeat to the number of times to repeat the cmd | |
123 | # until either timeout, or a response. If it is not set, or <=0, | |
124 | # then the command is only sent once. | |
125 | # | |
a98b1a1f EB |
126 | # If neither $silent nor $mismatch_only is set, and $cmd begins with '{', |
127 | # echo the command before sending it the first time. | |
128 | # | |
e940bc13 JC |
129 | # If $qemu_error_no_exit is set, then even if the expected response |
130 | # is not seen, we will not exit. $QEMU_STATUS[$1] will be set it -1 in | |
131 | # that case. | |
81c6ddf4 HR |
132 | # |
133 | # If $success_or_failure is set, then the last two strings are the | |
134 | # strings the response will be scanned for. The first of the two | |
135 | # indicates success, the latter indicates failure. Failure is handled | |
136 | # like a timeout. | |
8cedcffd | 137 | _send_qemu_cmd() |
e940bc13 JC |
138 | { |
139 | local h=${1} | |
140 | local count=1 | |
141 | local cmd= | |
142 | local use_error=${qemu_error_no_exit} | |
143 | shift | |
144 | ||
145 | if [ ${qemu_cmd_repeat} -gt 0 ] 2>/dev/null; then | |
146 | count=${qemu_cmd_repeat} | |
147 | use_error="no" | |
148 | fi | |
5d831be2 | 149 | # This array element extraction is done to accommodate pathnames with spaces |
81c6ddf4 HR |
150 | if [ -z "${success_or_failure}" ]; then |
151 | cmd=${@: 1:${#@}-1} | |
152 | shift $(($# - 1)) | |
153 | else | |
154 | cmd=${@: 1:${#@}-2} | |
155 | shift $(($# - 2)) | |
156 | fi | |
e940bc13 | 157 | |
a98b1a1f EB |
158 | # Display QMP being sent, but not HMP (since HMP already echoes its |
159 | # input back to output); decide based on leading '{' | |
160 | if [ -z "$silent" ] && [ -z "$mismatch_only" ] && | |
161 | [ "$cmd" != "${cmd#\{}" ]; then | |
162 | echo "${cmd}" | _filter_testdir | _filter_imgfmt | |
163 | fi | |
e940bc13 JC |
164 | while [ ${count} -gt 0 ] |
165 | do | |
166 | echo "${cmd}" >&${QEMU_IN[${h}]} | |
167 | if [ -n "${1}" ]; then | |
81c6ddf4 HR |
168 | if [ -z "${success_or_failure}" ]; then |
169 | qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" | |
170 | else | |
171 | qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" "${2}" | |
172 | fi | |
e940bc13 JC |
173 | if [ ${QEMU_STATUS[$h]} -eq 0 ]; then |
174 | return | |
175 | fi | |
176 | fi | |
177 | let count--; | |
178 | done | |
179 | if [ ${QEMU_STATUS[$h]} -ne 0 ] && [ -z "${qemu_error_no_exit}" ]; then | |
180 | echo "Timeout waiting for ${1} on handle ${h}" | |
181 | exit 1 #Timeout means the test failed | |
182 | fi | |
183 | } | |
184 | ||
185 | ||
186 | # Launch a QEMU process. | |
187 | # | |
188 | # Input parameters: | |
189 | # $qemu_comm_method: set this variable to 'monitor' (case insensitive) | |
190 | # to use the QEMU HMP monitor for communication. | |
191 | # Otherwise, the default of QMP is used. | |
72538537 | 192 | # $qmp_pretty: Set this variable to 'y' to enable QMP pretty printing. |
15cfba69 HR |
193 | # $keep_stderr: Set this variable to 'y' to keep QEMU's stderr output on stderr. |
194 | # If this variable is empty, stderr will be redirected to stdout. | |
e940bc13 JC |
195 | # Returns: |
196 | # $QEMU_HANDLE: set to a handle value to communicate with this QEMU instance. | |
197 | # | |
8cedcffd | 198 | _launch_qemu() |
e940bc13 JC |
199 | { |
200 | local comm= | |
201 | local fifo_out= | |
202 | local fifo_in= | |
203 | ||
204 | if (shopt -s nocasematch; [[ "${qemu_comm_method}" == "monitor" ]]) | |
205 | then | |
206 | comm="-monitor stdio" | |
207 | else | |
208 | local qemu_comm_method="qmp" | |
72538537 KW |
209 | if [ "$qmp_pretty" = "y" ]; then |
210 | comm="-monitor none -qmp-pretty stdio" | |
211 | else | |
212 | comm="-monitor none -qmp stdio" | |
213 | fi | |
e940bc13 JC |
214 | fi |
215 | ||
216 | fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE} | |
217 | fifo_in=${QEMU_FIFO_IN}_${_QEMU_HANDLE} | |
218 | mkfifo "${fifo_out}" | |
219 | mkfifo "${fifo_in}" | |
220 | ||
13a1d4a7 DB |
221 | object_options= |
222 | if [ -n "$IMGKEYSECRET" ]; then | |
223 | object_options="--object secret,id=keysec0,data=$IMGKEYSECRET" | |
224 | fi | |
225 | ||
15cfba69 HR |
226 | if [ -z "$keep_stderr" ]; then |
227 | QEMU_NEED_PID='y'\ | |
13a1d4a7 | 228 | ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ |
3bb8ef4b HR |
229 | 2>&1 \ |
230 | <"${fifo_in}" & | |
15cfba69 HR |
231 | elif [ "$keep_stderr" = "y" ]; then |
232 | QEMU_NEED_PID='y'\ | |
13a1d4a7 | 233 | ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ |
3bb8ef4b | 234 | <"${fifo_in}" & |
15cfba69 HR |
235 | else |
236 | exit 1 | |
237 | fi | |
e940bc13 JC |
238 | |
239 | if [[ "${BASH_VERSINFO[0]}" -ge "5" || | |
240 | ("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]] | |
241 | then | |
242 | # bash >= 4.1 required for automatic fd | |
243 | exec {_out_fd}<"${fifo_out}" | |
244 | exec {_in_fd}>"${fifo_in}" | |
245 | else | |
246 | let _out_fd++ | |
247 | let _in_fd++ | |
248 | eval "exec ${_out_fd}<'${fifo_out}'" | |
249 | eval "exec ${_in_fd}>'${fifo_in}'" | |
250 | fi | |
251 | ||
252 | QEMU_OUT[${_QEMU_HANDLE}]=${_out_fd} | |
253 | QEMU_IN[${_QEMU_HANDLE}]=${_in_fd} | |
254 | QEMU_STATUS[${_QEMU_HANDLE}]=0 | |
255 | ||
256 | if [ "${qemu_comm_method}" == "qmp" ] | |
257 | then | |
258 | # Don't print response, since it has version information in it | |
259 | silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities" | |
72538537 KW |
260 | if [ "$qmp_pretty" = "y" ]; then |
261 | silent=yes _timed_wait_for ${_QEMU_HANDLE} "^}" | |
262 | fi | |
e940bc13 JC |
263 | fi |
264 | QEMU_HANDLE=${_QEMU_HANDLE} | |
265 | let _QEMU_HANDLE++ | |
266 | } | |
267 | ||
268 | ||
e50a6121 | 269 | # Silently kills the QEMU process |
ea82aa42 HR |
270 | # |
271 | # If $wait is set to anything other than the empty string, the process will not | |
272 | # be killed but only waited for, and any output will be forwarded to stdout. If | |
273 | # $wait is empty, the process will be killed and all output will be suppressed. | |
8cedcffd | 274 | _cleanup_qemu() |
e940bc13 JC |
275 | { |
276 | # QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices | |
277 | for i in "${!QEMU_OUT[@]}" | |
278 | do | |
f6c8c2e0 | 279 | local QEMU_PID |
846a1d11 JC |
280 | if [ -f "${QEMU_TEST_DIR}/qemu-${i}.pid" ]; then |
281 | read QEMU_PID < "${QEMU_TEST_DIR}/qemu-${i}.pid" | |
282 | rm -f "${QEMU_TEST_DIR}/qemu-${i}.pid" | |
f6c8c2e0 JC |
283 | if [ -z "${wait}" ] && [ -n "${QEMU_PID}" ]; then |
284 | kill -KILL ${QEMU_PID} 2>/dev/null | |
285 | fi | |
286 | if [ -n "${QEMU_PID}" ]; then | |
287 | wait ${QEMU_PID} 2>/dev/null # silent kill | |
288 | fi | |
ea82aa42 | 289 | fi |
f6c8c2e0 | 290 | |
ea82aa42 HR |
291 | if [ -n "${wait}" ]; then |
292 | cat <&${QEMU_OUT[$i]} | _filter_testdir | _filter_qemu \ | |
69404d9e | 293 | | _filter_qemu_io | _filter_qmp | _filter_hmp |
ea82aa42 | 294 | fi |
e940bc13 JC |
295 | rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}" |
296 | eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors | |
297 | eval "exec ${QEMU_OUT[$i]}<&-" | |
ecaf8c8a KW |
298 | |
299 | unset QEMU_IN[$i] | |
300 | unset QEMU_OUT[$i] | |
e940bc13 JC |
301 | done |
302 | } |