don't unilaterally notrun this test -- check whether libc is busted, and
[xfstests-dev.git] / common.dump
1 #/bin/sh
2
3 #
4 # Functions useful for xfsdump/xfsrestore tests
5 #
6 # Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
7
8 # This program is free software; you can redistribute it and/or modify it
9 # under the terms of version 2 of the GNU General Public License as
10 # published by the Free Software Foundation.
11
12 # This program is distributed in the hope that it would be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
16 # Further, this software is distributed without any warranty that it is
17 # free of the rightful claim of any third person regarding infringement
18 # or the like.  Any license provided herein, whether implied or
19 # otherwise, applies only to this software file.  Patent licenses, if
20 # any, provided herein do not apply to combinations of this program with
21 # other software, or any other product whatsoever.
22
23 # You should have received a copy of the GNU General Public License along
24 # with this program; if not, write the Free Software Foundation, Inc., 59
25 # Temple Place - Suite 330, Boston MA 02111-1307, USA.
26
27 # Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
28 # Mountain View, CA  94043, or:
29
30 # http://www.sgi.com 
31
32 # For further information regarding this notice, see: 
33
34 # http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
35 #
36
37 # --- initializations ---
38 rm -f $here/$seq.full
39
40 if [ -n "$DEBUGDUMP" ]; then
41   _dump_debug=-v5
42   _restore_debug=-v5
43   _invutil_debug=-d
44 fi
45  
46 # Use dump/restore in qa directory for debugging
47 PATH="$here:$PATH"
48 export PATH
49 #which xfsdump
50 #which xfsrestore
51 #which xfsinvutil
52
53 # status returned for not run tests
54 NOTRUNSTS=2
55
56 # name those directories
57 dump_file=$tmp.dumpfile
58 # dump_file=$here/dumpfile #TEMP OVERRIDE DUMP FILE
59 dump_sdir=dumpdir
60 dump_dir=$SCRATCH_MNT/$dump_sdir
61 restore_sdir=restoredir
62 restore_dir=$SCRATCH_MNT/$restore_sdir
63 multi=3
64 dumptape=$TAPE_DEV
65 media_label="stress_tape_media"
66 session_label="stress_$seq"
67
68 nobody=4 # define this uid/gid as a number
69 do_quota_check=true # do quota check if quotas enabled
70
71 _need_to_be_root
72
73 # install our cleaner
74 trap "_cleanup; exit \$status" 0 1 2 3 15
75
76 # start inventory from a known base - move it aside for test
77 for dir in /var/xfsdump/inventory /var/lib/xfsdump/inventory; do
78     if [ -d $dir ]; then
79         [ -d $dir.$seq ] && rm -rf $dir.$seq
80         mv $dir $dir.$seq
81     fi
82 done
83
84 have_mtvariable=false
85 [ `uname` = "Linux" ] && have_mtvariable=true
86
87 #
88 # do a remote/local mt
89 #
90 _mt()
91 {
92     op=$1
93     if _isrmt; then  
94         # REMOTE
95         _rmtdev=`echo $dumptape | $AWK_PROG -F: '{print $2}'`
96
97         if echo $dumptape | grep '@' >/dev/null; then
98             _spec=`echo $dumptape | $AWK_PROG -F: '{print $1}'`
99             _rmtuser=`echo $_spec | $AWK_PROG -F@ '{print $1}'`
100             _rmthost=`echo $_spec | $AWK_PROG -F@ '{print $2}'`
101             rsh -n -l $_rmtuser $_rmthost "mt -t $_rmtdev $op"
102         else
103             _rmthost=`echo $dumptape | $AWK_PROG -F: '{print $1}'`
104             rsh -n $_rmthost "mt -t $_rmtdev $op"
105         fi
106     else
107         #LOCAL
108         mt -t $dumptape $op
109     fi
110 }
111
112 _check_onl()
113 {
114     _limit=10
115     i=0
116     while [ $i -lt $_limit ]; do  
117         echo "Checking online..." >>$here/$seq.full
118         if _mt status >$tmp.status 2>&1; then
119             break; 
120         else
121             sleep 2 
122         fi
123         i=`expr $i + 1`
124     done
125
126
127     if [ $i -eq $_limit ]; then
128         echo "ERROR: mt -f $dumptape failed"
129         cat $tmp.status
130
131         echo "mt -f $dumptape failed" >$seq.notrun 
132         status=$NOTRUNSTS
133         exit
134     fi 
135
136
137     if egrep -i 'onl|ready' $tmp.status | grep -iv 'not ready' >/dev/null; then
138         :
139     else
140         echo "ERROR: $dumptape is not online"
141         cat $tmp.status
142
143         echo "dumptape, $dumptape, is not online" >$seq.notrun 
144         status=$NOTRUNSTS
145         exit
146     fi
147 }
148
149 _wait_tape()
150 {
151     echo "Wait for tape, $dumptape, ..." >>$here/$seq.full
152
153     i=0
154     while [ $i -lt 20 ]; do  
155         echo "Checking status..." >>$here/$seq.full
156         if _mt status 2>&1 | tee -a $here/$seq.full | egrep -i "onl|ready" >/dev/null; then
157             break; 
158         else
159             sleep 2 
160         fi
161         i=`expr $i + 1`
162     done
163 }
164
165 #
166 # Keep trying so we know we really have rewound
167 #
168 _rewind()
169 {
170     echo "Initiate rewind..." >>$here/$seq.full
171     _wait_tape
172     _mt rewind >/dev/null
173     _wait_tape
174 }
175
176 #
177 # Do a custom erase because: 
178 # (i) some machines don't support it
179 # (ii) some machines take forever to do it
180 #
181 _erase_soft()
182 {
183     echo "Erasing tape" | tee -a $here/$seq.full
184     _rewind
185     _mt weof 3
186     _rewind
187 }
188
189 _erase_hard()
190 {
191     echo "Erasing tape" | tee -a $here/$seq.full
192     _mt erase
193 }
194
195 _isrmt()
196 {
197     echo $dumptape | grep ':' >/dev/null
198 }
199
200 #
201 # Get tape ready
202 #
203 _set_variable()
204 {
205     $have_mtvariable || return
206
207     if _isrmt; then
208         :
209     else
210         # LOCAL
211         echo "Put scsi tape driver into variable block size mode"
212         mt -f $dumptape setblk 0
213     fi  
214 }
215
216 _require_tape()
217 {
218     dumptape=$1
219
220     if [ -z "$dumptape" ]; then
221         echo "This test requires a dump tape - none was specified"
222         echo "No dump tape specified" >$seq.notrun 
223         status=$NOTRUNSTS
224         exit
225     fi
226
227     _check_onl
228     _set_variable
229 }
230
231 _error()
232 {
233     echo "Error: $*" | tee -a $here/$seq.full
234     echo "(see $here/$seq.full for details)"
235     status=1
236     exit
237 }
238
239 _wipe_fs()
240 {
241     _require_scratch
242
243     mkfs_xfs $SCRATCH_DEV>>$here/$seq.full  ||\
244         _error "mkfs failed"
245       
246     mount -t xfs $SCRATCH_DEV $SCRATCH_MNT >>$here/$seq.full ||\
247         _error "mount failed"
248 }
249
250
251 # Cleanup created dirs and files
252 # Called by trap
253 #
254 _cleanup()
255 {
256     cd $here
257     rm -f $tmp.*
258
259     if [ -n "$DEBUGDUMP" ]; then
260         # save it for inspection
261         for dir in /var/xfsdump/inventory /var/lib/xfsdump/inventory; do
262             [ -d $dir ] || continue
263             tar -cvf $seq.inventory.tar $dir
264             ls -lR $dir >$seq.inventory.ls
265         done
266     fi
267
268     # put inventory dir back
269     for dir in /var/xfsdump/inventory /var/lib/xfsdump/inventory; do
270         [ -d $dir.$seq ] || continue
271         rm -rf $dir             # get rid of new one
272         mv $dir.$seq $dir
273     done
274
275     if [ $status -ne $NOTRUNSTS ]; then
276         # Sleep added to stop _check_fs from complaining that the
277         # scratch_dev is still busy
278         sleep 10
279
280         _check_fs $SCRATCH_DEV
281     fi
282 }
283
284 #
285 # ensure that bulkstat data will
286 # match with incore data
287 # by forcing disk data to be written out
288 #
289 _stable_fs()
290 {
291     _saveddir=`pwd`; cd /
292     umount $SCRATCH_MNT >>$here/$seq.full ||\
293         _error "unmount failed"
294     mount -t xfs $SCRATCH_DEV $SCRATCH_MNT >>$here/$seq.full ||\
295         _error "mount failed"
296     cd $_saveddir
297 }
298
299 #
300 # Run src/fsstress to create a mixture of 
301 # files,dirs,links,symlinks
302 #
303 # Pinched from test 013.
304 #
305 _create_dumpdir_stress()
306 {
307     echo "Creating directory system to dump using src/fsstress."
308
309     _wipe_fs
310
311     _param="-f link=10 -f creat=10 -f mkdir=10 -f truncate=5 -f symlink=10"
312     _count=200
313     rm -rf $dump_dir
314     if ! mkdir $dump_dir; then
315         echo "    failed to mkdir $dump_dir"
316         status=1
317         exit
318     fi
319     echo ""
320     echo "-----------------------------------------------"
321     echo "fsstress : $_param"
322     echo "-----------------------------------------------"
323     if ! $here/src/fsstress $_param -s 1 $FSSTRESS_AVOID -n $_count -d $dump_dir >$tmp.out 2>&1
324     then
325         echo "    fsstress (count=$_count) returned $? - see $here/$seq.full"
326         
327         echo "--------------------------------------"       >>$here/$here/$seq.full
328         echo "output from fsstress:"                        >>$here/$here/$seq.full
329         echo "--------------------------------------"       >>$here/$here/$seq.full
330         cat $tmp.out                                        >>$here/$here/$seq.full
331         status=1
332     fi
333
334     _stable_fs
335 }
336
337 _mk_fillconfig1()
338 {
339     cat <<End-of-File >$tmp.config
340 # pathname      size in bytes   owner   group
341 #
342 small           10      $nobody $nobody
343 big             102400  daemon  sys
344 sub/small       10      bin     bin
345 sub/big         102400  $nobody sys
346 #
347 sub/a           1       $nobody $nobody
348 sub/b           2       $nobody $nobody
349 sub/c           4       $nobody $nobody
350 sub/d           8       $nobody $nobody
351 sub/e           16      $nobody $nobody
352 sub/f           32      $nobody $nobody
353 sub/g           64      $nobody $nobody
354 sub/h           128     $nobody $nobody
355 sub/i           256     $nobody $nobody
356 sub/j           512     $nobody $nobody
357 sub/k           1024    $nobody $nobody
358 sub/l           2048    $nobody $nobody
359 sub/m           4096    $nobody $nobody
360 sub/n           8192    $nobody $nobody
361 #
362 sub/a00         100     $nobody $nobody
363 sub/b00         200     $nobody $nobody
364 sub/c00         400     $nobody $nobody
365 sub/d00         800     $nobody $nobody
366 sub/e00         1600    $nobody $nobody
367 sub/f00         3200    $nobody $nobody
368 sub/g00         6400    $nobody $nobody
369 sub/h00         12800   $nobody $nobody
370 sub/i00         25600   $nobody $nobody
371 sub/j00         51200   $nobody $nobody
372 sub/k00         102400  $nobody $nobody
373 sub/l00         204800  $nobody $nobody
374 sub/m00         409600  $nobody $nobody
375 sub/n00         819200  $nobody $nobody
376 #
377 sub/a000        1000    $nobody $nobody
378 sub/e000        16000   $nobody $nobody
379 sub/h000        128000  $nobody $nobody
380 sub/k000        1024000 $nobody $nobody
381 End-of-File
382 }
383
384 _mk_fillconfig2()
385 {
386     cat <<End-of-File >$tmp.config
387 # pathname      size in bytes
388 #
389 smalll          10      $nobody $nobody
390 biggg           102400  $nobody $nobody
391 sub/smalll      10      $nobody $nobody
392 sub/biggg       102400  $nobody $nobody
393 End-of-File
394 }
395
396 _mk_fillconfig_perm()
397 {
398     # dir_guid: ugo=rwx,g+s on dir is for IRIX chmod(1)
399
400     cat <<End-of-File >$tmp.config
401 # pathname      size/dir  user group mode
402 #
403 file_suid       10      $nobody $nobody 04777
404 file_guid       10      $nobody $nobody 02777
405 file_sticky     10      $nobody $nobody 01777
406 file_mix1       10      $nobody $nobody 761
407 file_mix2       10      $nobody $nobody 642
408 dir_suid        d       $nobody $nobody 04777
409 dir_guid        d       $nobody $nobody ugo=rwx,g+s
410 dir_sticky      d       $nobody $nobody 01777
411 dir_mix1        d       $nobody $nobody 761
412 dir_mix2        d       $nobody $nobody 642
413 End-of-File
414 }
415
416 _mk_fillconfig_ea()
417 {
418     cat <<End-of-File >$tmp.config
419 # pathname      size    user    group    perm   name value namespace
420 #
421 smalll          10      $nobody $nobody  777    attr1 some_text   user 
422 biggg           102400  $nobody $nobody  777    attr2 some_text2  root
423 sub/smalll      10      $nobody $nobody  777    attr3 some_text3  user
424 sub/biggg       102400  $nobody $nobody  777    attr4 some_text4  root
425 dir             d       $nobody $nobody  777    attr5 dir_text    user
426 #
427 # Add more files so that there are more than the number
428 # of streams.
429 # There are bugs in dump/restore for # non-dir files < # streams
430 # It can be tested in another configuration.
431 # It is a pathalogical case.
432 #
433 sub/a           1       $nobody $nobody
434 sub/b           2       $nobody $nobody
435 sub/c           4       $nobody $nobody
436 sub/d           8       $nobody $nobody
437 sub/e           16      $nobody $nobody
438 sub/f           32      $nobody $nobody
439 sub/g           64      $nobody $nobody
440 sub/h           128     $nobody $nobody
441 sub/i           256     $nobody $nobody
442 sub/j           512     $nobody $nobody
443 sub/k           1024    $nobody $nobody
444 sub/l           2048    $nobody $nobody
445 sub/m           4096    $nobody $nobody
446 sub/n           8192    $nobody $nobody
447 End-of-File
448 }
449
450 #
451 # Create a bunch of directories/files of different sizes
452 # filled with data.
453 #
454 # Pinched from test 001.
455 #
456 _do_create_dumpdir_fill()
457 {
458     echo "Creating directory system to dump using src/fill."
459
460     mkdir -p $dump_dir ||\
461         _error "cannot mkdir \"$dump_dir\""
462     cd $dump_dir
463
464     $verbose && echo -n "Setup "
465     sed -e '/^#/d' $tmp.config \
466     | while read file nbytes owner group perms ea_name ea_value namespace
467     do
468         if [ $nbytes = "d" ]; then
469             # create a directory
470             dir=$file   
471             if [ ! -d $dir ]
472             then
473                 if mkdir $dir
474                 then
475                     :
476                 else
477                     $verbose && echo
478                     echo "Error: cannot mkdir \"$dir\""
479                     exit 1
480                 fi
481             fi
482         else
483             # create a directory/file
484             dir=`dirname $file`
485             if [ "$dir" != "." ]
486             then
487                 if [ ! -d $dir ]
488                 then
489                     if mkdir $dir
490                     then
491                         :
492                     else
493                         $verbose && echo
494                         echo "Error: cannot mkdir \"$dir\""
495                         exit 1
496                     fi
497                 fi
498             fi
499             rm -f $file
500             if $here/src/fill $file $file $nbytes
501             then
502                 :
503             else
504                 $verbose && echo
505                 echo "Error: cannot create \"$file\""
506                 exit 1
507             fi
508         fi
509         if [ -n "$owner" -a -n "$group" ]; then
510             chown $owner.$group $file
511         fi
512         if [ -n "$perms" ]; then
513             chmod $perms $file
514         fi
515         if [ -n "$ea_name" -a -n "$ea_value" ]; then
516             if [ "X$namespace" = "Xroot" ]; then
517                 attr -R -s $ea_name -V $ea_value $file
518             else
519                 attr -s $ea_name -V $ea_value $file
520             fi
521         fi
522         $verbose && echo -n "."
523     done
524     $verbose && echo
525
526     cd $here
527 }
528
529 _create_dumpdir_largefile()
530 {
531     _wipe_fs
532     mkdir -p $dump_dir ||\
533         _error "cannot mkdir \"$dump_dir\""
534     _largesize=4294967297
535     _largefile=$dump_dir/largefile
536     echo "dd a largefile at offset $_largesize"
537     dd if=/dev/zero of=$_largefile bs=1 seek=$_largesize count=10 2>&1
538     _stable_fs
539 }       
540
541 _create_dumpdir_fill()
542 {
543     _wipe_fs
544     _mk_fillconfig1
545     _do_create_dumpdir_fill
546     _stable_fs
547 }       
548
549 _create_dumpdir_fill2()
550 {
551     _wipe_fs
552     _mk_fillconfig2
553     _do_create_dumpdir_fill
554     _stable_fs
555 }       
556
557 _create_dumpdir_fill_perm()
558 {
559     _wipe_fs
560     _mk_fillconfig_perm
561     _do_create_dumpdir_fill
562     _stable_fs
563 }       
564
565 _create_dumpdir_fill_ea()
566 {
567     _wipe_fs
568     _mk_fillconfig_ea
569     _do_create_dumpdir_fill
570     _stable_fs
571 }       
572
573
574 #
575 # Append a subset of the fill'ed files
576 # So we can see if just these get dumped on an incremental
577 #
578 _append_dumpdir_fill()
579 {
580     cd $dump_dir
581     cat <<End-of-File >$tmp.config
582 # pathname
583 #
584 small   
585 sub/big 
586 #
587 sub/a
588 sub/c
589 sub/e
590 End-of-File
591     sed -e '/^#/d' $tmp.config \
592     | while read file
593     do
594         echo 'Extra text' >>$file
595     done
596
597     cd $here
598     _stable_fs
599 }
600
601 _do_create_dump_symlinks()
602 {
603     echo "Creating directory system of symlinks to dump."
604
605     mkdir -p $dump_dir ||\
606         _error "cannot mkdir \"$dump_dir\""
607     cd $dump_dir
608
609     $verbose && echo -n "Setup "
610     sed -e '/^#/d' $tmp.config \
611     | while read file nbytes owner group owner2 group2 perms perms2
612     do
613         dir=`dirname $file`
614         if [ "$dir" != "." ]
615         then
616             if [ ! -d $dir ]
617             then
618                 if mkdir $dir
619                 then
620                     :
621                 else
622                     $verbose && echo
623                     echo "Error: cannot mkdir \"$dir\""
624                     exit 1
625                 fi
626             fi
627         fi
628         rm -f $file
629         touch $file
630
631         # Do chmod on symlink using umask.
632         # This won't do the right thing as it subtracts permissions.
633         # However, I don't care, as long as I get some different perms
634         # for testing.
635         if [ -n "$perms2" ]; then
636             omask=`umask`
637             umask $perms2
638         fi
639         ln -s $file $file-link
640         if [ -n "$perms2" ]; then
641             umask $omask        
642         fi
643
644         if [ -n "$owner" -a -n "$group" ]; then
645             chown $owner.$group $file
646         fi
647         if [ -n "$owner" -a -n "$group" ]; then
648             chown -h $owner.$group $file-link
649         fi
650         if [ -n "$perms" ]; then
651             chmod $perms $file
652         fi
653         $verbose && echo -n "."
654     done
655     $verbose && echo
656
657     cd $here
658 }
659
660 _mk_symlink_config()
661 {
662     cat <<End-of-File >$tmp.config
663 # path  size    owner1  group1  owner2  group2  perm1   perm2 
664 #
665 a       0       $nobody $nobody daemon  sys     124     421
666 b       0       daemon  sys     bin     bin     347     743
667 sub/a   0       bin     bin     $nobody sys     777     777
668 sub/b   0       $nobody sys     $nobody $nobody 367     763
669 End-of-File
670 }
671
672 _create_dumpdir_symlinks()
673 {
674     _wipe_fs
675     _mk_symlink_config
676     _do_create_dump_symlinks
677     _stable_fs
678 }       
679
680 #
681 # create hardlinks of form $_fname, $_fname_h1 $_fname_h2 ...
682 #
683 _create_hardlinks()
684 {
685     _fname=$1   
686     _numlinks=$2
687
688     touch $_fname
689     _j=1
690     while [ $_j -le $_numlinks ]; do
691         _suffix=_h$_j
692         _hardlink=$_fname$_suffix
693         echo "creating hardlink $_hardlink to $_fname"
694         ln $_fname $_hardlink
695         _j=`expr $_j + 1`
696     done
697 }
698
699 #
700 # create a set of hardlinks
701 # create hardlinks of form file1, file1_h1 file1_h2 ...
702 # create hardlinks of form file2, file2_h1 file2_h2 ...
703 # create hardlinks of form file3, file3_h1 file3_h2 ...
704 #
705 _create_hardset()
706 {
707     _numsets=$1
708     _i=1
709     while [ $_i -le $_numsets ]; do
710         _create_hardlinks file$_i 5
711         _i=`expr $_i + 1`
712     done
713 }
714
715
716 _modify_level()
717 {
718     _level=$1
719     echo "mod level $_level" >$dump_dir/file$_level
720 }
721
722 _create_dumpdir_hardlinks()
723 {
724     _numsets=$1
725     _wipe_fs
726     echo "Creating directory system of hardlinks to incrementally dump."
727
728     mkdir -p $dump_dir ||\
729         _error "cannot mkdir \"$dump_dir\""
730     cd $dump_dir
731
732     _create_hardset $_numsets
733
734     cd $here
735     _stable_fs
736 }
737
738 #
739 # Filter for ls
740 # Filter out dates on symlinks and char devices
741 #
742 _ls_filter()
743 {
744   $AWK_PROG '
745         /^l/ { date = $8; sub(date,"DATE"); print}
746         /^c/ { date = $9; sub(date,"DATE"); print}
747         {print}' \
748   | sed -e 's/total [0-9][0-9]*/total TOTAL/'
749 }
750
751
752
753 # Filter out the non-deterministic dump msgs from
754 # xfsdump and xfsrestore
755 #
756 _dump_filter_main()
757 {
758   sed \
759       -e "s/`hostname`/HOSTNAME/"   \
760       -e "s#$SCRATCH_DEV#SCRATCH_DEV#"    \
761       -e "s#$SCRATCH_RAWDEV#SCRATCH_DEV#"    \
762       -e "s#$dumptape#TAPE_DEV#"    \
763       -e "s#$SCRATCH_MNT#SCRATCH_MNT#"    \
764       -e "s#$dump_file#DUMP_FILE#"  \
765       -e 's#/var/lib/xfsdump#/var/xfsdump#' \
766       -e 's/id:[        ]*[0-9a-f-]*/id: ID/'  \
767       -e 's/time:[      ].*/time: TIME/'       \
768       -e 's/date:[      ].*/date: DATE/'       \
769       -e 's/dump begun .*/dump begun DATE/'    \
770       -e 's/[0-9][0-9]* seconds/SECS seconds/' \
771       -e 's/restore.[0-9][0-9]*/restore.PID/' \
772       -e 's/ino [0-9][0-9]*/ino INO/' \
773       -e '/: dump size/s/[0-9][0-9]*/NUM/'     \
774       -e '/dump size:/s/[0-9][0-9]*/NUM/'      \
775       -e '/dump size per stream:/s/[0-9][0-9]*/NUM/' \
776       -e 's/\(media file size[   ]*\)[0-9][0-9]*/\1NUM/' \
777       -e 's/\(mfile size:[       ]*\)[0-9][0-9]*/\1NUM/' \
778       -e '/drive[        ]*[0-9][0-9]*:/d' \
779       -e '/\/dev\/tty/d' \
780       -e '/inventory session uuid/d' \
781       -e '/ - Running single-threaded/d' \
782       -e '/^.*I\/O metrics: .*$/d' \
783       -e 's/1048576/BLOCKSZ/' \
784       -e 's/2097152/BLOCKSZ/' \
785       -e 's/(pid[        ]*[1-9][0-9]*)/\(pid PID\)/' \
786   | perl -ne '
787       if ($_ =~ /(?:Dump|Restore) Summary/) {
788         $skip = 1;
789       } elsif ($_ =~ /(?:Dump|Restore) Status/) {
790         $skip = 0;
791       }
792       print if (! $skip);'
793 }
794
795 _dump_filter()
796 {
797    if $do_quota_check
798    then
799        _dump_filter_main | _check_quota_dumprestore | _check_quota_entries
800    else
801        _dump_filter_main
802    fi
803 }
804
805 _invutil_filter()
806 {
807   _dump_filter_main \
808   | sed \
809         -e 's/UUID[     ]*:[    ][0-9a-f-]*/UUID                :       ID/' \
810         -e 's/TIME OF DUMP[     ]*:.*/TIME OF DUMP      :       TIME/' \
811         -e 's/HOSTNAME:SCRATCH_MNT.*/HOSTNAME:SCRATCH_MNT/' \
812         -e 's#inventory/[0-9a-f-]*#inventory/UUID#' \
813
814 }
815
816
817 _dir_filter()
818 {
819   sed \
820     -e "s#$dump_file#DUMP_FILE#"      \
821     -e "s#$SCRATCH_DEV#SCRATCH_DEV#"        \
822     -e "s#$SCRATCH_RAWDEV#SCRATCH_DEV#"    \
823     -e "s#$dumptape#TAPE_DEV#"         \
824     -e "s#$dump_dir#DUMP_DIR#g"       \
825     -e "s#$restore_dir#RESTORE_DIR#g" \
826     -e "s#$SCRATCH_MNT#SCRATCH_MNT#g"       \
827     -e "s#$dump_sdir#DUMP_SUBDIR#g"   \
828     -e "s#$restore_sdir#RESTORE_SUBDIR#g" \
829     -e "s#$$#PID#g" \
830
831 }
832
833 #
834 # Note: requires a space between option letter and argument 
835 #
836 _parse_args()
837 {
838     OPTIND=0
839     dump_args=""
840     while [ $# -gt 0 ]
841     do
842         case $1
843         in
844         -f)
845             [ -z "$2" ] && _error "missing argument for -f"
846             dumptape=$2 
847             shift
848             ;;
849         -L)
850             [ -z "$2" ] && _error "missing argument for -L"
851             session_label=$2
852             shift
853             ;;
854         -o)
855             dump_args="$dump_args -o"
856             ;;
857         -F)
858             dump_args="$dump_args -F"
859             ;;
860         --multi)
861             multi=$2
862             shift
863             ;;
864         -q)
865             do_quota_check=true
866             ;;
867         -Q)
868             do_quota_check=false
869             ;;
870         -l)
871             [ -z "$2" ] && _error "missing argument for -l"
872             dump_args="$dump_args -l$2"
873             shift
874             ;;
875         *)
876             _error "invalid argument to common.dump function: $1"
877             ;;
878         esac
879         shift
880     done
881 }
882
883
884 #
885 # Dump a subdir
886 #
887 _do_dump_sub()
888 {
889     _parse_args $*
890
891     echo "Dumping to tape..."
892     opts="$_dump_debug$dump_args -s $dump_sdir -f $dumptape -M $media_label -L $session_label $SCRATCH_MNT"
893     echo "xfsdump $opts" | _dir_filter  
894     xfsdump $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
895 }
896
897 #
898 # Do dump to tape
899 #
900 _do_dump()
901 {
902     _parse_args $*
903
904     echo "Dumping to tape..."
905     opts="$_dump_debug$dump_args -f $dumptape -M $media_label -L $session_label $SCRATCH_MNT"
906     echo "xfsdump $opts" | _dir_filter  
907     xfsdump $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
908 }
909
910
911 #
912 # Do full dump with -m
913 #
914 _do_dump_min()
915 {
916     _parse_args $*
917
918     echo "Dumping to tape..."
919     onemeg=1048576
920     opts="$_dump_debug$dump_args -m -b $onemeg -l0 -f $dumptape -M $media_label -L $session_label $SCRATCH_MNT"
921     echo "xfsdump $opts" | _dir_filter  
922     xfsdump $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
923 }
924
925
926 #
927 # Do full dump to file
928 #
929 _do_dump_file()
930 {
931     _parse_args $*
932
933     echo "Dumping to file..."
934     opts="$_dump_debug$dump_args -f $dump_file -M $media_label -L $session_label $SCRATCH_MNT"
935     echo "xfsdump $opts" | _dir_filter  
936     xfsdump $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
937 }
938
939 #
940 # Do full dump to multiple files
941 #
942 _do_dump_multi_file()
943 {
944     _parse_args "$@"
945
946     multi_args=""
947
948     i=0
949     while [ $i -lt $multi ]
950     do
951         multi_args="$multi_args -f $dump_file.$i -M $media_label.$i"
952         i=`expr $i + 1`
953     done
954
955     echo "Dumping to files..."
956     opts="$_dump_debug$dump_args $multi_args -L $session_label $SCRATCH_MNT"
957     echo "xfsdump $opts" | _dir_filter  
958     xfsdump $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
959 }
960
961
962 _prepare_restore_dir()
963 {
964     rm -rf $restore_dir
965     mkdir $restore_dir ||\
966         _error "failed to mkdir $restore_dir"
967 }
968
969
970 #
971 # Get tape ready and restore dir
972 #
973 _prepare_restore()
974 {
975     _prepare_restore_dir
976
977     echo "Rewinding tape"
978     _rewind
979 }
980
981 #
982 # Restore the tape into $restore_dir
983 #
984 _do_restore()
985 {
986     _parse_args $*
987     _prepare_restore
988
989
990     echo "Restoring from tape..."
991     opts="$_restore_debug -f $dumptape  -L $session_label $restore_dir"
992     echo "xfsrestore $opts" | _dir_filter  
993     xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
994 }
995
996 #
997 # Restore the tape into $restore_dir using -m
998 #
999 _do_restore_min()
1000 {
1001     _parse_args $*
1002     _prepare_restore
1003
1004     echo "Restoring from tape..."
1005     onemeg=1048576
1006     opts="$_restore_debug -m -b $onemeg -f $dumptape  -L $session_label $restore_dir"
1007     echo "xfsrestore $opts" | _dir_filter  
1008     xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
1009 }
1010
1011 #
1012 # Restore the tape from a dump file
1013 #
1014 _do_restore_file()
1015 {
1016     _parse_args $*
1017     _prepare_restore_dir
1018
1019     echo "Restoring from file..."
1020     opts="$_restore_debug -f $dump_file  -L $session_label $restore_dir"
1021     echo "xfsrestore $opts" | _dir_filter  
1022     xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
1023 }
1024
1025 #
1026 # Cumulative restore from a file
1027 # Need to specify the dump level e.g. "-l 0"
1028 #
1029 _do_restore_file_cum()
1030 {
1031     _parse_args $*
1032     if echo $dump_args | grep '\-l0' >/dev/null; then
1033         _prepare_restore_dir
1034     fi
1035
1036     echo "Restoring cumumlative from file..."
1037     opts="$_restore_debug -f $dump_file -r $restore_dir"
1038     echo "xfsrestore $opts" | _dir_filter  
1039     xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
1040 }
1041
1042 _do_restore_toc()
1043 {
1044     echo "Contents of dump ..."
1045     opts="$_restore_debug -f $dump_file -t"
1046     echo "xfsrestore $opts" | _dir_filter
1047     cd $SCRATCH_MNT # for IRIX which needs xfs cwd
1048     xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter_main |\
1049     _check_quota_file |\
1050     _check_quota_entries |\
1051     $AWK_PROG 'NF != 1 { print; next }
1052                {files = sprintf("%s\n%s", files, $1)}
1053                 END { print files | "sort" } '
1054     # the above awk code is to alpha sort only the output
1055     # of files (and not the verbose restore msgs)
1056     cd $here # put back
1057 }
1058
1059 #
1060 # Restore the tape from multiple dump files
1061 #
1062 _do_restore_multi_file()
1063 {
1064     _parse_args "$@"
1065     _prepare_restore_dir
1066
1067     multi_args=""
1068
1069     i=0
1070     while [ $i -lt $multi ]
1071     do
1072         multi_args="$multi_args -f $dump_file.$i"
1073         i=`expr $i + 1`
1074     done
1075
1076     echo "Restoring from file..."
1077     opts="$_restore_debug $multi_args -L $session_label $restore_dir"
1078     echo "xfsrestore $opts" | _dir_filter  
1079     xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
1080 }
1081
1082 #
1083 # Do xfsdump piped into xfsrestore - xfsdump | xfsrestore
1084 #
1085 # Use -s as we want to dump and restore to the same xfs partition
1086 #
1087 _do_dump_restore()
1088 {
1089     _parse_args $*
1090     _prepare_restore_dir
1091     echo "xfsdump|xfsrestore ..."
1092     restore_opts="$_restore_debug - $restore_dir"
1093     dump_opts="$_dump_debug$dump_args -s $dump_sdir - $SCRATCH_MNT"
1094     echo "xfsdump $dump_opts | xfsrestore $restore_opts" | _dir_filter  
1095     xfsdump $dump_opts 2>$tmp.dump.mlog | xfsrestore $restore_opts 2>&1 | tee -a $here/$seq.full | _dump_filter
1096     _dump_filter <$tmp.dump.mlog
1097 }
1098
1099 #
1100 # Compare dumped subdirectory with restored dir
1101 # using ls -lR.
1102 # Thus no contents are compared but permissions, sizes,
1103 # owners, etc... are.
1104 #
1105 _ls_compare_sub()
1106 {
1107     #
1108     # verify we got back what we dumped
1109     #
1110     echo "Comparing listing of dump directory with restore directory"
1111     ls -lR $dump_dir | tee -a $here/$seq.full | _ls_filter >$tmp.dump_dir
1112     ls -lR $restore_dir/$dump_sdir | tee -a $here/$seq.full | _ls_filter \
1113     | sed -e "s#$restore_sdir\/##" >$tmp.restore_dir
1114
1115     diff -cs $tmp.dump_dir $tmp.restore_dir | sed -e "s#$tmp#TMP#g"
1116 }
1117
1118 #
1119 # filter out the date fields
1120 #
1121 _ls_nodate_filter()
1122 {
1123     $AWK_PROG 'NF == 9 { print $1, $2, $3, $4, $9 }'
1124 }
1125
1126 #
1127 # _ls_compare_sub but don't compare dates
1128 _ls_nodate_compare_sub()
1129 {
1130     #
1131     # verify we got back what we dumped
1132     #
1133     echo "Comparing listing of dump directory with restore directory"
1134     ls -lR $dump_dir | tee -a $here/$seq.full | _ls_filter | _ls_nodate_filter >$tmp.dump_dir
1135     ls -lR $restore_dir/$dump_sdir | tee -a $here/$seq.full | _ls_filter \
1136     | _ls_nodate_filter | sed -e "s#$restore_sdir\/##" >$tmp.restore_dir
1137
1138     diff -cs $tmp.dump_dir $tmp.restore_dir | sed -e "s#$tmp#TMP#g"
1139 }
1140
1141 #
1142 # Compare using recursive diff the files of the dumped
1143 # subdirectory.
1144 # This one will compare the contents.
1145 #
1146 _diff_compare_sub()
1147 {
1148     echo "Comparing dump directory with restore directory"
1149     diff -rs $dump_dir $restore_dir/$dump_sdir | _dir_filter
1150 }
1151
1152 _get_eas_on_path()
1153 {
1154     _path=$1
1155
1156 # Tim - this is the IRIX way...
1157     # find $_path -exec attr -l {} \; |\
1158     # awk '{print $9, $2}' |\
1159     # sed 's/["]//g' |\
1160     # sort |\
1161 # and this is now the Linux way...
1162     echo "User names"
1163     getfattr --absolute-names -Rh $_path |\
1164     perl -wn -e '
1165         if (m/^# file: (\S+)/) { $file = $1 }
1166         elsif (m/^user\.(\w+)/) { print $file, " ",$1,"\n" }' |\
1167     sort |\
1168     while read file ea_name; do
1169         attr -g $ea_name $file
1170     done
1171
1172     echo "Root names"
1173     getfattr --absolute-names -Rh -m xfsroot $_path |\
1174     perl -wn -e '
1175         if (m/^# file: (\S+)/) { $file = $1 }
1176         elsif (m/^xfsroot\.(\w+)/) { print $file, " ",$1,"\n" }' |\
1177     sort |\
1178     while read file ea_name; do
1179         attr -R -g $ea_name $file
1180     done
1181 }
1182
1183 #
1184 # Compare the extended attributes of the files/dirs
1185 # b/w the dumped and restore dirs.
1186 #
1187 #
1188 # Attribute "attr5" had a 8 byte value for /spare1/dump.5460/dir:
1189 # Attribute "attr5" had a 8 byte value for /spare1/restore.5460/dump.5460/dir:
1190 #
1191 _diff_compare_eas()
1192 {
1193     echo "Comparing dump directory with restore directory"
1194     echo "Looking at the extended attributes (EAs)"
1195     echo "EAs on dump"
1196     _get_eas_on_path $dump_dir | tee $seq.ea1 | _dir_filter
1197     echo "EAs on restore"
1198     _get_eas_on_path $restore_dir/$dump_sdir \
1199     | sed -e "s#$restore_sdir\/##" \
1200     | tee $seq.ea2 \
1201     | _dir_filter
1202     diff -s $seq.ea1 $seq.ea2
1203 }
1204
1205
1206 #
1207 # Compare using recursive diff the files of the dumped
1208 # filesystem
1209 #
1210 _diff_compare()
1211 {
1212     echo "Comparing dump directory with restore directory"
1213     diff -rs $SCRATCH_MNT $restore_dir | _dir_filter | _check_quota_diff
1214 }
1215
1216 #
1217 # Check out the dump inventory
1218 #
1219 _dump_inventory()
1220 {
1221     xfsdump $_dump_debug -I | tee -a $here/$seq.full | _dump_filter_main
1222 }
1223
1224 #
1225 # Do the xfsinvutil cmd with debug and filters
1226 # Need to set variable: "$middate" to the invutil date 
1227 #
1228 _do_invutil()
1229 {
1230     host=`hostname`
1231     echo "xfsinvutil $_invutil_debug -M $host:$SCRATCH_MNT \"$middate\" $*" >$here/$seq.full
1232     xfsinvutil $_invutil_debug $* -M $host:$SCRATCH_MNT "$middate" \
1233     | tee -a $here/$seq.full | _invutil_filter
1234 }
1235
1236 #
1237 # ensure we can find the user quota msg if user quotas are on
1238 # ensure we can find the group quota msg if group quotas are on
1239 #
1240 _check_quota()
1241 {
1242     usermsg=$1 
1243     groupmsg=$2 
1244     uquota=0
1245     gquota=0 
1246     $here/src/feature -U $SCRATCH_DEV && uquota=1
1247     $here/src/feature -G $SCRATCH_DEV && gquota=1
1248
1249     $AWK_PROG -v uquota=$uquota -v gquota=$gquota -v full=$here/$seq.full \
1250               -v usermsg="$usermsg" -v groupmsg="$groupmsg" '
1251         $0 ~ groupmsg {
1252                         print "Found group quota:", $0 >>full
1253                         found_gquota = 1
1254                         if (!gquota) {
1255                             print "Found extra:", $0
1256                         }
1257                         next
1258         }
1259         $0 ~ usermsg {
1260                         print "Found user quota:", $0 >>full
1261                         found_uquota = 1
1262                         if (!uquota) {
1263                             print "Found extra:", $0
1264                         }
1265                         next
1266         }
1267                         { print }
1268         END {
1269                 if (uquota && !found_uquota) {
1270                     print "Missing: ", usermsg
1271                 }
1272                 if (gquota && !found_gquota) {
1273                     print "Missing: ", groupmsg
1274                 }
1275         }
1276     '
1277 }
1278
1279 #
1280 # xfsrestore: 3 directories and 40 entries processed 
1281 #   $5 = 40 
1282 #   num entries needs to be reduced by num quota file(s) 
1283 #
1284 _check_quota_entries()
1285 {
1286     uquota=0
1287     gquota=0 
1288     $here/src/feature -U $SCRATCH_DEV && uquota=1
1289     $here/src/feature -G $SCRATCH_DEV && gquota=1
1290     $AWK_PROG -v uquota=$uquota -v gquota=$gquota '
1291         /entries processed/ { 
1292                 if (uquota) $5--
1293                 if (gquota) $5--
1294         }
1295         {print}'
1296 }
1297
1298 #
1299 # Look for:
1300 # xfsdump: saving user quota information for: SCRATCH_MNT
1301 # xfsdump: saving group quota information for: SCRATCH_MNT
1302 # xfsrestore: user quota information written to ...'
1303 # xfsrestore: group quota information written to ...'
1304 #
1305 _check_quota_dumprestore()
1306 {
1307    _check_quota 'user quota information' \
1308                 'group quota information'
1309 }
1310
1311 #
1312 # Look for:
1313 # Only in RESTORE_DIR: xfsdump_quotas
1314 # Only in RESTORE_DIR: xfsdump_quotas_group
1315 #
1316 _check_quota_diff()
1317 {
1318    _check_quota 'Only in RESTORE_DIR: xfsdump_quotas' \
1319        'Only in RESTORE_DIR: xfsdump_quotas_group' 
1320 }
1321
1322 #
1323 # Look for the quota file in the output
1324 # Ensure that it is there if it should be
1325 # Filter it out so that the output is always the same
1326 # even with no quotas
1327 #
1328 _check_quota_file()
1329 {
1330    _check_quota 'xfsdump_quotas' 'xfsdump_quotas_group'
1331 }
1332
1333 # make sure this script returns success
1334 /bin/true