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 72timeout_cmd () 73{ 74 if [ "$TIMEOUT" ] && [ "$TIMEOUT" != "0" ]; then 75 echo "timeout -k 1s --foreground $TIMEOUT" 76 fi 77} 78 79qmp () 80{ 81 echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1 82} 83 84run_migration () 85{ 86 if ! command -v nc >/dev/null 2>&1; then 87 echo "$FUNCNAME needs nc (netcat)" >&2 88 exit 2 89 fi 90 91 qemu=$1 92 shift 93 94 migsock=`mktemp -u -t mig-helper-socket.XXXXXXXXXX` 95 migout1=`mktemp -t mig-helper-stdout1.XXXXXXXXXX` 96 qmp1=`mktemp -u -t mig-helper-qmp1.XXXXXXXXXX` 97 qmp2=`mktemp -u -t mig-helper-qmp2.XXXXXXXXXX` 98 qmpout1=/dev/null 99 qmpout2=/dev/null 100 101 trap 'rm -f ${migout1} ${migsock} ${qmp1} ${qmp2}' EXIT 102 103 $qemu "$@" -chardev socket,id=mon1,path=${qmp1},server,nowait \ 104 -mon chardev=mon1,mode=control | tee ${migout1} & 105 106 $qemu "$@" -chardev socket,id=mon2,path=${qmp2},server,nowait \ 107 -mon chardev=mon2,mode=control -incoming unix:${migsock} & 108 109 # The test must prompt the user to migrate, so wait for the "migrate" keyword 110 while ! grep -q -i "migrate" < ${migout1} ; do 111 sleep 1 112 done 113 114 qmp ${qmp1} '"migrate", "arguments": { "uri": "unix:'${migsock}'" }' > ${qmpout1} 115 116 # Wait for the migration to complete 117 migstatus=`qmp ${qmp1} '"query-migrate"' | grep return` 118 while ! grep -q '"completed"' <<<"$migstatus" ; do 119 sleep 1 120 migstatus=`qmp ${qmp1} '"query-migrate"' | grep return` 121 if grep -q '"failed"' <<<"$migstatus" ; then 122 echo "ERROR: Migration failed." >&2 123 qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null 124 qmp ${qmp2} '"quit"'> ${qmpout2} 2>/dev/null 125 exit 2 126 fi 127 done 128 qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null 129 130 qmp ${qmp2} '"inject-nmi"'> ${qmpout2} 131 132 wait 133} 134 135migration_cmd () 136{ 137 if [ "$MIGRATION" = "yes" ]; then 138 echo "run_migration" 139 fi 140} 141 142search_qemu_binary () 143{ 144 local save_path=$PATH 145 local qemucmd qemu 146 147 export PATH=$PATH:/usr/libexec 148 for qemucmd in ${QEMU:-qemu-system-$ARCH_NAME qemu-kvm}; do 149 if $qemucmd --help 2>/dev/null | grep -q 'QEMU'; then 150 qemu="$qemucmd" 151 break 152 fi 153 done 154 155 if [ -z "$qemu" ]; then 156 echo "A QEMU binary was not found." 157 echo "You can set a custom location by using the QEMU=<path> environment variable." 158 exit 2 159 fi 160 command -v $qemu 161 export PATH=$save_path 162} 163 164initrd_create () 165{ 166 local ret 167 168 env_add_errata 169 ret=$? 170 171 unset INITRD 172 [ -f "$ENV" ] && INITRD="-initrd $ENV" 173 174 return $ret 175} 176 177env_add_errata () 178{ 179 local line errata ret=1 180 181 if [ -f "$ENV" ] && grep -q '^ERRATA_' <(env); then 182 for line in $(grep '^ERRATA_' "$ENV"); do 183 errata=${line%%=*} 184 test -v $errata && continue 185 eval export "$line" 186 done 187 elif [ ! -f "$ENV" ]; then 188 env_generate_errata 189 fi 190 191 if grep -q '^ERRATA_' <(env); then 192 export ENV_OLD="$ENV" 193 export ENV=$(mktemp) 194 trap_exit_push 'rm -f $ENV; [ "$ENV_OLD" ] && export ENV="$ENV_OLD" || unset ENV; unset ENV_OLD' 195 [ -f "$ENV_OLD" ] && grep -v '^ERRATA_' "$ENV_OLD" > $ENV 196 grep '^ERRATA_' <(env) >> $ENV 197 ret=0 198 fi 199 200 return $ret 201} 202 203env_generate_errata () 204{ 205 local kernel_version_string=$(uname -r) 206 local kernel_version kernel_patchlevel kernel_sublevel 207 local line commit minver errata v p s have 208 209 IFS=. read kernel_version kernel_patchlevel kernel_sublevel <<<$kernel_version_string 210 kernel_sublevel=${kernel_sublevel%%[!0-9]*} 211 212 [ "$ENVIRON_DEFAULT" != "yes" ] && return 213 [ ! -f "$ERRATATXT" ] && return 214 215 for line in $(grep -v '^#' "$ERRATATXT" | tr -d '[:blank:]' | cut -d: -f1,2); do 216 commit=${line%:*} 217 minver=${line#*:} 218 219 errata="ERRATA_$commit" 220 test -v $errata && continue 221 222 IFS=. read v p s <<<$minver 223 s=${s%%[!0-9]*} 224 225 if (( $kernel_version > $v || 226 ($kernel_version == $v && $kernel_patchlevel > $p) )); then 227 have=y 228 elif (( $kernel_version == $v && $kernel_patchlevel == $p )); then 229 if [ "$kernel_sublevel" ] && [ "$s" ]; then 230 if (( $kernel_sublevel >= $s )); then 231 have=y 232 else 233 have=n 234 fi 235 elif [ "$s" ] && (( $s != 0 )); then 236 have=n 237 else 238 have=y 239 fi 240 else 241 have=n 242 fi 243 eval export "$errata=$have" 244 done 245} 246 247trap_exit_push () 248{ 249 local old_exit=$(trap -p EXIT | sed "s/^[^']*'//;s/'[^']*$//") 250 trap -- "$1; $old_exit" EXIT 251} 252