
:
#	@(#) fsave.sh 22.2 90/03/05 
#
#	Copyright (C) The Santa Cruz Operation, 1988, 1989.
#	This Module contains Proprietary Information of
#	The Santa Cruz Operation, and should be treated as Confidential.
#
# 	fsave	Semi-automated filesystem backup
#
#
# NOTES	
# 	The tape size is decreased by $REDUCE precent, and all tape I/O	
# 	is checked for success.
# 	with non-0 statuses on error.)					
#

: ${OK=0} ${FAIL=1} ${USAGE=2} ${POSTPONED=3}
PATH=/bin:/usr/bin:/etc

REDUCE=10
BELL=
script=${0-fsave}
BACKUP="/usr/lib/sysadmin/cbackup"
BACKUP2="/usr/lib/sysadmin/cbackup"
TAPEPROG="/usr/bin/tape"
CHECKPROG1="cpio(C)"
CHECKPROG2="cpio(C)"
MESSAGE="Insert volume %d and press <RETURN> to continue or 'q' to exit."

# Print a usage message
usage() {
 	fsave filesystem [tape mediainfo] [level backupinfo] [sitename] [method]
	exit $FAIL
}

# Print an error message
error() {
	echo "\nError: $*" >&2
	return $FAIL
}

# Process arguments
checkargs() {
	case $# in
	[1-5])	FILSYS=$1
		DUMPINFO=$2
		TAPEINFO=$3
		LABEL=${4-System}
		METHOD=${5:-cpio}
		;;
	*)	usage
		;;
	esac
}

# Crack and default tape/floppy information
setmedia() {
	set not- $TAPEINFO	; shift
	TAPE=$1		; shift
	case $1 in
	k)	# floppy
		DENSITY=
		while : ; do
			shift
			case $1 in
			[0-9]*)	SIZES="$SIZES $1"
				;;
			*)	FORMAT="$*"
				break
				;;
			esac
		done
                flag=`expr "$TAPE" : ".*r\([a-z]\).*"`
                case $flag in
                f)  # floppy 
			ARCHIVE=floppy
		 	SIZES=${SIZES-1200}
		        ;; 
                c)  # cartridge tape
			ARCHIVE=tape
                	SIZES=${SIZES-"60000 125000 150000"}
                        ;;
                esac
		UNIT=Kb
                   ;;  
	d)	# magtape
		ARCHIVE=tape
		case $2 in
		[0-9]*)	DENSITY=$2
			;;
		*)	error "$script: Bad magtape density: $2"
			exit 2
			;;
		esac
		shift ; shift
		while : ; do
			case $1 in
			[0-9]*)	SIZES="$SIZES $1"
				;;
			*)	FORMAT="$*"
				break
				;;
			esac
			shift
		done
		SIZES=${SIZES-"600 450 300"}
		UNIT=feet
		;;
	"")	DENSITY=1600
		SIZES="2400 1200 600"
		FORMAT=
		;;
	*)	error "$script: Unknown media type: $1"
		exit 2
		;;
	esac
}

# Defaults for missing fields and set the date
setdefaults() {
	eval set not- "$DUMPINFO"	; shift
	LEVEL=${1-0}
	SIZE=${2--}
	SAVE=${3-"1 year"}
	VITAL=${4-important}
	MARK=${5-none}

	set `date`
	DATE="$3 $2 $6"
}

# Make sure all dependencies are present
dependencies() {
	# Make sure the FILSYS is character special 
	# if cpio'ing, block is acceptable 
	[ -c "$FILSYS" ] || [ "$METHOD" = "cpio" -a -b "$FILSYS" ] || {
			error "$script: Not a filesystem: $FILSYS"
			return $USAGE
	}
	# Make sure TAPE is character special
	[ -c "$TAPE" ] || {
			error "$script: Not a magtape or floppy drive: $TAPE"
			return $USAGE	
	}
	# Make sure backup method is known and possible for filesystem type
	FSTYPE=`fstyp $FILSYS`
	case "$METHOD" in
	cpio)	: OK
			;;
	xbackup)	if [ "$FSTYPE" != "XENIX" ]
			then
				error "$script: Cannot use xbackup on a non-XENIX\
					   filesystem: $FILSYS"
				return $USAGE
			fi
			BACKUP="/bin/xbackup"
			BACKUP2="/bin/xdump"
			CHECKPROG1="xdumpdir(1)"
			CHECKPROG2="xrestore(C)"
			;;
	*)	error "$script: Unknown or missing backup method: $METHOD"
		return $USAGE
		;;
	esac
	# Make sure they have a backup program, either /bin/xbackup, /bin/xdump
	# or /bin/cpio depending on filesystem type and requested method

	[ -x "$BACKUP" ] || {
		# no BACKUP, look for the second choice
		if [ -x "$BACKUP2" ] 
		then 	BACKUP=$BACKUP2
		else 	error "$script: Cannot find backup program"
			return $USAGE
		fi
	}
	if [ "$METHOD" = "xbackup" ]
	then
		[ -r /etc/ddate -a -w /etc/ddate ] || {
			error "$script: Missing or non-writable /etc/ddate"
			return $USAGE
		}
	fi
	if [ -r /etc/systemid ]
	then	WHERE=`cat /etc/systemid`
	else 	error "$script: WARNING -- System nameless, no /etc/systemid"
		WHERE=Unknown
	fi

}

# Process the command line information which will be passed to backup
setargs() {
	case "$LEVEL" in
	[0-9])	# Legal backup level
		;;
	[xX])	echo "Filesystem $FILSYS will not be backed up today."
		exit $OK
		;;
	*)	error "$script: Unknown backup level: $LEVEL"
		return $USAGE
		;;
	esac

	known=no
	for ft in $SIZES; do
		case $SIZE in
		-)	known=yes
			SIZE=$ft
			break
			;;
		$ft)	known=yes
			break
			;;
		esac
	done
	case $known/$DENSITY in
	yes/*)	: Ok	;;
	*)	error "$script: Invalid $ARCHIVE size: $SIZE $UNIT"
		return $USAGE
		;;
	esac
}

# Perform the backup here
dobackup() {
	GOOD=unknown
	until test $GOOD = yes; do

                echo " 
Level $LEVEL backup of filesystem $FILSYS, $DATE
	$ARCHIVE size:	$SIZE $UNIT
	$ARCHIVE drive:	$TAPE
This $ARCHIVE will be saved for $SAVE, and is $VITAL."
		case $GOOD in
		no)	error "NOTE - Repeating, since previous attempt failed."
			;;
		esac

		QUIT=no
		LEN=$SIZE
		while : ; do
			echo $BELL "
M)ounted volume, P)ostpone, C)heck or F)ormat volumes, R)etension, or H)elp: \c"
			read ANSWER ARG

			case "$ANSWER" in
			[mM])	case $ARG in
				"")	break
					;;
				esac
				found=no
				for ft in $SIZES; do
					case $ARG in
					$ft)	found=$ft
						break
						;;
					esac
				done
				case $found in
				no)	echo "
Unknown size: $ARG
Please use one of: $SIZES"
					return $USAGE
					;;
				*)	LEN=$found
					break
					;;
				esac
				;;
			[fF])	case $FORMAT in
				"")	error "Formating is not necessary for $TAPE"
					;;
				*)	$FORMAT
					;;
				esac
				;;
			[cC])	GOOD=yes
				break
				;;
			[pP])	error "Postponing this $VITAL backup of $FILSYS until later."
				case $QUIT.$VITAL in
				no.critical|no.necessary)
					echo "CAUTION - It is NOT wise to postpone a $VITAL backup!"
					;;
				*)	return $POSTPONED
					;;
				esac
				QUIT=yes
				;;
			[rR])	if [ -x $TAPEPROG ]
				then 	echo "\nRetensioning tape."
					$TAPEPROG reten
				else 	error "$TAPEPROG not present or installed."
				fi
				;;
			\?|[hH]*)	echo "
	Answer either:
	m[size]	Write-enabled volume is mounted on drive $TAPE.
	p	Postpone this backup of filesystem $FILSYS until later.
	c	(Re-)check backup volumes for errors.
	f	Format the currently mounted volume.
	r	Retension mounted cartridge tape using \"tape\".
A $VITAL backup (level $LEVEL backup) will be made.

Possible media sizes are: $SIZES
All volumes used to backup filesystem $FILSYS
must be formated and the same size.
"
				;;
			*)	error "Unknown answer (type H for help): $ANSWER"
				;;
			esac	
		done
		set `date +%H:%M`
		STRDAT="$1"
		if [ "$DENSITY" -o "$flag" = "c" ] 
		then
		   	: floppies dont vary in size
			LEN=`expr $LEN - $LEN \* $REDUCE / 100`
		fi
		case "$GOOD" in
		yes)	: Already backedup, just check that tapes are good
			;;
		*)	case $DENSITY in
			"")	[ $METHOD = xbackup ] && LEVEL=${LEVEL}kuf
				$BACKUP $LEVEL $LEN $TAPE $FILSYS
				;;
			*)	[ $METHOD = xbackup ] && LEVEL=${LEVEL}sufd
	 			$BACKUP $LEVEL $LEN $TAPE $DENSITY $FILSYS
				;;
			esac
			STATUS=$?
			case $STATUS in
			0)	# Ok
				GOOD=yes
				;;
			*)	error "WARNING -- Level $LEVEL backup of $FILSYS failed, error $STATUS"
				GOOD=no
				continue
				;;
			esac
			;;
		esac

		case $VITAL in
		critical)
			echo "Check $VITAL volumes for format errors"
			while : ; do
				echo $BELL "
M)ounted first volume, S)kip format check, or H)elp: \c"
				read ANSWER

				case "$ANSWER" in
				[mM])	case $METHOD in
					cpio)
						cpio -itC 10240 -I $TAPE -M "$MESSAGE" > /dev/null
						;;
					xbackup)
						xdumpdir f $TAPE > /dev/null
						;;
					esac
					STATUS=$?
					case $STATUS in
					0)	echo "Volume format appears to be good."
						;;
					*)	error "WARNING -- Volume format bad, error $STATUS"
						GOOD=no
						;;
					esac
					break
					;;
				[sS])	break
					;;
				\?|[hH]*)	echo "
Answer either:
	m	First volume of $FILSYS backup is mounted on drive $TAPE.
	s	Skip checking $VITAL backup volume of $FILSYS.
The format of the volume(s) will be checked, using $CHECKPROG1.
"
					;;
				*)	error "Unknown answer (H for help): $ANSWER"
					;;
				esac
			done
			;;
		esac
		case $GOOD in
		no)	continue
			;;
		esac
	
		echo "Check $VITAL volumes for read errors"
		TAPENO=first
		while : ; do
			while : ; do
      				echo $BELL "
M)ounted $TAPENO volume, E)rror on previous volume,
	D)one, S)kip checks, or H)elp: \c"
				read ANSWER

				case "$ANSWER" in
				[mM])	QUIT=no
					break
					;;
				[eE])	GOOD=no
					QUIT=yes
					break
					;;
				[sSdD])	QUIT=yes
					break
					;;
				\?|[hH]*)	echo "
Answer either:
	m	Volume $TAPENO mounted on drive $TAPE.
	e	Last volume of $FILSYS backup had a read error.
	d	All volumes done, no more to check.
	s	Skip further checking.
The $VITAL volume(s) will be checked for read errors, using $CHECKPROG2.
"
					;;
				*)	error "Unknown answer (H for help): $ANSWER"
					;;
				esac
			done
			case $QUIT.$GOOD in
			yes.*|*.no)	break
				;;
			esac
	
			echo "Checking backup archive integrity..."
			case $METHOD in
			cpio)
				cpio -itC 10240 -I $TAPE -M "$MESSAGE" > /dev/null
				;;
			xbackup)
				xrestore -Cf $TAPE $FILSYS
				;;
			esac
			STATUS=$?
			case $STATUS in
			0)	: Ok
				;;
			*)	error "WARNING -- Volume read error $STATUS"
				GOOD=no
				break
				;;
			esac
			TAPENO=next
		done
	done

	case $GOOD in
		yes)    set `date +%H:%M`
			ENDDAT="$1"
			echo "
Level $LEVEL backup started: $STRDAT
               ended: $ENDDAT

Label each media volume in the backup:
	$WHERE    level $LEVEL backup    $DATE
		      $FILSYS
	    Save until (today plus $SAVE)
        # of blocks     volume # of set

Be sure to write disable each volume\c"

		case "$MARK" in
			none)	echo ".\n "
				;;
			*)	echo ",
and to place $MARK on each volume.\n"
				;;
			esac
		return $OK
		;;
	esac
	return $FAIL
}

# main
# Check the arguments passed in by sysadmin or the human
checkargs "$@" || exit $FAIL

# Set the media information passed in TAPEINFO
setmedia || exit $FAIL

# Now make sure all the dependencies are present
dependencies || exit $?

# Set some variable default values
setdefaults || exit $FAIL

# Set up the arguments we will be passing to backup
setargs || exit $?

# Do the backup here
dobackup 
exit $?
