[BACK]Return to common.dump CVS log [TXT][DIR] Up to [Development] / xfs-cmds / xfstests

File: [Development] / xfs-cmds / xfstests / common.dump (download)

Revision 1.45, Mon Jan 5 17:08:20 2004 UTC (13 years, 9 months ago) by alkirkco
Branch: MAIN
Changes since 1.44: +8 -0 lines

Add support to properly dump and restore the new inode flags:
immutable, append, sync, noatime and nodump.  Add all inode
flags, new and old, to the list defined in _mk_fillconfig_ea()
of cmd/xfstests/common.dump.  Test 063 can be used to verify
the proper backup and restore of these flags.  Also update man
pages to 1) remove reference to miniroot (IRIX-only), 2) document
the new XFS_XFLAG_NODUMP inode flag as the preferred method to
exclude files, and 3) better describe how the media inventory
files can be used.

The code for the inode flags was contributed by Ethan Benson,
with copyright assignment obtained by Nathan Scott.
Modify routine _mk_fillconfig_ea() to test each xflag, new and
old.  This routine gets called by test 063 as it dumps and
restores the list of xflags and extended attributes defined in
_mk_fillconfig_ea().

#/bin/sh

#
# Functions useful for xfsdump/xfsrestore tests
#
# Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
# 
# This program is free software; you can redistribute it and/or modify it
# under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
# 
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# 
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like.  Any license provided herein, whether implied or
# otherwise, applies only to this software file.  Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
# 
# You should have received a copy of the GNU General Public License along
# with this program; if not, write the Free Software Foundation, Inc., 59
# Temple Place - Suite 330, Boston MA 02111-1307, USA.
# 
# Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
# Mountain View, CA  94043, or:
# 
# http://www.sgi.com 
# 
# For further information regarding this notice, see: 
# 
# http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
#

# --- initializations ---
rm -f $here/$seq.full

if [ -n "$DEBUGDUMP" ]; then
  _dump_debug=-v5
  _restore_debug=-v5
  _invutil_debug=-d
fi
 
# Use dump/restore in qa directory for debugging
PATH="$here:$PATH"
export PATH
#which xfsdump
#which xfsrestore
#which xfsinvutil

# status returned for not run tests
NOTRUNSTS=2

# name those directories
dump_file=$tmp.dumpfile
# dump_file=$here/dumpfile #TEMP OVERRIDE DUMP FILE
dump_sdir=dumpdir
dump_dir=$SCRATCH_MNT/$dump_sdir
restore_sdir=restoredir
restore_dir=$SCRATCH_MNT/$restore_sdir
multi=3
dumptape=$TAPE_DEV
media_label="stress_tape_media"
session_label="stress_$seq"

nobody=4 # define this uid/gid as a number
do_quota_check=true # do quota check if quotas enabled

_need_to_be_root

# install our cleaner
trap "_cleanup; exit \$status" 0 1 2 3 15

# start inventory from a known base - move it aside for test
for dir in /var/xfsdump/inventory /var/lib/xfsdump/inventory; do
    if [ -d $dir ]; then
	[ -d $dir.$seq ] && rm -rf $dir.$seq
	mv $dir $dir.$seq
    fi
done

have_mtvariable=false
[ `uname` = "Linux" ] && have_mtvariable=true

#
# do a remote/local mt
#
_mt()
{
    op=$1
    if _isrmt; then  
	# REMOTE
	_rmtdev=`echo $dumptape | $AWK_PROG -F: '{print $2}'`

        if echo $dumptape | grep '@' >/dev/null; then
	    _spec=`echo $dumptape | $AWK_PROG -F: '{print $1}'`
	    _rmtuser=`echo $_spec | $AWK_PROG -F@ '{print $1}'`
	    _rmthost=`echo $_spec | $AWK_PROG -F@ '{print $2}'`
	    rsh -n -l $_rmtuser $_rmthost "mt -t $_rmtdev $op"
	else
	    _rmthost=`echo $dumptape | $AWK_PROG -F: '{print $1}'`
	    rsh -n $_rmthost "mt -t $_rmtdev $op"
	fi
    else
	#LOCAL
	mt -t $dumptape $op
    fi
}

_check_onl()
{
    _limit=10
    i=0
    while [ $i -lt $_limit ]; do  
        echo "Checking online..." >>$here/$seq.full
	if _mt status >$tmp.status 2>&1; then
	    break; 
	else
	    sleep 2 
	fi
	i=`expr $i + 1`
    done


    if [ $i -eq $_limit ]; then
	echo "ERROR: mt -f $dumptape failed"
	cat $tmp.status

	echo "mt -f $dumptape failed" >$seq.notrun 
	status=$NOTRUNSTS
	exit
    fi 


    if egrep -i 'onl|ready' $tmp.status | grep -iv 'not ready' >/dev/null; then
	:
    else
	echo "ERROR: $dumptape is not online"
	cat $tmp.status

	echo "dumptape, $dumptape, is not online" >$seq.notrun 
	status=$NOTRUNSTS
	exit
    fi
}

_wait_tape()
{
    echo "Wait for tape, $dumptape, ..." >>$here/$seq.full

    i=0
    while [ $i -lt 20 ]; do  
        echo "Checking status..." >>$here/$seq.full
	if _mt status 2>&1 | tee -a $here/$seq.full | egrep -i "onl|ready" >/dev/null; then
	    break; 
	else
	    sleep 2 
	fi
	i=`expr $i + 1`
    done
}

#
# Keep trying so we know we really have rewound
#
_rewind()
{
    echo "Initiate rewind..." >>$here/$seq.full
    _wait_tape
    _mt rewind >/dev/null
    _wait_tape
}

#
# Do a custom erase because: 
# (i) some machines don't support it
# (ii) some machines take forever to do it
#
_erase_soft()
{
    echo "Erasing tape" | tee -a $here/$seq.full
    _rewind
    _mt weof 3
    _rewind
}

_erase_hard()
{
    echo "Erasing tape" | tee -a $here/$seq.full
    _mt erase
}

_isrmt()
{
    echo $dumptape | grep ':' >/dev/null
}

#
# Get tape ready
#
_set_variable()
{
    $have_mtvariable || return

    if _isrmt; then
	:
    else
	# LOCAL
	echo "Put scsi tape driver into variable block size mode"
	mt -f $dumptape setblk 0
    fi	
}

_require_tape()
{
    dumptape=$1

    if [ -z "$dumptape" ]; then
        echo "This test requires a dump tape - none was specified"
	echo "No dump tape specified" >$seq.notrun 
	status=$NOTRUNSTS
	exit
    fi

    _check_onl
    _set_variable
}

_wipe_fs()
{
    _require_scratch

    _scratch_mkfs_xfs >>$here/$seq.full || _fail "mkfs failed"
    _scratch_mount >>$here/$seq.full || _fail "mount failed"
}

# 
# Cleanup created dirs and files
# Called by trap
#
_cleanup()
{
    cd $here
    rm -f $tmp.*

    if [ -n "$DEBUGDUMP" ]; then
	# save it for inspection
	for dir in /var/xfsdump/inventory /var/lib/xfsdump/inventory; do
	    [ -d $dir ] || continue
	    tar -cvf $seq.inventory.tar $dir
	    ls -lR $dir >$seq.inventory.ls
	done
    fi

    # put inventory dir back
    for dir in /var/xfsdump/inventory /var/lib/xfsdump/inventory; do
	[ -d $dir.$seq ] || continue
	rm -rf $dir		# get rid of new one
	mv $dir.$seq $dir
    done

    if [ $status -ne $NOTRUNSTS ]; then
	# Sleep added to stop _check_scratch_fs from complaining that the
	# scratch_dev is still busy
	sleep 10

	_check_scratch_fs
    fi
}

#
# ensure that bulkstat data will
# match with incore data
# by forcing disk data to be written out
#
_stable_fs()
{
    _saveddir=`pwd`; cd /
    umount $SCRATCH_MNT >>$here/$seq.full || _fail "unmount failed"
    _scratch_mount >>$here/$seq.full || _fail "mount failed"
    cd $_saveddir
}

#
# Run fsstress to create a mixture of 
# files,dirs,links,symlinks
#
# Pinched from test 013.
#
_create_dumpdir_stress()
{
    echo "Creating directory system to dump using fsstress."

    _wipe_fs

    _param="-f link=10 -f creat=10 -f mkdir=10 -f truncate=5 -f symlink=10"
    _count=200
    rm -rf $dump_dir
    if ! mkdir $dump_dir; then
        echo "    failed to mkdir $dump_dir"
        status=1
        exit
    fi
    echo ""
    echo "-----------------------------------------------"
    echo "fsstress : $_param"
    echo "-----------------------------------------------"
    if ! $here/ltp/fsstress $_param -s 1 $FSSTRESS_AVOID -n $_count -d $dump_dir >$tmp.out 2>&1
    then
        echo "    fsstress (count=$_count) returned $? - see $here/$seq.full"
        
        echo "--------------------------------------"       >>$here/$here/$seq.full
        echo "output from fsstress:"                        >>$here/$here/$seq.full
        echo "--------------------------------------"       >>$here/$here/$seq.full
        cat $tmp.out                                        >>$here/$here/$seq.full
        status=1
    fi

    _stable_fs
}

_mk_fillconfig1()
{
    cat <<End-of-File >$tmp.config
# pathname	size in bytes	owner	group
#
small		10	$nobody	$nobody
big		102400	daemon	sys
sub/small	10	bin	bin
sub/big		102400	$nobody	sys
#
sub/a		1	$nobody	$nobody
sub/b		2	$nobody	$nobody
sub/c		4	$nobody	$nobody
sub/d		8	$nobody	$nobody
sub/e		16	$nobody	$nobody
sub/f		32	$nobody	$nobody
sub/g		64	$nobody	$nobody
sub/h		128	$nobody	$nobody
sub/i		256	$nobody	$nobody
sub/j		512	$nobody	$nobody
sub/k		1024	$nobody	$nobody
sub/l		2048	$nobody	$nobody
sub/m		4096	$nobody	$nobody
sub/n		8192	$nobody	$nobody
#
sub/a00		100	$nobody	$nobody
sub/b00		200	$nobody	$nobody
sub/c00		400	$nobody	$nobody
sub/d00		800	$nobody	$nobody
sub/e00		1600	$nobody	$nobody
sub/f00		3200	$nobody	$nobody
sub/g00		6400	$nobody	$nobody
sub/h00		12800	$nobody	$nobody
sub/i00		25600	$nobody	$nobody
sub/j00		51200	$nobody	$nobody
sub/k00		102400	$nobody	$nobody
sub/l00		204800	$nobody	$nobody
sub/m00		409600	$nobody	$nobody
sub/n00		819200	$nobody	$nobody
#
sub/a000	1000	$nobody	$nobody
sub/e000	16000	$nobody	$nobody
sub/h000	128000	$nobody	$nobody
sub/k000	1024000	$nobody	$nobody
End-of-File
}

_mk_fillconfig2()
{
    cat <<End-of-File >$tmp.config
# pathname	size in bytes
#
smalll		10	$nobody	$nobody
biggg		102400	$nobody	$nobody
sub/smalll	10	$nobody	$nobody
sub/biggg	102400	$nobody	$nobody
End-of-File
}

_mk_fillconfig_perm()
{
    # dir_guid: ugo=rwx,g+s on dir is for IRIX chmod(1)

    cat <<End-of-File >$tmp.config
# pathname	size/dir  user group mode
#
file_suid	10	$nobody	$nobody	04777
file_guid	10	$nobody	$nobody	02777
file_sticky	10	$nobody	$nobody	01777
file_mix1	10	$nobody	$nobody	761
file_mix2	10	$nobody	$nobody	642
dir_suid	d	$nobody	$nobody	04777
dir_guid	d	$nobody	$nobody	ugo=rwx,g+s
dir_sticky	d	$nobody	$nobody	01777
dir_mix1	d	$nobody	$nobody	761
dir_mix2	d	$nobody	$nobody	642
End-of-File
}

_mk_fillconfig_ea()
{
    cat <<End-of-File >$tmp.config
# pathname	size    user    group    perm   name value namespace
#
smalll		10	$nobody	$nobody  777    attr1 some_text   user 
biggg		102400	$nobody	$nobody  777    attr2 some_text2  root
sub/smalll	10	$nobody	$nobody  777    attr3 some_text3  user
sub/biggg	102400	$nobody	$nobody  777    attr4 some_text4  root
dir		d	$nobody $nobody  777    attr5 dir_text    user
xflag_realtime	10	$nobody $nobody  777    XFS_XFLAG_REALTIME  some_text5  root
xflag_prealloc	10	$nobody $nobody  777    XFS_XFLAG_PREALLOC  some_text6  root
xflag_immutable 10	$nobody $nobody  777    XFS_XFLAG_IMMUTABLE some_text7  root
xflag_append	10	$nobody $nobody  777    XFS_XFLAG_APPEND    some_text8  root
xflag_sync	10	$nobody $nobody  777    XFS_XFLAG_SYNC      some_text9  root
xflag_noatime	10	$nobody $nobody  777    XFS_XFLAG_NOATIME   some_text10 root
xflag_nodump	10	$nobody $nobody  777    XFS_XFLAG_NODUMP    some_text11 root
xflag_hasattr	10	$nobody $nobody  777    XFS_XFLAG_HASATTR   some_text12 root
#
# Add more files so that there are more than the number
# of streams.
# There are bugs in dump/restore for # non-dir files < # streams
# It can be tested in another configuration.
# It is a pathalogical case.
#
sub/a		1	$nobody	$nobody
sub/b		2	$nobody	$nobody
sub/c		4	$nobody	$nobody
sub/d		8	$nobody	$nobody
sub/e		16	$nobody	$nobody
sub/f		32	$nobody	$nobody
sub/g		64	$nobody	$nobody
sub/h		128	$nobody	$nobody
sub/i		256	$nobody	$nobody
sub/j		512	$nobody	$nobody
sub/k		1024	$nobody	$nobody
sub/l		2048	$nobody	$nobody
sub/m		4096	$nobody	$nobody
sub/n		8192	$nobody	$nobody
End-of-File
}

#
# Create a bunch of directories/files of different sizes
# filled with data.
#
# Pinched from test 001.
#
_do_create_dumpdir_fill()
{
    echo "Creating directory system to dump using src/fill."

    mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
    cd $dump_dir

    $verbose && echo -n "Setup "
    sed -e '/^#/d' $tmp.config \
    | while read file nbytes owner group perms ea_name ea_value namespace
    do
	if [ $nbytes = "d" ]; then
	    # create a directory
	    dir=$file	
	    if [ ! -d $dir ]
	    then
		if mkdir $dir
		then
		    :
		else
		    $verbose && echo
		    echo "Error: cannot mkdir \"$dir\""
		    exit 1
		fi
	    fi
	else
	    # create a directory/file
	    dir=`dirname $file`
	    if [ "$dir" != "." ]
	    then
		if [ ! -d $dir ]
		then
		    if mkdir $dir
		    then
			:
		    else
			$verbose && echo
			echo "Error: cannot mkdir \"$dir\""
			exit 1
		    fi
		fi
	    fi
	    rm -f $file
	    if $here/src/fill $file $file $nbytes
	    then
		:
	    else
		$verbose && echo
		echo "Error: cannot create \"$file\""
		exit 1
	    fi
	fi
	if [ -n "$owner" -a -n "$group" ]; then
	    chown $owner.$group $file
	fi
	if [ -n "$perms" ]; then
	    chmod $perms $file
	fi
	if [ -n "$ea_name" -a -n "$ea_value" ]; then
	    if [ "X$namespace" = "Xroot" ]; then
		attr -R -s $ea_name -V $ea_value $file
	    else
		attr -s $ea_name -V $ea_value $file
	    fi
	fi
	$verbose && echo -n "."
    done
    $verbose && echo

    cd $here
}

_create_dumpdir_largefile()
{
    _wipe_fs
    mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
    _largesize=4294967297
    _largefile=$dump_dir/largefile
    echo "dd a largefile at offset $_largesize"
    POSIXLY_CORRECT=yes \
    dd if=/dev/zero of=$_largefile bs=1 seek=$_largesize count=10 2>&1
    _stable_fs
}	

_create_dumpdir_fill()
{
    _wipe_fs
    _mk_fillconfig1
    _do_create_dumpdir_fill
    _stable_fs
}	

_create_dumpdir_fill2()
{
    _wipe_fs
    _mk_fillconfig2
    _do_create_dumpdir_fill
    _stable_fs
}	

_create_dumpdir_fill_perm()
{
    _wipe_fs
    _mk_fillconfig_perm
    _do_create_dumpdir_fill
    _stable_fs
}	

_create_dumpdir_fill_ea()
{
    _wipe_fs
    _mk_fillconfig_ea
    _do_create_dumpdir_fill
    _stable_fs
}	


#
# Append a subset of the fill'ed files
# So we can see if just these get dumped on an incremental
#
_append_dumpdir_fill()
{
    cd $dump_dir
    cat <<End-of-File >$tmp.config
# pathname
#
small	
sub/big	
#
sub/a
sub/c
sub/e
End-of-File
    sed -e '/^#/d' $tmp.config \
    | while read file
    do
        echo 'Extra text' >>$file
    done

    cd $here
    _stable_fs
}

_do_create_dump_symlinks()
{
    echo "Creating directory system of symlinks to dump."

    mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
    cd $dump_dir

    $verbose && echo -n "Setup "
    sed -e '/^#/d' $tmp.config \
    | while read file nbytes owner group owner2 group2 perms perms2
    do
	dir=`dirname $file`
	if [ "$dir" != "." ]
	then
	    if [ ! -d $dir ]
	    then
		if mkdir $dir
		then
		    :
		else
		    $verbose && echo
		    echo "Error: cannot mkdir \"$dir\""
		    exit 1
		fi
	    fi
	fi
	rm -f $file
	touch $file

	# Do chmod on symlink using umask.
	# This won't do the right thing as it subtracts permissions.
	# However, I don't care, as long as I get some different perms
	# for testing.
	if [ -n "$perms2" ]; then
	    omask=`umask`
	    umask $perms2
	fi
	ln -s $file $file-link
	if [ -n "$perms2" ]; then
	    umask $omask	
	fi

	if [ -n "$owner" -a -n "$group" ]; then
	    chown $owner.$group $file
	fi
	if [ -n "$owner" -a -n "$group" ]; then
	    chown -h $owner.$group $file-link
	fi
	if [ -n "$perms" ]; then
	    chmod $perms $file
	fi
	$verbose && echo -n "."
    done
    $verbose && echo

    cd $here
}

_mk_symlink_config()
{
    cat <<End-of-File >$tmp.config
# path	size	owner1	group1	owner2	group2	perm1	perm2 
#
a	0	$nobody	$nobody	daemon	sys	124	421
b	0	daemon	sys	bin	bin	347	743
sub/a	0	bin	bin	$nobody	sys	777	777
sub/b	0	$nobody	sys	$nobody	$nobody	367	763
End-of-File
}

_create_dumpdir_symlinks()
{
    _wipe_fs
    _mk_symlink_config
    _do_create_dump_symlinks
    _stable_fs
}	

#
# create hardlinks of form $_fname, $_fname_h1 $_fname_h2 ...
#
_create_hardlinks()
{
    _fname=$1	
    _numlinks=$2

    touch $_fname
    _j=1
    while [ $_j -le $_numlinks ]; do
        _suffix=_h$_j
	_hardlink=$_fname$_suffix
	echo "creating hardlink $_hardlink to $_fname"
	ln $_fname $_hardlink
	_j=`expr $_j + 1`
    done
}

#
# create a set of hardlinks
# create hardlinks of form file1, file1_h1 file1_h2 ...
# create hardlinks of form file2, file2_h1 file2_h2 ...
# create hardlinks of form file3, file3_h1 file3_h2 ...
#
_create_hardset()
{
    _numsets=$1
    _i=1
    while [ $_i -le $_numsets ]; do
	_create_hardlinks file$_i 5
	_i=`expr $_i + 1`
    done
}


_modify_level()
{
    _level=$1
    echo "mod level $_level" >$dump_dir/file$_level
}

_create_dumpdir_hardlinks()
{
    _numsets=$1
    _wipe_fs
    echo "Creating directory system of hardlinks to incrementally dump."

    mkdir -p $dump_dir || _fail "cannot mkdir \"$dump_dir\""
    cd $dump_dir

    _create_hardset $_numsets

    cd $here
    _stable_fs
}

#
# Filter for ls
# Filter out dates on symlinks and char devices
# Filter out size on directories because this can differ
# when transitioning to long inode numbers (ie. 64 bits).
#
_ls_filter()
{
  $AWK_PROG '
        /^l/ { date = $8; sub(date,"DATE"); print}
        /^c/ { date = $9; sub(date,"DATE"); print}
        /^d/ { size = $5; sub(size,"SIZE"); print}
        {print}' \
  | sed -e 's/total [0-9][0-9]*/total TOTAL/'
}


# 
# Filter out the non-deterministic dump msgs from
# xfsdump and xfsrestore
#
_dump_filter_main()
{
  sed \
      -e "s/`hostname`/HOSTNAME/"   \
      -e "s#$SCRATCH_DEV#SCRATCH_DEV#"    \
      -e "s#$SCRATCH_RAWDEV#SCRATCH_DEV#"    \
      -e "s#$dumptape#TAPE_DEV#"    \
      -e "s#$SCRATCH_MNT#SCRATCH_MNT#"    \
      -e "s#$dump_file#DUMP_FILE#"  \
      -e 's#/var/lib/xfsdump#/var/xfsdump#' \
      -e 's/id:[ 	]*[0-9a-f-]*/id: ID/'  \
      -e 's/time:[ 	].*/time: TIME/'       \
      -e 's/date:[ 	].*/date: DATE/'       \
      -e 's/dump begun .*/dump begun DATE/'    \
      -e 's/[0-9][0-9]* seconds/SECS seconds/' \
      -e 's/restore.[0-9][0-9]*/restore.PID/' \
      -e 's/ino [0-9][0-9]*/ino INO/' \
      -e '/: dump size/s/[0-9][0-9]*/NUM/'     \
      -e '/dump size:/s/[0-9][0-9]*/NUM/'      \
      -e '/dump size per stream:/s/[0-9][0-9]*/NUM/' \
      -e 's/\(media file size[	 ]*\)[0-9][0-9]*/\1NUM/' \
      -e 's/\(mfile size:[	 ]*\)[0-9][0-9]*/\1NUM/' \
      -e '/drive[	 ]*[0-9][0-9]*:/d' \
      -e '/\/dev\/tty/d' \
      -e '/inventory session uuid/d' \
      -e '/ - Running single-threaded/d' \
      -e '/^.*I\/O metrics: .*$/d' \
      -e 's/1048576/BLOCKSZ/' \
      -e 's/2097152/BLOCKSZ/' \
      -e 's/(pid[	 ]*[1-9][0-9]*)/\(pid PID\)/' \
  | perl -ne '
      if ($_ =~ /(?:Dump|Restore) Summary/) {
        $skip = 1;
      } elsif ($_ =~ /(?:Dump|Restore) Status/) {
        $skip = 0;
      }
      print if (! $skip);'
}

_dump_filter()
{
   if $do_quota_check
   then
       _dump_filter_main | _check_quota_dumprestore | _check_quota_entries
   else
       _dump_filter_main
   fi
}

_invutil_filter()
{
  _dump_filter_main \
  | sed \
	-e 's/UUID[ 	]*:[ 	][0-9a-f-]*/UUID		:	ID/' \
	-e 's/TIME OF DUMP[ 	]*:.*/TIME OF DUMP	:	TIME/' \
        -e 's/HOSTNAME:SCRATCH_MNT.*/HOSTNAME:SCRATCH_MNT/' \
        -e 's#inventory/[0-9a-f-]*#inventory/UUID#' \

}


_dir_filter()
{
  sed \
    -e "s#$dump_file#DUMP_FILE#"      \
    -e "s#$SCRATCH_DEV#SCRATCH_DEV#"        \
    -e "s#$SCRATCH_RAWDEV#SCRATCH_DEV#"    \
    -e "s#$dumptape#TAPE_DEV#"         \
    -e "s#$dump_dir#DUMP_DIR#g"       \
    -e "s#$restore_dir#RESTORE_DIR#g" \
    -e "s#$SCRATCH_MNT#SCRATCH_MNT#g"       \
    -e "s#$dump_sdir#DUMP_SUBDIR#g"   \
    -e "s#$restore_sdir#RESTORE_SUBDIR#g" \
    -e "s#$$#PID#g" \

}

#
# Note: requires a space between option letter and argument 
#
_parse_args()
{
    OPTIND=0
    dump_args=""
    while [ $# -gt 0 ]
    do
        case $1
        in
        -f)
            [ -z "$2" ] && _fail "missing argument for -f"
	    dumptape=$2	
	    shift
            ;;
        -L)
            [ -z "$2" ] && _fail "missing argument for -L"
	    session_label=$2
	    shift
            ;;
	-o)
	    dump_args="$dump_args -o"
            ;;
	-F)
	    dump_args="$dump_args -F"
            ;;
	--multi)
	    multi=$2
	    shift
	    ;;
        -q)
            do_quota_check=true
            ;;
        -Q)
            do_quota_check=false
            ;;
        -l)
            [ -z "$2" ] && _fail "missing argument for -l"
	    dump_args="$dump_args -l$2"
	    shift
            ;;
	*)
            _fail "invalid argument to common.dump function: $1"
            ;;
        esac
	shift
    done
}


#
# Dump a subdir
#
_do_dump_sub()
{
    _parse_args $*

    echo "Dumping to tape..."
    opts="$_dump_debug$dump_args -s $dump_sdir -f $dumptape -M $media_label -L $session_label $SCRATCH_MNT"
    echo "xfsdump $opts" | _dir_filter  
    xfsdump $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
}

#
# Do dump to tape
#
_do_dump()
{
    _parse_args $*

    echo "Dumping to tape..."
    opts="$_dump_debug$dump_args -f $dumptape -M $media_label -L $session_label $SCRATCH_MNT"
    echo "xfsdump $opts" | _dir_filter  
    xfsdump $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
}


#
# Do full dump with -m
#
_do_dump_min()
{
    _parse_args $*

    echo "Dumping to tape..."
    onemeg=1048576
    opts="$_dump_debug$dump_args -m -b $onemeg -l0 -f $dumptape -M $media_label -L $session_label $SCRATCH_MNT"
    echo "xfsdump $opts" | _dir_filter  
    xfsdump $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
}


#
# Do full dump to file
#
_do_dump_file()
{
    _parse_args $*

    echo "Dumping to file..."
    opts="$_dump_debug$dump_args -f $dump_file -M $media_label -L $session_label $SCRATCH_MNT"
    echo "xfsdump $opts" | _dir_filter  
    xfsdump $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
}

#
# Do full dump to multiple files
#
_do_dump_multi_file()
{
    _parse_args "$@"

    multi_args=""

    i=0
    while [ $i -lt $multi ]
    do
	multi_args="$multi_args -f $dump_file.$i -M $media_label.$i"
	i=`expr $i + 1`
    done

    echo "Dumping to files..."
    opts="$_dump_debug$dump_args $multi_args -L $session_label $SCRATCH_MNT"
    echo "xfsdump $opts" | _dir_filter  
    xfsdump $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
}


_prepare_restore_dir()
{
    rm -rf $restore_dir
    mkdir $restore_dir || _fail "failed to mkdir $restore_dir"
}


#
# Get tape ready and restore dir
#
_prepare_restore()
{
    _prepare_restore_dir

    echo "Rewinding tape"
    _rewind
}

#
# Restore the tape into $restore_dir
#
_do_restore()
{
    _parse_args $*
    _prepare_restore


    echo "Restoring from tape..."
    opts="$_restore_debug -f $dumptape  -L $session_label $restore_dir"
    echo "xfsrestore $opts" | _dir_filter  
    xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
}

#
# Restore the tape into $restore_dir using -m
#
_do_restore_min()
{
    _parse_args $*
    _prepare_restore

    echo "Restoring from tape..."
    onemeg=1048576
    opts="$_restore_debug -m -b $onemeg -f $dumptape  -L $session_label $restore_dir"
    echo "xfsrestore $opts" | _dir_filter  
    xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
}

#
# Restore the tape from a dump file
#
_do_restore_file()
{
    _parse_args $*
    _prepare_restore_dir

    echo "Restoring from file..."
    opts="$_restore_debug -f $dump_file  -L $session_label $restore_dir"
    echo "xfsrestore $opts" | _dir_filter  
    xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
}

#
# Cumulative restore from a file
# Need to specify the dump level e.g. "-l 0"
#
_do_restore_file_cum()
{
    _parse_args $*
    if echo $dump_args | grep '\-l0' >/dev/null; then
	_prepare_restore_dir
    fi

    echo "Restoring cumumlative from file..."
    opts="$_restore_debug -f $dump_file -r $restore_dir"
    echo "xfsrestore $opts" | _dir_filter  
    xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
}

_do_restore_toc()
{
    echo "Contents of dump ..."
    opts="$_restore_debug -f $dump_file -t"
    echo "xfsrestore $opts" | _dir_filter
    cd $SCRATCH_MNT # for IRIX which needs xfs cwd
    xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter_main |\
    _check_quota_file |\
    _check_quota_entries |\
    $AWK_PROG 'NF != 1 { print; next }
	       {files = sprintf("%s\n%s", files, $1)}
		END { print files | "sort" } '
    # the above awk code is to alpha sort only the output
    # of files (and not the verbose restore msgs)
    cd $here # put back
}

#
# Restore the tape from multiple dump files
#
_do_restore_multi_file()
{
    _parse_args "$@"
    _prepare_restore_dir

    multi_args=""

    i=0
    while [ $i -lt $multi ]
    do
	multi_args="$multi_args -f $dump_file.$i"
	i=`expr $i + 1`
    done

    echo "Restoring from file..."
    opts="$_restore_debug $multi_args -L $session_label $restore_dir"
    echo "xfsrestore $opts" | _dir_filter  
    xfsrestore $opts 2>&1 | tee -a $here/$seq.full | _dump_filter
}

#
# Do xfsdump piped into xfsrestore - xfsdump | xfsrestore
#
# Use -s as we want to dump and restore to the same xfs partition
#
_do_dump_restore()
{
    _parse_args $*
    _prepare_restore_dir
    echo "xfsdump|xfsrestore ..."
    restore_opts="$_restore_debug - $restore_dir"
    dump_opts="$_dump_debug$dump_args -s $dump_sdir - $SCRATCH_MNT"
    echo "xfsdump $dump_opts | xfsrestore $restore_opts" | _dir_filter  
    xfsdump $dump_opts 2>$tmp.dump.mlog | xfsrestore $restore_opts 2>&1 | tee -a $here/$seq.full | _dump_filter
    _dump_filter <$tmp.dump.mlog
}

#
# Compare dumped subdirectory with restored dir
# using ls -lR.
# Thus no contents are compared but permissions, sizes,
# owners, etc... are.
#
_ls_compare_sub()
{
    #
    # verify we got back what we dumped
    #
    echo "Comparing listing of dump directory with restore directory"
    ls -lR $dump_dir | tee -a $here/$seq.full | _ls_filter >$tmp.dump_dir
    ls -lR $restore_dir/$dump_sdir | tee -a $here/$seq.full | _ls_filter \
    | sed -e "s#$restore_sdir\/##" >$tmp.restore_dir

    diff -cs $tmp.dump_dir $tmp.restore_dir | sed -e "s#$tmp#TMP#g"
}

#
# filter out the date fields
#
_ls_nodate_filter()
{
    $AWK_PROG 'NF == 9 { print $1, $2, $3, $4, $9 }'
}

#
# _ls_compare_sub but don't compare dates
_ls_nodate_compare_sub()
{
    #
    # verify we got back what we dumped
    #
    echo "Comparing listing of dump directory with restore directory"
    ls -lR $dump_dir | tee -a $here/$seq.full | _ls_filter | _ls_nodate_filter >$tmp.dump_dir
    ls -lR $restore_dir/$dump_sdir | tee -a $here/$seq.full | _ls_filter \
    | _ls_nodate_filter | sed -e "s#$restore_sdir\/##" >$tmp.restore_dir

    diff -cs $tmp.dump_dir $tmp.restore_dir | sed -e "s#$tmp#TMP#g"
}

#
# Compare using recursive diff the files of the dumped
# subdirectory.
# This one will compare the contents.
#
_diff_compare_sub()
{
    echo "Comparing dump directory with restore directory"
    diff -rs $dump_dir $restore_dir/$dump_sdir | _dir_filter
}

_get_eas_on_path()
{
    _path=$1

# Tim - this is the IRIX way...
    # find $_path -exec attr -l {} \; |\
    # awk '{print $9, $2}' |\
    # sed 's/["]//g' |\
    # sort |\
# and this is now the Linux way...
    echo "User names"
    getfattr --absolute-names -Rh $_path |\
    perl -wn -e '
	if (m/^# file: (\S+)/) { $file = $1 }
	elsif (m/^user\.(\w+)/) { print $file, " ",$1,"\n" }' |\
    sort |\
    while read file ea_name; do
	attr -g $ea_name $file
    done

    echo "Root names"
    getfattr --absolute-names -Rh -m trusted $_path |\
    perl -wn -e '
	if (m/^# file: (\S+)/) { $file = $1 }
	elsif (m/^trusted\.(\w+)/) { print $file, " ",$1,"\n" }' |\
    sort |\
    while read file ea_name; do
	attr -R -g $ea_name $file
    done
}

#
# Compare the extended attributes of the files/dirs
# b/w the dumped and restore dirs.
#
#
# Attribute "attr5" had a 8 byte value for /spare1/dump.5460/dir:
# Attribute "attr5" had a 8 byte value for /spare1/restore.5460/dump.5460/dir:
#
_diff_compare_eas()
{
    echo "Comparing dump directory with restore directory"
    echo "Looking at the extended attributes (EAs)"
    echo "EAs on dump"
    _get_eas_on_path $dump_dir | tee $seq.ea1 | _dir_filter
    echo "EAs on restore"
    _get_eas_on_path $restore_dir/$dump_sdir \
    | sed -e "s#$restore_sdir\/##" \
    | tee $seq.ea2 \
    | _dir_filter
    diff -s $seq.ea1 $seq.ea2
}


#
# Compare using recursive diff the files of the dumped
# filesystem
#
_diff_compare()
{
    echo "Comparing dump directory with restore directory"
    diff -rs $SCRATCH_MNT $restore_dir | _dir_filter | _check_quota_diff
}

#
# Check out the dump inventory
#
_dump_inventory()
{
    xfsdump $_dump_debug -I | tee -a $here/$seq.full | _dump_filter_main
}

#
# Do the xfsinvutil cmd with debug and filters
# Need to set variable: "$middate" to the invutil date 
#
_do_invutil()
{
    host=`hostname`
    echo "xfsinvutil $_invutil_debug -M $host:$SCRATCH_MNT \"$middate\" $*" >$here/$seq.full
    xfsinvutil $_invutil_debug $* -M $host:$SCRATCH_MNT "$middate" \
    | tee -a $here/$seq.full | _invutil_filter
}

#
# ensure we can find the user quota msg if user quotas are on
# ensure we can find the group quota msg if group quotas are on
#
_check_quota()
{
    usermsg=$1 
    groupmsg=$2 
    uquota=0
    gquota=0 
    $here/src/feature -U $SCRATCH_DEV && uquota=1
    $here/src/feature -G $SCRATCH_DEV && gquota=1

    $AWK_PROG -v uquota=$uquota -v gquota=$gquota -v full=$here/$seq.full \
              -v usermsg="$usermsg" -v groupmsg="$groupmsg" '
	$0 ~ groupmsg {
			print "Found group quota:", $0 >>full
			found_gquota = 1
			if (!gquota) {
			    print "Found extra:", $0
			}
			next
	}
	$0 ~ usermsg {
			print "Found user quota:", $0 >>full
			found_uquota = 1
			if (!uquota) {
			    print "Found extra:", $0
			}
			next
	}
			{ print }
	END {
		if (uquota && !found_uquota) {
		    print "Missing: ", usermsg
		}
		if (gquota && !found_gquota) {
		    print "Missing: ", groupmsg
		}
	}
    '
}

#
# xfsrestore: 3 directories and 40 entries processed 
#   $5 = 40 
#   num entries needs to be reduced by num quota file(s) 
#
_check_quota_entries()
{
    uquota=0
    gquota=0 
    $here/src/feature -U $SCRATCH_DEV && uquota=1
    $here/src/feature -G $SCRATCH_DEV && gquota=1
    $AWK_PROG -v uquota=$uquota -v gquota=$gquota '
	/entries processed/ { 
		if (uquota) $5--
		if (gquota) $5--
	}
	{print}'
}

#
# Look for:
# xfsdump: saving user quota information for: SCRATCH_MNT
# xfsdump: saving group quota information for: SCRATCH_MNT
# xfsrestore: user quota information written to ...'
# xfsrestore: group quota information written to ...'
#
_check_quota_dumprestore()
{
   _check_quota 'user quota information' \
                'group quota information'
}

#
# Look for:
# Only in RESTORE_DIR: xfsdump_quotas
# Only in RESTORE_DIR: xfsdump_quotas_group
#
_check_quota_diff()
{
   _check_quota 'Only in RESTORE_DIR: xfsdump_quotas' \
       'Only in RESTORE_DIR: xfsdump_quotas_group' 
}

#
# Look for the quota file in the output
# Ensure that it is there if it should be
# Filter it out so that the output is always the same
# even with no quotas
#
_check_quota_file()
{
   _check_quota 'xfsdump_quotas' 'xfsdump_quotas_group'
}

# make sure this script returns success
/bin/true