1############################################################################## 2# run_qemu translates the ambiguous exit status in Table1 to that in Table2. 3# Table3 simply documents the complete status table. 4# 5# Table1: Before fixup 6# -------------------- 7# 0 - Unexpected exit from QEMU (possible signal), or the unittest did 8# not use debug-exit 9# 1 - most likely unittest succeeded, or QEMU failed 10# 11# Table2: After fixup 12# ------------------- 13# 0 - Everything succeeded 14# 1 - most likely QEMU failed 15# 16# Table3: Complete table 17# ---------------------- 18# 0 - SUCCESS 19# 1 - most likely QEMU failed 20# 2 - most likely a run script failed 21# 3 - most likely the unittest failed 22# 124 - most likely the unittest timed out 23# 127 - most likely the unittest called abort() 24# 1..127 - FAILURE (could be QEMU, a run script, or the unittest) 25# >= 128 - Signal (signum = status - 128) 26############################################################################## 27run_qemu () 28{ 29 local stdout errors ret sig 30 31 echo -n "$@" 32 initrd_create && 33 echo -n " #" 34 echo " $INITRD" 35 36 # stdout to {stdout}, stderr to $errors and stderr 37 exec {stdout}>&1 38 errors=$("${@}" $INITRD </dev/null 2> >(tee /dev/stderr) > /dev/fd/$stdout) 39 ret=$? 40 exec {stdout}>&- 41 42 [ $ret -eq 134 ] && echo "QEMU Aborted" >&2 43 44 if [ "$errors" ]; then 45 sig=$(grep 'terminating on signal' <<<"$errors") 46 if [ "$sig" ]; then 47 sig=$(sed 's/.*terminating on signal \([0-9][0-9]*\).*/\1/' <<<"$sig") 48 fi 49 fi 50 51 if [ $ret -eq 0 ]; then 52 # Some signals result in a zero return status, but the 53 # error log tells the truth. 54 if [ "$sig" ]; then 55 ((ret=sig+128)) 56 else 57 # Exiting with zero (non-debugexit) is an error 58 ret=1 59 fi 60 elif [ $ret -eq 1 ]; then 61 # Even when ret==1 (unittest success) if we also got stderr 62 # logs, then we assume a QEMU failure. Otherwise we translate 63 # status of 1 to 0 (SUCCESS) 64 if [ -z "$(echo "$errors" | grep -vi warning)" ]; then 65 ret=0 66 fi 67 fi 68 69 return $ret 70} 71 72run_qemu_status () 73{ 74 local stdout ret 75 76 exec {stdout}>&1 77 lines=$(run_qemu "$@" > >(tee /dev/fd/$stdout)) 78 ret=$? 79 exec {stdout}>&- 80 81 if [ $ret -eq 1 ]; then 82 testret=$(grep '^EXIT: ' <<<"$lines" | sed 's/.*STATUS=\([0-9][0-9]*\).*/\1/') 83 if [ "$testret" ]; then 84 if [ $testret -eq 1 ]; then 85 ret=0 86 else 87 ret=$testret 88 fi 89 fi 90 fi 91 92 return $ret 93} 94 95timeout_cmd () 96{ 97 if [ "$TIMEOUT" ] && [ "$TIMEOUT" != "0" ]; then 98 echo "timeout -k 1s --foreground $TIMEOUT" 99 fi 100} 101 102qmp () 103{ 104 echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1 105} 106 107run_migration () 108{ 109 if ! command -v nc >/dev/null 2>&1; then 110 echo "${FUNCNAME[0]} needs nc (netcat)" >&2 111 exit 2 112 fi 113 114 qemu=$1 115 shift 116 117 migsock=`mktemp -u -t mig-helper-socket.XXXXXXXXXX` 118 migout1=`mktemp -t mig-helper-stdout1.XXXXXXXXXX` 119 qmp1=`mktemp -u -t mig-helper-qmp1.XXXXXXXXXX` 120 qmp2=`mktemp -u -t mig-helper-qmp2.XXXXXXXXXX` 121 qmpout1=/dev/null 122 qmpout2=/dev/null 123 124 trap 'rm -f ${migout1} ${migsock} ${qmp1} ${qmp2}' EXIT 125 126 $qemu "$@" -chardev socket,id=mon1,path=${qmp1},server,nowait \ 127 -mon chardev=mon1,mode=control | tee ${migout1} & 128 129 $qemu "$@" -chardev socket,id=mon2,path=${qmp2},server,nowait \ 130 -mon chardev=mon2,mode=control -incoming unix:${migsock} & 131 132 # The test must prompt the user to migrate, so wait for the "migrate" keyword 133 while ! grep -q -i "migrate" < ${migout1} ; do 134 sleep 1 135 done 136 137 qmp ${qmp1} '"migrate", "arguments": { "uri": "unix:'${migsock}'" }' > ${qmpout1} 138 139 # Wait for the migration to complete 140 migstatus=`qmp ${qmp1} '"query-migrate"' | grep return` 141 while ! grep -q '"completed"' <<<"$migstatus" ; do 142 sleep 1 143 migstatus=`qmp ${qmp1} '"query-migrate"' | grep return` 144 if grep -q '"failed"' <<<"$migstatus" ; then 145 echo "ERROR: Migration failed." >&2 146 qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null 147 qmp ${qmp2} '"quit"'> ${qmpout2} 2>/dev/null 148 exit 2 149 fi 150 done 151 qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null 152 153 qmp ${qmp2} '"inject-nmi"'> ${qmpout2} 154 155 wait 156} 157 158migration_cmd () 159{ 160 if [ "$MIGRATION" = "yes" ]; then 161 echo "run_migration" 162 fi 163} 164 165search_qemu_binary () 166{ 167 local save_path=$PATH 168 local qemucmd qemu 169 170 export PATH=$PATH:/usr/libexec 171 for qemucmd in ${QEMU:-qemu-system-$ARCH_NAME qemu-kvm}; do 172 if $qemucmd --help 2>/dev/null | grep -q 'QEMU'; then 173 qemu="$qemucmd" 174 break 175 fi 176 done 177 178 if [ -z "$qemu" ]; then 179 echo "A QEMU binary was not found." >&2 180 echo "You can set a custom location by using the QEMU=<path> environment variable." >&2 181 return 2 182 fi 183 command -v $qemu 184 export PATH=$save_path 185} 186 187initrd_create () 188{ 189 local ret 190 191 env_add_errata 192 ret=$? 193 194 unset INITRD 195 [ -f "$ENV" ] && INITRD="-initrd $ENV" 196 197 return $ret 198} 199 200env_add_errata () 201{ 202 local line errata ret=1 203 204 if [ -f "$ENV" ] && grep -q '^ERRATA_' <(env); then 205 for line in $(grep '^ERRATA_' "$ENV"); do 206 errata=${line%%=*} 207 test -v $errata && continue 208 eval export "$line" 209 done 210 elif [ ! -f "$ENV" ]; then 211 env_generate_errata 212 fi 213 214 if grep -q '^ERRATA_' <(env); then 215 export ENV_OLD="$ENV" 216 export ENV=$(mktemp) 217 trap_exit_push 'rm -f $ENV; [ "$ENV_OLD" ] && export ENV="$ENV_OLD" || unset ENV; unset ENV_OLD' 218 [ -f "$ENV_OLD" ] && grep -v '^ERRATA_' "$ENV_OLD" > $ENV 219 grep '^ERRATA_' <(env) >> $ENV 220 ret=0 221 fi 222 223 return $ret 224} 225 226env_generate_errata () 227{ 228 local kernel_version_string=$(uname -r) 229 local kernel_version kernel_patchlevel kernel_sublevel kernel_extraversion 230 local line commit minver errata rest v p s x have 231 232 IFS=. read -r kernel_version kernel_patchlevel rest <<<$kernel_version_string 233 IFS=- read -r kernel_sublevel kernel_extraversion <<<$rest 234 kernel_sublevel=${kernel_sublevel%%[!0-9]*} 235 kernel_extraversion=${kernel_extraversion%%[!0-9]*} 236 237 ! [[ $kernel_sublevel =~ ^[0-9]+$ ]] && unset $kernel_sublevel 238 ! [[ $kernel_extraversion =~ ^[0-9]+$ ]] && unset $kernel_extraversion 239 240 [ "$ENVIRON_DEFAULT" != "yes" ] && return 241 [ ! -f "$ERRATATXT" ] && return 242 243 for line in $(grep -v '^#' "$ERRATATXT" | tr -d '[:blank:]' | cut -d: -f1,2); do 244 commit=${line%:*} 245 minver=${line#*:} 246 247 errata="ERRATA_$commit" 248 test -v $errata && continue 249 250 IFS=. read -r v p rest <<<"$minver" 251 IFS=- read -r s x <<<"$rest" 252 s=${s%%[!0-9]*} 253 x=${x%%[!0-9]*} 254 255 if ! [[ $v =~ ^[0-9]+$ ]] || ! [[ $p =~ ^[0-9]+$ ]]; then 256 echo "Bad minimum kernel version in $ERRATATXT, $minver" 257 exit 2 258 fi 259 ! [[ $s =~ ^[0-9]+$ ]] && unset $s 260 ! [[ $x =~ ^[0-9]+$ ]] && unset $x 261 262 if (( $kernel_version > $v || 263 ($kernel_version == $v && $kernel_patchlevel > $p) )); then 264 have=y 265 elif (( $kernel_version == $v && $kernel_patchlevel == $p )); then 266 if [ "$kernel_sublevel" ] && [ "$s" ]; then 267 if (( $kernel_sublevel > $s )); then 268 have=y 269 elif (( $kernel_sublevel == $s )); then 270 if [ "$kernel_extraversion" ] && [ "$x" ]; then 271 if (( $kernel_extraversion >= $x )); then 272 have=y 273 else 274 have=n 275 fi 276 elif [ "$x" ] && (( $x != 0 )); then 277 have=n 278 else 279 have=y 280 fi 281 else 282 have=n 283 fi 284 elif [ "$s" ] && (( $s != 0 )); then 285 have=n 286 else 287 have=y 288 fi 289 else 290 have=n 291 fi 292 eval export "$errata=$have" 293 done 294} 295 296trap_exit_push () 297{ 298 local old_exit=$(trap -p EXIT | sed "s/^[^']*'//;s/'[^']*$//") 299 trap -- "$1; $old_exit" EXIT 300} 301 302kvm_available () 303{ 304 [ -c /dev/kvm ] || 305 return 1 306 307 [ "$HOST" = "$ARCH_NAME" ] || 308 ( [ "$HOST" = aarch64 ] && [ "$ARCH" = arm ] ) || 309 ( [ "$HOST" = x86_64 ] && [ "$ARCH" = i386 ] ) 310} 311 312get_qemu_accelerator () 313{ 314 if [ "$ACCEL" = "kvm" ] && ! kvm_available; then 315 echo "KVM is needed, but not available on this host" >&2 316 return 2 317 fi 318 319 if [ "$ACCEL" ]; then 320 echo $ACCEL 321 elif kvm_available; then 322 echo kvm 323 else 324 echo tcg 325 fi 326} 327