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