#!/bin/bash # # Control script for QA # # Copyright (c) 2000-2002,2006 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it would be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write the Free Software Foundation, # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # # tmp=/tmp/$$ status=0 needwrap=true n_try=0 try="" n_bad=0 bad="" notrun="" interrupt=true export QA_CHECK_FS=${QA_CHECK_FS:=true} # number of diff lines from a failed test, 0 for whole output export DIFF_LENGTH=${DIFF_LENGTH:=10} # by default don't output timestamps timestamp=${TIMESTAMP:=false} # generic initialization iam=check # we need common.config if ! . ./common.config then echo "$iam: failed to source common.config" exit 1 fi # argument parsing first - currently very messy, needs cleanup. _setenvironment() { MSGVERB="text:action" export MSGVERB } usage() { echo "Usage: $0 [options] [testlist]"' common options -v verbose check options -xfs test XFS (default) -udf test UDF -nfs test NFS -l line mode diff -xdiff graphical mode diff -udiff show unified diff (default) -n show me, do not run tests -q quick [deprecated] -T output timestamps -r randomize test order --large-fs optimise scratch device for large filesystems testlist options -g group[,group...] include tests from these groups -x group[,group...] exclude tests from these groups NNN include test NNN NNN-NNN include test range (eg. 012-021) ' exit 0 } here=`pwd` rm -f $here/$iam.out _setenvironment check=${check-true} diff="diff -u" verbose=false group=false xgroup=false showme=false sortme=false expunge=true have_test_arg=false randomize=false rm -f $tmp.list $tmp.tmp $tmp.sed # Autodetect fs type based on what's on $TEST_DEV if [ "$HOSTOS" == "Linux" ] then export FSTYP=`blkid -c /dev/null -s TYPE -o value $TEST_DEV` else export FSTYP=xfs fi for r do if $group then # arg after -g group_list=$(sed -n < group \ -e 's/#.*//' \ -e 's/$/ /' \ -e "/^[0-9][0-9][0-9].* $r /"'{ s/ .*//p }') if [ -z "$group_list" ] then echo "Group \"$r\" is empty or not defined?" exit 1 fi [ ! -s $tmp.list ] && touch $tmp.list for t in $group_list do if grep -s "^$t\$" $tmp.list >/dev/null then : else echo "$t" >>$tmp.list fi done group=false continue elif $xgroup then # arg after -x [ ! -s $tmp.list ] && ls [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] >$tmp.list 2>/dev/null group_list=`sed -n $tmp.tmp mv $tmp.tmp $tmp.list numsed=0 rm -f $tmp.sed fi echo "/^$t\$/d" >>$tmp.sed numsed=`expr $numsed + 1` done sed -f $tmp.sed <$tmp.list >$tmp.tmp mv $tmp.tmp $tmp.list xgroup=false continue fi xpand=true case "$r" in -\? | -h | --help) # usage usage ;; -udf) # -udf ... set FSTYP to udf FSTYP=udf xpand=false ;; -xfs) # -xfs ... set FSTYP to xfs FSTYP=xfs xpand=false ;; -nfs) # -nfs ... set FSTYP to nfs FSTYP=nfs xpand=false ;; -g) # -g group ... pick from group file group=true xpand=false ;; -l) # line mode for diff, was default before diff="diff" xpand=false ;; -xdiff) # graphical diff mode xpand=false if [ ! -z "$DISPLAY" ] then which xdiff >/dev/null 2>&1 && diff=xdiff which gdiff >/dev/null 2>&1 && diff=gdiff which tkdiff >/dev/null 2>&1 && diff=tkdiff which xxdiff >/dev/null 2>&1 && diff=xxdiff fi ;; -udiff) # show a unified diff, default now, keep for backward compat xpand=false diff="$diff -u" ;; -q) # "quick", no longer used - always quick :-) xpand=false ;; -n) # show me, don't do it showme=true xpand=false ;; -r) # randomize test order randomize=true xpand=false ;; -T) # turn on timestamp output timestamp=true xpand=false ;; -v) verbose=true xpand=false ;; -x) # -x group ... exclude from group file xgroup=true xpand=false ;; '[0-9][0-9][0-9] [0-9][0-9][0-9][0-9]') echo "No tests?" status=1 exit $status ;; [0-9]*-[0-9]*) eval `echo $r | sed -e 's/^/start=/' -e 's/-/ end=/'` ;; [0-9]*-) eval `echo $r | sed -e 's/^/start=/' -e 's/-//'` 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/.* //'` if [ -z "$end" ] then echo "No tests in range \"$r\"?" status=1 exit $status fi ;; --large-fs) export LARGE_SCRATCH_DEV=yes xpand=false ;; -*) usage ;; --extra-space=*) export SCRATCH_DEV_EMPTY_SPACE=${r#*=} xpand=false ;; *) start=$r end=$r ;; esac # get rid of leading 0s as can be interpreted as octal start=`echo $start | sed 's/^0*//'` end=`echo $end | sed 's/^0*//'` if $xpand then have_test_arg=true $AWK_PROG /dev/null then # in group file ... OK echo $id >>$tmp.list else if [ -f expunged ] && $expunge && egrep "^$id([ ]|\$)" expunged >/dev/null then # expunged ... will be reported, but not run, later echo $id >>$tmp.list else # oops echo "$id - unknown test, ignored" fi fi done fi done if [ -s $tmp.list ] then # found some valid test numbers ... this is good : else if $have_test_arg then # had test numbers, but none in group file ... do nothing touch $tmp.list else # no test numbers, do everything from group file sed -n -e '/^[0-9][0-9][0-9]*/s/[ ].*//p' $tmp.list fi fi # should be sort -n, but this did not work for Linux when this # was ported from IRIX # list=`sort $tmp.list` rm -f $tmp.list $tmp.tmp $tmp.sed if $randomize then list=`echo $list | awk -f randomize.awk` fi case "$FSTYP" in xfs) [ "$XFS_LOGPRINT_PROG" = "" ] && _fatal "xfs_logprint not found" [ "$XFS_REPAIR_PROG" = "" ] && _fatal "xfs_repair not found" [ "$XFS_CHECK_PROG" = "" ] && _fatal "xfs_check not found" [ "$XFS_DB_PROG" = "" ] && _fatal "xfs_db not found" [ "$MKFS_XFS_PROG" = "" ] && _fatal "mkfs_xfs not found" ;; udf) [ "$MKFS_UDF_PROG" = "" ] && _fatal "mkfs_udf/mkudffs not found" ;; btrfs) [ "$MKFS_BTRFS_PROG" = "" ] && _fatal "mkfs.btrfs not found" ;; nfs) ;; esac # we need common.rc if ! . ./common.rc then echo "check: failed to source common.rc" exit 1 fi if [ `id -u` -ne 0 ] then echo "check: QA must be run as root" exit 1 fi _wallclock() { date "+%H %M %S" | $AWK_PROG '{ print $1*3600 + $2*60 + $3 }' } _timestamp() { now=`date "+%T"` echo -n " [$now]" } _wrapup() { # for hangcheck ... # remove files that were used by hangcheck # [ -f /tmp/check.pid ] && rm -rf /tmp/check.pid [ -f /tmp/check.sts ] && rm -rf /tmp/check.sts if $showme then : elif $needwrap then if [ -f check.time -a -f $tmp.time ] then cat check.time $tmp.time \ | $AWK_PROG ' { t[$1] = $2 } END { if (NR > 0) { for (i in t) print i " " t[i] } }' \ | sort -n >$tmp.out mv $tmp.out check.time fi if [ -f $tmp.expunged ] then notrun=`wc -l <$tmp.expunged | sed -e 's/ *//g'` n_try=`expr $n_try - $notrun` list=`echo "$list" | sed -f $tmp.expunged` fi echo "" >>check.log date >>check.log echo $list | fmt | sed -e 's/^/ /' >>check.log $interrupt && echo "Interrupted!" >>check.log if [ ! -z "$n_try" -a $n_try != 0 ] then echo "Ran:$try" fi if [ ! -z "$notrun" ] then echo "Not run:$notrun" echo "Not run:$notrun" >>check.log fi if [ ! -z "$n_bad" -a $n_bad != 0 ] then echo "Failures:$bad" echo "Failed $n_bad of $n_try tests" echo "Failures:$bad" | fmt >>check.log echo "Failed $n_bad of $n_try tests" >>check.log else echo "Passed all $n_try tests" echo "Passed all $n_try tests" >>check.log fi needwrap=false fi rm -f /tmp/*.rawout /tmp/*.out /tmp/*.err /tmp/*.time rm -f /tmp/check.pid /tmp/check.sts rm -f $tmp.* } trap "_wrapup; exit \$status" 0 1 2 3 15 # for hangcheck ... # Save pid of check in a well known place, so that hangcheck can be sure it # has the right pid (getting the pid from ps output is not reliable enough). # rm -rf /tmp/check.pid echo $$ >/tmp/check.pid # for hangcheck ... # Save the status of check in a well known place, so that hangcheck can be # sure to know where check is up to (getting test number from ps output is # not reliable enough since the trace stuff has been introduced). # rm -rf /tmp/check.sts echo "preamble" >/tmp/check.sts # don't leave old full output behind on a clean run rm -f check.full [ -f check.time ] || touch check.time # print out our test configuration echo "FSTYP -- `_full_fstyp_details`" echo "PLATFORM -- `_full_platform_details`" if [ ! -z "$SCRATCH_DEV" ]; then echo "MKFS_OPTIONS -- `_scratch_mkfs_options`" echo "MOUNT_OPTIONS -- `_scratch_mount_options`" fi echo if [ ! -z "$SCRATCH_DEV" ]; then umount $SCRATCH_DEV 2>/dev/null # call the overridden mkfs - make sure the FS is built # the same as we'll create it later. if ! _scratch_mkfs $flag >$tmp.err 2>&1 then echo "our local _scratch_mkfs routine ..." cat $tmp.err echo "check: failed to mkfs \$SCRATCH_DEV using specified options" exit 1 fi # call the overridden mount - make sure the FS mounts with # the same options that we'll mount with later. if ! _scratch_mount >$tmp.err 2>&1 then echo "our local mount routine ..." cat $tmp.err echo "check: failed to mount \$SCRATCH_DEV using specified options" exit 1 fi fi seq="check" _check_test_fs [ -n "$TESTS_REMAINING_LOG" ] && echo $list > $TESTS_REMAINING_LOG for seq in $list do err=false echo -n "$seq" if [ -n "$TESTS_REMAINING_LOG" ] ; then sed -e "s/$seq//" -e 's/ / /' -e 's/^ *//' $TESTS_REMAINING_LOG > $TESTS_REMAINING_LOG.tmp mv $TESTS_REMAINING_LOG.tmp $TESTS_REMAINING_LOG sync fi if $showme then echo continue elif [ -f expunged ] && $expunge && egrep "^$seq([ ]|\$)" expunged >/dev/null then echo " - expunged" rm -f $seq.out.bad echo "/^$seq\$/d" >>$tmp.expunged elif [ ! -f $seq ] then echo " - no such test?" echo "/^$seq\$/d" >>$tmp.expunged else # really going to try and run this one # rm -f $seq.out.bad lasttime=`sed -n -e "/^$seq /s/.* //p" /tmp/check.sts start=`_wallclock` $timestamp && echo -n " ["`date "+%T"`"]" [ ! -x $seq ] && chmod u+x $seq # ensure we can run it $LOGGER_PROG "run xfstest $seq" ./$seq >$tmp.rawout 2>&1 sts=$? $timestamp && _timestamp stop=`_wallclock` _fix_malloc <$tmp.rawout >$tmp.out rm -f $tmp.rawout if [ -f core ] then echo -n " [dumped core]" mv core $seq.core err=true fi if [ -f $seq.notrun ] then $timestamp || echo -n " [not run] " $timestamp && echo " [not run]" && echo -n " $seq -- " cat $seq.notrun notrun="$notrun $seq" else if [ $sts -ne 0 ] then echo -n " [failed, exit status $sts]" err=true fi if [ ! -f $seq.out ] then echo " - no qualified output" err=true else if diff $seq.out $tmp.out >/dev/null 2>&1 then if $err then : else echo "$seq `expr $stop - $start`" >>$tmp.time echo -n " `expr $stop - $start`s" fi echo "" else echo " - output mismatch (see $seq.out.bad)" mv $tmp.out $seq.out.bad $diff $seq.out $seq.out.bad | { if test "$DIFF_LENGTH" -le 0; then cat else head -n "$DIFF_LENGTH" fi; } | \ sed -e 's/^\(.\)/ \1/' echo " ..." echo " (Run '$diff $seq.out $seq.out.bad' to see the" \ "entire diff)" err=true fi fi fi fi # come here for each test, except when $showme is true # if $err then bad="$bad $seq" n_bad=`expr $n_bad + 1` quick=false fi if [ ! -f $seq.notrun ] then try="$try $seq" n_try=`expr $n_try + 1` _check_test_fs fi seq="after_$seq" done interrupt=false status=`expr $n_bad` exit