]>
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 | # | |
126 | # If $qemu_error_no_exit is set, then even if the expected response | |
127 | # is not seen, we will not exit. $QEMU_STATUS[$1] will be set it -1 in | |
128 | # that case. | |
81c6ddf4 HR |
129 | # |
130 | # If $success_or_failure is set, then the last two strings are the | |
131 | # strings the response will be scanned for. The first of the two | |
132 | # indicates success, the latter indicates failure. Failure is handled | |
133 | # like a timeout. | |
8cedcffd | 134 | _send_qemu_cmd() |
e940bc13 JC |
135 | { |
136 | local h=${1} | |
137 | local count=1 | |
138 | local cmd= | |
139 | local use_error=${qemu_error_no_exit} | |
140 | shift | |
141 | ||
142 | if [ ${qemu_cmd_repeat} -gt 0 ] 2>/dev/null; then | |
143 | count=${qemu_cmd_repeat} | |
144 | use_error="no" | |
145 | fi | |
5d831be2 | 146 | # This array element extraction is done to accommodate pathnames with spaces |
81c6ddf4 HR |
147 | if [ -z "${success_or_failure}" ]; then |
148 | cmd=${@: 1:${#@}-1} | |
149 | shift $(($# - 1)) | |
150 | else | |
151 | cmd=${@: 1:${#@}-2} | |
152 | shift $(($# - 2)) | |
153 | fi | |
e940bc13 JC |
154 | |
155 | while [ ${count} -gt 0 ] | |
156 | do | |
157 | echo "${cmd}" >&${QEMU_IN[${h}]} | |
158 | if [ -n "${1}" ]; then | |
81c6ddf4 HR |
159 | if [ -z "${success_or_failure}" ]; then |
160 | qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" | |
161 | else | |
162 | qemu_error_no_exit=${use_error} _timed_wait_for ${h} "${1}" "${2}" | |
163 | fi | |
e940bc13 JC |
164 | if [ ${QEMU_STATUS[$h]} -eq 0 ]; then |
165 | return | |
166 | fi | |
167 | fi | |
168 | let count--; | |
169 | done | |
170 | if [ ${QEMU_STATUS[$h]} -ne 0 ] && [ -z "${qemu_error_no_exit}" ]; then | |
171 | echo "Timeout waiting for ${1} on handle ${h}" | |
172 | exit 1 #Timeout means the test failed | |
173 | fi | |
174 | } | |
175 | ||
176 | ||
177 | # Launch a QEMU process. | |
178 | # | |
179 | # Input parameters: | |
180 | # $qemu_comm_method: set this variable to 'monitor' (case insensitive) | |
181 | # to use the QEMU HMP monitor for communication. | |
182 | # Otherwise, the default of QMP is used. | |
72538537 | 183 | # $qmp_pretty: Set this variable to 'y' to enable QMP pretty printing. |
15cfba69 HR |
184 | # $keep_stderr: Set this variable to 'y' to keep QEMU's stderr output on stderr. |
185 | # If this variable is empty, stderr will be redirected to stdout. | |
e940bc13 JC |
186 | # Returns: |
187 | # $QEMU_HANDLE: set to a handle value to communicate with this QEMU instance. | |
188 | # | |
8cedcffd | 189 | _launch_qemu() |
e940bc13 JC |
190 | { |
191 | local comm= | |
192 | local fifo_out= | |
193 | local fifo_in= | |
194 | ||
195 | if (shopt -s nocasematch; [[ "${qemu_comm_method}" == "monitor" ]]) | |
196 | then | |
197 | comm="-monitor stdio" | |
198 | else | |
199 | local qemu_comm_method="qmp" | |
72538537 KW |
200 | if [ "$qmp_pretty" = "y" ]; then |
201 | comm="-monitor none -qmp-pretty stdio" | |
202 | else | |
203 | comm="-monitor none -qmp stdio" | |
204 | fi | |
e940bc13 JC |
205 | fi |
206 | ||
207 | fifo_out=${QEMU_FIFO_OUT}_${_QEMU_HANDLE} | |
208 | fifo_in=${QEMU_FIFO_IN}_${_QEMU_HANDLE} | |
209 | mkfifo "${fifo_out}" | |
210 | mkfifo "${fifo_in}" | |
211 | ||
13a1d4a7 DB |
212 | object_options= |
213 | if [ -n "$IMGKEYSECRET" ]; then | |
214 | object_options="--object secret,id=keysec0,data=$IMGKEYSECRET" | |
215 | fi | |
216 | ||
15cfba69 HR |
217 | if [ -z "$keep_stderr" ]; then |
218 | QEMU_NEED_PID='y'\ | |
13a1d4a7 | 219 | ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ |
3bb8ef4b HR |
220 | 2>&1 \ |
221 | <"${fifo_in}" & | |
15cfba69 HR |
222 | elif [ "$keep_stderr" = "y" ]; then |
223 | QEMU_NEED_PID='y'\ | |
13a1d4a7 | 224 | ${QEMU} ${object_options} -nographic -serial none ${comm} "${@}" >"${fifo_out}" \ |
3bb8ef4b | 225 | <"${fifo_in}" & |
15cfba69 HR |
226 | else |
227 | exit 1 | |
228 | fi | |
e940bc13 JC |
229 | |
230 | if [[ "${BASH_VERSINFO[0]}" -ge "5" || | |
231 | ("${BASH_VERSINFO[0]}" -ge "4" && "${BASH_VERSINFO[1]}" -ge "1") ]] | |
232 | then | |
233 | # bash >= 4.1 required for automatic fd | |
234 | exec {_out_fd}<"${fifo_out}" | |
235 | exec {_in_fd}>"${fifo_in}" | |
236 | else | |
237 | let _out_fd++ | |
238 | let _in_fd++ | |
239 | eval "exec ${_out_fd}<'${fifo_out}'" | |
240 | eval "exec ${_in_fd}>'${fifo_in}'" | |
241 | fi | |
242 | ||
243 | QEMU_OUT[${_QEMU_HANDLE}]=${_out_fd} | |
244 | QEMU_IN[${_QEMU_HANDLE}]=${_in_fd} | |
245 | QEMU_STATUS[${_QEMU_HANDLE}]=0 | |
246 | ||
247 | if [ "${qemu_comm_method}" == "qmp" ] | |
248 | then | |
249 | # Don't print response, since it has version information in it | |
250 | silent=yes _timed_wait_for ${_QEMU_HANDLE} "capabilities" | |
72538537 KW |
251 | if [ "$qmp_pretty" = "y" ]; then |
252 | silent=yes _timed_wait_for ${_QEMU_HANDLE} "^}" | |
253 | fi | |
e940bc13 JC |
254 | fi |
255 | QEMU_HANDLE=${_QEMU_HANDLE} | |
256 | let _QEMU_HANDLE++ | |
257 | } | |
258 | ||
259 | ||
e50a6121 | 260 | # Silently kills the QEMU process |
ea82aa42 HR |
261 | # |
262 | # If $wait is set to anything other than the empty string, the process will not | |
263 | # be killed but only waited for, and any output will be forwarded to stdout. If | |
264 | # $wait is empty, the process will be killed and all output will be suppressed. | |
8cedcffd | 265 | _cleanup_qemu() |
e940bc13 JC |
266 | { |
267 | # QEMU_PID[], QEMU_IN[], QEMU_OUT[] all use same indices | |
268 | for i in "${!QEMU_OUT[@]}" | |
269 | do | |
f6c8c2e0 | 270 | local QEMU_PID |
846a1d11 JC |
271 | if [ -f "${QEMU_TEST_DIR}/qemu-${i}.pid" ]; then |
272 | read QEMU_PID < "${QEMU_TEST_DIR}/qemu-${i}.pid" | |
273 | rm -f "${QEMU_TEST_DIR}/qemu-${i}.pid" | |
f6c8c2e0 JC |
274 | if [ -z "${wait}" ] && [ -n "${QEMU_PID}" ]; then |
275 | kill -KILL ${QEMU_PID} 2>/dev/null | |
276 | fi | |
277 | if [ -n "${QEMU_PID}" ]; then | |
278 | wait ${QEMU_PID} 2>/dev/null # silent kill | |
279 | fi | |
ea82aa42 | 280 | fi |
f6c8c2e0 | 281 | |
ea82aa42 HR |
282 | if [ -n "${wait}" ]; then |
283 | cat <&${QEMU_OUT[$i]} | _filter_testdir | _filter_qemu \ | |
69404d9e | 284 | | _filter_qemu_io | _filter_qmp | _filter_hmp |
ea82aa42 | 285 | fi |
e940bc13 JC |
286 | rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}" |
287 | eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors | |
288 | eval "exec ${QEMU_OUT[$i]}<&-" | |
ecaf8c8a KW |
289 | |
290 | unset QEMU_IN[$i] | |
291 | unset QEMU_OUT[$i] | |
e940bc13 JC |
292 | done |
293 | } |