btrfs-progs: tests: check for TEST_LOG values by a regex
[platform/upstream/btrfs-progs.git] / tests / common
1 #!/bin/bash
2 #
3 # Common routines for all tests
4 #
5
6 # assert that argument is not empty and is an existing path (file or directory)
7 _assert_path()
8 {
9         local path
10
11         path="$1"
12         if [ -z "$path" ]; then
13                 echo "ASSERTION FAIL: $path is not valid"
14                 exit 1
15         fi
16
17         if [ -f "$path" -o -d "$path" -o -b "$path" ]; then
18                 return 0
19         fi
20         echo "ASSERTION FAIL: $path is not valid"
21         exit 1
22 }
23
24 _fail()
25 {
26         echo "$*" | tee -a "$RESULTS"
27         exit 1
28 }
29
30 # log a message to the results file
31 _log()
32 {
33         echo "$*" | tee -a "$RESULTS"
34 }
35
36 _not_run()
37 {
38         echo "    [NOTRUN] $*"
39         exit 0
40 }
41
42 run_check()
43 {
44         echo "############### $@" >> "$RESULTS" 2>&1
45         if [[ $TEST_LOG =~ tty ]]; then echo "CMD: $@" > /dev/tty; fi
46         if [ "$1" = 'root_helper' ]; then
47                 "$@" >> "$RESULTS" 2>&1 || _fail "failed: $@"
48         else
49                 $INSTRUMENT "$@" >> "$RESULTS" 2>&1 || _fail "failed: $@"
50         fi
51 }
52
53 # same as run_check but the stderr+stdout output is duplicated on stdout and
54 # can be processed further
55 run_check_stdout()
56 {
57         echo "############### $@" >> "$RESULTS" 2>&1
58         if [[ $TEST_LOG =~ tty ]]; then echo "CMD(stdout): $@" > /dev/tty; fi
59         if [ "$1" = 'root_helper' ]; then
60                 "$@" 2>&1 | tee -a "$RESULTS" || _fail "failed: $@"
61         else
62                 $INSTRUMENT "$@" 2>&1 | tee -a "$RESULTS" || _fail "failed: $@"
63         fi
64 }
65
66 # same as run_check but does not fail the test if it's handled gracefully by
67 # the tool, unexpected failure like segfault or abor will exit forcibly
68 # output is logged
69 run_mayfail()
70 {
71         local ret
72
73         echo "############### $@" >> "$RESULTS" 2>&1
74         if [[ $TEST_LOG =~ tty ]]; then echo "CMD(mayfail): $@" > /dev/tty; fi
75         if [ "$1" = 'root_helper' ]; then
76                 "$@" >> $RESULTS 2>&1
77         else
78                 $INSTRUMENT "$@" >> "$RESULTS" 2>&1
79         fi
80         ret=$?
81         if [ $ret != 0 ]; then
82                 echo "failed (ignored, ret=$ret): $@" >> "$RESULTS"
83                 if [ $ret == 139 ]; then
84                         _fail "mayfail: returned code 139 (SEGFAULT), not ignored"
85                 elif [ $ret == 134 ]; then
86                         _fail "mayfail: returned code 134 (SIGABRT), not ignored"
87                 fi
88                 return $ret
89         fi
90 }
91
92 # first argument is error message to print if it fails, otherwise
93 # same as run_check but expects the command to fail, output is logged
94 run_mustfail()
95 {
96         local msg
97
98         msg="$1"
99         shift
100
101         echo "############### $@" >> "$RESULTS" 2>&1
102         if [[ $TEST_LOG =~ tty ]]; then echo "CMD(mustfail): $@" > /dev/tty; fi
103         if [ "$1" = 'root_helper' ]; then
104                 "$@" >> "$RESULTS" 2>&1
105         else
106                 $INSTRUMENT "$@" >> "$RESULTS" 2>&1
107         fi
108         if [ $? != 0 ]; then
109                 echo "failed (expected): $@" >> "$RESULTS"
110                 return 0
111         else
112                 echo "succeeded (unexpected!): $@" >> "$RESULTS"
113                 _fail "unexpected success: $msg"
114                 return 1
115         fi
116 }
117
118 check_prereq()
119 {
120         if ! [ -f "$TOP/$1" ]; then
121                 _fail "Failed prerequisites: $1";
122         fi
123 }
124
125 check_global_prereq()
126 {
127         which $1 &> /dev/null
128         if [ $? -ne 0 ]; then
129                 _fail "Failed system wide prerequisities: $1";
130         fi
131 }
132
133 check_image()
134 {
135         local image
136
137         image=$1
138         echo "testing image $(basename $image)" >> "$RESULTS"
139         $TOP/btrfs check "$image" >> "$RESULTS" 2>&1
140         [ $? -eq 0 ] && _fail "btrfs check should have detected corruption"
141
142         run_check $TOP/btrfs check --repair "$image"
143         run_check $TOP/btrfs check "$image"
144 }
145
146 # Extract a usable image from packed formats
147 # - raw btrfs filesystem images, suffix .raw
148 # - dtto compressed by XZ, suffix .raw.xz
149 # - meta-dump images with suffix .img
150 # - dtto compressed by XZ, suffix .img.xz
151 # - compressed send stream, .stream.xz
152 extract_image()
153 {
154         local image
155         local cleanme
156
157         image="$1"
158         case "$image" in
159         *.img)
160                 rm -f "$image.restored"
161                 : ;;
162         *.img.xz)
163                 xz --decompress --keep "$image" || \
164                         _fail "failed to decompress image $image" >&2
165                 image=${image%%.xz}
166                 rm -f "$image.restored"
167                 cleanme=$image
168                 ;;
169         *.raw)
170                 cp --sparse=auto "$image" "$image.restored"
171                 ;;
172         *.raw.xz)
173                 xz --decompress --keep "$image" || \
174                         _fail "failed to decompress image $image" >&2
175                 image=${image%%.xz}
176                 mv "$image" "$image.restored"
177                 ;;
178         *.stream.xz)
179                 xz --decompress --keep "$image" || \
180                         _fail "failed to decompress file $image" >&2
181                 image=${image%%.xz}
182                 mv "$image" "$image.restored"
183                 ;;
184         esac
185
186         if ! [ -f "$image.restored" ]; then
187                 echo "restoring image $(basename $image)" >> "$RESULTS"
188                 "$TOP/btrfs-image" -r "$image" "$image.restored" \
189                         &>> "$RESULTS" \
190                         || _fail "failed to restore image $image" >&2
191         fi
192
193         [ -f "$cleanme" ] && rm -f "$cleanme"
194
195         echo "$image.restored"
196 }
197
198 # Process all image dumps in a given directory
199 check_all_images()
200 {
201         local dir
202         local extracted
203
204         dir="$1"
205         for image in $(find "$dir" \( -iname '*.img' -o \
206                                 -iname '*.img.xz' -o    \
207                                 -iname '*.raw' -o       \
208                                 -iname '*.raw.xz' \) | sort)
209         do
210                 extracted=$(extract_image "$image")
211                 check_image "$extracted"
212                 rm -f "$extracted"
213         done
214 }
215
216 # some tests need to mount the recovered image and do verifications call
217 # 'setup_root_helper' and then check for have_root_helper == 1 if the test
218 # needs to fail otherwise; using sudo by default for now
219 SUDO_HELPER=
220 NEED_SUDO_VALIDATE=unknown
221 export SUDO_HELPER
222 export NEED_SUDO_VALIDATE
223 root_helper()
224 {
225         if [ $UID -eq 0 ]; then
226                 "$@"
227         else
228                 if [ "$NEED_SUDO_VALIDATE" = 'yes' ]; then
229                         sudo -v -n &>/dev/null || \
230                                 _not_run "Need to validate sudo credentials"
231                         sudo -n "$@"
232                 elif [ "$NEED_SUDO_VALIDATE" = 'no' ]; then
233                         sudo -n /bin/true &> /dev/null || \
234                                 _not_run "Need to validate sudo user settings"
235                         sudo -n "$@"
236                 else
237                         # should not happen
238                         _not_run "Need to validate root privileges"
239                 fi
240         fi
241 }
242
243 setup_root_helper()
244 {
245         if [ $UID -eq 0 -o -n "$SUDO_HELPER" ]; then
246                 return
247         fi
248
249         # Test for old sudo or special settings, which make sudo -v fail even
250         # if user setting is NOPASSWD
251         sudo -n /bin/true &>/dev/null && NEED_SUDO_VALIDATE=no
252
253         # Newer sudo or default sudo setting
254         sudo -v -n &>/dev/null && NEED_SUDO_VALIDATE=yes
255
256         if [ "$NEED_SUDO_VALIDATE" = 'unknown' ]; then
257                 _not_run "Need to validate root privileges"
258         fi
259         SUDO_HELPER=root_helper
260 }
261
262 prepare_test_dev()
263 {
264         # num[K/M/G/T...]
265         local size="$1"
266
267         [[ "$TEST_DEV" ]] && return
268         [[ "$size" ]] || size='2G'
269
270         echo "\$TEST_DEV not given, use $TOP/test/test.img as fallback" >> \
271                 "$RESULTS"
272         TEST_DEV="$TOP/tests/test.img"
273
274         truncate -s "$size" "$TEST_DEV" || _not_run "create file for loop device failed"
275 }
276
277 run_check_mount_test_dev()
278 {
279         setup_root_helper
280
281         local loop_opt
282         if [[ -b "$TEST_DEV" ]]; then
283                 loop_opt=""
284         elif [[ -f "$TEST_DEV" ]]; then
285                 loop_opt="-o loop"
286         else
287                 _fail "Invalid \$TEST_DEV: $TEST_DEV"
288         fi
289
290         [[ -d "$TEST_MNT" ]] || {
291                 _fail "Invalid \$TEST_MNT: $TEST_MNT"
292         }
293
294         run_check $SUDO_HELPER mount $loop_opt "$@" "$TEST_DEV" "$TEST_MNT"
295 }
296
297 run_check_umount_test_dev()
298 {
299         setup_root_helper
300         run_check $SUDO_HELPER umount "$@" "$TEST_DEV"
301 }
302
303 check_kernel_support()
304 {
305         if ! grep -iq 'btrfs' /proc/filesystems; then
306                 echo "WARNING: btrfs filesystem not listed in /proc/filesystems, some tests might fail"
307                 return 1
308         fi
309         return 0
310 }
311
312 init_env()
313 {
314         TEST_MNT="${TEST_MNT:-$TOP/tests/mnt}"
315         export TEST_MNT
316         mkdir -p "$TEST_MNT" || { echo "Failed mkdir -p $TEST_MNT"; exit 1; }
317
318 }
319 init_env