xref: /openbmc/qemu/tests/qemu-iotests/common.rc (revision b1f4b9b8)
1#!/usr/bin/env bash
2#
3# Copyright (C) 2009 Red Hat, Inc.
4# Copyright (c) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <http://www.gnu.org/licenses/>.
18#
19
20# bail out, setting up .notrun file
21_notrun()
22{
23    echo "$*" >"$TEST_DIR/$seq.notrun"
24    echo "$seq not run: $*"
25    status=0
26    exit
27}
28
29if ! command -v gsed >/dev/null 2>&1; then
30    if sed --version 2>&1 | grep -v 'not GNU sed' | grep 'GNU sed' > /dev/null;
31    then
32        gsed()
33        {
34            sed "$@"
35        }
36    else
37        gsed()
38        {
39            _notrun "GNU sed not available"
40        }
41    fi
42fi
43
44dd()
45{
46   if [ "$HOSTOS" == "Linux" ]
47   then
48        command dd --help | grep noxfer > /dev/null 2>&1
49
50        if [ "$?" -eq 0 ]
51            then
52                command dd status=noxfer $@
53            else
54                command dd $@
55            fi
56   else
57        command dd $@
58   fi
59}
60
61# poke_file 'test.img' 512 '\xff\xfe'
62poke_file()
63{
64    printf "$3" | dd "of=$1" bs=1 "seek=$2" conv=notrunc &>/dev/null
65}
66
67# poke_file_le $img_filename $offset $byte_width $value
68# Example: poke_file_le "$TEST_IMG" 512 2 65534
69poke_file_le()
70{
71    local img=$1 ofs=$2 len=$3 val=$4 str=''
72
73    while ((len--)); do
74        str+=$(printf '\\x%02x' $((val & 0xff)))
75        val=$((val >> 8))
76    done
77
78    poke_file "$img" "$ofs" "$str"
79}
80
81# poke_file_be $img_filename $offset $byte_width $value
82# Example: poke_file_be "$TEST_IMG" 512 2 65279
83poke_file_be()
84{
85    local img=$1 ofs=$2 len=$3 val=$4
86    local str=$(printf "%0$((len * 2))x\n" $val | sed 's/\(..\)/\\x\1/g')
87
88    poke_file "$img" "$ofs" "$str"
89}
90
91# peek_file_le 'test.img' 512 2 => 65534
92peek_file_le()
93{
94    local val=0 shift=0 byte
95
96    # coreutils' od --endian is not portable, so manually assemble bytes.
97    for byte in $(od -j"$2" -N"$3" -An -v -tu1 "$1"); do
98        val=$(( val | (byte << shift) ))
99        shift=$((shift + 8))
100    done
101    printf %llu $val
102}
103
104# peek_file_be 'test.img' 512 2 => 65279
105peek_file_be()
106{
107    local val=0 byte
108
109    # coreutils' od --endian is not portable, so manually assemble bytes.
110    for byte in $(od -j"$2" -N"$3" -An -v -tu1 "$1"); do
111        val=$(( (val << 8) | byte ))
112    done
113    printf %llu $val
114}
115
116# peek_file_raw 'test.img' 512 2 => '\xff\xfe'. Do not use if the raw data
117# is likely to contain \0 or trailing \n.
118peek_file_raw()
119{
120    dd if="$1" bs=1 skip="$2" count="$3" status=none
121}
122
123config=common.config
124test -f $config || config=../common.config
125if ! test -f $config
126then
127    echo "$0: failed to find common.config"
128    exit 1
129fi
130if ! . $config
131    then
132    echo "$0: failed to source common.config"
133    exit 1
134fi
135
136# Set the variables to the empty string to turn Valgrind off
137# for specific processes, e.g.
138# $ VALGRIND_QEMU_IO= ./check -qcow2 -valgrind 015
139
140: ${VALGRIND_QEMU_VM=$VALGRIND_QEMU}
141: ${VALGRIND_QEMU_IMG=$VALGRIND_QEMU}
142: ${VALGRIND_QEMU_IO=$VALGRIND_QEMU}
143: ${VALGRIND_QEMU_NBD=$VALGRIND_QEMU}
144: ${VALGRIND_QSD=$VALGRIND_QEMU}
145
146# The Valgrind own parameters may be set with
147# its environment variable VALGRIND_OPTS, e.g.
148# $ VALGRIND_OPTS="--leak-check=yes" ./check -qcow2 -valgrind 015
149
150_qemu_proc_exec()
151{
152    local VALGRIND_LOGFILE="$1"
153    shift
154    if [[ "${VALGRIND_QEMU}" == "y" && "${NO_VALGRIND}" != "y" ]]; then
155        exec valgrind --log-file="${VALGRIND_LOGFILE}" --error-exitcode=99 "$@"
156    else
157        exec "$@"
158    fi
159}
160
161_qemu_proc_valgrind_log()
162{
163    local VALGRIND_LOGFILE="$1"
164    local RETVAL="$2"
165    if [[ "${VALGRIND_QEMU}" == "y" && "${NO_VALGRIND}" != "y" ]]; then
166        if [ $RETVAL == 99 ]; then
167            cat "${VALGRIND_LOGFILE}"
168        fi
169        rm -f "${VALGRIND_LOGFILE}"
170    fi
171}
172
173_qemu_wrapper()
174{
175    local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
176    (
177        if [ -n "${QEMU_NEED_PID}" ]; then
178            echo $BASHPID > "${QEMU_TEST_DIR}/qemu-${_QEMU_HANDLE}.pid"
179        fi
180
181        GDB=""
182        if [ -n "${GDB_OPTIONS}" ]; then
183            GDB="gdbserver ${GDB_OPTIONS}"
184        fi
185
186        VALGRIND_QEMU="${VALGRIND_QEMU_VM}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
187            $GDB "$QEMU_PROG" $QEMU_OPTIONS "$@"
188    )
189    RETVAL=$?
190    _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
191    return $RETVAL
192}
193
194_qemu_img_wrapper()
195{
196    local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
197    (
198        VALGRIND_QEMU="${VALGRIND_QEMU_IMG}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
199            "$QEMU_IMG_PROG" $QEMU_IMG_OPTIONS "$@"
200    )
201    RETVAL=$?
202    _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
203    return $RETVAL
204}
205
206_qemu_io_wrapper()
207{
208    local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
209    local QEMU_IO_ARGS="$QEMU_IO_OPTIONS"
210    if [ "$IMGOPTSSYNTAX" = "true" ]; then
211        QEMU_IO_ARGS="--image-opts $QEMU_IO_ARGS"
212        if [ -n "$IMGKEYSECRET" ]; then
213            QEMU_IO_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IO_ARGS"
214        fi
215    fi
216    (
217        VALGRIND_QEMU="${VALGRIND_QEMU_IO}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
218            "$QEMU_IO_PROG" $QEMU_IO_ARGS "$@"
219    )
220    RETVAL=$?
221    _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
222    return $RETVAL
223}
224
225_qemu_nbd_wrapper()
226{
227    local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
228    (
229        VALGRIND_QEMU="${VALGRIND_QEMU_NBD}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
230            "$QEMU_NBD_PROG" --pid-file="${QEMU_TEST_DIR}/qemu-nbd.pid" \
231             $QEMU_NBD_OPTIONS "$@"
232    )
233    RETVAL=$?
234    _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
235    return $RETVAL
236}
237
238_qemu_storage_daemon_wrapper()
239{
240    local VALGRIND_LOGFILE="${TEST_DIR}"/$$.valgrind
241    (
242        if [ -n "${QSD_NEED_PID}" ]; then
243            echo $BASHPID > "${QEMU_TEST_DIR}/qemu-storage-daemon.pid"
244        fi
245        VALGRIND_QEMU="${VALGRIND_QSD}" _qemu_proc_exec "${VALGRIND_LOGFILE}" \
246            "$QSD_PROG" $QSD_OPTIONS "$@"
247    )
248    RETVAL=$?
249    _qemu_proc_valgrind_log "${VALGRIND_LOGFILE}" $RETVAL
250    return $RETVAL
251}
252
253# Valgrind bug #409141 https://bugs.kde.org/show_bug.cgi?id=409141
254# Until valgrind 3.16+ is ubiquitous, we must work around a hang in
255# valgrind when issuing sigkill. Disable valgrind for this invocation.
256_NO_VALGRIND()
257{
258    NO_VALGRIND="y" "$@"
259}
260
261export QEMU=_qemu_wrapper
262export QEMU_IMG=_qemu_img_wrapper
263export QEMU_IO=_qemu_io_wrapper
264export QEMU_NBD=_qemu_nbd_wrapper
265export QSD=_qemu_storage_daemon_wrapper
266
267if [ "$IMGOPTSSYNTAX" = "true" ]; then
268    DRIVER="driver=$IMGFMT"
269    QEMU_IMG_EXTRA_ARGS="--image-opts $QEMU_IMG_EXTRA_ARGS"
270    if [ -n "$IMGKEYSECRET" ]; then
271        QEMU_IMG_EXTRA_ARGS="--object secret,id=keysec0,data=$IMGKEYSECRET $QEMU_IMG_EXTRA_ARGS"
272    fi
273    if [ "$IMGFMT" = "luks" ]; then
274        DRIVER="$DRIVER,key-secret=keysec0"
275    fi
276    if [ "$IMGPROTO" = "file" ]; then
277        TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
278        TEST_IMG="$DRIVER,file.filename=$TEST_DIR/t.$IMGFMT"
279    elif [ "$IMGPROTO" = "nbd" ]; then
280        TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
281        TEST_IMG="$DRIVER,file.driver=nbd,file.type=unix"
282        TEST_IMG="$TEST_IMG,file.path=$SOCK_DIR/nbd"
283    elif [ "$IMGPROTO" = "fuse" ]; then
284        TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
285        TEST_IMG="$DRIVER,file.filename=$SOCK_DIR/fuse-t.$IMGFMT"
286    elif [ "$IMGPROTO" = "ssh" ]; then
287        TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
288        TEST_IMG="$DRIVER,file.driver=ssh,file.host=127.0.0.1,file.path=$TEST_IMG_FILE"
289    elif [ "$IMGPROTO" = "nfs" ]; then
290        TEST_DIR="$DRIVER,file.driver=nfs,file.filename=nfs://127.0.0.1/$TEST_DIR"
291        TEST_IMG=$TEST_DIR/t.$IMGFMT
292    else
293        TEST_IMG="$DRIVER,file.driver=$IMGPROTO,file.filename=$TEST_DIR/t.$IMGFMT"
294    fi
295else
296    QEMU_IMG_EXTRA_ARGS=
297    if [ "$IMGPROTO" = "file" ]; then
298        TEST_IMG=$TEST_DIR/t.$IMGFMT
299    elif [ "$IMGPROTO" = "nbd" ]; then
300        TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
301        TEST_IMG="nbd+unix:///?socket=$SOCK_DIR/nbd"
302    elif [ "$IMGPROTO" = "fuse" ]; then
303        TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
304        TEST_IMG="$SOCK_DIR/fuse-t.$IMGFMT"
305    elif [ "$IMGPROTO" = "ssh" ]; then
306        TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
307        REMOTE_TEST_DIR="ssh://\\($USER@\\)\\?127.0.0.1\\(:[0-9]\\+\\)\\?$TEST_DIR"
308        TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE"
309    elif [ "$IMGPROTO" = "nfs" ]; then
310        TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
311        REMOTE_TEST_DIR="nfs://127.0.0.1$TEST_DIR"
312        TEST_IMG="nfs://127.0.0.1$TEST_IMG_FILE"
313    else
314        TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
315    fi
316fi
317ORIG_TEST_IMG_FILE=$TEST_IMG_FILE
318ORIG_TEST_IMG="$TEST_IMG"
319
320FUSE_PIDS=()
321FUSE_EXPORTS=()
322
323if [ -z "$TEST_DIR" ]; then
324        TEST_DIR=$PWD/scratch
325fi
326
327QEMU_TEST_DIR="${TEST_DIR}"
328
329if [ ! -e "$TEST_DIR" ]; then
330        mkdir "$TEST_DIR"
331fi
332
333if [ ! -d "$TEST_DIR" ]; then
334    echo "common.rc: Error: \$TEST_DIR ($TEST_DIR) is not a directory"
335    exit 1
336fi
337
338if [ -z "$REMOTE_TEST_DIR" ]; then
339    REMOTE_TEST_DIR="$TEST_DIR"
340fi
341
342if [ ! -d "$SAMPLE_IMG_DIR" ]; then
343    echo "common.rc: Error: \$SAMPLE_IMG_DIR ($SAMPLE_IMG_DIR) is not a directory"
344    exit 1
345fi
346
347_use_sample_img()
348{
349    SAMPLE_IMG_FILE="${1%\.bz2}"
350    TEST_IMG="$TEST_DIR/$SAMPLE_IMG_FILE"
351    bzcat "$SAMPLE_IMG_DIR/$1" > "$TEST_IMG"
352    if [ $? -ne 0 ]
353    then
354        echo "_use_sample_img error, cannot extract '$SAMPLE_IMG_DIR/$1'"
355        exit 1
356    fi
357}
358
359_stop_nbd_server()
360{
361    if [ -f "${QEMU_TEST_DIR}/qemu-nbd.pid" ]; then
362        local QEMU_NBD_PID
363        read QEMU_NBD_PID < "${QEMU_TEST_DIR}/qemu-nbd.pid"
364        kill ${QEMU_NBD_PID}
365        rm -f "${QEMU_TEST_DIR}/qemu-nbd.pid" "$SOCK_DIR/nbd"
366    fi
367}
368
369# Gets the data_file value from IMGOPTS and replaces the '$TEST_IMG'
370# pattern by '$1'
371# Caution: The replacement is done with sed, so $1 must be escaped
372#          properly.  (The delimiter is '#'.)
373_get_data_file()
374{
375    if ! echo "$IMGOPTS" | grep -q 'data_file='; then
376        return 1
377    fi
378
379    echo "$IMGOPTS" | sed -e 's/.*data_file=\([^,]*\).*/\1/' \
380                    | sed -e "s#\\\$TEST_IMG#$1#"
381}
382
383# Translate a $TEST_IMG to its corresponding $TEST_IMG_FILE for
384# different protocols
385_test_img_to_test_img_file()
386{
387    case "$IMGPROTO" in
388        file)
389            echo "$1"
390            ;;
391
392        fuse)
393            echo "$1" | sed -e "s#$SOCK_DIR/fuse-#$TEST_DIR/#"
394            ;;
395
396        nfs)
397            echo "$1" | sed -e "s#nfs://127.0.0.1##"
398            ;;
399
400        ssh)
401            echo "$1" | \
402                sed -e "s#ssh://\\($USER@\\)\\?127.0.0.1\\(:[0-9]\\+\\)\\?##"
403            ;;
404
405        *)
406            return 1
407            ;;
408    esac
409}
410
411_make_test_img()
412{
413    # extra qemu-img options can be added by tests
414    # at least one argument (the image size) needs to be added
415    local extra_img_options=""
416    local optstr=""
417    local img_name=""
418    local use_backing=0
419    local backing_file=""
420    local object_options=""
421    local opts_param=false
422    local misc_params=()
423
424    if [[ $IMGPROTO == fuse && $TEST_IMG == $SOCK_DIR/fuse-* ]]; then
425        # The caller may be trying to overwrite an existing image
426        _rm_test_img "$TEST_IMG"
427    fi
428
429    if [ -z "$TEST_IMG_FILE" ]; then
430        img_name=$TEST_IMG
431    elif [ "$IMGOPTSSYNTAX" != "true" -a \
432           "$TEST_IMG_FILE" = "$ORIG_TEST_IMG_FILE" ]; then
433        # Handle cases of tests only updating TEST_IMG, but not TEST_IMG_FILE
434        img_name=$(_test_img_to_test_img_file "$TEST_IMG")
435        if [ "$?" != 0 ]; then
436            img_name=$TEST_IMG_FILE
437        fi
438    else
439        # $TEST_IMG_FILE is not the default value, so it definitely has been
440        # modified by the test
441        img_name=$TEST_IMG_FILE
442    fi
443
444    if [ -n "$IMGOPTS" ]; then
445        imgopts_expanded=$(echo "$IMGOPTS" | sed -e "s#\\\$TEST_IMG#$img_name#")
446        optstr=$(_optstr_add "$optstr" "$imgopts_expanded")
447    fi
448    if [ -n "$IMGKEYSECRET" ]; then
449        object_options="--object secret,id=keysec0,data=$IMGKEYSECRET"
450        optstr=$(_optstr_add "$optstr" "key-secret=keysec0")
451    fi
452
453    for param; do
454        if [ "$use_backing" = "1" -a -z "$backing_file" ]; then
455            backing_file=$param
456            continue
457        elif $opts_param; then
458            optstr=$(_optstr_add "$optstr" "$param")
459            opts_param=false
460            continue
461        fi
462
463        case "$param" in
464            -b)
465                use_backing=1
466                ;;
467
468            -o)
469                opts_param=true
470                ;;
471
472            --no-opts)
473                optstr=""
474                ;;
475
476            *)
477                misc_params=("${misc_params[@]}" "$param")
478                ;;
479        esac
480    done
481
482    if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
483        optstr=$(_optstr_add "$optstr" "cluster_size=$CLUSTER_SIZE")
484    fi
485
486    if [ -n "$optstr" ]; then
487        extra_img_options="-o $optstr $extra_img_options"
488    fi
489
490    if [ $IMGPROTO = "nbd" ]; then
491        _stop_nbd_server
492    fi
493
494    # XXX(hch): have global image options?
495    (
496     if [ $use_backing = 1 ]; then
497        $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options -b "$backing_file" "$img_name" "${misc_params[@]}" 2>&1
498     else
499        $QEMU_IMG create $object_options -f $IMGFMT $extra_img_options "$img_name" "${misc_params[@]}" 2>&1
500     fi
501    ) | _filter_img_create
502
503    # Start an NBD server on the image file, which is what we'll be talking to.
504    # Once NBD gains resize support, we may also want to use -f raw at the
505    # server and interpret format over NBD, but for now, the format is
506    # interpreted at the server and raw data sent over NBD.
507    if [ $IMGPROTO = "nbd" ]; then
508        # Pass a sufficiently high number to -e that should be enough for all
509        # tests
510        eval "$QEMU_NBD -v -t -k '$SOCK_DIR/nbd' -f $IMGFMT -e 42 -x '' $TEST_IMG_FILE >/dev/null &"
511        sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
512    fi
513
514    if [ $IMGPROTO = "fuse" -a -f "$img_name" ]; then
515        local export_mp
516        local pid
517        local pidfile
518        local timeout
519
520        export_mp=$(echo "$img_name" | sed -e "s#$TEST_DIR/#$SOCK_DIR/fuse-#")
521        if ! echo "$export_mp" | grep -q "^$SOCK_DIR"; then
522            echo 'Cannot use FUSE exports with images outside of TEST_DIR' >&2
523            return 1
524        fi
525
526        touch "$export_mp"
527        rm -f "$SOCK_DIR/fuse-output"
528
529        # Usually, users would export formatted nodes.  But we present fuse as a
530        # protocol-level driver here, so we have to leave the format to the
531        # client.
532        # Switch off allow-other, because in general we do not need it for
533        # iotests.  The default allow-other=auto has the downside of printing a
534        # fusermount error on its first attempt if allow_other is not
535        # permissible, which we would need to filter.
536        QSD_NEED_PID=y $QSD \
537              --blockdev file,node-name=export-node,filename=$img_name,discard=unmap \
538              --export fuse,id=fuse-export,node-name=export-node,mountpoint="$export_mp",writable=on,growable=on,allow-other=off \
539              &
540
541        pidfile="$QEMU_TEST_DIR/qemu-storage-daemon.pid"
542
543        # Wait for the PID file
544        while [ ! -f "$pidfile" ]; do
545            sleep 0.5
546        done
547
548        pid=$(cat "$pidfile")
549        rm -f "$pidfile"
550
551        FUSE_PIDS+=($pid)
552        FUSE_EXPORTS+=("$export_mp")
553    fi
554}
555
556_rm_test_img()
557{
558    local img=$1
559
560    if [[ $IMGPROTO == fuse && $img == $SOCK_DIR/fuse-* ]]; then
561        # Drop a FUSE export
562        local df_output
563        local i
564        local image_file
565        local index=''
566        local timeout
567
568        for i in "${!FUSE_EXPORTS[@]}"; do
569            if [ "${FUSE_EXPORTS[i]}" = "$img" ]; then
570                index=$i
571                break
572            fi
573        done
574
575        if [ -z "$index" ]; then
576            # Probably gone already
577            return 0
578        fi
579
580        kill "${FUSE_PIDS[index]}"
581
582        # Wait until the mount is gone
583        timeout=10 # *0.5 s
584        while true; do
585            # Will show the mount point; if the mount is still there,
586            # it will be $img.
587            df_output=$(df "$img" 2>/dev/null)
588
589            # But df may also show an error ("Transpoint endpoint not
590            # connected"), so retry in such cases
591            if [ -n "$df_output" ]; then
592                if ! echo "$df_output" | grep -q "$img"; then
593                    break
594                fi
595            fi
596
597            sleep 0.5
598
599            timeout=$((timeout - 1))
600            if [ "$timeout" = 0 ]; then
601                echo 'Failed to take down FUSE export' >&2
602                return 1
603            fi
604        done
605
606        rm -f "$img"
607
608        unset "FUSE_PIDS[$index]"
609        unset "FUSE_EXPORTS[$index]"
610
611        image_file=$(echo "$img" | sed -e "s#$SOCK_DIR/fuse-#$TEST_DIR/#")
612        _rm_test_img "$image_file"
613        return
614    fi
615
616    if [ "$IMGFMT" = "vmdk" ]; then
617        # Remove all the extents for vmdk
618        "$QEMU_IMG" info "$img" 2>/dev/null | grep 'filename:' | cut -f 2 -d: \
619            | xargs -I {} rm -f "{}"
620    elif [ "$IMGFMT" = "qcow2" ]; then
621        # Remove external data file
622        if data_file=$(_get_data_file "$img"); then
623            rm -f "$data_file"
624        fi
625    fi
626    rm -f "$img"
627}
628
629_cleanup_test_img()
630{
631    case "$IMGPROTO" in
632
633        nbd)
634            _stop_nbd_server
635            rm -f "$TEST_IMG_FILE"
636            ;;
637
638        fuse)
639            local mp
640
641            for mp in "${FUSE_EXPORTS[@]}"; do
642                _rm_test_img "$mp"
643            done
644
645            FUSE_PIDS=()
646            FUSE_EXPORTS=()
647            ;;
648
649        file)
650            _rm_test_img "$TEST_DIR/t.$IMGFMT"
651            _rm_test_img "$TEST_DIR/t.$IMGFMT.orig"
652            _rm_test_img "$TEST_DIR/t.$IMGFMT.base"
653            if [ -n "$SAMPLE_IMG_FILE" ]
654            then
655                rm -f "$TEST_DIR/$SAMPLE_IMG_FILE"
656                SAMPLE_IMG_FILE=
657                TEST_IMG="$ORIG_TEST_IMG"
658            fi
659            ;;
660
661        rbd)
662            rbd --no-progress rm "$TEST_DIR/t.$IMGFMT" > /dev/null
663            ;;
664
665    esac
666}
667
668_check_test_img()
669{
670    (
671        if [ "$IMGOPTSSYNTAX" = "true" ]; then
672            $QEMU_IMG check $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1
673        else
674            $QEMU_IMG check "$@" -f $IMGFMT "$TEST_IMG" 2>&1
675        fi
676    ) | _filter_testdir | _filter_qemu_img_check
677
678    # return real qemu_img check status, to analyze in
679    # _check_test_img_ignore_leaks
680    return ${PIPESTATUS[0]}
681}
682
683_check_test_img_ignore_leaks()
684{
685    out=$(_check_test_img "$@")
686    status=$?
687    if [ $status = 3 ]; then
688        # This must correspond to success output in dump_human_image_check()
689        echo "No errors were found on the image."
690        return 0
691    fi
692    echo "$out"
693    return $status
694}
695
696_img_info()
697{
698    if [[ "$1" == "--format-specific" ]]; then
699        local format_specific=1
700        shift
701    else
702        local format_specific=0
703    fi
704
705    discard=0
706    regex_json_spec_start='^ *"format-specific": \{'
707    $QEMU_IMG info $QEMU_IMG_EXTRA_ARGS "$@" "$TEST_IMG" 2>&1 | \
708        sed -e "s#$REMOTE_TEST_DIR#TEST_DIR#g" \
709            -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
710            -e "s#$TEST_DIR#TEST_DIR#g" \
711            -e "s#$SOCK_DIR/fuse-#TEST_DIR/#g" \
712            -e "s#$IMGFMT#IMGFMT#g" \
713            -e 's/\(compression type: \)\(zlib\|zstd\)/\1COMPRESSION_TYPE/' \
714            -e "/^disk size:/ D" \
715            -e "/actual-size/ D" | \
716        while IFS='' read -r line; do
717            if [[ $format_specific == 1 ]]; then
718                discard=0
719            elif [[ $line == "Format specific information:" ]]; then
720                discard=1
721            elif [[ $line =~ $regex_json_spec_start ]]; then
722                discard=2
723                regex_json_spec_end="^${line%%[^ ]*}\\},? *$"
724            fi
725            if [[ $discard == 0 ]]; then
726                echo "$line"
727            elif [[ $discard == 1 && ! $line ]]; then
728                echo
729                discard=0
730            elif [[ $discard == 2 && $line =~ $regex_json_spec_end ]]; then
731                discard=0
732            fi
733        done
734}
735
736# bail out, setting up .casenotrun file
737# The function _casenotrun() is used as a notifier. It is the
738# caller's responsibility to make skipped a particular test.
739#
740_casenotrun()
741{
742    echo "    [case not run] $*" >>"$TEST_DIR/$seq.casenotrun"
743}
744
745# just plain bail out
746#
747_fail()
748{
749    echo "$*" | tee -a "$TEST_DIR/$seq.full"
750    echo "(see $seq.full for details)"
751    status=1
752    exit 1
753}
754
755# tests whether $IMGFMT is one of the supported image formats for a test
756#
757_supported_fmt()
758{
759    # "generic" is suitable for most image formats. For some formats it doesn't
760    # work, however (most notably read-only formats), so they can opt out by
761    # setting IMGFMT_GENERIC to false.
762    for f; do
763        if [ "$f" = "$IMGFMT" -o "$f" = "generic" -a "$IMGFMT_GENERIC" = "true" ]; then
764            if [ "$IMGFMT" = "luks" ]; then
765                _require_working_luks
766            fi
767            return
768        fi
769    done
770
771    _notrun "not suitable for this image format: $IMGFMT"
772}
773
774# tests whether $IMGFMT is one of the unsupported image format for a test
775#
776_unsupported_fmt()
777{
778    for f; do
779        if [ "$f" = "$IMGFMT" ]; then
780            _notrun "not suitable for this image format: $IMGFMT"
781        fi
782    done
783}
784
785# tests whether $IMGPROTO is one of the supported image protocols for a test
786#
787_supported_proto()
788{
789    for f; do
790        if [ "$f" = "$IMGPROTO" -o "$f" = "generic" ]; then
791            return
792        fi
793    done
794
795    _notrun "not suitable for this image protocol: $IMGPROTO"
796}
797
798# tests whether $IMGPROTO is specified as an unsupported image protocol for a test
799#
800_unsupported_proto()
801{
802    for f; do
803        if [ "$f" = "$IMGPROTO" ]; then
804            _notrun "not suitable for this image protocol: $IMGPROTO"
805            return
806        fi
807    done
808}
809
810# tests whether the host OS is one of the supported OSes for a test
811#
812_supported_os()
813{
814    for h
815    do
816        if [ "$h" = "$HOSTOS" ]
817        then
818            return
819        fi
820    done
821
822    _notrun "not suitable for this OS: $HOSTOS"
823}
824
825_supported_cache_modes()
826{
827    for mode; do
828        if [ "$mode" = "$CACHEMODE" ]; then
829            return
830        fi
831    done
832    _notrun "not suitable for cache mode: $CACHEMODE"
833}
834
835# Check whether the filesystem supports O_DIRECT
836_check_o_direct()
837{
838    testfile="$TEST_DIR"/_check_o_direct
839    $QEMU_IMG create -f raw "$testfile" 1M > /dev/null
840    out=$($QEMU_IO -f raw -t none -c quit "$testfile" 2>&1)
841    rm -f "$testfile"
842
843    [[ "$out" != *"O_DIRECT"* ]]
844}
845
846_require_o_direct()
847{
848    if ! _check_o_direct; then
849        _notrun "file system on $TEST_DIR does not support O_DIRECT"
850    fi
851}
852
853_check_cache_mode()
854{
855    if [ $CACHEMODE == "none" ] || [ $CACHEMODE == "directsync" ]; then
856        _require_o_direct
857    fi
858}
859
860_check_cache_mode
861
862# $1 - cache mode to use by default
863# $2 - (optional) cache mode to use by default if O_DIRECT is not supported
864_default_cache_mode()
865{
866    if $CACHEMODE_IS_DEFAULT; then
867        if [ -z "$2" ] || _check_o_direct; then
868            CACHEMODE="$1"
869        else
870            CACHEMODE="$2"
871        fi
872        QEMU_IO="$QEMU_IO --cache $CACHEMODE"
873        _check_cache_mode
874        return
875    fi
876}
877_supported_aio_modes()
878{
879    for mode; do
880        if [ "$mode" = "$AIOMODE" ]; then
881            return
882        fi
883    done
884    _notrun "not suitable for aio mode: $AIOMODE"
885}
886_default_aio_mode()
887{
888    AIOMODE="$1"
889    QEMU_IO="$QEMU_IO --aio $1"
890}
891
892_unsupported_imgopts()
893{
894    for bad_opt
895    do
896        # Add a space so tests can match for whitespace that marks the
897        # end of an option (\b or \> are not portable)
898        if echo "$IMGOPTS " | grep -q 2>/dev/null "$bad_opt"
899        then
900            _notrun "not suitable for image option: $bad_opt"
901        fi
902    done
903}
904
905# Caution: Overwrites $TEST_DIR/t.luks
906_require_working_luks()
907{
908    file="$TEST_DIR/t.luks"
909
910    output=$(
911        $QEMU_IMG create -f luks \
912            --object secret,id=sec0,data=hunter0 \
913            -o key-secret=sec0 \
914            -o iter-time=10 \
915            "$file" \
916            1M \
917            2>&1
918    )
919    status=$?
920
921    IMGFMT='luks' _rm_test_img "$file"
922
923    if [ $status != 0 ]; then
924        reason=$(echo "$output" | grep "$file:" | sed -e "s#.*$file: *##")
925        if [ -z "$reason" ]; then
926            reason="Failed to create a LUKS image"
927        fi
928        _notrun "$reason"
929    fi
930}
931
932# this test requires that a specified command (executable) exists
933#
934_require_command()
935{
936    if [ "$1" = "QEMU" ]; then
937        c=$QEMU_PROG
938    elif [ "$1" = "QEMU_IMG" ]; then
939        c=$QEMU_IMG_PROG
940    elif [ "$1" = "QEMU_IO" ]; then
941        c=$QEMU_IO_PROG
942    elif [ "$1" = "QEMU_NBD" ]; then
943        c=$QEMU_NBD_PROG
944    else
945        eval c=\$$1
946    fi
947    [ -x "$c" ] || _notrun "$1 utility required, skipped this test"
948}
949
950# Check that a set of drivers has been whitelisted in the QEMU binary
951#
952_require_drivers()
953{
954    available=$($QEMU -drive format=help | \
955                sed -e '/Supported formats:/!d' -e 's/Supported formats://')
956    for driver
957    do
958        if ! echo "$available" | grep -q " $driver\( \|$\)"; then
959            _notrun "$driver not available"
960        fi
961    done
962}
963
964# Check that we have a file system that allows huge (but very sparse) files
965#
966_require_large_file()
967{
968    if ! truncate --size="$1" "$TEST_IMG"; then
969        _notrun "file system on $TEST_DIR does not support large enough files"
970    fi
971    rm "$TEST_IMG"
972}
973
974# Check that a set of devices is available in the QEMU binary
975#
976_require_devices()
977{
978    available=$($QEMU -M none -device help | \
979                grep ^name | sed -e 's/^name "//' -e 's/".*$//')
980    for device
981    do
982        if ! echo "$available" | grep -q "$device" ; then
983            _notrun "$device not available"
984        fi
985    done
986}
987
988_require_one_device_of()
989{
990    available=$($QEMU -M none -device help | \
991                grep ^name | sed -e 's/^name "//' -e 's/".*$//')
992    for device
993    do
994        if echo "$available" | grep -q "$device" ; then
995            return
996        fi
997    done
998    _notrun "$* not available"
999}
1000
1001_qcow2_dump_header()
1002{
1003    if [[ "$1" == "--no-filter-compression" ]]; then
1004        local filter_compression=0
1005        shift
1006    else
1007        local filter_compression=1
1008    fi
1009
1010    img="$1"
1011    if [ -z "$img" ]; then
1012        img="$TEST_IMG"
1013    fi
1014
1015    if [[ $filter_compression == 0 ]]; then
1016        $PYTHON qcow2.py "$img" dump-header
1017    else
1018        $PYTHON qcow2.py "$img" dump-header | _filter_qcow2_compression_type_bit
1019    fi
1020}
1021
1022# make sure this script returns success
1023true
1024