67128381ec6ed1751fe55a5925eff0f17f6148db
[xfstests-dev.git] / common.rc
1 ##/bin/bash
2 #-----------------------------------------------------------------------
3 #  Copyright (c) 2000-2006 Silicon Graphics, Inc.  All Rights Reserved.
4 #  This program is free software; you can redistribute it and/or modify
5 #  it under the terms of the GNU General Public License as published by
6 #  the Free Software Foundation; either version 2 of the License, or
7 #  (at your option) any later version.
8 #
9 #  This program is distributed in the hope that it will be useful,
10 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 #  GNU General Public License for more details.
13 #
14 #  You should have received a copy of the GNU General Public License
15 #  along with this program; if not, write to the Free Software
16 #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
17 #  USA
18 #
19 #  Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
20 #  Mountain View, CA 94043, USA, or: http://www.sgi.com
21 #-----------------------------------------------------------------------
22
23 dd()
24 {
25    if [ "$HOSTOS" == "Linux" ]
26    then 
27         command dd --help | grep noxfer > /dev/null 2>&1
28         
29         if [ "$?" -eq 0 ]
30             then
31                 command dd status=noxfer $@
32             else
33                 command dd $@
34         fi
35    else
36         command dd $@
37    fi
38 }
39
40 # ls -l w/ selinux sometimes puts a dot at the end:
41 # -rwxrw-r--. id1 id2 file1
42
43 _ls_l()
44 {
45         ls -l $* | sed "s/\(^[-rwxdlbcpsStT]*\)\. /\1 /"
46 }
47
48 _mount_opts()
49 {
50     case $FSTYP in
51     xfs)
52         export MOUNT_OPTIONS=$XFS_MOUNT_OPTIONS
53         ;;
54     udf)
55         export MOUNT_OPTIONS=$UDF_MOUNT_OPTIONS
56         ;;
57     nfs)
58         export MOUNT_OPTIONS=$NFS_MOUNT_OPTIONS
59         ;;
60     ext2|ext3|ext4)
61         # acls & xattrs aren't turned on by default on ext$FOO
62         export MOUNT_OPTIONS="-o acl,user_xattr $EXT_MOUNT_OPTIONS"
63         ;;
64     reiserfs)
65         # acls & xattrs aren't turned on by default on reiserfs
66         export MOUNT_OPTIONS="-o acl,user_xattr $REISERFS_MOUNT_OPTIONS"
67         ;;
68     gfs2)
69         # acls aren't turned on by default on gfs2
70         export MOUNT_OPTIONS="-o acl $GFS2_MOUNT_OPTIONS"
71         ;;
72     *)
73         ;;
74     esac
75 }
76
77 _mkfs_opts()
78 {
79     case $FSTYP in
80     xfs)
81         export MKFS_OPTIONS=$XFS_MKFS_OPTIONS
82         ;;
83     udf)
84         [ ! -z "$udf_fsize" ] && \
85             UDF_MKFS_OPTIONS="$UDF_MKFS_OPTIONS -s $udf_fsize"
86         export MKFS_OPTIONS=$UDF_MKFS_OPTIONS
87         ;;
88     nfs)
89         export MKFS_OPTIONS=$NFS_MKFS_OPTIONS
90         ;;
91     reiserfs)
92         export MKFS_OPTIONS="$REISERFS_MKFS_OPTIONS -q"
93         ;;
94     gfs2)
95         export MKFS_OPTIONS="$GFS2_MKFS_OPTIONS -O -p lock_nolock"
96         ;;
97     *)
98         ;;
99     esac
100 }
101
102 _fsck_opts()
103 {
104     case $FSTYP in
105     ext2|ext3|ext4)
106         export FSCK_OPTIONS="-nf"
107         ;;
108     reiserfs)
109         export FSCK_OPTIONS="--yes"
110         ;;
111     *)
112         export FSCK_OPTIONS="-n"
113         ;;
114     esac
115 }
116
117 [ -z "$FSTYP" ] && FSTYP=xfs
118 [ -z "$MOUNT_OPTIONS" ] && _mount_opts
119 [ -z "$MKFS_OPTIONS" ] && _mkfs_opts
120 [ -z "$FSCK_OPTIONS" ] && _fsck_opts
121
122
123 # we need common.config
124 if [ "$iam" != "check" ]
125 then
126     if ! . ./common.config
127         then
128         echo "$iam: failed to source common.config"
129         exit 1
130     fi
131 fi
132
133 # make sure we have a standard umask
134 umask 022
135
136 _mount()
137 {
138     $MOUNT_PROG `_mount_ops_filter $*`
139 }
140
141 _scratch_options()
142 {
143     type=$1
144     SCRATCH_OPTIONS=""
145
146     if [ "$FSTYP" != "xfs" ]; then
147         return
148     fi
149
150     case $type in
151     mkfs)
152         [ "$HOSTOS" != "IRIX" ] && SCRATCH_OPTIONS="$SCRATCH_OPTIONS -f"
153         rt_opt="-r"
154         log_opt="-l"
155         ;;
156     mount)
157         rt_opt="-o"
158         log_opt="-o"
159         ;;
160     esac
161     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
162         SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${rt_opt}rtdev=$SCRATCH_RTDEV"
163     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
164         SCRATCH_OPTIONS="$SCRATCH_OPTIONS ${log_opt}logdev=$SCRATCH_LOGDEV"
165 }
166
167 _test_options()
168 {
169     type=$1
170     TEST_OPTIONS=""
171
172     if [ "$FSTYP" != "xfs" ]; then
173         return
174     fi
175
176     case $type in
177     mkfs)
178         rt_opt="-r"
179         log_opt="-l"
180         ;;
181     mount)
182         rt_opt="-o"
183         log_opt="-o"
184         ;;
185     esac
186     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_RTDEV" ] && \
187         TEST_OPTIONS="$TEST_OPTIONS ${rt_opt}rtdev=$TEST_RTDEV"
188     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_LOGDEV" ] && \
189         TEST_OPTIONS="$TEST_OPTIONS ${log_opt}logdev=$TEST_LOGDEV"
190 }
191
192 _mount_ops_filter()
193 {
194     params="$*"
195     
196     #get mount point to handle dmapi mtpt option correctly
197     let last_index=$#-1
198     [ $last_index -gt 0 ] && shift $last_index
199     FS_ESCAPED=$1
200     
201     # irix is fussy about how it is fed its mount options
202     # - multiple -o's are not allowed
203     # - no spaces between comma delimitered options
204     # the sed script replaces all -o's (except the first) with a comma
205     # not required for linux, but won't hurt
206     
207     echo $params | sed -e 's/[[:space:]]*-o[[:space:]]*/UnIqUe/1; s/[[:space:]]*-o[[:space:]]*/,/g; s/UnIqUe/ -o /1' \
208         | sed -e 's/dmapi/dmi/' \
209         | $PERL_PROG -ne "s#mtpt=[^,|^\n|^\s]*#mtpt=$FS_ESCAPED\1\2#; print;"
210
211 }
212
213 _scratch_mount_options()
214 {
215     _scratch_options mount
216
217     echo $SCRATCH_OPTIONS $MOUNT_OPTIONS $* $SCRATCH_DEV $SCRATCH_MNT
218 }
219
220 _scratch_mount()
221 {
222     _mount -t $FSTYP `_scratch_mount_options $*`
223 }
224
225 _scratch_unmount()
226 {
227     $UMOUNT_PROG $SCRATCH_DEV
228 }
229
230 _scratch_remount()
231 {
232     _scratch_unmount
233     _scratch_mount
234 }
235
236 _test_mount()
237 {
238     _test_options mount
239     _mount -t $FSTYP $TEST_OPTIONS $TEST_FS_MOUNT_OPTS $* $TEST_DEV $TEST_DIR
240 }
241
242 _scratch_mkfs_options()
243 {
244     _scratch_options mkfs
245     echo $SCRATCH_OPTIONS $MKFS_OPTIONS $* $SCRATCH_DEV
246 }
247
248 _scratch_mkfs_xfs()
249 {
250     # extra mkfs options can be added by tests
251     local extra_mkfs_options=$*
252
253     local tmp_dir=/tmp/
254
255     _scratch_options mkfs
256
257     # save mkfs output in case conflict means we need to run again.
258     # only the output for the mkfs that applies should be shown
259     $MKFS_XFS_PROG $SCRATCH_OPTIONS $MKFS_OPTIONS $extra_mkfs_options $SCRATCH_DEV \
260         2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
261     local mkfs_status=$?
262
263     # a mkfs failure may be caused by conflicts between
264     # $MKFS_OPTIONS and $extra_mkfs_options
265
266     if [ $mkfs_status -ne 0 -a ! -z "$extra_mkfs_options" ]; then
267         echo "** mkfs failed with extra mkfs options added to \"$MKFS_OPTIONS\" by test $seq **" \
268             >>$here/$seq.full
269         echo "** attempting to mkfs using only test $seq options: $extra_mkfs_options **" \
270             >>$here/$seq.full
271         # running mkfs again. overwrite previous mkfs output files
272         $MKFS_XFS_PROG $SCRATCH_OPTIONS $extra_mkfs_options $SCRATCH_DEV \
273             2>$tmp_dir.mkfserr 1>$tmp_dir.mkfsstd
274         mkfs_status=$?
275     fi
276
277     # output stored mkfs output
278     cat $tmp_dir.mkfserr >&2
279     cat $tmp_dir.mkfsstd
280     rm -f $tmp_dir.mkfserr $tmp_dir.mkfsstd
281
282     if [ "$USE_BIG_LOOPFS" = yes ]; then
283         [ -z "$RETAIN_AG_BYTES" ] && RETAIN_AG_BYTES=0
284         ./tools/ag-wipe -q -r $RETAIN_AG_BYTES $SCRATCH_DEV
285     fi
286
287     return $mkfs_status
288 }
289
290 _scratch_mkfs()
291 {
292     case $FSTYP in
293     xfs)
294         _scratch_mkfs_xfs $*
295         ;;
296     nfs*)
297         # do nothing for nfs
298         ;;
299     udf)
300         $MKFS_UDF_PROG $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
301         ;;
302     *)
303         /sbin/mkfs -t $FSTYP -- $MKFS_OPTIONS $* $SCRATCH_DEV > /dev/null
304         ;;
305     esac
306 }
307
308 _scratch_xfs_db_options()
309 {
310     SCRATCH_OPTIONS=""
311     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
312         SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
313     echo $SCRATCH_OPTIONS $* $SCRATCH_DEV
314 }
315
316 _scratch_xfs_logprint()
317 {
318     SCRATCH_OPTIONS=""
319     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
320         SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
321     $XFS_LOGPRINT_PROG $SCRATCH_OPTIONS $* $SCRATCH_DEV
322 }
323
324 _scratch_xfs_check()
325 {
326     SCRATCH_OPTIONS=""
327     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
328         SCRATCH_OPTIONS="-l $SCRATCH_LOGDEV"
329     $XFS_CHECK_PROG $SCRATCH_OPTIONS $* $SCRATCH_DEV
330 }
331
332 _scratch_xfs_repair()
333 {
334     SCRATCH_OPTIONS=""
335     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
336         SCRATCH_OPTIONS="-l$SCRATCH_LOGDEV"
337     [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
338         SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -r$SCRATCH_RTDEV"
339     [ "$USE_BIG_LOOPFS" = yes ] && SCRATCH_OPTIONS=$SCRATCH_OPTIONS" -t"
340     $XFS_REPAIR_PROG $SCRATCH_OPTIONS $* $SCRATCH_DEV
341 }
342
343 _get_pids_by_name()
344 {
345     if [ $# -ne 1 ]
346     then
347         echo "Usage: _get_pids_by_name process-name" 1>&2
348         exit 1
349     fi
350
351     # Algorithm ... all ps(1) variants have a time of the form MM:SS or
352     # HH:MM:SS before the psargs field, use this as the search anchor.
353     #
354     # Matches with $1 (process-name) occur if the first psarg is $1
355     # or ends in /$1 ... the matching uses sed's regular expressions,
356     # so passing a regex into $1 will work.
357
358     ps $PS_ALL_FLAGS \
359     | sed -n \
360         -e 's/$/ /' \
361         -e 's/[         ][      ]*/ /g' \
362         -e 's/^ //' \
363         -e 's/^[^ ]* //' \
364         -e "/[0-9]:[0-9][0-9]  *[^ ]*\/$1 /s/ .*//p" \
365         -e "/[0-9]:[0-9][0-9]  *$1 /s/ .*//p"
366 }
367
368 # fix malloc libs output
369 #
370 _fix_malloc()
371 {
372     # filter out the Electric Fence notice
373     $PERL_PROG -e '
374         while (<>) {
375             if (defined $o && /^\s+Electric Fence/) {
376                 chomp($o);
377                 print "$o";
378                 undef $o;
379                 next;
380             }
381             print $o if (defined $o);
382
383             $o=$_;
384         }
385         print $o if (defined $o);
386     '
387 }
388
389 # check if run as root
390 #
391 _need_to_be_root()
392 {
393     id=`id | $SED_PROG -e 's/(.*//' -e 's/.*=//'`
394     if [ "$id" -ne 0 ]
395     then
396         echo "Arrgh ... you need to be root (not uid=$id) to run this test"
397         exit 1
398     fi
399 }
400
401
402 #
403 # _df_device : get an IRIX style df line for a given device
404 #
405 #       - returns "" if not mounted
406 #       - returns fs type in field two (ala IRIX)
407 #       - joins line together if split by fancy df formatting
408 #       - strips header etc
409 #
410
411 _df_device()
412 {
413     if [ $# -ne 1 ]
414     then
415         echo "Usage: _df_device device" 1>&2
416         exit 1
417     fi
418
419     $DF_PROG 2>/dev/null | $AWK_PROG -v what=$1 '
420         match($1,what) && NF==1 {
421             v=$1
422             getline
423             print v, $0
424             exit
425         }
426         match($1,what) {
427             print
428             exit
429         }
430     '
431 }
432
433 #
434 # _df_dir : get an IRIX style df line for device where a directory resides
435 #
436 #       - returns fs type in field two (ala IRIX)
437 #       - joins line together if split by fancy df formatting
438 #       - strips header etc
439 #
440
441 _df_dir()
442 {
443     if [ $# -ne 1 ]
444     then
445         echo "Usage: _df_dir device" 1>&2
446         exit 1
447     fi
448
449     $DF_PROG $1 2>/dev/null | $AWK_PROG -v what=$1 '
450         NR == 2 && NF==1 {
451             v=$1
452             getline
453             print v, $0;
454             exit 0
455         }
456         NR == 2 {
457             print;
458             exit 0
459         }
460         {}
461     '
462     # otherwise, nada
463 }
464
465 # return percentage used disk space for mounted device
466
467 _used()
468 {
469     if [ $# -ne 1 ]
470     then
471         echo "Usage: _used device" 1>&2
472         exit 1
473     fi
474
475     _df_device $1 | $AWK_PROG '{ sub("%", "") ; print $6 }'
476 }
477
478 # return the FS type of a mounted device
479 #
480 _fs_type()
481 {
482     if [ $# -ne 1 ]
483     then
484         echo "Usage: _fs_type device" 1>&2
485         exit 1
486     fi
487
488     _df_device $1 | $AWK_PROG '{ print $2 }'
489 }
490
491 # return the FS mount options of a mounted device
492 #
493 # should write a version which just parses the output of mount for IRIX
494 # compatibility, but since this isn't used at all, at the moment I'll leave
495 # this for now
496 #
497 _fs_options()
498 {
499     if [ $# -ne 1 ]
500     then
501         echo "Usage: _fs_options device" 1>&2
502         exit 1
503     fi
504
505     $AWK_PROG -v dev=$1 '
506         match($1,dev) { print $4 }
507     ' </proc/mounts
508 }
509
510 # returns device number if a file is a block device
511 #
512 _is_block_dev()
513 {
514     if [ $# -ne 1 ]
515     then
516         echo "Usage: _is_block_dev dev" 1>&2
517         exit 1
518     fi
519
520     [ -b $1 ] && src/lstat64 $1 | $AWK_PROG '/Device type:/ { print $9 }'
521 }
522
523 # Do a command, log it to $seq.full, optionally test return status
524 # and die if command fails. If called with one argument _do executes the
525 # command, logs it, and returns its exit status. With two arguments _do
526 # first prints the message passed in the first argument, and then "done"
527 # or "fail" depending on the return status of the command passed in the
528 # second argument. If the command fails and the variable _do_die_on_error
529 # is set to "always" or the two argument form is used and _do_die_on_error
530 # is set to "message_only" _do will print an error message to
531 # $seq.out and exit.
532
533 _do()
534 {
535     if [ $# -eq 1 ]; then
536         _cmd=$1
537     elif [ $# -eq 2 ]; then
538         _note=$1
539         _cmd=$2
540         echo -n "$_note... "
541     else
542         echo "Usage: _do [note] cmd" 1>&2
543         status=1; exit
544     fi
545
546     (eval "echo '---' \"$_cmd\"") >>$here/$seq.full
547     (eval "$_cmd") >$tmp._out 2>&1; ret=$?
548     cat $tmp._out | _fix_malloc >>$here/$seq.full
549     if [ $# -eq 2 ]; then
550         if [ $ret -eq 0 ]; then
551             echo "done"
552         else
553             echo "fail"
554         fi
555     fi
556     if [ $ret -ne 0  ] \
557         && [ "$_do_die_on_error" = "always" \
558             -o \( $# -eq 2 -a "$_do_die_on_error" = "message_only" \) ]
559     then
560         [ $# -ne 2 ] && echo
561         eval "echo \"$_cmd\" failed \(returned $ret\): see $seq.full"
562         status=1; exit
563     fi
564
565     return $ret
566 }
567
568 # bail out, setting up .notrun file
569 #
570 _notrun()
571 {
572     echo "$*" >$seq.notrun
573     echo "$seq not run: $*"
574     status=0
575     exit
576 }
577
578 # just plain bail out
579 #
580 _fail()
581 {
582     echo "$*" | tee -a $here/$seq.full
583     echo "(see $seq.full for details)"
584     status=1
585     exit 1
586 }
587
588 # tests whether $FSTYP is one of the supported filesystems for a test
589 #
590 _supported_fs()
591 {
592     for f
593     do
594         if [ "$f" = "$FSTYP" -o "$f" = "generic" ]
595         then
596             return
597         fi
598     done
599
600     _notrun "not suitable for this filesystem type: $FSTYP"
601 }
602
603 # tests whether $FSTYP is one of the supported OSes for a test
604 #
605 _supported_os()
606 {
607     for h
608     do
609         if [ "$h" = "$HOSTOS" ]
610         then
611             return
612         fi
613     done
614
615     _notrun "not suitable for this OS: $HOSTOS"
616 }
617
618 # this test needs a scratch partition - check we're ok & unmount it
619 #
620 _require_scratch()
621 {
622     case "$FSTYP" in
623         nfs*)
624                  echo $SCRATCH_DEV | grep -q ":" > /dev/null 2>&1
625                  if [ -z "$SCRATCH_DEV" -o "$?" != "0" ]
626                  then
627                      _notrun "this test requires a valid \$SCRATCH_DEV"
628                  fi
629                  ;;
630         *)
631                  if [ -z "$SCRATCH_DEV" -o "`_is_block_dev $SCRATCH_DEV`" = "" ]
632                  then
633                      _notrun "this test requires a valid \$SCRATCH_DEV"
634                  fi
635                  if [ "`_is_block_dev $SCRATCH_DEV`" = "`_is_block_dev $TEST_DEV`" ]
636                  then
637                      _notrun "this test requires a valid \$SCRATCH_DEV"
638                  fi
639                  ;;
640     esac
641
642     # mounted?
643     if _mount | grep -q $SCRATCH_DEV
644     then
645         # if it's mounted, make sure its on $SCRATCH_MNT
646         if ! _mount | grep $SCRATCH_DEV | grep -q $SCRATCH_MNT
647         then
648             echo "\$SCRATCH_DEV is mounted but not on \$SCRATCH_MNT - aborting"
649             exit 1
650         fi
651         # and then unmount it
652         if ! $UMOUNT_PROG $SCRATCH_DEV
653         then
654             echo "failed to unmount $SCRATCH_DEV"
655             exit 1
656         fi
657     fi
658 }
659
660 # this test needs a logdev
661 #
662 _require_logdev()
663 {
664     [ -z "$SCRATCH_LOGDEV" -o ! -b "$SCRATCH_LOGDEV" ] && \
665         _notrun "This test requires a valid \$SCRATCH_LOGDEV"
666     [ "$USE_EXTERNAL" != yes ] && \
667         _notrun "This test requires USE_EXTERNAL to be enabled"
668
669     # ensure its not mounted
670     $UMOUNT_PROG $SCRATCH_LOGDEV 2>/dev/null
671 }
672
673 # this test requires loopback device support
674 #
675 _require_loop()
676 {
677     if [ "$HOSTOS" != "Linux" ]
678     then
679         _notrun "This test requires linux for loopback device support"
680     fi
681
682     modprobe loop >/dev/null 2>&1
683     if grep loop /proc/devices >/dev/null 2>&1
684     then
685         :
686     else
687         _notrun "This test requires loopback device support"
688     fi
689 }
690
691 # this test requires that (large) loopback device files are not in use
692 #
693 _require_nobigloopfs()
694 {
695     [ "$USE_BIG_LOOPFS" = yes ] && \
696         _notrun "Large filesystem testing in progress, skipped this test"
697 }
698
699 # this test requires that a realtime subvolume is in use, and
700 # that the kernel supports realtime as well.
701 #
702 _require_realtime()
703 {
704     [ "$USE_EXTERNAL" = yes ] || \
705         _notrun "External volumes not in use, skipped this test"
706     [ "$SCRATCH_RTDEV" = "" ] && \
707         _notrun "Realtime device required, skipped this test"
708 }
709
710 # this test requires that a specified command (executable) exists
711 #
712 _require_command()
713 {
714     [ -x "$1" ] || _notrun "$1 utility required, skipped this test"
715 }
716
717 # this test requires that external log/realtime devices are not in use
718 #
719 _require_nonexternal()
720 {
721     [ "$USE_EXTERNAL" = yes ] && \
722         _notrun "External device testing in progress, skipped this test"
723 }
724
725 # check for the fsgqa user on the machine
726 #
727 _require_user()
728 {
729     qa_user=fsgqa
730     cat /etc/passwd | grep -q $qa_user
731     [ "$?" == "0" ] || _notrun "$qa_user user not defined."
732 }
733
734 # check that xfs_io, glibc, kernel, and filesystem all (!) support
735 # fallocate
736 #
737 _require_xfs_io_falloc()
738 {
739         testio=`$XFS_IO_PROG -F -f -c "falloc 0 1m" $TEST_DIR/$tmp.io 2>&1`
740         rm -f $TEST_DIR/$tmp.io 2>&1 > /dev/null
741         echo $testio | grep -q "not found" && \
742                 _notrun "xfs_io fallocate support is missing"
743         echo $testio | grep -q "Operation not supported" && \
744                 _notrun "xfs_io fallocate command failed (old kernel/wrong fs?)"
745 }
746
747 # Check that a fs has enough free space (in 1024b blocks)
748 #
749 _require_fs_space()
750 {
751         MNT=$1
752         BLOCKS=$2       # in units of 1024
753         let GB=$BLOCKS/1024/1024
754
755         FREE_BLOCKS=`df -klP $MNT | grep -v Filesystem | awk '{print $4}'`
756         [ $FREE_BLOCKS -lt $BLOCKS ] && \
757                 _notrun "This test requires at least ${GB}GB free on $MNT to run"
758 }
759
760 # check that a FS on a device is mounted
761 # if so, return mount point
762 #
763 _is_mounted()
764 {
765     if [ $# -ne 1 ]
766     then
767         echo "Usage: _is_mounted device" 1>&2
768         exit 1
769     fi
770
771     device=$1
772
773     if _mount | grep "$device " | $AWK_PROG -v pattern="type $FSTYP" '
774         pattern        { print $3 ; exit 0 }
775         END            { exit 1 }
776     '
777     then
778         echo "_is_mounted: $device is not a mounted $FSTYP FS"
779         exit 1
780     fi
781 }
782
783 # remount a FS to a new mode (ro or rw)
784 #
785 _remount()
786 {
787     if [ $# -ne 2 ]
788     then
789         echo "Usage: _remount device ro/rw" 1>&2
790         exit 1
791     fi
792     device=$1
793     mode=$2
794
795     if ! mount -o remount,$mode $device
796     then
797         echo "_remount: failed to remount filesystem on $device as $mode"
798         exit 1
799     fi
800 }
801
802 # Run the appropriate repair/check on a filesystem
803 #
804 # if the filesystem is mounted, it's either remounted ro before being
805 # checked or it's unmounted and then remounted
806 #
807
808 # If set, we remount ro instead of unmounting for fsck
809 USE_REMOUNT=0
810
811 _umount_or_remount_ro()
812 {
813     if [ $# -ne 1 ]
814     then
815         echo "Usage: _umount_or_remount_ro <device>" 1>&2
816         exit 1
817     fi
818
819     device=$1
820     mountpoint=`_is_mounted $device`
821
822     if [ $USE_REMOUNT -eq 0 ]; then
823         $UMOUNT_PROG $device
824     else
825         _remount $device ro
826     fi
827     echo "$mountpoint"
828 }
829
830 _mount_or_remount_rw()
831 {
832     if [ $# -ne 3 ]
833     then
834         echo "Usage: _mount_or_remount_rw <opts> <device> <mountpoint>" 1>&2
835         exit 1
836     fi
837     mount_opts=$1
838     device=$2
839     mountpoint=$3
840
841     if [ $USE_REMOUNT -eq 0 ]
842     then
843         if ! _mount -t $FSTYP $mount_opts $device $mountpoint
844         then
845             echo "!!! failed to remount $device on $mountpoint"
846             return 0 # ok=0
847         fi
848     else
849         _remount $device rw
850     fi
851
852     return 1 # ok=1
853 }
854
855 # Check a generic filesystem in no-op mode; this assumes that the
856 # underlying fsck program accepts "-n" for a no-op (check-only) run,
857 # and that it will still return an errno for corruption in this mode.
858 #
859 # Filesystems which don't support this will need to define their
860 # own check routine.
861 #
862 _check_generic_filesystem()
863 {
864     device=$1
865
866     # If type is set, we're mounted
867     type=`_fs_type $device`
868     ok=1
869
870     if [ "$type" = "$FSTYP" ]
871     then
872         # mounted ...
873         mountpoint=`_umount_or_remount_ro $device`
874     fi
875
876     fsck -t $FSTYP $FSCK_OPTIONS $device >$tmp.fsck 2>&1
877     if [ $? -ne 0 ]
878     then
879         echo "_check_generic_filesystem: filesystem on $device is inconsistent (see $seq.full)"
880
881         echo "_check_generic filesystem: filesystem on $device is inconsistent" >>$here/$seq.full
882         echo "*** fsck.$FSTYP output ***"                     >>$here/$seq.full
883         cat $tmp.fsck                                         >>$here/$seq.full
884         echo "*** end fsck.$FSTYP output"                     >>$here/$seq.full
885
886         ok=0
887     fi
888     rm -f $tmp.fsck
889
890     if [ $ok -eq 0 ]
891     then
892         echo "*** mount output ***"                             >>$here/$seq.full
893         _mount                                                  >>$here/$seq.full
894         echo "*** end mount output"                             >>$here/$seq.full
895     elif [ "$type" = "$FSTYP" ]
896     then
897         # was mounted ...
898         _mount_or_remount_rw "$MOUNT_OPTIONS" $device $mountpoint
899         ok=$?
900     fi
901
902     [ $ok -eq 0 ] && exit 1
903     return 0
904 }
905
906 # run xfs_check and friends on a FS.
907
908 _check_xfs_filesystem()
909 {
910     if [ $# -ne 3 ]
911     then
912         echo "Usage: _check_xfs_filesystem device <logdev>|none <rtdev>|none" 1>&2
913         exit 1
914     fi
915
916     extra_mount_options=""
917     device=$1
918     if [ "$2" != "none" ]; then
919         extra_log_options="-l$2"
920         extra_mount_options="-ologdev=$2"
921     fi
922
923     if [ "$3" != "none" ]; then
924         extra_rt_options="-r$3"
925         extra_mount_options=$extra_mount_options" -ortdev=$3"
926     fi
927     extra_mount_options=$extra_mount_options" $MOUNT_OPTIONS"
928
929     [ "$FSTYP" != xfs ] && return 0
930     testoption=""
931     [ "$USE_BIG_LOOPFS" = yes ] && testoption=-t
932
933     type=`_fs_type $device`
934     ok=1
935
936     if [ "$type" = "xfs" ]
937     then
938         # mounted ...
939         mountpoint=`_umount_or_remount_ro $device`
940     fi
941
942     $XFS_LOGPRINT_PROG -t $extra_log_options $device 2>&1 \
943                 | tee $tmp.logprint | grep -q "<CLEAN>"
944     if [ $? -ne 0 -a "$HOSTOS" = "Linux" ]
945     then
946         echo "_check_xfs_filesystem: filesystem on $device has dirty log (see $seq.full)"
947
948         echo "_check_xfs_filesystem: filesystem on $device has dirty log"   >>$here/$seq.full
949         echo "*** xfs_logprint -t output ***"                   >>$here/$seq.full
950         cat $tmp.logprint                                       >>$here/$seq.full
951         echo "*** end xfs_logprint output"                      >>$here/$seq.full
952
953         ok=0
954     fi
955
956     $XFS_CHECK_PROG $testoption $extra_log_options $device 2>&1 |\
957          _fix_malloc >$tmp.fs_check
958     if [ -s $tmp.fs_check ]
959     then
960         echo "_check_xfs_filesystem: filesystem on $device is inconsistent (c) (see $seq.full)"
961
962         echo "_check_xfs_filesystem: filesystem on $device is inconsistent" >>$here/$seq.full
963         echo "*** xfs_check output ***"                         >>$here/$seq.full
964         cat $tmp.fs_check                                       >>$here/$seq.full
965         echo "*** end xfs_check output"                         >>$here/$seq.full
966
967         ok=0
968     fi
969     # repair doesn't scale massively at this stage, optionally skip it for now
970     [ "$USE_BIG_LOOPFS" = yes ] || \
971     $XFS_REPAIR_PROG -n $extra_log_options $extra_rt_options $device >$tmp.repair 2>&1
972     if [ $? -ne 0 ]
973     then
974         echo "_check_xfs_filesystem: filesystem on $device is inconsistent (r) (see $seq.full)"
975
976         echo "_check_xfs_filesystem: filesystem on $device is inconsistent" >>$here/$seq.full
977         echo "*** xfs_repair -n output ***"                     >>$here/$seq.full
978         cat $tmp.repair | _fix_malloc                           >>$here/$seq.full
979         echo "*** end xfs_repair output"                        >>$here/$seq.full
980
981         ok=0
982     fi
983     rm -f $tmp.fs_check $tmp.logprint $tmp.repair
984
985     if [ $ok -eq 0 ]
986     then
987         echo "*** mount output ***"                             >>$here/$seq.full
988         _mount                                                  >>$here/$seq.full
989         echo "*** end mount output"                             >>$here/$seq.full
990     elif [ "$type" = "xfs" ]
991     then
992         _mount_or_remount_rw "$extra_mount_options" $device $mountpoint
993     fi
994
995     [ $ok -eq 0 ] && exit 1
996     return 0
997 }
998
999 # Filter the knowen errors the UDF Verifier reports.
1000 _udf_test_known_error_filter()
1001 {
1002         egrep -v "PVD  60  Error: Interchange Level: 1, Maximum Interchange Level: 0|FSD  28  Error: Interchange Level: 1, Maximum Interchange Level: 1,|PVD  72  Warning: Volume Set Identifier: \"\*IRIX UDF\",|Warning: [0-9]+ unused blocks NOT marked as unallocated."
1003
1004 }
1005
1006 _check_udf_filesystem()
1007 {
1008     [ "$DISABLE_UDF_TEST" == "1" ] && return
1009
1010     if [ $# -ne 1 -a $# -ne 2 ]
1011     then
1012         echo "Usage: _check_udf_filesystem device [last_block]" 1>&2
1013         exit 1
1014     fi
1015
1016     if [ ! -x $here/src/udf_test ]
1017     then
1018         echo "udf_test not installed, please download and build the Philips"
1019         echo "UDF Verification Software from http://www.extra.research.philips.com/udf/."
1020         echo "Then copy the udf_test binary to $here/src/."
1021         echo "If you do not wish to run udf_test then set environment variable DISABLE_UDF_TEST"
1022         echo "to 1."
1023         return
1024     fi
1025
1026     device=$1
1027     if [ $# -eq 2 ];
1028     then
1029         LAST_BLOCK=`expr \( $2 - 1 \)`
1030         OPT_ARG="-lastvalidblock $LAST_BLOCK"
1031     fi
1032
1033     rm -f $seq.checkfs
1034     sleep 1 # Due to a problem with time stamps in udf_test
1035     $here/src/udf_test $OPT_ARG $device | tee $here/$seq.checkfs | egrep "Error|Warning" | \
1036         _udf_test_known_error_filter | \
1037         egrep -iv "Error count:.*[0-9]+.*total occurrences:.*[0-9]+|Warning count:.*[0-9]+.*total occurrences:.*[0-9]+" | \
1038         sed "s/^.*$/Warning UDF Verifier reported errors see $seq.checkfs./g"
1039
1040 }
1041
1042 _check_xfs_test_fs()
1043 {
1044     TEST_LOG="none"
1045     TEST_RT="none"
1046     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_LOGDEV" ] && \
1047         TEST_LOG="$TEST_LOGDEV"
1048
1049     [ "$USE_EXTERNAL" = yes -a ! -z "$TEST_RTDEV" ] && \
1050         TEST_RT="$TEST_RTDEV"
1051
1052     _check_xfs_filesystem $TEST_DEV $TEST_LOG $TEST_RT
1053
1054     # check for ipath consistency
1055     if $XFS_GROWFS_PROG -n $TEST_DIR | grep -q 'inode-paths=1'; then
1056         # errors go to stderr
1057         xfs_check_ipaths $TEST_DIR >/dev/null
1058         xfs_repair_ipaths -n $TEST_DIR >/dev/null
1059     fi
1060 }
1061
1062 _check_test_fs()
1063 {
1064     case $FSTYP in
1065     xfs)
1066         _check_xfs_test_fs
1067         ;;
1068     nfs)
1069         # no way to check consistency for nfs
1070         ;;
1071     udf)
1072         # do nothing for now
1073         ;;
1074     *)
1075         _check_generic_filesystem $TEST_DEV
1076         ;;
1077     esac
1078 }
1079
1080 _check_scratch_fs()
1081 {
1082     case $FSTYP in
1083     xfs)
1084         SCRATCH_LOG="none"
1085         SCRATCH_RT="none"
1086         [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_LOGDEV" ] && \
1087             SCRATCH_LOG="$SCRATCH_LOGDEV"
1088
1089         [ "$USE_EXTERNAL" = yes -a ! -z "$SCRATCH_RTDEV" ] && \
1090             SCRATCH_RT="$SCRATCH_RTDEV"
1091
1092         _check_xfs_filesystem $SCRATCH_DEV $SCRATCH_LOG $SCRATCH_RT
1093         ;;
1094     udf)
1095         _check_udf_filesystem $SCRATCH_DEV $udf_fsize
1096         ;;
1097     nfs*)
1098         # Don't know how to check an NFS filesystem, yet.
1099         ;;
1100     *)
1101         _check_generic_filesystem $SCRATCH_DEV
1102         ;;
1103     esac
1104 }
1105
1106 _full_fstyp_details()
1107 {
1108      [ -z "$FSTYP" ] && FSTYP=xfs
1109      if [ $FSTYP = xfs ]; then
1110         if [ -d /proc/fs/xfs ]; then
1111             if grep -q 'debug 0' /proc/fs/xfs/stat; then
1112                 FSTYP="$FSTYP (non-debug)"
1113             elif grep -q 'debug 1' /proc/fs/xfs/stat; then
1114                 FSTYP="$FSTYP (debug)"
1115             fi
1116         else
1117             if uname -a | grep -qi 'debug'; then
1118                 FSTYP="$FSTYP (debug)"
1119             else
1120                 FSTYP="$FSTYP (non-debug)"
1121             fi
1122         fi
1123      fi
1124      echo $FSTYP
1125 }
1126
1127 _full_platform_details()
1128 {
1129      os=`uname -s`
1130      host=`hostname -s`
1131      kernel=`uname -r`
1132      platform=`uname -m`
1133      echo "$os/$platform $host $kernel"
1134 }
1135
1136 _setup_udf_scratchdir()
1137 {
1138     [ "$FSTYP" != "udf" ] \
1139         && _fail "setup_udf_testdir: \$FSTYP is not udf"
1140     [ -z "$SCRATCH_DEV" -o ! -b "$SCRATCH_DEV" ] \
1141         && _notrun "this test requires a valid \$SCRATCH_DEV"
1142     [ -z "$SCRATCH_MNT" ] \
1143         && _notrun "this test requires a valid \$SCRATCH_MNT"
1144
1145     # mounted?
1146     if _mount | grep -q $SCRATCH_DEV
1147     then
1148         # if it's mounted, make sure its on $TEST_RW_DIR
1149         if ! _mount | grep $SCRATCH_DEV | grep -q $SCRATCH_MNT
1150         then
1151             _fail "\$SCRATCH_DEV is mounted but not on \$SCRATCH_MNT - aborting"
1152         fi
1153         $UMOUNT_PROG $SCRATCH_DEV
1154     fi
1155
1156     _scratch_mkfs
1157     _scratch_mount
1158
1159     testdir=$SCRATCH_MNT
1160 }
1161
1162 _setup_nfs_scratchdir()
1163 {
1164     [ "$FSTYP" != "nfs" ] \
1165         && _fail "setup_nfs_testdir: \$FSTYP is not nfs"
1166     [ -z "$SCRATCH_DEV" ] \
1167         && _notrun "this test requires a valid host fs for \$SCRATCH_DEV"
1168     [ -z "$SCRATCH_MNT" ] \
1169         && _notrun "this test requires a valid \$SCRATCH_MNT"
1170
1171     # mounted?
1172     if _mount | grep -q $SCRATCH_DEV
1173     then
1174         # if it's mounted, make sure its on $SCRATCH_MNT
1175         if ! _mount | grep $SCRATCH_DEV | grep -q $SCRATCH_MNT
1176         then
1177             _fail "\$SCRATCH_DEV is mounted but not on \$SCRATCH_MNT - aborting"
1178         fi
1179         $UMOUNT_PROG $SCRATCH_DEV
1180     fi
1181
1182     _scratch_mkfs
1183     _scratch_mount
1184
1185     testdir=$SCRATCH_MNT
1186 }
1187
1188 #
1189 # Warning for UDF and NFS:
1190 # this function calls _setup_udf_scratchdir and _setup_udf_scratchdir
1191 # which actually uses the scratch dir for the test dir.
1192 #
1193 # This was done because testdir was intended to be a persistent
1194 # XFS only partition.  This should eventually change, and treat
1195 # at least local filesystems all the same.
1196 #
1197 _setup_testdir()
1198 {
1199     case $FSTYP in
1200     udf)
1201         _setup_udf_scratchdir
1202         ;;
1203     nfs*)
1204         _setup_nfs_scratchdir
1205         ;;
1206     *)
1207         testdir=$TEST_DIR
1208         ;;
1209     esac
1210 }
1211
1212 _cleanup_testdir()
1213 {
1214     case $FSTYP in
1215     udf)
1216         # umount testdir as it is $SCRATCH_MNT which could be used by xfs next
1217         [ -n "$testdir" ] && $UMOUNT_PROG $testdir
1218         ;;
1219     nfs*)
1220         # umount testdir as it is $SCRATCH_MNT which could be used by xfs next
1221         [ -n "$testdir" ] && $UMOUNT_PROG $testdir
1222         ;;
1223     *)
1224         # do nothing, testdir is $TEST_DIR
1225         :
1226         ;;
1227     esac
1228 }
1229
1230 _link_out_file()
1231 {
1232    if [ -z "$1" ]; then
1233       echo Error must pass \$seq.
1234       exit
1235    fi
1236    rm -f $1
1237    if [ "`uname`" == "IRIX64" ] || [ "`uname`" == "IRIX" ]; then
1238       ln -s $1.irix $1
1239    elif [ "`uname`" == "Linux" ]; then
1240       ln -s $1.linux $1
1241    else
1242       echo Error test $seq does not run on the operating system: `uname`
1243       exit
1244    fi
1245 }
1246
1247 _die()
1248 {
1249         echo $@
1250         exit 1
1251 }
1252
1253 _nfiles()
1254 {
1255         f=0
1256         while [ $f -lt $1 ]
1257         do
1258                 file=f$f
1259                 echo > $file
1260                 if [ $size -gt 0 ]; then
1261                     dd if=/dev/zero of=$file bs=1024 count=$size
1262                 fi
1263                 let f=$f+1
1264         done
1265 }
1266
1267 # takes dirname, depth
1268 _descend()
1269 {
1270         dirname=$1; depth=$2
1271         mkdir $dirname  || die "mkdir $dirname failed"
1272         cd $dirname
1273
1274         _nfiles $files           # files for this dir
1275
1276         [ $depth -eq 0 ] && return
1277         let deep=$depth-1 # go 1 down
1278
1279         [ $verbose = true ] && echo "descending, depth from leaves = $deep"
1280
1281         d=0
1282         while [ $d -lt $dirs ]
1283         do
1284                 _descend d$d $deep &
1285                 let d=$d+1
1286                 wait
1287         done
1288 }
1289
1290 # Populate a filesystem with inodes for performance experiments
1291 #
1292 # usage: populate [-v] [-n ndirs] [-f nfiles] [-d depth] [-r root] [-s size]
1293 #
1294 _populate_fs()
1295 {
1296     here=`pwd`
1297     dirs=5          # ndirs in each subdir till leaves
1298     size=0          # sizeof files in K
1299     files=100       # num files in _each_ subdir
1300     depth=2         # depth of tree from root to leaves
1301     verbose=false
1302     root=root       # path of initial root of directory tree
1303
1304     while getopts "d:f:n:r:s:v" c
1305     do
1306         case $c in
1307         d)      depth=$OPTARG;;
1308         n)      dirs=$OPTARG;;
1309         f)      files=$OPTARG;;
1310         s)      size=$OPTARG;;
1311         v)      verbose=true;;
1312         r)      root=$OPTARG;;
1313         esac
1314     done
1315
1316     _descend $root $depth
1317     wait
1318
1319     cd $here
1320
1321     [ $verbose = true ] && echo done
1322 }
1323
1324 # query whether the given file has the given inode flag set
1325 #
1326 _test_inode_flag()
1327 {
1328     flag=$1
1329     file=$2
1330
1331     if which $XFS_IO_PROG >/dev/null; then
1332         if $XFS_IO_PROG -r -c 'lsattr -v' "$file" | grep -q "$flag" ; then
1333             return 0
1334         fi
1335     fi
1336     return 1
1337 }
1338
1339 # query the given files extsize allocator hint in bytes (if any)
1340 #
1341 _test_inode_extsz()
1342 {
1343     file=$1
1344     blocks=""
1345
1346     if which $XFS_IO_PROG >/dev/null; then
1347         blocks=`$XFS_IO_PROG -r -c 'stat' "$file" | \
1348                 awk '/^xattr.extsize =/ { print $3 }'`
1349     fi
1350     [ -z "$blocks" ] && blocks="0"
1351     echo $blocks
1352 }
1353
1354
1355 ################################################################################
1356
1357 if [ "$iam" != new -a "$iam" != bench ]
1358 then
1359     # make some further configuration checks here
1360
1361     if [ "$TEST_DEV" = ""  ]
1362     then
1363         echo "common.rc: Error: \$TEST_DEV is not set"
1364         exit 1
1365     fi
1366
1367     # if $TEST_DEV is not mounted, mount it now as XFS
1368     if [ -z "`_fs_type $TEST_DEV`" ]
1369     then
1370         # $TEST_DEV is not mounted
1371         if ! _test_mount
1372         then
1373             echo "common.rc: retrying test device mount with external set"
1374             [ "$USE_EXTERNAL" != "yes" ] && export USE_EXTERNAL=yes
1375             if ! _test_mount
1376             then
1377                 echo "common.rc: could not mount $TEST_DEV on $TEST_DIR"
1378                 exit 1
1379             fi
1380         fi
1381     fi
1382
1383     if [ "`_fs_type $TEST_DEV`" != "$FSTYP" ]
1384     then
1385         echo "common.rc: Error: \$TEST_DEV ($TEST_DEV) is not a MOUNTED $FSTYP filesystem"
1386         $DF_PROG $TEST_DEV
1387         exit 1
1388     fi
1389 fi
1390
1391 # make sure this script returns success
1392 /bin/true