Newsgroups: comp.sources.unix
From: rca@ingres.com (Bob Arnold)
Subject: v28i069: saenv_alldisks - sysadmin env, disk management and backups, Part05/06
References: <1.771948808.8446@gw.home.vix.com>
Sender: unix-sources-moderator@gw.home.vix.com
Approved: vixie@gw.home.vix.com

Submitted-By: rca@ingres.com (Bob Arnold)
Posting-Number: Volume 28, Issue 69
Archive-Name: saenv_alldisks/part05

#!/bin/sh
# this is saenv_alld.05 (part 5 of saenv_alld)
# do not concatenate these parts, unpack them in order with /bin/sh
# file src/backup/backup continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 5; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping src/backup/backup'
else
echo 'x - continuing file src/backup/backup'
sed 's/^X//' << 'SHAR_EOF' >> 'src/backup/backup' &&
X	;;
X	noauto)
X		autoverify=false
X		autoarg=$1
X	;;
X	nocheck)
X		check=false
X	;;
X	nofitguess)
X		fitguess=false
X	;;
X	nojoke)
X		joke=false
X	;;
X	nolabelq)
X		labelq=false
X	;;
X	nomail)
X		mail=false
X		mailarg=nomail
X	;;
X	nooffline)
X		offline=false
X	;;
X	noprobq)
X		probq=false
X	;;
X	noupdate)
X		update=false
X	;;
X	notcont)
X		cont2next=false
X	;;
X	showdd)
X		showdd=true
X		BDDSHOW=true
X		export BDDSHOW
X		showddarg=$1
X	;;
X	skip)
X		shift
X		fileskip="$1"
X		getmode=knownskip
X		labelq=false
X	;;
X	target)
X		shift
X		target="$1"
X		targetarg=true
X	;;
X	verifytoo|verify2)
X		verifytoo=true
X	;;
X	[0-9]|[12][0-9])
X		extravol=$1
X		nvol=`expr $extravol + 1`
X		n=$extravol
X		while test $n -gt 0 ; do
X			case "$2" in
X			/*|unknown)
X				shift
X				firstfslist="$firstfslist $1"
X				case "$2" in
X				cont*)
X					shift
X					# use "cont" as canonical spelling
X					firstfslist="$firstfslist cont"
X				;;
X				esac
X				n=`expr $n - 1`
X			;;
X			*)
X				break
X			;;
X			esac
X		done
X	;;
X	[01][0-9][0123][0-9].*[a-z])
X		parent=$1
X		offline=false
X		joke=false
X		labelq=false
X	;;
X	*)
X		echo "$pr: Option '$1' not understood.  Quitting."
X		echo "$USAGE"
X		exit 1
X	;;
X	esac
X	shift
Xdone
X# pass these args to any child backup processes, for example:
X# when a backup does a "verifytoo"
X# when a "verify alldisks" does a "verify onedisk"
Xchildargs="$cpioarg $showddarg $autoarg $mailarg"
X
X## make sure we know who is doing this backup ('cron' option sets $OPER to
X## cron, otherwise we hope to get it from our environment)
Xfor f in $oplist $oplistloc ; do
X	test -f $f && opfiles="$opfiles $f"
Xdone
Xwhile test "$OPER" = "" -o "$OPER" = '??' -o -z "`egrep '^'$OPER'[ 	]|^'$OPER'$' $opfiles`" ; do
X	echo "$pr: I don't know who you are."
X	echo $epre "$pr: Please enter your initials: "$esuf
X	eval "$READ" OPER
X	# break out of here if we know who $OPER is
X	egrep "^$OPER[ 	]|^$OPER\$" $opfiles > /dev/null && break
X	# otherwise try to find out
X	while : ; do
X		echo "$pr: I don't know who '$OPER' is."
X		echo $epre "$pr: Do you wish to be added as a backup operator? [yn] "$esuf
X		eval "$READ" ans
X		case $ans in
X		[nN]*)			
X			break 2
X		;;
X		[yY]*)
X			echo $epre "$pr: Enter your login name: "$esuf
X			eval "$READ" login
X			case $login in
X			*' '*|[A-Z0-9]*)
X				echo "$pr: Invalid login name '$login'"
X				continue
X			;;
X			[a-z]*)
X				: do nothing since we seem to be ok
X			;;
X			*)
X				echo "$pr: Invalid login name '$login'"
X				continue
X			;;
X			esac
X			echo $epre "$pr: Enter your Full Name: "$esuf
X			eval "$READ" name
X			echo "$OPER	$login		$name" >> $oplist
X			break 2
X		;;
X		esac
X	done
Xdone
Xoperlogin=`grep "^$OPER[ 	]" $opfiles | awk '{print $2; exit}'`
Xexport OPER	# in case we do verifytoo or this is a 'verify alldisks'
X
X## if backups have to be done as root, make sure the operator is su'd
Xif test `ls -l $0 2>&- | grep -c '^...x'` -eq 1 ; then
X	# find out effective user id - this is a guessing game but the
X	# following rule seems best: whoami > id > $USER > $LOGNAME
X	whoami=`( whoami ) 2> /dev/null`
X	id=`( id | sed -e 's/).*//' -e 's/.*(//' ) 2> /dev/null`
X	for arg in whoami id USER LOGNAME ; do
X		eval "test -n \"\$$arg\" && result=\$$arg && break"
X	done
X	case $result in
X	*root)	: we are root so we are OK ;;
X	*)	echo "$pr: Backups on $lhost must be done as root." ; exit 1 ;;
X	esac
Xfi
X
X## check mode specs and make some early decisions
Xcase "$mode" in
X'')
X	echo "$pr: 'mode' was not specified.  Valid modes are:"
X	echo "$pr: 'help', 'full', 'incr', 'get', 'verify', or 'devcheck'."
X	echo "$USAGE"
X	exit 1
X;;
Xfull|incr|tincr)
X	report=$breport
X	if test -z "$multi" ; then
X		echo "$pr: 'filesystem' was not specified.  Valid filesystems are:"
X		echo "$pr: '/fsname', 'alldisks', 'listN', 'list listfile', or 'unlisted'."
X		echo "$USAGE"
X		exit 1
X	fi
X;;
Xget|verify)
X	report=$gvreport
X	if test -z "$getmode" ; then
X		echo "$pr: 'getmode' was not specified.  Valid getmodes are:"
X		echo "$pr: 'onedisk', 'listdisks', '/fsname', 'lastdisk', or alldisks'."
X		echo "$USAGE"
X		exit 1
X	fi
X;;
Xdevcheck)
X	: nothing special needs to be done here
X;;
X*)
X	echo "$pr: Do not understand mode '$mode'."
X	echo "$USAGE"
X	exit 1
X;;
Xesac
X
X## double check on a couple of unusual possible requests
X# if the operator says to do an incremental of just one filesystem, verify it.
Xcase $mode$multi in
X*incrfalse)
X	checkq="Do you REALLY want to run an INCREMENTAL on '$fs'?"
X	eval "$CHECKQ"
X;;
X# if the operator specified a full alldisks but there are list files present
Xfulltrue)
X	if test "$multitype" = alldisks -a "`echo bkp.list[0-9]*`" != "bkp.list[0-9]*" ; then
X		echo "$pr: There are list files in backup's home directory,"
X		echo "$pr: so we are probably managing tape usage for full"
X		echo "$pr: backups of $lhost with a 'list1/unlisted' scheme."
X		ls -l bkp.list[0-9]*
X		checkq="Are you SURE you want to do a 'full alldisks'?"
X		eval "$CHECKQ"
X	fi
X;;
Xesac
X
X## check media stuff
X# select device data file
Xif test -f $hdir/$devdata ; then
X	devdata=$hdir/$devdata
X	echo "$pr: WARNING: using '$devdata' for device data."
Xelif test -f $DTGT/$devdata ; then
X	devdata=$DTGT/$devdata
Xelse
X	echo "$pr: No '$devdata' in '$DTGT' or '$hdir'.  Quitting."
Xfi
X# see if $mhost and $media are ok; note: a host may have no valid local media
Xmtype=`expr "$media" : '\([^0-9]*\)'`
Xmdata=`egrep "^$mhost[ 	]+$media[ 	]" $devdata`
Xcase "$mtype" in
X# if operator didn't specify media
X'')
X	echo "$pr: 'media' was not specified."
X	badmedia=true
X;;
X# if $mtype is null, no more validation needed since we always have /dev/null
Xnull)
X	: do nothing
X;;
X# $mtype is dir or file, so we are writing or reading a file, not a tape device
Xdir|file)
X	# make sure we're doing the right thing
X	case "$mode" in
X	devcheck)
X		echo "$pr: 'devcheck' mode not supported for 'file' archives.  Quitting."
X		exit 1
X	;;
X	get|verify)
X		case $diskfile$multi in
X		-true)	echo "$pr: Cannot read alldisks from STDIN" ; exit 1 ;;
X		esac
X	;;
X	# some kind of backup
X	*)
X		case $diskfile$multi in
X		-true)	echo "$pr: Cannot write alldisks to STDOUT" ; exit 1 ;;
X		esac
X	;;
X	esac
X;;
X# $mtype is devnames, so make sure we are in devcheck mode
Xdevnames)
X	if test "$mode" != devcheck ; then
X		echo "$pr: Cannot specify device names except in devcheck mode."
X		badmedia=true
X	fi
X;;
X# $mtype is dat or video, so we only need to see if $media is valid
Xdat|video)
X	if test -z "$mdata" ; then
X		echo "$pr: '$media' is not a valid media for host '$mhost'"
X		badmedia=true
X	fi
X;;
X# $mtype isn't null, dat or video, so see if $media is valid, and also
X# make sure we don't do a full multi-filesystem backup to non-video/dat media
X*)
X	if test -z "$mdata" ; then
X		echo "$pr: '$media' is not a valid media for host '$mhost'"
X		badmedia=true
X	elif test "$mode" = full -a "$multi" = true -a "$fitguess" = true ; then
X		echo "$pr: A 'full alldisks' will not fit on a '$mtype'."
X		badmedia=true
X	fi
X;;
Xesac
Xif test "$badmedia" = true ; then
X	# print devices available on the media host and quit
X	vmedia=`egrep "^$mhost[ 	]" $devdata | awk '{print $2}'`
X	vmedia=`echo $vmedia`		# strip newlines
X	if test -n "vmedia" ; then
X		echo "$pr: $mhost has these media: '$vmedia'."
X	fi
X	echo "$pr: Look at '$devdata' for a list of valid"
X	echo "$pr: media hosts and their devices."
X	echo "$pr: Quitting."
X	exit 1
Xfi
X# now that media info is ok, get info from $devdata by way of $mdata
X# for dir, file, null, and devnames, obs of 5120 is arbitrary,
X# maxocount of 100000 blocks is very arbitrary, and we pick 330000
X# for backup program options because it's our biggest valid "$bopt"
Xcase $mtype in
Xdir|file|null)
X	set $mhost $mtype xx 100000 null null 330000
X;;
Xdevnames)
X	set $mhost $mtype xx 100000 $rewdev $norewdev
X;;
X*)
X	set $mdata
X;;
Xesac
Xreserved=$3		# document that we don't use this field since 4.22
Xmaxocount=$4		# maximum number of output blocks per tape
Xrewdev=/dev/$5		# name of rewind device we're using
Xnorewdev=/dev/$6	# name of no-rewind device we're using
X# should say "shift 6" here but CCI's BSD "sh" doesn't like it
Xshift ; shift ; shift ; shift ; shift ; shift
Xbopts="$*"		# backup program (cpio/dump) options, if any
X# if $media is null, check with user, and set variables
Xif test $media = null ; then
X	echo "$pr: WARNING!!! media is '$media' !!!"
X	echo "$pr: This backup will be USELESS !!!"
X	eval "$EXITQ"
X	update=false
X	offline=false
Xfi
X# if we're skipping media checks and we haven't already checked it, then
Xif test $check != true -a -z "$parent" ; then
X	echo "$pr: WARNING: You are skipping media checks !!!"
X	echo "$pr: You had better know what YOU are doing !!!"
X	eval "$EXITQ"
Xfi
X
X###### Handle some real strange problems
Xcase $mlocal$multi$OS_S in
X# This shouldn't be a problem, but it is, so we'd better not even try this:
XfalsefalseAIX)
X	echo "$pr: AIX network cpio onedisk backups *don't* work."
X	echo "$pr: FYI, this is mysterious, because, so far as we know:"
X	echo "$pr: 1) AIX network cpio multi-filesystem backups *do* work."
X	echo "$pr: 2) Both onedisk and multi-filesystem network cpio backups"
X	echo "$pr: for other UNIXs *do* work."
X	echo "$pr: The problem is that the archive is missing the first 88k or"
X	echo "$pr: so of the archive.  It is unknown why this happens."
X	exit 1
X;;
Xesac
X# This is a real problem:
Xcase $mlocal$multi$mistape$OS_S$OSLEVEL_S$rewdev in
Xfalsetruetruedgux5.4*/dev/rmt/*)
X	echo "$pr: WARNING: Under dgux 5.4, if a multi-filesystem network"
X	echo "$pr: backup to a '/dev/rmt' device uses more than one tape,"
X	echo "$pr: and it looks like it works beautifully, BE AWARE:"
X	echo "$pr: the filesystem which is split accross two tapes may be"
X	echo "$pr: missing 50 blocks (or so) of buffered data which the remote"
X	echo "$pr: system was unable to write to it's tape drive when it hit"
X	echo "$pr: physical EOT (end of tape)."
X	echo "$pr: You can try setting up and using a pseudo mag tape"
X	echo "$pr: '/dev/pmt' device on $lhost instead."
X	eval "$EXITQ"
X;;
Xesac
X
X# now that our mode has been set, we can make sure we don't conflict
X# with another currently running backup/get/verify
Xif test -f $lockf -a $mode != devcheck -a -z "$parent" ; then
X	echo "$pr: A conflicting cpio backup/get/verify seems to be in progress."
X	cat $lockf
X	echo "$pr: Check with 'ps $PSALL_K'.  Quitting."
X	# take the lock file out of $rmlist before exiting!
X	rmlist=`echo $rmlist | sed -e "s,$lockf ,,"`
X	exit
Xfi
X
X# See if we know how many extra volumes are in the backup set.
X# This only makes sense if we're doing a get or verify.
Xif test -n "$extravol" ; then
X	case $mode in
X	get|verify)	: we are ok but do we do not have to do anything ;;
X	*)		echo "$USAGE" ; exit 1 ;;
X	esac
Xfi
X
X# if user specified a restore target on the command line, make sure we're
X# in "get" mode and that they really did specify *some* target (which we'll
X# check out more thoroughly later).
Xif test "$targetarg" = true ; then
X	case $mode in
X	get)
X		if test -z "$target" ; then
X			echo "$pr: Target directory not specified.  Quitting."
X			echo "$USAGE"
X			exit 1
X		fi
X	;;
X	*)
X		echo "$pr: 'target <dir>' only valid for 'get' mode.  Quitting."
X		echo "$USAGE"
X		exit 1
X	;;
X	esac
Xfi
X
X# if user specified a listfile on the command line, make sure it exists
X# and has something in it.
Xif test -n "$listf" ; then
X	if test ! -f $listf ; then
X		echo "$pr: No such listfile '$listf'.  Quitting."
X		exit 1
X	elif test ! -s $listf ; then
X		echo "$pr: Listfile '$listf' is empty.  Quitting."
X		exit 1
X	fi
Xfi
X
X## we've checked as much command syntax as we can without making a working
X## directory, but we need one now.
X# It's name has a short form "$wdir" and long form "$workdir".
X# It's "$wdir" name is based on the
X# a) date, b) mode, and c) onedisk vs. multi-filesystem archive.
X# "g" for get, "f" for full, "i" for incremental, "t" for test_incremental,
X# and "v" for verify;
X# "m" for multi-filesystem (alldisks), "o" for onedisk
Xcase "$mode$multi" in
Xdevcheck*)	wdir=$date4.${time6}d  ;;
Xget*)		wdir=$date4.${time6}g  ;;
Xverifytrue)	wdir=$date4.${time6}vm ;;
Xverify*)	wdir=$date4.${time6}vo ;;
Xfulltrue)	wdir=$date4.${time6}fm ;;
Xincrtrue)	wdir=$date4.${time6}im ;;
Xtincrtrue)	wdir=$date4.${time6}tm ;;
Xfull*)		wdir=$date4.${time6}fo ;;
Xincr*)		wdir=$date4.${time6}io ;;
Xtincr*)		wdir=$date4.${time6}to ;;
Xesac
Xcase "$parent" in
X'')	workdir=$hdir/$wdir ;;
X*)	workdir=$hdir/$parent/$wdir ;;
Xesac
X# make sure creation of $workdir succeeds, because if it doesn't the
X# filesystem is probably full, and we can end up with a truncated bkp.donot
X# among other disasters.
Xmkdir $workdir
Xif test $? -ne 0 ; then
X	echo "$pr: Could not make '$workdir'."
X	echo "$pr: The filesystem holding backup's home directory is probably full."
X	echo "$pr: Quitting."
X	exit 1
Xfi
Xcd $workdir
X
X## sample "df" outputs - needed if we're doing a backup
X#
X## normal BSD output
X# Filesystem            kbytes    used   avail capacity  Mounted on
X# /dev/xd0a              15720    4564    9584    32%    /
X#
X## System V output (including "/adj" multi-cpu concept from 3B4000 (bigbird))
X# /         (/dev/dsk/c0t7d0s0):        0 blocks    51134 i-nodes
X# /adj      (/dev/adj        ):    32568 blocks     4582 i-nodes
X# /proc     (/proc           ):        0 blocks      859 i-nodes
X# /adj/pe96/dev (/adj/pe96/dev/icfs):      179 blocks      413 i-nodes
X# /install/62 (/adj/pe96/dev/dsk/c0t4d0s0):   328800 blocks    61126 i-nodes
X#
X## AIX 2.2.1: output with "/native" NFS-ish concept.  Note 7 fields.
X# Device             Mounted on            total     free  used     ifree  used
X# /dev/hd0           /                     38684     8144   78%      9297    7%
X# /                  /native               38684     8144   78%      9297    7%
X#
X## AIX 3.1:  Note 7 fields but mountpoint is the last field as it should be.
X# Filesystem    Total KB    free %used   iused %iused Mounted on
X# /dev/hd4         40960    1128   97%    1245    12% /
X# /dev/hd2        376832   47336   87%    7852     8% /usr
X#
X## TI Sys V 3.2.1: Note *two* colons:
X#/                   (/dev/dsk/sys:root):           1726 blocks     2139 i-nodes
X#/pipe               (/dev/dsk/sys:pipe):            989 blocks      452 i-nodes
X#/usr                (/dev/dsk/sys:usr):            1357 blocks     5925 i-nodes
X#/install/62/supp    (/dev/dsk/dsk2:supp):         91011 blocks    36947 i-nodes
X#
X## IRIX 3.3.2: note /debug which is not a real filesystem
X# Filesystem                 Type  blocks     use   avail %use  Mounted on
X# /dev/root                   efs   31360   26001    5359  83%  /
X# /dev/usr                    efs 1860180 1132421  727759  61%  /usr
X# /debug                      dbg  143936   12344  131592   9%  /debug
X#
X## NonStop-UX 4.0 "df" doesn't show filesystem type so we have to look it
X## up in /etc/vfstab or use "df -n".
X## NonStop-UX 4.0 "df -k -l"
X# abalone 125# df -k -l
X# filesystem         kbytes   used     avail    capacity  mounted on
X# /dev/vol/root      65536    56069    9467     86%       /
X# /proc              0        0        0         0%       /proc
X# /dev/fd            0        0        0         0%       /dev/fd
X# /config            0        0        0         0%       /config
X# /dev/vol/usr       256000   195626   60374    76%       /usr
X# /dev/dsk/sc1d3s10  282933   149152   133781   53%       /install/64
X## NonStop-UX 4.0 "df -n"
X# abalone 126# df -n
X# /                  : vxfs
X# /proc              : proc
X# /dev/fd            : fdfs
X# /config            : cfs
X# /usr               : vxfs
X# /install/64        : ufs
X# abalone 127#
X## NonStop-UX 4.0 end of "df" outputs
X#
X## END of "df" sample outputs
X
X# if we are doing a backup of one or more filesystems, then
X# get df output and make sure our bkp.donot file excludes strange filesystems
X# else take care of a few other little things
Xcase $mode$fsbkp in
Xdevcheck*|get*|verify*)
X	: do nothing special
X;;
Xfullfalse)
X	if test ! -d $fs ; then
X		echo "$pr: $fs is not a directory.  Quitting."
X		exit 1
X	fi
X	devlist=$fs
X;;
X*false)
X	echo "$pr: Incrementals OK for filesystems only.  Quitting."
X	exit 1
X;;
Xfull*|incr*|tincr*)
X	## get list of valid filesystems for backup.
X	# see sample "df" outputs above
X	# We use "df" because it's output is more similar across OS platforms
X	# than "mount" and Sys V mount doesn't always show the root filesystem.
X	# Unfortunately, df can hang waiting for info from an NFS filesystem.
X	# "df > $dft1 & ; sleep 5 ; ..." isn't a workaround because in that
X	# usage "df" won't put out any info until it completes.
X	# Oh, well, there's no good answer yet, except on some machines
X	# where "df" has a filesystem type key
X	if test "$OS_S" = NonStop-UX ; then
X		dfargs="-l"
X	elif test -n "$DFFSTYPE_K" -a -n "$LOCFSTYPE_S" ; then
X		dfargs="$DFFSTYPE_K $LOCFSTYPE_S"
X	else
X		dfargs=""
X	fi
X	df $dfargs | egrep '/dev/' > $dft1
X
X	# if we have SysV df output
X	if egrep '\):' $dft1 > /dev/null ; then
X		sed -e 's/(/ /' -e 's/):/ /' $dft1 | awk '{printf "%-16s %6d %s %6d %s %s\n",$2,$3,$4,$5,$6,$1}' > $dft2
X	# else if we're AIX 2.2.1
X	elif awk '{print $2}' $dft1 | grep / > /dev/null ; then
X		egrep '/dev/' $dft1                | awk '{printf "%-16s %6d %6d %4s %6d %4s %s\n",$1,$3,$4,$5,$6,$7,$2}' > $dft2
X	# else we're normal BSD or AIX 3.1
X	else
X		cp $dft1 $dft2
X	fi
X
X	# Some operating systems have filesystems we never want to back up
X	case "$OS_S$OSLEVEL_S" in
X	AIX2.2.1|IRIX3*|NonStop-UX4.0)
X		case "$OS_S$OSLEVEL_S" in
X		AIX2.2.1)	bumfs=/native ;;
X		IRIX3*)		bumfs=/debug ;;
X		NonStop-UX4.0)	bumfs=/config ;;
X		esac
X		if test ! -f $nobkp ; then
X			echo $bumfs > $nobkp
X		elif egrep $bumfs $nobkp > /dev/null ; then
X			: do nothing we are already protected
X		else
X			echo $bumfs >> $nobkp
X			sort -u -o $nobkp $nobkp
X		fi
X	;;
X	esac
X
X	## We have three filters for filesystems which we may not want
X	## to back up.  Two of them are config files, and the third we
X	## implement in code.
X	#
X	# filesystem filters:
X	# a) $nobkp, lists filesystems we never want to back up, and we make
X	#	sure it includes the following filesystems (see $bumfs above)
X	#	For AIX 2.2.1, don't back up /native (see above)
X	#	For IRIX 3.*, don't back up /debug
X	#	For NonStop-UX, don't back up /config
X	#	Otherwise, $nobkp is configured by the user
X	# b) $nofm, lists filesystems we never want to do full multivolume
X	# backups on (i.e. we don't do full alldisks with).  Typically
X	# this file might list 1Gig filesystems which we want to do
X	# seperate full onedisk backups on.
X	# c) don't backup /cdrom/unnamed_cdrom, /cdrom*, /export/swap, /proc,
X	# /tmp, or NFS filesystems
X	#
X	## We also may have some number of listfiles (e.g. bkp.list0) to check
X	## valid formats.  The format for the listfiles is the same as the
X	## filesystem filter files.
X	#
X	# NOTE:
X	# we must carefully delimit filesystem name for egrep, both here and
X	# in $nobkptmp.
X	# The regular expression must include '[<SPACE><TAB>]/fsname<DOLLAR>'
X	# This example would prevent backing up a /scratch filesystem:
X	# [ 	]/scratch$
X
X	# massage config file filesystem filters into $nobkptmp, if we
X	# have them and want to use them;
X	# also massage $listf into $listftmp if necessary
X	rm -f $nobkptmp $listftmp
X	case $mode$multi in
X	fulltrue)	fsfilters="$nobkp $nofm" ;;
X	*)		fsfilters="$nobkp" ;;
X	esac
X	case "$multitype" in
X	unlisted)
X		cd $hdir
X		listfiles=`echo bkp.list[0-9]*`
X		if test "$listfiles" != "bkp.list[0-9]*" ; then
X			# sed strips comments and blank lines in $listfiles
X			sed -e 's/[ 	]*\#.*//' -e '/^[ 	]*$/d' $listfiles > $workdir/bkp.listed
X			fsfilters="$fsfilters $workdir/bkp.listed"
X		fi
X		cd $workdir
X	;;
X	esac
X	for ff in $fsfilters $listf ; do
X		if test -f $ff ; then
X			## make sure $ff is in correct format
X			# assume leading blanks, trailing blanks, and blank
X			# lines are benign, and quietly fix them if present
X			sed -e 's/^[ 	]*//' -e 's/[ 	]*$//' -e '/^$/d' $ff > $ff.t
X			if test `wc -c < $ff.t` -lt `wc -c < $ff` ; then
X				mv $ff.t $ff
X			fi
X			# strip comments, then see if $ff.t1 has any
X			# real data left
X			sed -e 's/[ 	]*\#.*//' -e '/^[ 	]*$/d' $ff > $ff.t1
X			if test ! -s $ff.t1 ; then
X				case $ff in
X				*/bkp.donot|*/bkp.nofm)
X					echo "$pr: WARNING - '$ff' is empty or has only comments; please fix or remove; continuing ..." | tee -a $failrpt
X					continue
X				;;
X				*)
X					echo "$pr: Listfile '$ff' is empty.  Quitting." | tee -a $failrpt
X					exit 1
X				;;
X				esac
X			fi
X			# check for common mistakes: putting device name
X			# instead of mount point.
X			if egrep '^/(adj/.*)*dev/' $ff > /dev/null ; then
X				echo "$pr: '$ff' contains device names"
X				echo "$pr: instead of mount points.  Quitting."
X				exit 1
X			fi
X			## make sure $nobkptmp is in correct format, with a
X			# [<SPACE><TAB>]filesystemname<DOLLAR>	(for dump)
X			# [<SPACE><TAB>]directoryname<DOLLAR>	(for cpio)
X			sed -n -e 's,^\(/[a-zA-Z0-9_/\.\+-]*\)$,[ 	]\1$,p' $ff.t1 > $ff.t
X			nlinesorig=`wc -l < $ff.t1`
X			nlinestmp=` wc -l < $ff.t`
X			# if the number of lines in $ff.t1 and $ff.t
X			# are unequal, create failure report and quit.
X			if test $nlinesorig -eq $nlinestmp ; then
X				case $ff in
X				*/bkp.donot|*/bkp.nofm|*/bkp.listed)
X					cat $ff.t >> $nobkptmp
X				;;
X				*)
X					cat $ff.t >> $listftmp
X				;;
X				esac
X			else
X				exec 1> $failrpt
X				echo ""
X				echo "$pr: '$ff' is not in correct format."
X				echo "$pr: '$ff' must list one filesystem per line"
X				echo "$pr: (although comments beginning with '#' are OK)"
X				echo "$pr: Please fix '$ff'.  Quitting."
X				exec 1>&9
X				cat $failrpt
X				exit 1
X			fi
X			rm -f $ff.t1 $ff.t
X		fi
X	done
X
X	# strip unwanted filesystems, now that we have $nobkptmp
X	# "/adj/.*dev/" selects Sys V devices, e.g. /adj/pe96/dev/ on 3B4000's
X	# "/cdrom" is for SunOS's read only CDROM
X	# "/cdrom/unnamed_cdrom" is for Solaris's 2.2+ read only CDROM
X	# "/export/swap", "/proc", and "/tmp" are scratch so we don't care
X	#
X	# first egrep strips filesystems we never want
X	# "if" subshell strips any filesystems in $nobkptmp if it exists
X	# second egrep selects info on devices
X	egrep -v '[ 	]/(cdrom.*|export/swap|proc|tmp)$' $dft2 \
X	| if test ! -s $nobkptmp ; then
X		cat
X	else
X		# $egrepff, $egrepfi, $egrepfo, and $egrepfv for $EGREPF
X		egrepff=$nobkptmp
X		egrepfi=""
X		egrepfo=""
X		egrepfv="-v"
X		eval "$EGREPF"
X	fi \
X	| egrep '^/dev/|^/adj/.*dev/' > $dft3
X
X	# put /, /usr, and /var *first*
X	# (In alldisks versions before 3.00, / and /usr were last.)
X	# (From alldisks versions 3.00 thru 4.46, / and /usr were first.)
X	# (Since alldisks version 4.47, /, /usr, and /var are first.)
X	egrep    '[ 	]/$'			$dft3 >  $dfout
X	egrep    '[ 	]/usr$'			$dft3 >> $dfout
X	egrep    '[ 	]/var$'			$dft3 >> $dfout
X	egrep -v '[ 	](/|/usr|/var)$'	$dft3 >> $dfout
X
X	# select filesystems from $listf
X	if test -n "$listf" ; then
X		mv $dfout $dflocal
X		# $egrepff, $egrepfi, $egrepfo, and $egrepfv for $EGREPF
X		egrepff=$listftmp
X		egrepfi=$dflocal
X		egrepfo=$dfout
X		egrepfv=""
X		eval "$EGREPF"
X	fi
X
X	if test ! -s $dfout ; then
X		echo "$pr: '$dfout' is empty.  Something is wrong."
X		echo "$pr: Quitting."
X		exit 1
X	fi
X
X	## get list of actual filesystem devices - necessary because
X	## a) 4.1BSD dump matches 1st *similar* pattern, not real thing
X	## b) NCR SVR4 does not look up mount point in /etc/vfstab
X	# if $fs wasn't specified then we're doing an alldisks backup
X	if test -z "$fs" ; then
X		devlist=`awk '{print $1}' $dfout`
X	# else $fs was specified, so check its validity
X	else
X		# if $fs is in $dfout we're cool
X		devlist=`egrep "[ 	]$fs\$" $dfout | awk '{print $1}'`
X		if test -z "$devlist" ; then
X			# maybe $fs is in $nobkp (and hence in $dft2 but not $dfout)
X			devlist=`egrep "[ 	]$fs\$" $dft2 | awk '{print $1}'`
X			if test -n "$devlist" ; then
X				echo "$pr: Filesystem '$lhost:$fs' is not usually backed up."
X				eval "$EXITQ"
X			# else we really aren't a mounted filesystem
X			else
X				echo "$pr: Bad filesystem name '$fs'"
X				exit 1
X			fi
X		fi
X	fi
X;;
Xesac
X
Xecho "$pr: Your command looks AOK to me.  Thanks."
X
X# build local and remote commands (no dd command since we're using $bdd script)
Xcase $mhost in
X$lhost)	mlocal=true ;;		# the media is local
X*)	mlocal=false ;;		# the media is remote
Xesac
Xif test $mlocal = true ; then
X	cmp="cmp"
X	ls="ls"
X	mt="mt"
X	rm="rm"
X	tar="tar"
Xelif test -z "$rsh" ; then
X	echo "$pr: \$RSH_C is not set in /etc/saenv:"
X	grep '^RSH_C=' /etc/saenv
X	echo "$pr: Quitting."
X	exit 1
X# "date" output is same on BSD, SunOS, SysV, NCROS, UTS, AIX, Solaris, SVR4
X#elif test `$rsh $mhost date 2> /dev/null | wc -w` -ne 6 ; then
Xelif $rsh $mhost date > /dev/null 2>&1 ; then
X	cmp="$rsh $mhost cmp"
X	ls="$rsh $mhost ls"
X	mt="$rsh $mhost mt"
X	rm="$rsh $mhost rm"
X	tar="$rsh $mhost tar"
Xelse
X	echo "$pr: $rsh $mhost date"
X	$rsh $mhost date
X	echo "$pr: 'root' on $lhost does not have permission to run"
X	echo "$pr: remote shell commands at media host $mhost.  Check:"
X	echo "$pr: -> Make sure '$lhost root' is in /.rhosts on $mhost."
X	echo "$pr: -> Make sure '$lhost' has a valid entry in /etc/hosts on $mhost."
X	echo "$pr: Quitting."
X	exit
Xfi
X
X## make sure backup.dd script is usable
X# export environment variables needed by backup.dd
XMHOST=$mhost
XLHOST=$lhost
Xexport MHOST LHOST RSH_C
X# if we haven't tested it already, do so now
Xif test -z "$parent" ; then
X	eval $SHOWDD Make sure $bdd script is usable
X	echo "$pr: you should never see this" | $bdd of=/dev/null 2> err.dd
X	if test $? -ne 0 ; then
X		cat err.dd
X		echo "$pr: '$bdd' is not usable for some reason.  Quitting."
X		exit 1
X	fi
Xfi
Xrm -f err.dd
X
X# build mt command if mt exists
Xif test $mhost = $lhost ; then
X	mtkey="$MT_K"
Xelse
X	mtkey="`$rsh $mhost grep 'MT_K=' /etc/saenv | sed -n -e '/^MT_K=/s/^MT_K=\([^ 	]*\)[ 	].*/\1/p'`"
Xfi
Xcase "$mtkey" in
X'')	mt='' ;;		# mt command does not exist on media host
X*)	mt="$mt $mtkey" ;;	# mt command does exist on media host
Xesac
X
X## figure out which backup/get program(s) we're using
X# if the user specified cpio on the command line
Xif test "$bprog" = cpio ; then
X	restore=cpio
X# else if we're on Dynix Sequent using a video drive
Xelif test -n "$HDUMP_P" -a $mtype = video ; then
X	bprog=$HDUMP_P
X	restore=$RESTOR_P
X# else if we have BSD dump by some name
Xelif test -n "$DUMP_P" ; then
X	bprog=$DUMP_P
X	restore=$RESTOR_P
X# else we're using cpio
Xelse
X	bprog=cpio
X	restore=cpio
Xfi
Xif test $mhost != $lhost ; then
X	# set remote dump/restore if bprog is "dump"
X	case $bprog in
X	*dump*)
X		# set remote dump - warn and die if unavailable
X		case $bprog in
X		$HDUMP_P)	bprog=$HRDUMP_P ;;	# Dynix "hdump/hrdump"
X		*)		bprog=$RDUMP_P ;;	# normal "dump/rdump"
X		esac
X		if test -z "$bprog" ; then
X			echo "$pr: Remote dump unavailable on '$lhost' (see \$RDUMP_P in /etc/saenv)."
X			echo "$pr: Cannot do dumps over net from '$lhost'."
X			echo "$pr: Try 'cpio' option to do network cpio backups."
X			exit 1
X		fi
X		# set remote restore - warn and die if unavailable
X		if test -n "$RRESTOR_P" ; then
X			restore=$RRESTOR_P
X		else
X			echo "$pr: Remote restore unavailable on '$lhost' (see \$RRESTOR_P in /etc/saenv)."
X			echo "$pr: Cannot do restores over net from '$lhost'."
X			echo "$pr: Try 'cpio' option to do network cpio restores."
X			exit 1
X		fi
X	;;
X	esac
Xfi
X# header program
Xcase $bprog in
Xcpio)	headprog=cpio ;;	# header archive is cpio format
X*dump*)	headprog=tar ;;		# header archive is tar format
Xesac
X# lock out other cpio backups/gets/verifies, or lock if we're asked to
Xif test $bprog = cpio -o $optlk = true ; then
X	echo "$pr: LOCK: PID=$$, $workdir, $pr $cmdargs" > $lockf
Xfi
X# other initial stuff - if we're updating make sure we can
Xcase $update$bprog in
X*cpio)
X	# if this is a bad (but real) joke
X	if test $joke = true -a $mode != devcheck ; then
X		echo "$pr: We are using cpio - help!"
X		echo "$pr: Oh, I'm feeling sick ... "
X		echo $epre "$pr:   cough, "$esuf
X		sleep 1
X		echo $epre " choke . . . "$esuf
X		sleep 1
X		echo "gagghhhhh"
X		echo "$pr: (THUD)."
X		echo ''
X		sleep 2
X		echo "$pr: Bones: He's dead, Jim."
X		sleep 2
X		echo ''
X		echo "$pr: Spock: Correction - he's braindead."
X		echo ''
X		sleep 2
X		echo "$pr: Kirk: Well then, Bones, thanks to the miracle of"
X		echo "$pr: the alldisks script, we can still do the backup."
X		echo "$pr: Carry on."
X		echo ''
X	fi
X;;
Xtrue*dump*)
X	# make sure /etc/dumpdates exists
X	if test ! -f /etc/dumpdates ; then
X		echo "$pr: /etc/dumpdates does not exist, creating /etc/dumpdates."
X		echo "$pr: We do this because some versions of BSD dump abort if"
X		echo "$pr: /etc/dumpdates doesn't exist."
X		echo "$pr: This is probably the first time BSD dump has been used on $lhost."
X		touch /etc/dumpdates
X		echo "$pr: `ls -l$LSGROUP_K /etc/dumpdates`"
X		echo "$pr: We're OK now, continuing with the backup."
X	fi
X
X	# Make a feeble effort to make sure dump can read and write dumpdates.
X	# We test to see if the script can read and write dumpdates, and
X	# act accordingly.  However, that doesn't tell us what dump/rdump
X	# will do when we call it.  Unfortunately, this is the best we can do.
X	# Even using "dump W" to test readability won't reliably produce
X	# useful results, because under HP-UX 8.00 (and probably many other
X	# UNIXs), if "dump W" is called from a setuid root script, it can read
X	# /etc/dumpdates even if permissions are 000.
X	if test ! -r /etc/dumpdates -o ! -w /etc/dumpdates ; then
X		touch /etc/dumpdates
X		echo "$pr: `ls -l$LSGROUP_K /etc/dumpdates`" | tee -a $workdir/$report
X		echo chmod u+rw /etc/dumpdates | tee -a $workdir/$report
X		chmod u+rw /etc/dumpdates
X	fi
X	# quit if we weren't able to fix it
X	if test ! -r /etc/dumpdates -o ! -w /etc/dumpdates ; then
X		echo "$pr: `ls -l$LSGROUP_K /etc/dumpdates`" | tee -a $workdir/$report
X		echo "$pr: Cannot read/write /etc/dumpdates.  Quitting."
X		exit 1
X	fi
X
X	# HACK4HPUX8 is from $site; it may make dumpdates 664 group operator
X	eval "$HACK4HPUX8"
X;;
Xesac
X
X# now that $bprog and $restore are set, turn off actual backup work
X# for demonstrations
Xif test $demo = true ; then
X	bprog="echo $pr demo: $bprog"		# echo backup command
X	restore="echo $pr demo: $restore"	# echo get command
X	mt="echo $pr demo: $mt"			# echo mt command
X	# dd command is tricky, so tailor it wherever it is used
Xfi
X
X# decide whether we're using a file, dir, rewind device, norewind device
X# mdevbase wouldn't be needed if we were only supporting tape devices,
X# but since we're supporting alldisks to disk files, we'll be reasigning
X# mdev based on $mdevbase.
Xif   test $mtype = dir ; then
X	if   test $mode = get -o $mode = verify ; then
X		# a parent could be like either "0206.164423fm"
X		# or "0206.164423fm/0206.164448vm"
X		if test -n "$parent" ; then
X			# $parenttop is roughly the opposite of basename $parent
X			parenttop=`echo $parent | sed -e 's/\/.*//'`
X			mdevbase=$diskfile/$parenttop
X		# or we have no parent, and we assume the directory has
X		# files from only one backup
X		else
X			cd $diskfile
X			mdevbase=$diskfile/`echo [01][0-9][0123][0-9].*[a-z].[0-9][0-9] | sed -e 's/ .*$//' -e 's/\.[0-9][0-9]$//'`
X			cd $workdir
X		fi
X	else
X		mdevbase=$diskfile/$wdir
X	fi
Xelif test $mtype = file ; then
X	mdevbase=$diskfile
Xelif test $mode = get -o $mode = verify ; then
X	mdevbase=$rewdev
Xelif test "$multi" = false ; then
X	mdevbase=$rewdev
Xelse
X	mdevbase=$norewdev
Xfi
Xmdev=$mdevbase
X
X## deal with cpio/dump/restore keys and options
X# if the backup/get/verify program is cpio
Xcase $bprog in
Xcpio)
X	# check $maxocount
X	case $maxocount in
X	[1-9][0-9]*)
X		: do nothing
X	;;
X	*)
X		echo "$pr: Maximum output blocks for $mhost:$media in"
X		echo "$pr: $devdata is '$maxocount'.  Quitting."
X		exit 1
X	;;
X	esac
X	# get cpio options
X	ckey=''		# initialize cpio key
X	for i in $bopts ; do
X		# see comments in the NOTES file about making
X		# "cpio ... | dd ... " work, given possible problems with
X		# cpio output block size, pipesize, dd's ibs and obs, and
X		# the device driver for the output device; also the size
X		# $RSH_C on both hosts can handle if were doing a backup
X		# over the net.
X		# $cpioobs	cpio's output blocksize
X		# $ckey		cpio key (ckey=C$obs || ckey=B)
X		# $obs		from $devdata
X		# based on pipesize from $SAHOST:$SABIN/getpipesize
X		case $i in
X		C)
X			ckey=${ckey}C$obs	# cpio block size is $obs
X			ibs=$obs		# easiest if they match
X		;;
X		DAT1|DAT2|E82|E85|QIC*|TK50|TK70)
X			continue		# this info for humans only
X		;;
X# TI Sys V can't read multiple cpio archives put on with their -T option
X#		T)
X#			ckey=${ckey}T		# write portable cpio archives on TI's
X#		;;
X		*)
X			if test $mistape != true ; then
X				echo "$pr: dump option '$i' in '$devdata' ignored."
X			fi
X		;;
X		esac
X	done
X	# if $ckey doesn't include "C" then
X	if echo "$ckey" | grep -v C > /dev/null ; then
X		ckey=B$ckey
X		ibs=5120		# make dd ibs match
X	fi
X;;
X# $bprog is BSD dump/restore (by some name)
X# we build the dump command line here.  It's also convenient to build
X# most (not all) of the restore key.  We'll need to finish the
X# job later if we're really doing a get, by asking the user whether
X# to do an interactive restore or to restore the entire dump.
X*dump*)
X	# set dump level
X	case $mode in
X	full)	dlevel=0 ;;
X	incr)	dlevel=$incr ;;
X	tincr)	dlevel=$test_incr ;;
X	esac
X	# if we're not supposed to update or we're dumping to the bit-bucket
X	if test $update != true -o $media = null ; then
X		updkey=		# don't update /etc/dumpdates
X	else
X		updkey=u	# update /etc/dumpdates
X	fi
X	# figure out restore opts key, restore opts, dump key, and dump opts
X	# we have to deal with DEC_OSF/1 strangeness here for roptkey, since the
X	# roptkey can't have an "f" in it because rrestore's command syntax is:
X	# /usr/sbin/rrestore -f host:/device -$rmode$roptkey $ropts
X	# According to the manual page DEC_OSF/1 doesn't mess with the
X	# syntax for local restore's, but this works too:
X	# /usr/sbin/restore  -f      /device -$rmode$roptkey $ropts
X	case "$OS_S" in
X	DEC_OSF/1)	roptkey='' ;;
X	*)		roptkey=f  ;;
X	esac
X	dkey=$dlevel${updkey}f
X	dopts=''			# dump options based on $dkey and $bopts
X	d2mtype=''			# DG dump2's media type option
X	d2stats=''			# DG dump2's statistics report option
X
X	# modify the keys according to dump/restore options, if any
X	for i in $bopts ; do
X		case $i in
X		# "-d" (density in BPI)
X		# 1600, 3200 and 6250 for 9tracks
X		# 6670 for tk50's
X		# ???? for tk70's
X		# 1000 for QIC11/QIC24/QIC150 carts,
X		# 23000 for MIPS 120M carts
X		# 141000 for auspex 8500 exabytes
X		1000|1600|3200|6250|6670|23000|141000)
X			dkey=${dkey}d
X		;;
X		# "-t" (tracks: cartridge only)
X		# 4 for QIC11, 9 for QIC24, 18 for QIC150
X		4|9|18)
X			dkey=${dkey}t
X		;;
X		# "-b" (blocking factor: either 512 characters or
X		# 1024 characters per tape block depending on the OS)
X		# 126 for videos on suns, 346 for video on DYNIX,
X		# 100 for auspex 8500 exabytes,
X		# else any even two-digit number
X		100|126|346|[1-9][02468])
X			dkey=${dkey}$DRB_K		# tapeblock size ...
X			roptkey=${roptkey}$DRB_K	#     was specified ...
X			if test -n "$DRB_K" ; then
X				ropts="$ropts $i"	#             and is $i
X			else
X				echo "$pr: Blocksize '$i' in $devdata"
X				echo "$pf: ignored, because this OS does not support it."
X			fi
X		;;
X		# "-s" (size in feet)
X		# 11500 for auspex 8500 exabytes
X		# 70000 for dats
X		# 165000 for Exabyte 8200s
X		# 330000 for Exabyte 8500s
X		# any other three- or four-digit number ending in "00" or "25"
X		# (see $mdev for why)
X		11500|70000|165000|330000|[1-9][02][05]|[1-9][0-9][02][05])
X			dkey=${dkey}s		# size was specified
X		;;
X		# "c" for Sun cartridge drives
X		# "C" for Bull cartridge drives
X		c|C)
X			# only need to change dump key not restore key for suns
X			dkey=${dkey}$i		# cart was specified (suns)
X			continue		# so $i isn't put in $dopts
X		;;
X		M)
X			d2mtype="$i $mtype"	# dump2's mediatype key and arg
X			continue		# so $i isn't put in $dopts
X		;;
X		s)
X			d2stats=s		# dump2's statistics key
X			continue		# so $i isn't put in $dopts
X		;;
X		DAT1|DAT2|E82|E85|QIC*|TK50|TK70)
X			continue		# this info for humans only
X		;;
X		*)
X			echo "$pr: I do not understand $bprog option '$i' in '$devdata'"
X			echo "$pr: Quitting."
X			exit 1
X		;;
X		esac
X		dopts="$dopts $i"
X	done
X
X	# Dec's OSF/1 version of dump/rdump automatically ejects the tape
X	# after the dump is done, unless you put the "N" in the dump key.
X	case "$OS_S" in
X	DEC_OSF/1)	dkey=${dkey}N ;;
X	esac
X
X	# build backup command for local vs. remote media
X	# $DRMINUS is for Bull OS, ICL, and other weirdos
X	# dump2 code is for DG's dump2
X	case $bprog in
X	*dump2)
X		test -n "$opfifo"  && d2opts="$d2opts $DRMINUS$opfifo"
X		test -n "$d2mtype" && d2opts="$d2opts $DRMINUS$d2mtype"
X		test -n "$d2stats" && d2opts="$d2opts $DRMINUS$d2stats"
X	;;
X	*)
X		if test -n "$opfifo$d2mtype$d2stats" ; then
X			echo "$pr: Data General 'dump2' arguments '$opfifo$d2mtype$d2stats' in '$devdata'"
X			echo "$pr: do not work on non-DG machines.  Quitting."
X			exit 1
X		fi
X	;;
X	esac
X	case $mhost$diskfile in
X	$lhost-)
X		# the "sleep" is to give the shell time to open b.$fsnn.out
X		bcmd='$bprog $DRMINUS$dkey        $mdev $dopts $d2opts $fsdev 1>&8 2> b.$fsnn.out & bpid=$! ; sleep 2 ; tail -f b.$fsnn.out & tailpid=$!'
X	;;
X	*-)
X		echo "$pr: Cannot dump to standard out on remote host."
X		exit 1
X	;;
X	$lhost*)
X		bcmd='$bprog $DRMINUS$dkey        $mdev $dopts $d2opts $fsdev 2>&1 | tee -i b.$fsnn.out'
X	;;
X	*)
X		bcmd='$bprog $DRMINUS$dkey $mhost:$mdev $dopts $d2opts $fsdev 2>&1 | tee -i b.$fsnn.out'
X	;;
X	esac
X;;
Xesac
X
X###############################################################################
X## Device testing
X## if $demo is false, $check is true, and $mtype isn't dir, file or null ; then
X##	case $mode in
X##	get|verify)
X##		verify read of rewind device
X##	;;
X##	full|incr|tincr|devcheck)
X##		verify write to rewind *and* norewind devices
X##	;;
X##	esac
X## endif
X## The actual test code is written to avoid indenting more than one level
X
X## First, make sure rewind and norewind devices are block/character
X## special files (trust symlinks).
X## (But don't do it if $mtype is dir or file.)
X# The "ls -l" writes to standard error if $rewdev doesn't exist,
X# so "wc -l" gives 0.  This trickiness is needed because we may be
X# dealing with a remote machine.  Remote shell (rsh) reports success
X# if it had permission to run a command on the remote box, and doesn't
X# care if the command itself works or not.  Also, we assume symbolic
X# links are cool because it's really hard to verify them, especially on
X# remote boxes.  That's why we egrep for '^[bcl]'.
Xif test $mtype != dir -a $mtype != file -a `$ls -l   $rewdev | egrep -c '^[bcl]'` -ne 1 ; then
X	badrewdev=true
X	echo "$pr: No device node for rewind device '$rewdev'"     >> $failrpt
Xfi
Xif test $mtype != dir -a $mtype != file -a `$ls -l $norewdev | egrep -c '^[bcl]'` -ne 1 ; then
X	badnorewdev=true
X	echo "$pr: No device node for norewind device '$norewdev'" >> $failrpt
Xfi
Xif test "$badrewdev" = true -o "$badnorewdev" = true ; then
X	echo "$pr: Media data file '$devdata' is wrong." >> $failrpt
X	echo "$pr: Notify a UNIX System Administrator IMMEDIATELY ! ! !" >> $failrpt
X	cat $failrpt
X	exit 1
Xfi
X
X## Second, set up media test block sizes and test files on the media host.
X## Do before all real media tests.
Xcase $bprog$multi in
Xcpio*)
X	mtestibs=10b	# header file is cpio, backup is cpio
X;;
X*dump*true)
X	mtestibs=20b	# header file is tar
X;;
X*dump*)
X	mtestibs=63k	# backup is dump, so choose max dump blocksize
X	# deal here with special weird mtestibs requirements:
X	# Bull's B.O.S. can't read more than 60k from a cart
X	# DYNIX and DYNIX/ptx can't read more than 32k from "xt" devices;
X	# we could get down to that level, but this ought to be good enough.
X	case "$OS_S" in
X	B.O.S.)			mtestibs=60k ;;
X	DYNIX|DYNIX/ptx)	mtestibs=32k ;;
X	esac
X;;
Xesac
X# For media test files, we can't just use /etc/passwd and /etc/group
X# because the test files must be modulus 512 in size for cartridge drives
X# (a hardware limitation).  We also need test files to be modulus 10k for
X# some video units (we don't know why, but 1k is too small).  On the
X# other hand 5k is the max on AT&T 3B5 (coyote), maybe because it's
X# pipesize is so strange (6144 characters).  So, we create the first and
X# second test files on the fly.  All media test files should be in a
X# world writeable directory, not $workdir, because we may have to create
X# it on a remote machine.
X#
X# We need test files for rewind/norewind device testing and also for
X# tape testing for cpio backups.
Xcase $mode in
Xdevcheck|full|incr|tincr)
X	eval $SHOWDD Create two test files
X	echo "script: '$pr', mtestf1 '$mtestf1'; workdir '$lhost:$workdir'" \
X	| $bdd of=$mtestf1 bs=$mtestobs conv=sync 2> /dev/null
X	echo "script: '$pr', mtestf2 '$mtestf2'; workdir '$lhost:$workdir'" \
X	| $bdd of=$mtestf2 bs=$mtestobs conv=sync 2> /dev/null
X;;
Xesac
X
X## Third, if we're doing a get/verify, make sure we can read the rewind device
X## (But check other stuff if $mtype is dir or file)
Xwhile test $demo = false -a $check = true -a \( $mode = get -o $mode = verify \) -a $mtype != null ; do
X	# if we're reading from file or directory, we have simple tests;
X	# if it's null we don't do anything
X	case "$mtype" in
X	dir)
X		if test ! -d $diskfile ; then
X			if test $? -ne 0 ; then
X				echo "$pr: Cannot read $mtype $diskfile.  Quitting."
X				exit 1
X			fi
X		fi
X	;;
X	file)
X		if test ! -f $diskfile ; then
X			if test $? -ne 0 ; then
X				echo "$pr: Cannot read $mtype $diskfile.  Quitting."
X				exit 1
X			fi
X		fi
X	;;
X	esac
X	if test -z "$parent" -a $mtype != file -a $mtype != dir ; then
X		eval $SHOWDD Make sure we can read the rewind device
X		$bdd if=$rewdev of=/dev/null count=1 bs=$mtestibs 2> err.dd
X		if test $? -eq 0 ; then
X			rm -f err.dd
X		else
X			cat err.dd
X			eval "$CHKMREAD"
X			eval "$EXITQ"
X			continue
X		fi
X	fi
X	break
Xdone
X
X## Fourth, if we're making a backup or doing a devcheck, we check both
X## the rewind and norewind device names from $devdata.  This is so important
X## that we do it whether or not we'll end up using the norewind device.
X## (But check other stuff if $mtype is dir, file, or null)
X#
X# Later on, if it's a cart and we're using cpio, we'll need to test the
X# cart to make sure that we can write large amounts of data to it.
X# Oddly enough, low density (low "ftpi" (frame tracks per inch)) carts
X# work with high density drives if we're only writing a block or two.
X# This is strange, but I've tested it pretty extensively in 150M and
X# 120M cartridge drives using carts of 8000, 10000, and 12500 ftpi.
X# We only have to worry about this if it's cpio because BSD dump takes
X# care of this kind of problem for us.
X#
X# We only intend to do this code once, but we have to use a "while"
X# so we can "break" out of it if $rewdev is wrong.
Xwhile test $demo = false -a $check = true -a \( $mode = full -o $mode = incr -o $mode = tincr -o $mode = devcheck \) ; do
X
X	# if we're writing to a file or directory, we have simple tests;
X	# if it's null we don't do anything
X	case "$mtype" in
X	dir)
X		if test ! -d $diskfile ; then
X			mkdir $diskfile
X			if test $? -ne 0 ; then
X				echo "$pr: Cannot create $mtype $diskfile.  Quitting."
X				exit 1
X			fi
X		fi
X		break
X	;;
X	file)
X		if test $diskfile != "-" -a ! -f $diskfile ; then
X			echo "$pr: can we create $diskfile" > $diskfile
X			if test $? -ne 0 ; then
X				echo "$pr: Cannot create $mtype $diskfile.  Quitting."
X				exit 1
X			fi
X		fi
X		break
X	;;
X	null)
X		break
X	;;
X	esac
X
X	## First, make sure we can write to the rewind device - the operator may
X	## have forgotten to put the drive on line or left off the write ring.
X	$rm -f $mtestf3			# just to make sure
X	while : ; do
X		# write 1st file, rewind media
X		eval $SHOWDD Make sure we can write to the rewind device
X		$bdd if=$mtestf1 of=$rewdev bs=$mtestobs 2> err.dd
X		bddstat=$?
X		recout=`   egrep records err.dd | awk     'NR == 2 {print $1}'`
X		if test $bddstat -eq 0 -a "$recout" = "1+0" ; then
X			rm -f err.dd
X			break
X		else
X			cat err.dd
X			eval "$CHKMWRITE"
X			eval "$EXITQ"
X		fi
X	done
X
X	## Second, make sure the rewind device name is really a rewind device.
X	# Write 1st file, rewind media, then read it back out.  The count=40
X	# prevents humungous read from accidental norewind device, which
X	# could mean writing to and possibly filling up the filesystem
X	# containing $mtestf3.
X	eval $SHOWDD Make sure rewind device name really does a rewind
X	$bdd if=$mtestf1 of=$rewdev   bs=$mtestobs          2> /dev/null
X	$bdd if=$rewdev  of=$mtestf3  bs=$mtestobs count=40 2> err.dd
X	bddstat=$?
X	recin=`   egrep records err.dd | awk     'NR == 1 {print $1}'`
X	# if we got a bad read from the media
X	if test $bddstat -ne 0 -o "$recin" != "1+0" ; then
X
X		exec 1> $failrpt
X		echo "$pr: Expected '$bdd' status '0'; got status '$bddstat'."
X		echo "$pr: Expected '1+0 records in/out'; got:"
X		cat err.dd
X		echo "$pr: This may be a real HARDWARE problem."
X		exec 1>&9
X		cat $failrpt
X		eval "$CHKMREAD"
X		echo "$pr: Quitting."
X		exit 1
X	fi
X	rm -f err.dd
X	# input should be identical to output
X	if test `$cmp $mtestf1 $mtestf3 2>&1 | wc -l` -gt 0 ; then
X		badrewdev=true
X		$cmp $mtestf1 $mtestf3 >> $failrpt
X		echo "$pr: '$mhost:$rewdev' is supposed to be a rewind device but is NOT." >> $failrpt
X		break	# can't reliably test the norewind device now
X	fi
X
X	## Third and last, verify the norewind device is a norewind device.
X	# The structure here is OK since we just verified the rewind device.
X	# put first file on media, don't rewind
X	# put different file on media, rewind it
X	# read first file back out, rewind media
X	eval $SHOWDD Make sure norewind device name really does not rewind
X	$bdd if=$mtestf1 of=$norewdev bs=$mtestobs          2> /dev/null
X	$bdd if=$mtestf2 of=$rewdev   bs=$mtestobs          2> /dev/null
X	$bdd if=$rewdev  of=$mtestf3  bs=$mtestobs          2> /dev/null
X	# input should be identical to output
X	if test `$cmp $mtestf1 $mtestf3 2>&1 | wc -l` -gt 0 ; then
X		badnorewdev=true
X		$cmp $mtestf1 $mtestf3 >> $failrpt
X		# check for possible reasons
X		if test `$cmp $mtestf2 $mtestf3 2>&1 | wc -l` -eq 0 ; then
X			echo "$pr: GACK! The so-called norewind device actually rewinds the $media!" >> $failrpt
X		fi
X		echo "$pr: '$mhost:$norewdev' is supposed to be a norewind device but is NOT." >> $failrpt
X	fi
X
X	break	# defense! we only want to do this code once.
Xdone
X
X## Fifth - evaluate and report results of device testing
X# (note: keep media test files for later)
Xif test "$badrewdev" = true -o "$badnorewdev" = true ; then
X	echo "$pr: Media data file '$devdata' is wrong." >> $failrpt
X	echo "$pr: Notify a UNIX System Administrator IMMEDIATELY ! ! !" >> $failrpt
X	cat $failrpt
X	exit 1
Xfi
X
X## Sixth and last - clean up and quit if we were asked only to check the media
Xcase $mode in
Xdevcheck)
X	echo "$pr devcheck: The rewind device:   '$rewdev' and"
X	echo "$pr devcheck: the norewind device: '$norewdev'"
X	echo "$pr devcheck: on media host $mhost PASS the devcheck tests."
X	exit 0
X;;
Xesac
X
X###############################################################################
X
X## start the report
Xcd $workdir
Xexec 1> $report
Xecho "#Invocation: $pr $cmdargs"
Xecho "#Version:    $version"
Xecho "#Start time: $date"
Xecho "#Workdir:    $wdir"
Xecho "#Dev Data:   $devdata"
Xecho "#lhost	mhost	mode	media	mdevbase	multi	OPER	voln	hfstat"
X# print variables (note $hfstat isn't set since the header file hasn't
X# been put on the media yet)
Xecho "$lhost	$mhost	$mode	$media	$mdevbase	$multi	$OPER	$voln	${hfstat-NA}"
Xexec 1>&9
X
X## OK!  Ready to *make* the backup or *get/verify* files from the backup!
Xcase $mode in
Xfull|incr|tincr)
X
X	# show operator our assumptions
X	echo ""
X	echo $pr:
X	echo "backup	media	media			media		backup"
X	echo "level	host	alias	workdir		device		program"
X	echo "-------	-------	-------	-------------	---------------	-----------"
X	echo "$mode	$mhost	$media	$wdir	$mdevbase	$bprog"
X	echo ""
X	echo "$pr: About to backup:"
X	case $multi$fsbkp in
X	*false)	echo "$devlist	(directory, not a filesystem)" ;;
X	true*)	awk '			{print $1 "	(" $NF ")" }' $dfout ;;
X	*)	awk '$1 == "'$devlist'"	{print $1 "	(" $NF ")" }' $dfout ;;
X	esac
X	echo ""
X
X	# later on, if we're doing a cpio onedisk backup to a cart, we'll
X	# need this $mtestf4 for every cart
X	if test $bprog = cpio -a $mdev = $rewdev -a $mtype = cart ; then
X		# create 150k test file - do it in 50k
X		# chunks because many machines can't
X		# do it all at once
X		eval $SHOWDD Create 150k test file for carts
X		echo "$pr: $workdir 150k $mtestf4" | $bdd of=$mtestf4 bs=50k conv=sync        2> err.dd
X		echo "$pr: $workdir 150k $mtestf4" | $bdd of=$mtestf4 bs=50k conv=sync seek=1 2> err.dd
X		echo "$pr: $workdir 150k $mtestf4" | $bdd of=$mtestf4 bs=50k conv=sync seek=2 2> err.dd
X		# show user if it's not 150k
X		$ls -l $mtestf4 | grep -v ' 153600 '
X	fi
X
X	## do the backup
X	fsnn=00			# 2-digit filesystem number
X	# put the list of known problems into $problist and
X	# list of known not_problems into $falseprob for later check
X	echo "$KNOWNPROBS" > $problist
X	echo "$KNOWNFALSEPROBS" > $falseprob
X	# start the exit status list
X	echo '#bstat	devname		fsname	known_errors' > $statlist
X	# if multi-volume backup or it's a onedisk but we're putting on a
X	# header anyway, put tar/cpio header file onto media;
X	# the header is tar if we're using dump, cpio if we're using cpio;
X	# the header includes $dfout, $report, all scripts, and any/all
X	# config files ($hdir/bkp.media overrides $DTGT/bkp.media)
X	#if test $multi = true -o $header = true ; then
X	if test $multi = true ; then
X		# put required files in $workdir
X		# we must make sure we have local paths, not absolute paths
X		x="$dfout $report $pr `basename $bdd` bkp.media"
X		ln ../$pr .
X		cp $bdd   .
X		cp $devdata bkp.media
X		case "$multitype" in
X		list)
X			# so we always have the standard name 'bkp.listf'
X			bnlistf=`basename $listf`
X			cp $listf $bnlistf
X			ln $bnlistf bkp.listf
X		;;
X		esac
X		cp    ../bkp.donot . 2> /dev/null && x="$x bkp.donot"
X		cp    ../bkp.host  . 2> /dev/null && x="$x bkp.host"
X		test -f  bkp.listed               && x="$x bkp.listed"
X		test -f  bkp.listf                && x="$x bkp.listf"
X		cp    ../bkp.media . 2> /dev/null && x="$x bkp.media"
X		cp    ../bkp.nofm  . 2> /dev/null && x="$x bkp.nofm"
X		cp $DTGT/bkp.site  . 2> /dev/null && x="$x bkp.site" 
X		test -n "$bnlistf"                && x="$x $bnlistf"
X		# added because NonStop-UX and other OS have multiple
X		# filesystem types and it's often documented in thes files
X		for f in $fstablist ; do
X			cp /etc/$f . 2> /dev/null && x="$x $f"
X		done
X		headlist="$x"
X		if test $bprog = cpio ; then
X			echo "$pr: ================================backup>>> alldisks_header (cpio)"
X		else
X			echo "$pr: ================================backup>>> alldisks_header (tar)"
X		fi
X		# make absolutely sure the header gets on the media - don't
X		# continue until it does
X
X		eval "$MDEV"
X		while : ; do
X			# each case has 3 lines
X			#	1) echo commented command line to $report
X			#	2) echo command line to screen
X			#	3) do or "demo" the command (prettified by ";:")
X			eval $SHOWDD Put alldisks header on $mhost:$media using $bdd
X			case $bprog$demo in
X			cpiotrue)
X				echo         \#find $headlist -print "| { cpio -oc$ckey $copt" '2> err.head ; echo $? > stat.head ; } | {' $bdd of=$mdev obs=5k  2> err.dd '; echo $? > stat.dd ; }' >> $report
X				echo           find $headlist -print "| { cpio -oc$ckey $copt" '2> err.head ; echo $? > stat.head ; } | {' $bdd of=$mdev obs=5k  2> err.dd '; echo $? > stat.dd ; }'
X				echo $pr: demo find $headlist -print "| { cpio -oc$ckey $copt" '2> err.head ; echo $? > stat.head ; } | {' $bdd of=$mdev obs=5k  2> err.dd '; echo $? > stat.dd ; }'
X			;;
X			cpio*)
X				echo         \#find $headlist -print "| { cpio -oc$ckey $copt" '2> err.head ; echo $? > stat.head ; } | {' $bdd of=$mdev obs=5k  2> err.dd '; echo $? > stat.dd ; }' >> $report
X				echo           find $headlist -print "| { cpio -oc$ckey $copt" '2> err.head ; echo $? > stat.head ; } | {' $bdd of=$mdev obs=5k  2> err.dd '; echo $? > stat.dd ; }'
X				: ;            find $headlist -print  | { cpio -oc$ckey $copt   2> err.head ; echo $? > stat.head ; } | {  $bdd of=$mdev obs=5k  2> err.dd  ; echo $? > stat.dd ; }
X			;;
X			*dump*true)
X				echo         \#\{ tar cfb - 20 $headlist 2> err.head '; echo $? > stat.head ; }               | {' $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }' >> $report
X				echo           \{ tar cfb - 20 $headlist 2> err.head '; echo $? > stat.head ; }               | {' $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }'
X				echo $pr: demo \{ tar cfb - 20 $headlist 2> err.head '; echo $? > stat.head ; }               | {' $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }'
X			;;
X			*dump*)
X				#echo         \#\{ tar cfb - 20 $headlist 2> err.head '; echo $? > stat.head ; }               | {' $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }' >> $report
X				#echo           \{ tar cfb - 20 $headlist 2> err.head '; echo $? > stat.head ; }               | {' $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }'
X				#: ;             { tar cfb - 20 $headlist 2> err.head  ; echo $? > stat.head ; }               | {  $bdd of=$mdev obs=10k 2> err.dd  ; echo $? > stat.dd ; }
X				echo         \#\{ tar cfb $tarhead 20 $headlist 2> err.head '; echo $? > stat.head ; }               ; {' cat $tarhead | $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }' >> $report
X				echo           \{ tar cfb $tarhead 20 $headlist 2> err.head '; echo $? > stat.head ; }               ; {' cat $tarhead | $bdd of=$mdev obs=10k 2> err.dd '; echo $? > stat.dd ; }'
X				: ;             { tar cfb $tarhead 20 $headlist 2> err.head  ; echo $? > stat.head ; }               ; {  cat $tarhead | $bdd of=$mdev obs=10k 2> err.dd  ; echo $? > stat.dd ; }
X#				{ tar cfb $tarfile 20 $headlist 2> err.head  ; echo $? > stat.head ; }               ; {  $bdd if=$tarfile of=$mdev obs=20b 2> err.dd  ; echo $? > stat.dd ; }
X			;;
X			esac
X			cat err.head err.dd | tee -a $report
X			hfstat=`cat stat.head``cat stat.dd`
X			# if the disk holding $bhdir fills up, $hfstat could
X			# be a null string, and "sh" treats a null string
X			# as numerically equal to zero, so test carefully
X			if test -z "$hfstat" ; then
X				echo "$pr: The disk holding $bhdir"
X				echo "$pr: is probably full."
X				df $bhdir	# works on most newer UNIX's
X				echo "$pr: Please consult a UNIX sysadmin."
X				echo "$pr: Quitting."
X				exit 1
X			# else if $hfstat is "00" we are ok
X			elif test "$hfstat" -eq 0 ; then
X				break
X			# else we've got a problem
X			else
X				echo "$pr: Something went wrong with putting the $headprog header archive"
X				echo "$pr: on the $media.  Check:"
X				eval "$CHKMWRITE"
X				eval "$EXITQ"
X			fi
X		done
X	fi
X
X	# put backups on tape, and keep track of which filesystems are on
X	# which tapes
X	voln=1			# volume number of cart/dat/tape/tk/video
X	sumrecin=0		# sum of dd output records for cpio archives
X	obleft=$maxocount	# number of output blocks left on media
X	nearend=false		# are we so near the end of the media that
X				# we have to change tapes
X	echo $sumrecin $obleft > $pass	# initialize $pass
X	/bin/rm -f $firstblist
X	for fsdev in $devlist ; do
X		eval "$FSNNPLUS1"
X		eval "$MDEV"
X		case $fsbkp in
X		# occasionally we back up a directory
X		false)
X			fs=$fsdev
X		;;
X		# but normally we're backing up a filesystem
X		*)
X			# get $fs from $dft2 - if we're backing up a filesystem
X			# listed in $nobkp, $fs will be in $dft2 but not $dfout
X			fs=`egrep "^$fsdev[ 	]" $dft2 | awk '{print $NF}'`
X		;;
X		esac
X		echo "$pr: ================================backup>>> $fs"
X
X		# if we're using some version of dump
X		case $bprog in
X		*dump*)
X			# special code for  NonStop-UX4.0 which has both
X			# vxfs and ufs filesystem types: choose which dump
X			# to use ufsdump or vxdump.
X			case "$OS_S$OSLEVEL_S" in
X			NonStop-UX4.0)
X				fstype=`awk '/^#/ {next} ; $3 == "'$fs'" {print $4}' /etc/vfstab`
X				case $fstype in
X				ufs)	bprog=$DUMP_P ;;
X				vxfs)	bprog=/sbin/vxdump ;;
X				esac
X			;;
X			esac
X			# echo the backup command - trickier than you'd think!!
X			# we need the x=`echo ...` to get the desired evaluation
X			# the first sed expression compresses whitespace to one
X			# space, the second one puts a backquote in front
X			# of every single shell-special character we might see
X			# in $bcmd, the third puts single quotes around $! in
X			# case we are dumping to standard out
X			x=`echo $bcmd | sed -e 's/[ 	][ 	]*/ /g' -e 's/[&;|>]/\\\\&/g' -e "s/\$\!/'\$\!'/"`
X			eval echo "$pr: $x"
X			eval echo "\#bcmd: $x" \>\> $report
X 
X			# if we're rdumping to a disk file on another host
X			# then make sure it exists, since SunOS, Solaris,
X			# and perhaps other rdump's seem to require the
X			# file to exist before it can open the file for
X			# writing the dump archive.
X			case $bprog$mtype in
X			*dump*file|*dump*dir)
X				if test $mhost != $lhost ; then
X					$rsh $mhost touch $mdev
X				fi
X			;;
X			esac
X
X			# now do it for real (but sync twice first just in case)
X			sync ; sync
X			# if we were dumping to a tape or diskfile
X			if test -z "$diskfile" -o "$diskfile" != "-" ; then
X				eval $bcmd		# do dump in forground
X				eval bstat$fsnn=$?	# get exit status
X			# else we're dumping to standard out
X			else
X				eval $bcmd		# do dump in background
X				wait $bpid		# wait for it
X				eval bstat$fsnn=$?	# exit status from wait
X				echo $epre "$pr: Killing 'tail' on b.$fsnn.out: "$esuf
X				kill -9 $tailpid 2> /dev/null	# kill tail
X			fi
X			# If we couldn't read/write dumpdates, then fix,
X			# report, and break out of filesystem loop.  If
X			# it happened when trying to update dumpdates,
X			# this is the best we can do because dump has
X			# already written the entire archive before
X			# trying the update.  We might handle this earlier
X			# with $HACK4HPUX8, but probably not.
X			updateprob=`egrep '/etc/dumpdates: Permission denied' b.$fsnn.out`
X			if test -n "$updateprob" ; then
X				echo "$pr: There were permissions problems reading or writing /etc/dumpdates."
X				echo "$pr: Permissions were (using 'ls -l /etc/dumpdates'):"
X				echo "$pr: `ls -l$LSGROUP_K /etc/dumpdates`" | tee -a $workdir/$report
X				chmod 664 /etc/dumpdates
X				chgrp operator /etc/dumpdates
X				echo "$pr: Fixed permissions are now:"
X				echo "$pr: `ls -l$LSGROUP_K /etc/dumpdates`" | tee -a $workdir/$report
X				echo "$pr: Try the backup again - it should work next time."
X				# break out of loop so we can do postprocessing
X				break
X			fi
X			# If we couldn't read the actual device we're dumping,
X			# then fix and try the dump again.  This strategy works
X			# because we know dump hasn't moved the tape.
X			permprob=`egrep '[cC]annot open' b.$fsnn.out`
X			if test -n "$permprob" ; then
X				# actual device dumped is often raw device, but
X				# can be block device under some configurations
X				# like DGUX with disk-spanning filesystems
X				actualdev=`echo $permprob | awk '{print $NF}'`
X				if test -n "`echo $actualdev | egrep '^/dev/[-a-zA-Z0-9_:/]*$'`" ; then
X					echo "$pr: NOTE: There were permissions problems reading the actual device."
X					echo "$pr: Permissions were (using 'ls -l$LSGROUP_K $actualdev'):"
X					echo "$pr: `ls -l$LSGROUP_K $actualdev`" | tee -a $workdir/$report
X					chgrp operator $actualdev
X					chmod g+r $actualdev
X					echo "$pr: Fixed permissions are now:"
X					echo "$pr: `ls -l$LSGROUP_K $actualdev`" | tee -a $workdir/$report
X					echo "$pr: Trying the dump again."
X					mv b.$fsnn.out b.$fsnn.out.prob
X					sync ; sync
X					eval $bcmd
X					eval bstat$fsnn=$?
X				fi
X			fi
X		# else we're using cpio - much trickier than dump/rdump
X		;;
X		cpio)
X			# There's a ton of stuff to do here as a frontend
X			# to cpio.  As much as possible, we basically have
X			# to do everything that BSD dump does.
X
X			## The first BIG problem is to generate a list of files
X			# for $fs *only*.  This list has to exclude any
X			# filesystem mounted on top of the one we're backing
X			# up, e.g. we exclude "/usr" if we're backing up "/".
X			# We also exclude anything in $nobkp if it exists.
X			# Once the list is generated we can basically do:
X			# "cd $fs ; find $top $stayinfs $newer | fgrep -v -f $filter"
X			# This requires adding a leading "X" and trailing "/" in
X			# each dir/fs name.
X
X			# First, build $filter to screen mounted subdirs
X			# and anything relevant in $nobkp from list.
X			# We're trying to create list of *excluded* stuff here.
X			# Use $dft2, not $dfout, since it has all filesystems.
X			cd $workdir
X			case "$fs$fsbkp" in
X			# we're backing up the root filesystem
X			/true)
X				# egrep -v filters root, awk appends "/"
X				egrep -v "^$fsdev[ 	]" $dft2 \
X				| awk '{print $NF"/"}' > $filtert1
X				if test -r $nobkp ; then
X					cat $nobkp >> $filtert1
X				fi
X				# AIX 3.2 cpio does "exit 2" if it sees devices,
X				# AIX 3.[01] cpio does "exit 0" but complains
X				# if it sees devices,
X				case "$OS_S" in
X				AIX)	echo /dev >> $filtert1 ;;
X				esac
X				# sed substitutes leading "X" and trailing "/"
X				sed -e 's,^/,X,' -e 's,[^/]$,&/,' $filtert1 > $filter
X			;;
X			# we're backing up some other filesystem
X			*true)
X				# awk appends "/", egrep matches for $fs,
X				# next egrep -v filters $fs itself
X				# Second egrep can't be grep because
X				# a bug in AIX 2.2.1 grep -v yields a
X				# newline when it's input is empty!
X				# Bummer because Ultrix 2.0 egrep -v
X				# has the same bug.
X				awk '{print $NF"/"}' $dft2 \
X				| egrep    "^${fs}/" \
X				| egrep -v "^${fs}/$" > $filtert1
X				if test -r $nobkp ; then
X					# sed appends "/", egrep matches $fs
X					# egrep -v filters $fs itself
X					sed -e 's,$,/,' $nobkp \
X					| egrep    "^$fs/" \
X					| egrep -v "^$fs/$" >> $filtert1
X				fi
X				# sed substitutes "X" for $fs"/"
X				sed -e "s,^$fs/,X," $filtert1 > $filter
X			;;
X			# $fs isn't a filesystem so create an empty $filter
X			*)
X				> $filter
X			;;
X			esac
X
X			# Second, put list of files at the top level of $fs
X			# in $top
X			#
X			# sneaky: .?* matches because ".." always exists
X			# Pray there aren't too many files at top level of $fs.
X			# (This could be made slightly more efficient, but
X			# save that for later.)
X			# Anyway, take our first cut at $top:
X			top=`cd $fs ; echo .?* * | sed -e 's/\.\.//'`
X			# if $filter has real stuff in it then use it to
X			# strip mounted filesystems from $top.
X			if test -s $filter ; then
X				# Create $topfilter: the sed removes two-plus
X				# level subdirs (with two slashes) since it's
X				# too hard to deal with filtering those,
X				# and changes trailing "/" to "X" for fgrep
X				# which doesn't support metacharacters
X				sed -e '/\/.*\//d' -e 's,^.\(.*\)/$,X\1X,' $filter > $topfilter
X				# Needed the following "if test ..." to
X				# deal with HP-UX's fgrep -v, which fails if
X				# handed a null filter file.  But what the
X				# heck, this is smarter anyway.
X				if test -s $topfilter ; then
X					# "for" echo's X${i}X thru fgrep filter
X					# thru sed to strip "X"s through
X					# awk to merge back into one line
X					for i in $top ; do echo X${i}X ; done \
X					| fgrep -v -f $topfilter \
X					| sed -e 's/^X\(.*\)X$/\1/' \
X					| awk '{printf "%s ", $1}' > $toplist
X					top=`cat $toplist`
X				fi
X			fi
X
X			# Third, start $flist (list of files to be backed up).
X			# Begin with hard-coded paths for $report and $flist;
X			# we have to do this for ease of cpio file restoration.
X			# Unfortunately, this means that we can only run one
X			# backup at a time.
X			echo "$pr: generating list of files to put in cpio archive for $fs"
X			echo /usr/tmp/$report	>  $flist
X			echo /usr/tmp/$flist	>> $flist
X
X			# Fourth, put list of files we're backing up into $flist
X			# If we're doing an incremental of $fs, find out when
X			# it's last successful full backup was.
X			newer=''
X			if test $mode = incr ; then
X				lastfull=`grep '^full[ 	].*[ 	]'$fs'[ 	]*$' $bdatef | awk '{print $2}'`
X				if test -n "$lastfull" ; then
X					touch $lastfull $touchf
X					if test $? -ne 0 -o ! -f $touchf ; then
X						echo "$pr: Something went wrong with creating the touch file.  Quitting."
X						exit 1
X					fi
X					newer="-newer $touchf"
X				fi
X			fi
X			# try to force "find" to stay in the filesystem
X			# use $FINDXDEV_S if we have it, else try "FINDFSTYPE_S"
X			if   test -n "$FINDXDEV_S"   ; then
X				stayinfs=$FINDXDEV_S
X			elif test -n "$FINDFSTYPE_S" ; then
X				stayinfs=$FINDFSTYPE_S
X			else
X				stayinfs=''
X			fi
X			cd $fs
X			# get the start date of this backup
X			# we'd like datecpio to be able to set to the nearest
X			# second, unfortunately although date can report it
X			# that way Sys V touch can't set it that way.  Drat.
X			datecpio=`date '+%m%d%H%M%y%t%a %h %d %H:%M 19%y'`
X			# ideally we'd sort the output from find, but it
X			# could be too big for sort to handle which would
X			# be a bummer.
X			# At last, we can use $top and $filter to generate
X			# flist:
X			if test -s $workdir/$filter ; then
X				# sed's add and strip an "X" for fgrep filter
X				find $top $stayinfs $newer -print | sed -e 's/^/X/' | fgrep -v -f $workdir/$filter | sed -e 's/^X//' >> $workdir/$flist
X			else
X				find $top $stayinfs $newer -print >> $workdir/$flist
X			fi
X			rm -f $touchf
X
X			# Fifth and last, put $report and $flist into /usr/tmp
X			# where we're planning to back them up *first*!
X			# just in case we can save some space, try to hardlink
X			# them to /usr/tmp - don't want to archive a symlink!
X			# Remove them from /usr/tmp to prep for link attempt.
X			echo "#cpio archive of '$fs' filesystem" >> $workdir/$report
X			rm -f /usr/tmp/$flist /usr/tmp/$report
X			ln    $workdir/$flist $workdir/$report /usr/tmp 2> /dev/null \
X			|| cp $workdir/$flist $workdir/$report /usr/tmp
X			# need to do this because /usr/tmp may not have enough room for $flist
X			if test $? -ne 0 ; then
X				echo "$pr: 'cp $workdir/$flist /usr/tmp' failed" | tee -a $workdir/b.$fsnn.out
X				echo "$pr: Backup of '$fs' ABORTED, need more room in /usr/tmp." | tee -a $workdir/$b.$fsnn.out
X				break
X			fi
X
X			## The second BIG problem is that our backup may not
X			# fit on the media.  So we have to pipe the cpio into
X			# a while loop which manages the process of changing
X			# tapes and writing the archive onto the media.
X			fsvoln=1	# volume number for cpio archive of *this* filesystem
X			recinint=	# dd records in (integer truncation)
X			recoutint=	# dd records out (integer truncation)
X			# get info from initialization or "| while" loop
X			set `cat $pass`
X			sumrecin=$1
X			obleft=$2
X			## if earlier cpio archives filled up most of the
X			# current volume, change the media.
X			# "100" is an arbitrary small number
X			if test $obleft -lt 100 ; then
X				# we use nearend later when tracking the
X				# number of volumes in the backup
X				nearend=true
X				voln=`expr $voln + 1`
X				sumrecin=0
X				obleft=$maxocount
X				eval "$REW"
X				echo "$pr: Please put in $media volume $voln"
X				eval "$BREAKQ"
X			fi
X			cd $fs
X			# have to use a file to record cpio and dd exit status
X			# This is weird: "{ date ; x=$? ; } ; echo $x" works
X			# but "{ date ; x=$? ; } | cat ; echo $x" fails
X			# We'll break out of the while when we're done or if
X			# the user says to quit
X			echo "$pr: dd'ing archive of '$fs' onto filesystem volume $fsvoln"
X			echo "$pr: { cpio -oc$ckey < /usr/tmp/$flist 2> $workdir/err.cpio ; echo \$? > $workdir/stat.cpio ; } \\"
X			echo "$pr: | while : ; do"
X			{ cpio -oc$ckey < /usr/tmp/$flist 2> $workdir/err.cpio ; echo $? > $workdir/stat.cpio ; } \
X			| while : ; do
X				cd $workdir
X				## but do some initial media checking first
X				# if we're not an alldisks then it's OK for us
X				# to check media for write protection or
X				# other problems.
X				# If we *are* doing an alldisks, it would still
X				# be OK to check if we're at the beginning
X				# of a tape, but since I don't know what
X				# happens when cpio hits EOT there's no way
X				# to test for this (yet).
X				if test $mdev = $rewdev ; then
X					eval $SHOWDD Make sure we can write to this volume
X					$bdd if=$mtestf1 bs=$obs of=$rewdev count=1  2> err.dd
X					if test $? -ne 0 ; then
X						cat err.dd | tee -a b.$fsnn.out
X						eval "$CHKMWRITE"
X						eval "$BREAKQ"
X						# continue if we don't break out
X						continue
X					fi
X				fi
X
X				# if it's a cart, test it for density (ftpi)
X				# compatibility.  We do this by trying to write
X				# thirty blocks to the cart.  If this fails
X				# we have a problem.  Empirical tests show that
X				# it will fail within eighteen blocks (and
X				# more often with fourteen or even seven),
X				# but we'll write thirty just to make sure.
X				# Also, only do this if it's a onedisk.
X				# We may never get here but if we do this
X				# test is very important.
X				if test $mtype = cart -a $mdev = $rewdev ; then
X					# write it to cart (use conv=sync in
X					# case we fill up /tmp so it's not 150k)
X					eval $SHOWDD Try to write 150k test file to $media to check density
X					$bdd if=$mtestf4 bs=$obs of=$rewdev count=30 conv=sync 2> err.dd
X					if test $? -ne 0 ; then
X						cat err.dd | tee -a b.$fsnn.out
X						echo "$pr: Your $mtype is incompatible with"
X						echo "$pr: the density of drive $mhost:$media."
X						echo "$pr: Replace your $mtype with a 12,500ftpi $mtype."
X						eval "$BREAKQ"
X						# continue if we don't break out
X						continue
X					fi
X				fi
X
X				## ok, now we're finally putting the cpio
X				## archive on the media
X				icount=`expr $obleft \* $obs / $ibs`
X				# if we're writing to a local archive
X				if test $MHOST = $LHOST ; then
X					echo "$pr:		$bdd of=$mdev ibs=$ibs obs=$obs count=$icount 2> err.dd"
X					eval $SHOWDD Putting archive on this volume
X					$bdd of=$mdev ibs=$ibs obs=$obs count=$icount 2> err.dd
X					bddstat=$?
X				# else we're doing backup over the net
X				# we have to split up archive into 1k blocks
X				# before sending it over the net
X				else
X					realmhost=$MHOST
X					eval $SHOWDD Putting archive on this volume,
X					eval $SHOWDD using one to split and the other to join
X					echo "$pr:		{   MHOST=$LHOST     ; $bdd          ibs=5k obs=1k   count=$icount 2> err.split ; echo \$? > stat.split ; } \\"
X					echo "$pr:		| { MHOST=$realmhost ; $bdd of=$mdev ibs=1k obs=$obs               2> err.join  ; echo \$? > stat.join  ; }"
X					{   MHOST=$LHOST     ; $bdd          ibs=5k obs=1k   count=$icount 2> err.split ; echo $? > stat.split ; } \
X					| { MHOST=$realmhost ; $bdd of=$mdev ibs=1k obs=$obs               2> err.join  ; echo $? > stat.join  ; }
X					splitstat=`cat stat.split`
X					joinstat=`cat stat.join`
X					bddstat=$splitstat$joinstat
X					# try to ignore data from split
X					grep 'records in'  err.split >  err.dd
X					grep 'records out' err.join  >> err.dd
X				fi
X				# pass info to parent shell
X				echo $bddstat > stat.dd
X				cat err.dd >> b.$fsnn.out
X				echo $fs volume $fsvoln dd status: $bddstat >> b.$fsnn.out
X				# the semicolon in the awk shouldn't be needed,
X				# but the AIX 3.1 version requires it
X				recinint=` awk -F+ '$2 ~ /records in/  && $1 ~ /^[0-9][0-9]*$/ {x=$1} ; END {if (x == "") x=0 ; print x}' err.dd`
X				recoutint=`awk -F+ '$2 ~ /records out/ && $1 ~ /^[0-9][0-9]*$/ {x=$1} ; END {if (x == "") x=0 ; print x}' err.dd`
X				rm -f err.dd
X				# if we had a problem or this filesystem is done
X				if test $bddstat -ne 0 -o $recoutint -ne $obleft ; then
X					sumrecin=`expr $sumrecin + $recinint`
X					# if we had a problem with this
X					# filesystem, change the media
X					if test $bddstat -ne 0 ; then
X						obleft=0	# force change
X					# else we're ok
X					else
X						# this is a holdover from when we supported different block sizes,
X						# but it could be simplified to:
X						# obleft=`expr $maxocount - $sumrecin`
X						obleft=`expr $maxocount - \( $sumrecin \* $ibs / $obs \)`
X					fi
X					# pass info from this "| while"
X					# subshell to its parent
X					echo $sumrecin $obleft > $pass
X					if test $bddstat -eq 0 ; then
X						break
X					else
X						errs='err.split err.join err.dd'
X						for err in $errs ; do
X							if test -f $err ; then
X								echo $err
X								cat $err
X							fi
X						done
X						echo "$pr: Backup of '$fs' volume $fsvoln ABORTED." | tee -a b.$fsnn.out
X						# exit of "| while" subshell
X						# should abort only this
X						# filesystem
X						exit 1
X					fi
X				# else we need to change volumes for this filesystem
X				else
X					sumrecin=0
X					obleft=$maxocount
X					# pass info from this "| while"
X					# subshell to its parent
X					echo $sumrecin $obleft > $pass
X					# make sure the media gets rewound
X					eval "$REW"
X					fsvoln=`expr $fsvoln + 1`
X					# emulate dump's "Change Volumes" message
X					echo "$pr: Change Volumes: put in filesystem '$fs' volume $fsvoln" | tee -a b.$fsnn.out
X					eval "$BREAKQ"
X				fi
X			done
X			# end of "| while" loop
X			echo "$pr: done"
X			# attempt to put cpio archive on $media is done.
X
X			## finish up the work for this cpio archive
X			cd $workdir
X			# show the user cpio's message if any
X			cat err.cpio
X			cat err.cpio >> b.$fsnn.out
X			cpiostat=`cat stat.cpio`
X			# The AIX 3.2 version of cpio has several "features"
X			# 1) it won't back up special files or FIFOs (named
X			# pipes); when asked to do so it exits with
X			# status "2" and says something like:
X			#	cpio: special file <ingres/log/ingres_log> not archived
X			# 2) if cpio is asked to back up a file which doesn't
X			# exist, it exits with status "2" and says roughly:
X			#	< tmp/Ex20006 > ?
X			# (Other versions of cpio complain about missing files
X			# but still exit with status 0.)
X			# If these are the only problem in the logs, we can
X			# safely "lie" about the exit status of the cpio
X			# process.  Lines we don't worry about in err.cpio
X			# under AIX 3.x look like this:
X			#	cpio: special file <ingres/log/ingres_log> not archived
X			#	< tmp/Ex20006 > ?
X			#	cpio: 0511-025 Cannot get information about /ingres/data/default/replicatedb/aaaaabgn.t00
X			#	10 blocks
X			# Hopefully, err.cpio includes only lines we don't
X			# worry about.
X			case $OS_S$cpiostat in
X			AIX2)
X				nlines=`wc -l < err.cpio`
X				nottoworry=`egrep -c '^[0-9]* blocks$|special file' err.cpio`
X				missingfiles=`awk '
X					/^< .+ > \?$/ {print $2}
X					/cpio: .*special file <.+> not archived/ {print substr($4,2,length($4)-2)}
X					/cpio: .*Cannot get information about / {print $NF}'
X				' err.cpio`
X				# make sure any supposedly missing files
X				# are really missing
X				x=0
X				if test -n "$missingfiles" ; then
X					cd $fs
X					for f in $missingfiles ; do
X						test ! -f $f && x=`expr $x + 1`
X					done
X					cd $workdir
X				fi
X				nottoworry=`expr $nottoworry + $x`
X				if test $nlines -eq $nottoworry ; then
X					cpiostat=0
X				fi
X			;;
X			esac
X			echo $fs cpio status: $cpiostat >> b.$fsnn.out
X			cpiostat=$cpiostat`cat stat.dd`
X			rm -f err.cpio
X			eval bstat$fsnn=$cpiostat
X			# if cpio is successful and we're updating
X			if test $cpiostat -eq 0 -a $update = true ; then
X				if test -f $bdatef ; then
X					# the sed is a tad clumsy because $fs
X					# has slashes in it
X					sed -e 's,^'$mode'[ 	].*[ 	]'$fs'[ 	]*$,,' -e '/^[ 	]*$/d' $bdatef > $bdatef.tmp
X				fi
X				echo "$mode	$datecpio	$fs" >> $bdatef.tmp
X				sort +7 -8 +0 -1 $bdatef.tmp > $bdatef
X				rm -f $bdatef.tmp
X			fi
X		;;
X		esac
X
X		## Kevin Malloy put this in - I suppose it's needed
X		if test "$OS_S" = dgux ; then
X			sleep 60
X		fi
X
X		## warn about known problems in this backup (see $KNOWNPROBS
X		## and $KNOWNFALSEPROBS)
X		bprogerr="`fgrep -f $problist b.$fsnn.out | fgrep -v -f $falseprob`"
X		test -n "$bprogerr" && bprogerr="	$bprogerr"
X		eval echo \""\$bstat$fsnn	$fsdev	$fs$bprogerr"\" \>\> $statlist
X
X		## report on first backups on each tape as we go along
X		# We don't care about media write errors on the first
X		# backup since that only means the tape was bad or
X		# too short.  The operator just restarts these, which
X		# doesn't add a new volume to the set.
X		if test $fsnn -eq 1 ; then
X			echo "Volume '$voln': First backup is $fs" >> $firstblist
X		# else if this backup is a dump and it got media write errors,
X		# then it started in the middle of the media and had to be
X		# restarted with a new volume.  It's important to get
X		# dump's "write error" message right.
X		# Some message types (with samples from the listed OS):
X		# Pyramid OSx, Ultrix 2.0/3.0, SunOS 3.2:
X		# 	DUMP: Write error on tape 4
X		# CCI SysV, Gould UTS 2.1a, Pyramid OSx, Seguent DYNIX:
X		# 	DUMP: Tape write error on tape 1
X		# 4.3BSD, CCI BSD, Mt. Xinu BSD, SunOS 4.X:
X		# 	DUMP: Tape write error 277 feet into tape 4
X		# 	DUMP: Write error on tape 1
X		# Bull B.O.S. 02.00:
X		#	FSDUMP: Tape write error 815 feet into tape 1
X		# SVR4 variants from NCR and ???:
X		#	UFSDUMP: ?????
X		# SVR4 variants from Pyramid:
X		#	UFSDUMP: Tape write error: EOT (end of tape) encountered 419 feet into tape1
X		# DG/UX says
X		#	write: No space left on device
X		#	Error writing tape: Address already in use
X		# but notice that it does *not* say "DUMP: whatever".
X		# We rely on this.
X		# cpio - don't know what this looks like, maybe we avoid anyway
X		elif egrep 'DUMP:.* [Ww]rite error:* .* tape *[1-9]' b.$fsnn.out > /dev/null ; then
X			voln=`expr $voln + 1`
X			echo "Volume '$voln': First backup is $fs" >> $firstblist
X		# else we are doing a cpio alldisks backup and we got so close
X		# to the end of the media that we had to prompt for a new one
X		# before this cpio archive could start
X		elif test "$nearend" = true ; then
X			echo "Volume '$voln': First backup is $fs" >> $firstblist
X			nearend=false
X		fi
X		# else do nothing - this backup started in the middle
X		# of the media but did not run out room.
X
X		## Did this backup take more than one volume?  In other
X		## words, was it continued onto the next tape?
X		# This can happen if:
X		# a) we're doing a onedisk backup that won't fit on one tape
X		# b) we're doing an alldisks backup using cpio
X		# c) we're doing an alldisks backup using a version of dump
X		# that knows how to handle EOT (e.g. DG's "dump2" and
X		# Solaris 2.X "ufsdump")
X		# d) we're doing an incremental alldisks backup, and an
X		# incremental of one of the filesystems is too big to fit
X		# on one tape
X		#
X		# The key is to look for the following messages in
X		# the b.$fsnn.out file:
X		# This alldisks script says "Change Volumes",
X		# SunOS 4.0.3 and Solaris 2.2 say "Change Volumes" too,
X		# OSF from DEC says "Change Cartridges",
X		# DG's "dump2" says "dump2: Time to change tapes." - dump2
X		# does this even when it hits EOT on a video drive when using
X		# using the -M option - gads!
X		# Solaris 2.2 ufsdump says:
X		# DUMP: End-of-tape detected
X		# DUMP: Change Volumes: Mount volume #N
X		# All others say "Change Tapes." when it's time to start the
X		# next tape.
X		#
X		# Unfortunately, some versions of dump say "Change Tapes"
X		# when they are rewriting the volume, too:
X		# ULTRIX V3.1 dump gets a -SIGTERM, it says
X		#	DUMP: SIGTERM()  try rewriting
X		#	DUMP: Rewriting attempted as response to unknown signal.
X		#	DUMP: Change Tapes: Mount tape #1
X		#
X		# Pyramid's OSx "dump" says:
X		#	DUMP: Tape write error on tape 1
X		#	.....
X		#	DUMP: replace the faulty tape with a new one;
X		#	DUMP: this dump volume will be rewritten.
X		#	DUMP: Change Tapes: Mount tape #1
X		#
X		# Pyramid's SVR4 OSx "ufsdump" says:
X		#	UFSDUMP: Tape write error: EOT (end of tape) encountered 419 feet into tape1
X		#	UFSDUMP: NEEDS ATTENTION: Do you want to restart?: ("yes" or "no")
X		#	UFSDUMP: This tape will rewind.  After it is rewound,
X		#	UFSDUMP: replace the tape and this dump volume will be rewritten,
X		#	UFSDUMP: or abort and restart the dump, specifying correct tape capacity.
X		#	UFSDUMP: Closing tape device
X		# Note that if it hits premature EOT,
X		# it never says   "Change Tapes: Mount tape #1",
X		# but it does say "Change Tapes: Mount tape #2" (and 3, 4, ...)
X		# and it also says "will be rewritten"
X
X		# So, we have to get rather tricky.
X		x=`egrep -c 'Change Tapes|Change Volumes|Change Cartridges|change tapes' b.$fsnn.out`
X		y=`egrep -c 'try rewriting|will be rewritten' b.$fsnn.out`
X		z=`egrep -c 'Mount tape #1' b.$fsnn.out`
X		if test $y -eq 1 -a $z -eq 0 ; then
X			y=0
X		fi
X		x=`expr $x - $y`
X		while test $x -gt 0 ; do
X			voln=`expr $voln + 1`
X			x=`expr $x - 1`
X			echo "Volume '$voln': First backup is $fs (continued)" >> $firstblist
X		done
X	done
X	## finished with writing backup to media!!
X
X	## do $REW/$OFFLINE as soon as loop finishes so user doesn't
X	## have to wait
X	# if we're verifying this backup, rewind now, take it offline
X	# after the verify completes
X	if test $verifytoo = true ; then
X		eval "$REW" 
X	# else do $OFFLINE work in "/" in case user wants to
X	# umount a filesystem we may have just backed up
X	# and do it in background so operator doesn't have to wait as long
X	else
X		cd /		
X		eval "$OFFLINE" &
X	fi
X	cd $workdir		# now finish up in $workdir
X	echo "Volume '$voln': Last volume." >> $firstblist
X	rm -f $pass
X
X	## generate report for mailing to $rptto.  Report to include:
X	# put standard out in $report
X	exec 1>> $report
X	echo "#lhost	mhost	mode	media	mdevbase	multi	OPER	voln	hfstat"
X	# print variables (if $hfstat is set use it else substitute "NA")
X	echo "$lhost	$mhost	$mode	$media	$mdevbase	$multi	$OPER	$voln	${hfstat-NA}"
X	cat $statlist $firstblist
X	if test -s $nobkptmp ; then
X		sed -e 's/^\[[	 ]*\]\(.*\)\$/#Not backed up: \1/' $nobkptmp
X	fi
X	echo "#End time:   `date`"
X	exec 1>&9
X
X	## mail semi-final backup report to $rptto
X	eval "$MAILRPT"
X
X	## get operator info - known problems and operator report
X	# Give BIG warning message if we had problems (see $KNOWNPROBS)
X	# exit status 0 or 1 are OK for dump, but exit status 1 bad for cpio
X	awk '
X		BEGIN {bprog="'$bprog'"} # get $bprog
X		$0 ~ /^\#bstat/ {next}	# skip header if any
X		NF != 3 {print; next}	# we have known problems
X		$1 >  1 {print; next}	# exit status > 1 always bad
X		$1 == 1 && bprog ~ /cpio/ {print; next}	# status 1 bad for cpio
X	' $statlist > $statprob
X	# if we have no problems, clean up
X	if test ! -s $statprob ; then
X		rm -f $statprob $probsent
X	# else report them if we have to
X	else
X		# foreach problem filesystem
X		grep '^[0-9][0-9]*	' $statprob \
X		| while read probstat probfs probdir probdes ; do
X			# if the problem has been reported
X			if test -f $probsent && egrep "	$probfs	" $probsent ; then
X				: do nothing - we already tried to report it
X			# else get ready to report it now
X			else
X				echo "$wdir	$probstat	$probfs	$probdir	$probdes" | tee -a $probsend
X				# "DUMP: read error! sector 49310 of /dev/rdsk/c0t1d0s6" (Solaris 2.3 ufsdump got a block read error)
X				if egrep "$probfs.*(bread|read error!)" $statprob > /dev/null ; then
X					echo "$pr: WARNING!  Block read errors found!"
X					echo "$pr: Block read errors could mean either:"
X					echo "$pr: a) The disk has hard errors - a real bummer."
X					echo "$pr:    Check system logs with dmesg/messages/uerf/hdelogger/errpt/whatever."
X					echo "$pr: b) The disk is ok but the filesystem is corrupt,"
X					echo "$pr:    e.g. an inode is pointing at impossibly large block numbers."
X					echo "$pr:    Fix by umount'ing and fsck'ing the filesystem."
X					echo "$pr:"
X				fi | tee -a $probsend
X			fi
X		done
X		# tell operator
X		echo ''
X		echo "$pr: WARNING! The backup report shows big PROBLEMS:"
X		cat $statprob
X		echo "$pr: Please REPORT THIS to na-system !!!"
X		eval "$EXITQ"
X	fi
X
X	## finish report at last
X	if test -f $failrpt ; then
X		exec 1>> $report
X		echo "Operator '$OPER' reported that this backup failed for the following reason:"
X		cat $failrpt
X		echo ""		# make sure there's a newline
X		echo "End of Operator failure report."
X		exec 1>&9
X	fi
X	# report generation done, so put standard out back on the tty
X
X	## finish
X	if test $verifytoo != true ; then
X		echo "$pr: This backup is done."
X	else
X		echo "$pr: This backup is done; will start 'verifytoo'."
X		# if we just made a multi-volume tape set, try to take the
X		# tape offline and then tell the operator to put the
X		# first tape in the drive
X		case $mistape$voln in
X		true[2-9]|true[1-9][0-9])
X			eval "$OFFLINE"
X			echo "$pr: This backup took $voln tapes."
X			echo "$pr: Before we begin the 'verifytoo', please put"
X			echo "$pr: volume '1' of this alldisks tape set into $media."
X			eval "$MREADYQ"
X		;;
X		esac
X		extravol=`expr $voln - 1`
X		case "$multi" in
X		false)	vfsarg=onedisk ;;
X		true)	vfsarg=alldisks ;;
X		esac
X		vcmd="./$pr verify $vfsarg $marg $diskfile $extravol $wdir $childargs nomail"
X		echo ''
X		echo $vcmd | tee -a $report
X		echo ''
X		cd $hdir
X		$vcmd
X		cd $workdir
X		echo "#VerToo end: `date`" >> $report
X		# take it offline in background so user doesn't have to wait
X		eval "$OFFLINE" &
X	fi
X;;
X
X## do get or verify if that's what we're doing
Xget|verify)
X
X	## onvol by definition is "1" if it's a onedisk backup, even
X	## if the backup spanned tapes (as in a 9track backup);
X	## otherwise we set it later
X	if test $mode = verify -a $getmode = onedisk ; then
X		onvol=1
X	fi
X
X	## get number of volumes (in most cases we care but some we don't):
X	## $mode    type	do_we_care_about_$nvol_and_$onvol
X	## get	    onedisk	no_and_no: we're not autoverifying
X	## get	    alldisks	yes_and_yes: we need positioning
X	## verify   onedisk	yes_and_yes: to autoverify if we can
X	## verify   alldisks	yes_and_yes: we need positioning
X	## So, "$nvol" can be null if we're doing a get from a onedisk backup;
X	#
X	# if it's a get from a onedisk, we don't really care but user may
X	# have specified so why not?
X	if test $mode = get -a $getmode = onedisk ; then
X		nvol=$nvol
X	# else we care, so try to figure it out ...
X	# if we're getting from disk file(s), we don't really have
X	# any tapes but we need to act as if it's all on one tape
X	elif test $mtype = file -o $mtype = dir ; then
X		nvol=1
X	# else if it's a onedisk, assume it will always fit on a video tape
X	elif test $getmode = onedisk -a $mtype = video ; then
X		nvol=1
X	# else we've got to find out the number of volumes/tapes and the 
X	# name of the first filesystem on each volume/tape
X	else
X		# for any cpio backup or an alldisks backup, we need to know:
X		# while test $bprog = cpio -o $getmode = knownfs -o $getmode = listdisks -o $getmode = lastdisk -o $getmode = alldisks ; do
X		# for any onedisk or alldisks backup
X		while : ; do
X			if test -n "$nvol" ; then
X				echo "$pr: This backup set has '$nvol' volume(s)."
X			else
X				echo "$pr: How many volumes are in this backup set?"
X				echo $epre "$pr: Enter the number: "$esuf
X				eval "$READ" nvol
X			fi
X			# validate $nvol
X			if test "$nvol" -lt 1 -o "$nvol" -gt $maxvol ; then
X				echo "$pr: '$nvol' can't be correct.  Try again."
X				nvol=''
X				continue
X			else
X				extravol=`expr $nvol - 1`
X				break
X			fi
X		done
X	fi
X	# if $nvol isn't set, then we don't need to know
X	case "$nvol\X$mtype" in
X	*file|*dir)	x="$nvol (mtype=$mtype)" ;;
X	X*)		x=NA ;;
X	*)		x=$nvol ;;
X	esac
X	echo "#volumes in backup set: $x" >> $report
X
X	# if we think we're getting from a multi-filesystem backup, then
X	# extract the header archive and get positioning info
X	case $getmode in
X	knownfs|knownskip|listdisks|lastdisk|alldisks)
X		# If this is a multi-fs backup we need to extract from the
X		# tar/cpio header file, or get the necessary info from the
X		# parent directory.
X		#
X		# If we are extracting from media, make absolutely sure it
X		# succeeds, and don't continue until it does.  This is the
X		# second time we've actually tried to read from the media.
X		fsnn=00
X		eval "$MDEV"
X		cd $workdir
X		while : ; do
X			# Do tar/cpio extraction (or get $dfout from the parent)
X			# The count for the "dd" below is to make sure that
X			# we don't read a huge file if we aren't reading a
X			# header archive, which should be less than 200k.
X			case $bprog$showdd$mhost in
X			cpio*)		: ;;
X			*false*)	: ;;
X			*true$lhost)	: ;;
X			*true*)		eval $SHOWDD Get alldisks header from $mhost:$media ;;
X			esac
X			case $parent-$bprog$demo$mhost in
X			# parent is a backup called with "verifytoo"
X			*[fit]?-*)		eval "$LNFSTABLIST" ; ln ../$dfout ../$breport            . ;;
X			# parent is ordinary verify
X			*[a-z]-*)		eval "$LNFSTABLIST" ; ln ../$dfout ../$breport ../$volmap . ;;
X			# the eight choices have no parent, i.e. this an
X			# ordinary verify
X			*cpiotrue$lhost)	echo "$pr demo: cpio -icum$ckey < $mdev" ;;
X			*cpio*$lhost)		: ;		cpio -icum$ckey < $mdev  ;;
X			*cpiotrue*)		echo "$pr demo: $bdd if=$mdev bs=5k 2\> /dev/null \| cpio -icum$ckey" ;;
X			*cpio*)			: ;		$bdd if=$mdev bs=5k 2>  /dev/null  | cpio -icum$ckey  ;;
X			*true$lhost)		echo "$pr demo: tar xf $mdev" ;;
X			*$lhost)		: ;		tar xf $mdev  ;;
X			*true*)			echo "$pr demo: $bdd if=$mdev bs=10k count=20 2\> /dev/null \| tar xf -" ;;
X			*)			: ;		$bdd if=$mdev bs=10k count=20 2>  /dev/null  | tar xf -  ;;
X			esac
X			hfstat=$?
X			# if we had no problems getting $dfout
X			# note that SunOS 4.1.2 tar exits ok when it reads
X			# a dump - very strange!
X			if test "$hfstat" -eq 0 -a -s $dfout ; then
X				break
X			else
X				echo "$pr: We had some trouble extracting the header archive from the $media."
X				echo "$pr: Doing some investigating ..."
X				if test ! -s $dfout ; then
X					echo "$pr: Filesystem list '$dfout' was not extracted."
X					echo "$pr: Extracting the header archive failed.  Check:"
X					echo "$pr: -> Is the $media a 'onedisk' backup (not an 'alldisks')?"
X					eval "$CHKMEDIA"
X					echo "$pr: Quitting."
X					exit 1
X				else
X					echo "$pr: Filesystem list '$dfout' was extracted - ok so far ..."
X					echo "$pr: Doing simple checks on '$dfout' ..."
X					# $dfout should have same number of words on each line
X					isit1=`awk '{print NF}' $dfout | sort -n -u | wc -l`
SHAR_EOF
true || echo 'restore of src/backup/backup failed'
fi
echo 'End of saenv_alld part 5'
echo 'File src/backup/backup is continued in part 6'
echo 6 > _shar_seq_.tmp
exit 0
