xfstests: fold common into check
[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
32 export QA_CHECK_FS=${QA_CHECK_FS:=true}
33 # number of diff lines from a failed test, 0 for whole output
34 export DIFF_LENGTH=${DIFF_LENGTH:=10}
35
36 # by default don't output timestamps
37 timestamp=${TIMESTAMP:=false}
38
39 # generic initialization
40 iam=check
41
42 # we need common.config
43 if ! . ./common.config
44 then
45     echo "$iam: failed to source common.config"
46     exit 1
47 fi
48
49 # argument parsing first - currently very messy, needs cleanup.
50 _setenvironment()
51 {
52     MSGVERB="text:action"
53     export MSGVERB
54 }
55
56 usage()
57 {
58     echo "Usage: $0 [options] [testlist]"'
59
60 common options
61     -v                  verbose
62
63 check options
64     -xfs                test XFS (default)
65     -udf                test UDF
66     -nfs                test NFS
67     -l                  line mode diff
68     -xdiff              graphical mode diff
69     -udiff              show unified diff (default)
70     -n                  show me, do not run tests
71     -q                  quick [deprecated]
72     -T                  output timestamps
73     -r                  randomize test order
74     --large-fs          optimise scratch device for large filesystems
75
76 testlist options
77     -g group[,group...] include tests from these groups
78     -x group[,group...] exclude tests from these groups
79     NNN                 include test NNN
80     NNN-NNN             include test range (eg. 012-021)
81 '
82             exit 0
83 }
84
85 here=`pwd`
86 rm -f $here/$iam.out
87 _setenvironment
88
89 check=${check-true}
90
91 diff="diff -u"
92 verbose=false
93 group=false
94 xgroup=false
95 showme=false
96 sortme=false
97 expunge=true
98 have_test_arg=false
99 randomize=false
100 rm -f $tmp.list $tmp.tmp $tmp.sed
101
102 # Autodetect fs type based on what's on $TEST_DEV
103 if [ "$HOSTOS" == "Linux" ]
104 then
105     export FSTYP=`blkid -c /dev/null -s TYPE -o value $TEST_DEV`
106 else
107     export FSTYP=xfs
108 fi
109
110 for r
111 do
112
113     if $group
114     then
115         # arg after -g
116        group_list=$(sed -n < group \
117                        -e 's/#.*//' \
118                        -e 's/$/ /' \
119                        -e "/^[0-9][0-9][0-9].* $r /"'{ s/ .*//p }')
120         if [ -z "$group_list" ]
121         then
122             echo "Group \"$r\" is empty or not defined?"
123             exit 1
124         fi
125         [ ! -s $tmp.list ] && touch $tmp.list
126         for t in $group_list
127         do
128             if grep -s "^$t\$" $tmp.list >/dev/null
129             then
130                 :
131             else
132                 echo "$t" >>$tmp.list
133             fi
134         done
135         group=false
136         continue
137
138     elif $xgroup
139     then
140         # arg after -x
141         [ ! -s $tmp.list ] && ls [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] >$tmp.list 2>/dev/null
142         group_list=`sed -n <group -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
143 s/ .*//p
144 }'`
145         if [ -z "$group_list" ]
146         then
147             echo "Group \"$r\" is empty or not defined?"
148             exit 1
149         fi
150         numsed=0
151         rm -f $tmp.sed
152         for t in $group_list
153         do
154             if [ $numsed -gt 100 ]
155             then
156                 sed -f $tmp.sed <$tmp.list >$tmp.tmp
157                 mv $tmp.tmp $tmp.list
158                 numsed=0
159                 rm -f $tmp.sed
160             fi
161             echo "/^$t\$/d" >>$tmp.sed
162             numsed=`expr $numsed + 1`
163         done
164         sed -f $tmp.sed <$tmp.list >$tmp.tmp
165         mv $tmp.tmp $tmp.list
166         xgroup=false
167         continue
168     fi
169
170     xpand=true
171     case "$r"
172     in
173
174         -\? | -h | --help)      # usage
175             usage
176             ;;
177
178         -udf)   # -udf ... set FSTYP to udf
179             FSTYP=udf
180             xpand=false
181             ;;
182
183         -xfs)   # -xfs ... set FSTYP to xfs
184             FSTYP=xfs
185             xpand=false
186             ;;
187
188         -nfs)   # -nfs ... set FSTYP to nfs
189             FSTYP=nfs
190             xpand=false
191             ;;
192
193         -g)     # -g group ... pick from group file
194             group=true
195             xpand=false
196             ;;
197
198         -l)     # line mode for diff, was default before
199             diff="diff"
200             xpand=false
201             ;;
202
203         -xdiff) # graphical diff mode
204             xpand=false
205
206             if [ ! -z "$DISPLAY" ]
207             then
208                 which xdiff >/dev/null 2>&1 && diff=xdiff
209                 which gdiff >/dev/null 2>&1 && diff=gdiff
210                 which tkdiff >/dev/null 2>&1 && diff=tkdiff
211                 which xxdiff >/dev/null 2>&1 && diff=xxdiff
212             fi
213             ;;
214
215         -udiff) # show a unified diff, default now, keep for backward compat
216             xpand=false
217             diff="$diff -u"
218             ;;
219
220         -q)     # "quick", no longer used - always quick :-)
221             xpand=false
222             ;;
223
224         -n)     # show me, don't do it
225             showme=true
226             xpand=false
227             ;;
228         -r)     # randomize test order
229             randomize=true
230             xpand=false
231             ;;
232
233         -T)     # turn on timestamp output
234             timestamp=true
235             xpand=false
236             ;;
237
238         -v)
239             verbose=true
240             xpand=false
241             ;;
242         -x)     # -x group ... exclude from group file
243             xgroup=true
244             xpand=false
245             ;;
246         '[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]')
247             echo "No tests?"
248             status=1
249             exit $status
250             ;;
251
252         [0-9]*-[0-9]*)
253             eval `echo $r | sed -e 's/^/start=/' -e 's/-/ end=/'`
254             ;;
255
256         [0-9]*-)
257             eval `echo $r | sed -e 's/^/start=/' -e 's/-//'`
258             end=`echo [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] | sed -e 's/\[0-9]//g' -e 's/  *$//' -e 's/.* //'`
259             if [ -z "$end" ]
260             then
261                 echo "No tests in range \"$r\"?"
262                 status=1
263                 exit $status
264             fi
265             ;;
266
267         --large-fs)
268             export LARGE_SCRATCH_DEV=yes
269             xpand=false
270             ;;
271
272         -*)
273             usage
274             ;;
275
276         --extra-space=*)
277             export SCRATCH_DEV_EMPTY_SPACE=${r#*=}
278             xpand=false
279             ;;
280
281         *)
282             start=$r
283             end=$r
284             ;;
285
286     esac
287
288     # get rid of leading 0s as can be interpreted as octal
289     start=`echo $start | sed 's/^0*//'`
290     end=`echo $end | sed 's/^0*//'`
291
292     if $xpand
293     then
294         have_test_arg=true
295         $AWK_PROG </dev/null '
296 BEGIN   { for (t='$start'; t<='$end'; t++) printf "%03d\n",t }' \
297         | while read id
298         do
299             if grep -s "^$id " group >/dev/null
300             then
301                 # in group file ... OK
302                 echo $id >>$tmp.list
303             else
304                 if [ -f expunged ] && $expunge && egrep "^$id([         ]|\$)" expunged >/dev/null
305                 then
306                     # expunged ... will be reported, but not run, later
307                     echo $id >>$tmp.list
308                 else
309                     # oops
310                     echo "$id - unknown test, ignored"
311                 fi
312             fi
313         done
314     fi
315
316 done
317
318 if [ -s $tmp.list ]
319 then
320     # found some valid test numbers ... this is good
321     :
322 else
323     if $have_test_arg
324     then
325         # had test numbers, but none in group file ... do nothing
326         touch $tmp.list
327     else
328         # no test numbers, do everything from group file
329         sed -n -e '/^[0-9][0-9][0-9]*/s/[       ].*//p' <group >$tmp.list
330     fi
331 fi
332
333 # should be sort -n, but this did not work for Linux when this
334 # was ported from IRIX
335 #
336 list=`sort $tmp.list`
337 rm -f $tmp.list $tmp.tmp $tmp.sed
338
339 if $randomize
340 then
341     list=`echo $list | awk -f randomize.awk`
342 fi
343
344 case "$FSTYP" in
345     xfs)
346          [ "$XFS_LOGPRINT_PROG" = "" ] && _fatal "xfs_logprint not found"
347          [ "$XFS_REPAIR_PROG" = "" ] && _fatal "xfs_repair not found"
348          [ "$XFS_CHECK_PROG" = "" ] && _fatal "xfs_check not found"
349          [ "$XFS_DB_PROG" = "" ] && _fatal "xfs_db not found"
350          [ "$MKFS_XFS_PROG" = "" ] && _fatal "mkfs_xfs not found"
351          ;;
352     udf)
353          [ "$MKFS_UDF_PROG" = "" ] && _fatal "mkfs_udf/mkudffs not found"
354          ;;
355     btrfs)
356          [ "$MKFS_BTRFS_PROG" = "" ] && _fatal "mkfs.btrfs not found"
357          ;;
358     nfs)
359          ;;
360 esac
361
362 # we need common.rc
363 if ! . ./common.rc
364 then
365     echo "check: failed to source common.rc"
366     exit 1
367 fi
368
369 if [ `id -u` -ne 0 ]
370 then
371     echo "check: QA must be run as root"
372     exit 1
373 fi
374
375 _wallclock()
376 {
377     date "+%H %M %S" | $AWK_PROG '{ print $1*3600 + $2*60 + $3 }'
378 }
379
380 _timestamp()
381 {
382     now=`date "+%T"`
383     echo -n " [$now]"
384 }
385
386 _wrapup()
387 {
388     # for hangcheck ...
389     # remove files that were used by hangcheck
390     #
391     [ -f /tmp/check.pid ] && rm -rf /tmp/check.pid
392     [ -f /tmp/check.sts ] && rm -rf /tmp/check.sts
393
394     if $showme
395     then
396         :
397     elif $needwrap
398     then
399         if [ -f check.time -a -f $tmp.time ]
400         then
401             cat check.time $tmp.time \
402             | $AWK_PROG '
403         { t[$1] = $2 }
404 END     { if (NR > 0) {
405             for (i in t) print i " " t[i]
406           }
407         }' \
408             | sort -n >$tmp.out
409             mv $tmp.out check.time
410         fi
411
412         if [ -f $tmp.expunged ]
413         then
414             notrun=`wc -l <$tmp.expunged | sed -e 's/  *//g'`
415             n_try=`expr $n_try - $notrun`
416             list=`echo "$list" | sed -f $tmp.expunged`
417         fi
418
419         echo "" >>check.log
420         date >>check.log
421         echo $list | fmt | sed -e 's/^/    /' >>check.log
422         $interrupt && echo "Interrupted!" >>check.log
423         
424         if [ ! -z "$n_try" -a $n_try != 0 ]
425         then
426             echo "Ran:$try"
427         fi
428
429         if [ ! -z "$notrun" ]
430         then
431             echo "Not run:$notrun"
432             echo "Not run:$notrun" >>check.log
433         fi
434
435         if [ ! -z "$n_bad" -a $n_bad != 0 ]
436         then
437             echo "Failures:$bad"
438             echo "Failed $n_bad of $n_try tests"
439             echo "Failures:$bad" | fmt >>check.log
440             echo "Failed $n_bad of $n_try tests" >>check.log
441         else
442             echo "Passed all $n_try tests"
443             echo "Passed all $n_try tests" >>check.log
444         fi
445         needwrap=false
446     fi
447
448     rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time
449     rm -f /tmp/check.pid /tmp/check.sts
450     rm -f $tmp.*
451 }
452
453 trap "_wrapup; exit \$status" 0 1 2 3 15
454
455 # for hangcheck ...
456 # Save pid of check in a well known place, so that hangcheck can be sure it
457 # has the right pid (getting the pid from ps output is not reliable enough).
458 #
459 rm -rf /tmp/check.pid
460 echo $$ >/tmp/check.pid
461
462 # for hangcheck ...
463 # Save the status of check in a well known place, so that hangcheck can be
464 # sure to know where check is up to (getting test number from ps output is
465 # not reliable enough since the trace stuff has been introduced).
466 #
467 rm -rf /tmp/check.sts
468 echo "preamble" >/tmp/check.sts
469
470 # don't leave old full output behind on a clean run
471 rm -f check.full
472
473 [ -f check.time ] || touch check.time
474
475 # print out our test configuration
476 echo "FSTYP         -- `_full_fstyp_details`"
477 echo "PLATFORM      -- `_full_platform_details`"
478 if [ ! -z "$SCRATCH_DEV" ]; then
479   echo "MKFS_OPTIONS  -- `_scratch_mkfs_options`"
480   echo "MOUNT_OPTIONS -- `_scratch_mount_options`"
481 fi
482 echo
483
484
485 if [ ! -z "$SCRATCH_DEV" ]; then
486   umount $SCRATCH_DEV 2>/dev/null
487   # call the overridden mkfs - make sure the FS is built
488   # the same as we'll create it later.
489
490   if ! _scratch_mkfs $flag >$tmp.err 2>&1
491   then
492       echo "our local _scratch_mkfs routine ..."
493       cat $tmp.err
494       echo "check: failed to mkfs \$SCRATCH_DEV using specified options"
495       exit 1
496   fi
497
498   # call the overridden mount - make sure the FS mounts with
499   # the same options that we'll mount with later.
500   if ! _scratch_mount >$tmp.err 2>&1
501   then
502       echo "our local mount routine ..."
503       cat $tmp.err
504       echo "check: failed to mount \$SCRATCH_DEV using specified options"
505       exit 1
506   fi
507 fi
508
509 seq="check"
510 _check_test_fs
511
512 [ -n "$TESTS_REMAINING_LOG" ] && echo $list > $TESTS_REMAINING_LOG
513
514 for seq in $list
515 do
516     err=false
517     echo -n "$seq"
518     if [ -n "$TESTS_REMAINING_LOG" ] ; then
519         sed -e "s/$seq//" -e 's/  / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp
520         mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG
521         sync
522     fi
523
524     if $showme
525     then
526         echo
527         continue
528     elif [ -f expunged ] && $expunge && egrep "^$seq([  ]|\$)" expunged >/dev/null
529     then
530         echo " - expunged"
531         rm -f $seq.out.bad
532         echo "/^$seq\$/d" >>$tmp.expunged
533     elif [ ! -f $seq ]
534     then
535         echo " - no such test?"
536         echo "/^$seq\$/d" >>$tmp.expunged
537     else
538         # really going to try and run this one
539         #
540         rm -f $seq.out.bad
541         lasttime=`sed -n -e "/^$seq /s/.* //p" <check.time`
542         if [ "X$lasttime" != X ]; then
543                 echo -n " ${lasttime}s ..."
544         else
545                 echo -n "       "       # prettier output with timestamps.
546         fi
547         rm -f core $seq.notrun
548
549         # for hangcheck ...
550         echo "$seq" >/tmp/check.sts
551
552         start=`_wallclock`
553         $timestamp && echo -n " ["`date "+%T"`"]"
554         [ ! -x $seq ] && chmod u+x $seq # ensure we can run it
555         $LOGGER_PROG "run xfstest $seq"
556         ./$seq >$tmp.rawout 2>&1
557         sts=$?
558         $timestamp && _timestamp
559         stop=`_wallclock`
560
561         _fix_malloc <$tmp.rawout >$tmp.out
562         rm -f $tmp.rawout
563
564         if [ -f core ]
565         then
566             echo -n " [dumped core]"
567             mv core $seq.core
568             err=true
569         fi
570
571         if [ -f $seq.notrun ]
572         then
573             $timestamp || echo -n " [not run] "
574             $timestamp && echo " [not run]" && echo -n "        $seq -- "
575             cat $seq.notrun
576             notrun="$notrun $seq"
577         else
578             if [ $sts -ne 0 ]
579             then
580                 echo -n " [failed, exit status $sts]"
581                 err=true
582             fi
583             if [ ! -f $seq.out ]
584             then
585                 echo " - no qualified output"
586                 err=true
587             else
588                 if diff $seq.out $tmp.out >/dev/null 2>&1
589                 then
590                     if $err
591                     then
592                         :
593                     else
594                         echo "$seq `expr $stop - $start`" >>$tmp.time
595                         echo -n " `expr $stop - $start`s"
596                     fi
597                     echo ""
598                 else
599                     echo " - output mismatch (see $seq.out.bad)"
600                     mv $tmp.out $seq.out.bad
601                     $diff $seq.out $seq.out.bad | {
602                         if test "$DIFF_LENGTH" -le 0; then
603                                 cat
604                         else
605                                 head -n "$DIFF_LENGTH"
606                         fi; } | \
607                         sed -e 's/^\(.\)/    \1/'
608                     echo "     ..."
609                     echo "     (Run '$diff $seq.out $seq.out.bad' to see the" \
610                          "entire diff)"
611                     err=true
612                 fi
613             fi
614         fi
615
616     fi
617
618     # come here for each test, except when $showme is true
619     #
620     if $err
621     then
622         bad="$bad $seq"
623         n_bad=`expr $n_bad + 1`
624         quick=false
625     fi
626     if [ ! -f $seq.notrun ]
627     then
628         try="$try $seq"
629         n_try=`expr $n_try + 1`
630         _check_test_fs
631     fi
632     
633     seq="after_$seq"
634 done
635
636 interrupt=false
637 status=`expr $n_bad`
638 exit