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