xfstests generic/313: test ctime and mtime are updated on truncate and ftruncate
[xfstests-dev.git] / check
1 #!/bin/bash
2 #
3 # Control script for QA
4 #
5 # Copyright (c) 2000-2002,2006 Silicon Graphics, Inc.  All Rights Reserved.
6 #
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License as
9 # published by the Free Software Foundation.
10 #
11 # This program is distributed in the hope that it would 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, write the Free Software Foundation,
18 # Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 #
20 #
21
22 tmp=/tmp/$$
23 status=0
24 needwrap=true
25 n_try=0
26 try=""
27 n_bad=0
28 bad=""
29 notrun=""
30 interrupt=true
31 diff="diff -u"
32 showme=false
33 have_test_arg=false
34 randomize=false
35 here=`pwd`
36 FSTYP=xfs
37 xfile=""
38
39 # start the initialisation work now
40 iam=check
41
42 export MSGVERB="text:action"
43 export QA_CHECK_FS=${QA_CHECK_FS:=true}
44
45 # number of diff lines from a failed test, 0 for whole output
46 export DIFF_LENGTH=${DIFF_LENGTH:=10}
47
48 # by default don't output timestamps
49 timestamp=${TIMESTAMP:=false}
50
51 rm -f $tmp.list $tmp.tmp $tmp.grep $here/$iam.out $tmp.xlist
52
53 # we need common/config
54 if ! . ./common/config
55 then
56     echo "$iam: failed to source common/config"
57     exit 1
58 fi
59
60 # Autodetect fs type based on what's on $TEST_DEV
61 if [ "$HOSTOS" == "Linux" ]; then
62     FSTYP=`blkid -c /dev/null -s TYPE -o value $TEST_DEV`
63 fi
64 export FSTYP
65
66 SUPPORTED_TESTS="[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]"
67 SRC_GROUPS="generic shared"
68 export SRC_DIR="tests"
69 export RESULT_BASE=${RESULT_BASE:="$here/results"}
70
71 usage()
72 {
73     echo "Usage: $0 [options] [testlist]"'
74
75 check options
76     -xfs                test XFS (default)
77     -udf                test UDF
78     -nfs                test NFS
79     -l                  line mode diff
80     -udiff              show unified diff (default)
81     -n                  show me, do not run tests
82     -T                  output timestamps
83     -r                  randomize test order
84     --large-fs          optimise scratch device for large filesystems
85
86 testlist options
87     -g group[,group...] include tests from these groups
88     -x group[,group...] exclude tests from these groups
89     -X file             exclude individual tests
90     [testlist]          include tests matching names in testlist
91 '
92             exit 0
93 }
94
95 get_group_list()
96 {
97         grp=$1
98
99         for d in $SRC_GROUPS $FSTYP; do
100                 l=$(sed -n < $SRC_DIR/$d/group \
101                         -e 's/#.*//' \
102                         -e 's/$/ /' \
103                         -e "s;\(^[0-9][0-9][0-9]\).* $grp .*;$SRC_DIR/$d/\1;p")
104                 grpl="$grpl $l"
105         done
106         echo $grpl
107 }
108
109 # find all tests, excluding files that are test metadata such as group files.
110 # This assumes that tests are defined purely by alphanumeric filenames with no
111 # ".xyz" extensions in the name.
112 get_all_tests()
113 {
114         touch $tmp.list
115         for d in $SRC_GROUPS $FSTYP; do
116                 ls $SRC_DIR/$d/* | \
117                         grep -v "\..*" | \
118                         grep -v group >> $tmp.list 2>/dev/null
119         done
120 }
121
122 # takes the list of tests to run in $tmp.list, and removes the tests passed to
123 # the function from that list.
124 trim_test_list()
125 {
126         test_list="$*"
127
128         rm -f $tmp.grep
129         numsed=0
130         for t in $test_list
131         do
132             if [ $numsed -gt 100 ]; then
133                 grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
134                 mv $tmp.tmp $tmp.list
135                 numsed=0
136                 rm -f $tmp.grep
137             fi
138             echo "^$t\$" >>$tmp.grep
139             numsed=`expr $numsed + 1`
140         done
141         grep -v -f $tmp.grep <$tmp.list >$tmp.tmp
142         mv $tmp.tmp $tmp.list
143 }
144
145
146 _wallclock()
147 {
148     date "+%H %M %S" | $AWK_PROG '{ print $1*3600 + $2*60 + $3 }'
149 }
150
151 _timestamp()
152 {
153     now=`date "+%T"`
154     echo -n " [$now]"
155 }
156
157 # Process command arguments first.
158 while [ $# -gt 0 ]; do
159         case "$1" in
160         -\? | -h | --help) usage ;;
161
162         -udf)   FSTYP=udf ;;
163         -xfs)   FSTYP=xfs ;;
164         -nfs)   FSTYP=nfs ;;
165
166         -g)     group=$2 ; shift ;
167                 group_list=$(get_group_list $group)
168                 if [ -z "$group_list" ]; then
169                     echo "Group \"$group\" is empty or not defined?"
170                     exit 1
171                 fi
172
173                 [ ! -s $tmp.list ] && touch $tmp.list
174                 for t in $group_list; do
175                         grep -s "^$t\$" $tmp.list >/dev/null || \
176                                                         echo "$t" >>$tmp.list
177                 done
178
179                 ;;
180
181         -x)     xgroup=$2 ; shift ;
182
183                 # Note: behaviour is dependent on command line ordering of
184                 # -g and -x parameters. If there are no preceding -g commands,
185                 # this works on all tests, otherwise just the tests specified by
186                 # the early -g inclusions.
187                 [ ! -s $tmp.list ] && get_all_tests
188
189                 group_list=$(get_group_list $xgroup)
190                 if [ -z "$group_list" ]; then
191                     echo "Group \"$xgroup\" is empty or not defined?"
192                     exit 1
193                 fi
194
195                 trim_test_list $group_list
196                 ;;
197
198         -X)     xfile=$2; shift ;
199                 for d in $SRC_GROUPS $FSTYP; do
200                         [ -f $SRC_DIR/$d/$xfile ] || continue
201                         for f in `cat $SRC_DIR/$d/$xfile`; do
202                                 echo $d/$f >> $tmp.xlist
203                         done
204                 done
205                 ;;
206
207         -l)     diff="diff" ;;
208         -udiff) diff="$diff -u" ;;
209
210         -n)     showme=true ;;
211         -r)     randomize=true ;;
212
213         -T)     timestamp=true ;;
214
215         --large-fs) export LARGE_SCRATCH_DEV=yes ;;
216         --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} ;;
217
218         -*)     usage ;;
219         *)      # not an argument, we've got tests now.
220                 have_test_arg=true ;;
221         esac
222
223         # if we've found a test specification, the break out of the processing
224         # loop before we shift the arguments so that this is the first argument
225         # that we process in the test arg loop below.
226         if $have_test_arg; then
227                 break;
228         fi
229
230         shift
231 done
232
233 # Process tests from command line now.
234 if $have_test_arg; then
235         while [ $# -gt 0 ]; do
236                 case "$1" in
237                 -*)     echo "Argments before tests, please!"
238                         status=1
239                         exit $status
240                         ;;
241                 *)      test_dir=`dirname $1`
242                         test_name=`basename $1`
243                         group_file=$SRC_DIR/$test_dir/group
244
245                         if egrep "^$test_name" $group_file >/dev/null ; then
246                                 # in group file ... OK
247                                 echo $SRC_DIR/$1 >>$tmp.list
248                         else
249                                 # oops
250                                 echo "$1 - unknown test, ignored"
251                         fi
252                         ;;
253                 esac
254
255                 shift
256         done
257 fi
258
259 if [ -s $tmp.list ]; then
260     # found some valid test numbers ... this is good
261     :
262 elif $have_test_arg; then
263         # had test numbers, but none in group file ... do nothing
264         touch $tmp.list
265 else
266         # no test numbers, do everything from group file
267         sed -n -e '/^[0-9][0-9][0-9]*/s/[       ].*//p' <group >$tmp.list
268 fi
269
270 # sort the list of tests into numeric order
271 list=`sort -n $tmp.list`
272 rm -f $tmp.list $tmp.tmp $tmp.grep
273
274 if $randomize
275 then
276     list=`echo $list | awk -f randomize.awk`
277 fi
278
279 # we need common/rc
280 if ! . ./common/rc
281 then
282     echo "check: failed to source common/rc"
283     exit 1
284 fi
285
286 if [ `id -u` -ne 0 ]
287 then
288     echo "check: QA must be run as root"
289     exit 1
290 fi
291
292 # Ok, time to start running...
293
294 _wrapup()
295 {
296     seq="check"
297     check="$RESULT_BASE/check"
298
299     if $showme
300     then
301         :
302     elif $needwrap
303     then
304         if [ -f $check.time -a -f $tmp.time ]
305         then
306             cat $check.time $tmp.time \
307             | $AWK_PROG '
308         { t[$1] = $2 }
309 END     { if (NR > 0) {
310             for (i in t) print i " " t[i]
311           }
312         }' \
313             | sort -n >$tmp.out
314             mv $tmp.out $check.time
315         fi
316
317         echo "" >>$check.log
318         date >>$check.log
319         echo $list | fmt | sed -e 's/^/    /' -e "s;$SRC_DIR/;;g" >>$check.log
320         $interrupt && echo "Interrupted!" >>$check.log
321         
322         if [ ! -z "$n_try" -a $n_try != 0 ]
323         then
324             echo "Ran:$try"
325         fi
326
327         if [ ! -z "$notrun" ]
328         then
329             echo "Not run:$notrun"
330             echo "Not run:$notrun" >>$check.log
331         fi
332
333         if [ ! -z "$n_bad" -a $n_bad != 0 ]
334         then
335             echo "Failures:$bad"
336             echo "Failed $n_bad of $n_try tests"
337             echo "Failures:$bad" | fmt >>$check.log
338             echo "Failed $n_bad of $n_try tests" >>$check.log
339         else
340             echo "Passed all $n_try tests"
341             echo "Passed all $n_try tests" >>$check.log
342         fi
343         needwrap=false
344     fi
345
346     rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
347     rm -f $tmp.*
348 }
349
350 trap "_wrapup; exit \$status" 0 1 2 3 15
351
352 mkdir -p $RESULT_BASE
353 if [ ! -d $RESULT_BASE ]; then
354         echo "failed to create results directory $RESULTS_BASE"
355         exit 1;
356 fi
357
358 seq="check"
359 check="$RESULT_BASE/check"
360
361 # don't leave old full output behind on a clean run
362 rm -f $check.full
363
364 [ -f $check.time ] || touch $check.time
365
366 # print out our test configuration
367 echo "FSTYP         -- `_full_fstyp_details`"
368 echo "PLATFORM      -- `_full_platform_details`"
369 if [ ! -z "$SCRATCH_DEV" ]; then
370   echo "MKFS_OPTIONS  -- `_scratch_mkfs_options`"
371   echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
372 fi
373 echo
374
375
376 if [ ! -z "$SCRATCH_DEV" ]; then
377   umount $SCRATCH_DEV 2>/dev/null
378   # call the overridden mkfs - make sure the FS is built
379   # the same as we'll create it later.
380
381   if ! _scratch_mkfs $flag >$tmp.err 2>&1
382   then
383       echo "our local _scratch_mkfs routine ..."
384       cat $tmp.err
385       echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
386       exit 1
387   fi
388
389   # call the overridden mount - make sure the FS mounts with
390   # the same options that we'll mount with later.
391   if ! _scratch_mount >$tmp.err 2>&1
392   then
393       echo "our local mount routine ..."
394       cat $tmp.err
395       echo "check: failed to mount \$SCRATCH_DEV using specified options"
396       exit 1
397   fi
398 fi
399
400 seqres="$check"
401 _check_test_fs
402
403 for seq in $list
404 do
405     err=false
406
407     # the filename for the test and the name output are different.
408     # we don't include the tests/ directory in the name output.
409     seqnum=`echo $seq | sed -e "s;$SRC_DIR/;;"`
410
411     # Similarly, the result directory needs to replace the tests/
412     # part of the test location.
413     group=`dirname $seq`
414     export RESULT_DIR=`echo $group | sed -e "s;$SRC_DIR;$RESULT_BASE;"`
415     mkdir -p $RESULT_DIR
416     seqres="$RESULT_BASE/$seqnum"
417
418     echo -n "$seqnum"
419
420     if $showme
421     then
422         echo
423         continue
424     elif [ ! -f $seq ]
425     then
426         echo " - no such test?"
427     else
428         # really going to try and run this one
429         #
430         rm -f $seqres.out.bad
431
432         # check if we really should run it
433         if [ -s $tmp.xlist ]; then
434                 if grep $seqnum $tmp.xlist > /dev/null 2>&1 ; then
435                         echo "       [expunged]"
436                         continue
437                 fi
438         fi
439
440         # slashes now in names, sed barfs on them so use grep
441         lasttime=`grep -w ^$seqnum $check.time | awk '// {print $2}'`
442         if [ "X$lasttime" != X ]; then
443                 echo -n " ${lasttime}s ..."
444         else
445                 echo -n "       "       # prettier output with timestamps.
446         fi
447         rm -f core $seqres.notrun
448
449         start=`_wallclock`
450         $timestamp && echo -n " ["`date "+%T"`"]"
451         [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
452         $LOGGER_PROG "run xfstest $seqnum"
453         ./$seq >$tmp.rawout 2>&1
454         sts=$?
455         $timestamp && _timestamp
456         stop=`_wallclock`
457
458         _fix_malloc <$tmp.rawout >$tmp.out
459         rm -f $tmp.rawout
460
461         if [ -f core ]
462         then
463             echo -n " [dumped core]"
464             mv core $RESULT_BASE/$seqnum.core
465             err=true
466         fi
467
468         if [ -f $seqres.notrun ]
469         then
470             $timestamp || echo -n " [not run] "
471             $timestamp && echo " [not run]" && echo -n "        $seqnum -- "
472             cat $seqres.notrun
473             notrun="$notrun $seqnum"
474         else
475             if [ $sts -ne 0 ]
476             then
477                 echo -n " [failed, exit status $sts]"
478                 err=true
479             fi
480             if [ ! -f $seq.out ]
481             then
482                 echo " - no qualified output"
483                 err=true
484             else
485                 if diff $seq.out $tmp.out >/dev/null 2>&1
486                 then
487                     if $err
488                     then
489                         :
490                     else
491                         echo "$seqnum `expr $stop - $start`" >>$tmp.time
492                         echo -n " `expr $stop - $start`s"
493                     fi
494                     echo ""
495                 else
496                     echo " - output mismatch (see $seqres.out.bad)"
497                     mv $tmp.out $seqres.out.bad
498                     $diff $seq.out $seqres.out.bad | {
499                         if test "$DIFF_LENGTH" -le 0; then
500                                 cat
501                         else
502                                 head -n "$DIFF_LENGTH"
503                         fi; } | \
504                         sed -e 's/^\(.\)/    \1/'
505                     echo "     ..."
506                     echo "     (Run '$diff $seq.out $seqres.out.bad' to see the" \
507                          "entire diff)"
508                     err=true
509                 fi
510             fi
511         fi
512
513     fi
514
515     # come here for each test, except when $showme is true
516     #
517     if $err
518     then
519         bad="$bad $seqnum"
520         n_bad=`expr $n_bad + 1`
521         quick=false
522     fi
523     if [ ! -f $seqres.notrun ]
524     then
525         try="$try $seqnum"
526         n_try=`expr $n_try + 1`
527         _check_test_fs
528     fi
529
530     seq="after_$seqnum"
531 done
532
533 interrupt=false
534 status=`expr $n_bad`
535 exit