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