# set -x
#
# trestore, a shell script to simplify restoration of backups of any kind
#
#	Author	: K. Drenth
#	Date	: Mon Jan 24 08:53:34 PST 1994
#
#	Version : 1.0
#	Revision: Mon Jan 24 08:53:34 PST 1994
#	Descr.	: Initial version
#
VERSION="1.0"
PATH=/usr/bin/menu:$PATH;	export PATH
UXXOUT=/tmp/$$;			export UXXOUT
# Global variable declarations
BUPTYPE=0
CPIOLVL=""
BLKSIZE=32768
UNATTEN=0
TAPEDEV=""
TAPE_OK=1
TOCSKIP=0
ARCHIVE=""
N_ARCHS=0
NAMONLY=""
NEWONLY="u"

usage()
{
	echo '
USAGE:

trestore -vfbnduatCL

	 -v		Select Volume Backup
	 -f		Select File Backup
	 -b		Select Both Backup types 
	 -n		Enable names only readback 
	 -d		Enable newer files only 
	 -u		Run Unattended
	 -a archive(s)	Specify archive numbers to restore (Unattended only)
	 -t device	specify backup device without /dev/rmt
Note !			must be a non-rewind device !!
	 -C blocksize	Specify cpio block size
	 -L option	Specify extra cpio options
'
	exit 0
}

#
# Return an indexed parameter from input parameter list
#
index_parm()
{
	I=$1
	shift
	J=0
	for PARM in "$@"
	do
		if [ $I -eq $J ]
		then
			echo "`DeWild "$PARM"`"
			return
		fi
		J=`expr $J + 1`
	done
}

#
# Ask user for type of backup
#
ask_vol_or_files()
{
	UserSelectSingle -h"Select Type of Backup"\
			   "File(s)" "Volume(s)" "Both" "Quit"

	case `AssignUSS` in
		'File(s)'	)	BUPTYPE=1;;
		'Volume(s)'	)	BUPTYPE=2;;
		'Both'		)	BUPTYPE=3;;
		*		)	exit    1;;
	esac
}

#
# Ask user for backup device if none is specified yet
#
ask_tapedev()
{
	if [ "$TAPEDEV" = "" ]
	then
		TAPEDRIVES=`/bin/ls /dev/rmt | grep -v 0`

		UserSelectSingle -h"Select Tapedrive" $TAPEDRIVES

		TAPEDEV=`AssignUSS`
		if [ "$TAPEDEV" = "EsCaPeD" ]
		then
			exit 1
		fi
		clear
	fi

# try to test if the tapedrive is ready and on-line
	STATUS=`mt -t /dev/rmt/$TAPEDEV status | grep er=`

	if [ "$STATUS" != "er=0" ]
	then
		UserSelectSingle -h"Tapedrive not OK $STATUS, continue ?" No Yes

		NOYES=`AssignUSS`
		if [ "$NOYES" = "No" ] || [ "$NOYES" = "EsCaPeD" ]
		then
			exit 1
		fi
		TAPE_OK=0
	else
		TAPE_OK=1
	fi
	sleep 1
}

#
# Ask user if only newer files to be restored
#
ask_newer_only()
{
 	DEF=0
	if [ "$NEWONLY" = "" ]
	then
		DEF=1
	fi
	UserSelectSingle -h'Restore NEWER files only ?' -d"$DEF" "No" "Yes"

	case `AssignUSS` in
		'No'	)	NEWONLY=u;;
		'Yes'	)	NEWONLY="";;
		*	)	exit    1;;
	esac
}

#
# Ask user if only newer files to be restored
#
ask_list_names()
{
 	DEF=0
	if [ "$NAMONLY" = "t" ]
	then
		DEF=1
	fi
	UserSelectSingle -h'List NAMES, do NOT restore ?' -d"$DEF" "No" "Yes"

	case `AssignUSS` in
		'No'	)	NAMONLY="";;
		'Yes'	)	NAMONLY=t;;
		*	)	exit    1;;
	esac
}

#
# test if tape is already on End Of Media
#
tape_is_EOM()
{
	EOM=0
	DDSTAT=""
	MTSTAT=""
# try to read one tape sector
	DDSTAT=`dd if=/dev/rmt/$TAPEDEV of=/dev/null bs=512 count=1 2>&1 |\
		awk '{ print $1;\
		       exit; }'` 
	if [ "$DDSTAT" != "1+0" ]
	then
# read failed try to obtain tape drive status to see if we're on a FileMark
		MTSTAT=`mt -t /dev/rmt/$TAPEDEV status | grep FM`
		if [ "$MTSTAT" = "" ]
		then
			echo "\n\007Probably Tape Error, Status:\n\
			      `mt -t /dev/rmt/$TAPEDEV status`"
			exit 2
		else
			EOM=1
		fi
	else
# backspace the just read sector
		mt -t /dev/rmt/$TAPEDEV bsr 1
	fi

	return $EOM
}

#
# space the tape $1 files forward
#
tape_space()
{
	if [ $TAPE_OK -eq 1 ]
	then
		echo "Skipping $1 dataset(s) on  /dev/rmt/$TAPEDEV...\c"
		mt -t /dev/rmt/$TAPEDEV fsf $1
		echo "done"
		if [ $? -ne 0 ]
		then
			exit $?
		fi
	else
		return 1
	fi
}

#
# rewind the tape and skip $TOCSKIP number of files forward if applicable
#
tape_rewind()
{
	if [ $TAPE_OK -eq 1 ]
	then
		echo "Rewinding /dev/rmt/$TAPEDEV...\c"
		mt -t /dev/rmt/$TAPEDEV rewind
		if [ $? -ne 0 ]
		then
			exit $?
		fi

		sleep 1
# space the tape forward if applicable
		if [ $TOCSKIP -ge 1 ]
		then
			tape_space $TOCSKIP
		else
			echo "done"
		fi
	else
		return 1
	fi
}

#
# read TOCs from tape
#
read_TOCs()
{
	TOCSKIP=0
	CPIO_OK=0
	tape_rewind
	echo "Scanning archives...\c"
	I=0
	while [ $CPIO_OK -eq 0 ]
	do
# are we at EOM ?
		tape_is_EOM
		CPIO_OK=$?
		if [ $CPIO_OK -eq 0 ]
		then
# the data on the tape must be a TOC, so read it
			rm /tmp/tbackup.contents		       \
					         2>/dev/null >/dev/null
			cpio -icC $BLKSIZE		  	       \
			     -I/dev/rmt/$TAPEDEV 2>/dev/null
			cp /tmp/tbackup.contents /tmp/tbackup$I.contents
			echo `expr $TOCSKIP + 1` >>/tmp/tbackup$I.contents
# determine the number of tape files contained in this archive
			NARCHIVES=`wc -l</tmp/tbackup.contents`
			rm /tmp/tbackup.contents 
			NARCHIVES=`expr $NARCHIVES - 3`
			TOCSKIP=`expr $TOCSKIP + $NARCHIVES`
			echo "$I...\c"
			I=`expr $I + 1`
			mt -t /dev/rmt/$TAPEDEV fsf $NARCHIVES
		fi
	done
	echo "done"
	N_ARCHS=$I
}

#
# readback the archive 
#
tape_readback()
{
EEN='$1'

	OLDSKIP=$TOCSKIP
	TOCSKIP=`tail -1 /tmp/tbackup$1.contents`
	RD_SETS=`wc -l</tmp/tbackup$1.contents`
	RD_SETS=`expr $RD_SETS - 5`
	RD_TYPE=`awk  "/Volume Backup|File Backup/ { print $EEN;\
				     		      exit }"\
		 </tmp/tbackup$I.contents`

	tape_space `expr $TOCSKIP - $OLDSKIP`

	I=0
	RD_NAMS=""
	RD_DEFS=""
	RD_NUMS=""
	while [ $I -lt $RD_SETS ]
	do
		RD_LINE=`expr $I + 5`
		RD_NAMS="$RD_NAMS `AssignFIL $RD_LINE /tmp/tbackup$1.contents|\
				   awk '{ print $1;\
					 exit }'`"
		RD_DEFS="$RD_DEFS `AssignFIL $RD_LINE /tmp/tbackup$1.contents|\
				   awk '{ print $1;\
					 exit }'`+"
		RD_NUMS="$RD_NUMS $I"
		I=`expr $I + 1`
	done

	if [ $UNATTEN -ne 1 ]
	then 
		UserSelectMultiple\
			 -n\
			 -h"Select $RD_TYPE backup Dataset(s) to restore"\
			 $RD_DEFS

		RD_NUMS=`AssignUSM`
		if [ "$RD_NUMS" = "EsCaPeD" ]
		then
			exit 1
		fi
	fi

	I=0
	while [ $I -lt $RD_SETS ]
	do

		REST_OK=0
		for J in $RD_NUMS
		do
			if [ $J -eq $I ]
			then
				REST_OK=1
			fi
		done

		if [ $TAPE_OK -eq 1 ] && [ $REST_OK -eq 1 ]
		then
			RESTDIR=`index_parm $I $RD_NAMS`
			if [ "$RD_TYPE" = "File" ]
			then
				RD_LINE=`expr $I + 5`
				RESTMSK=`AssignFIL\
					  $RD_LINE\
					  /tmp/tbackup$1.contents |\
					 awk '{ 
						for (i=2;i<=NF;i++) {
						 split ($i,SLASH,"\134")
						 if (SLASH[1]!="") {
						   printf SLASH[1]
						 }
						 printf SLASH[2]
						 printf (" ")
					        }
					      }'`
			else
				RESTMSK="*"
			fi
			if [ $UNATTEN -ne 1 ]
			then
				SAVIFS=$IFS
				IFS='^	\
'
				UserEnterValue\
					-h"Enter restore path and file mask"\
					-w 40\
					$RESTDIR	$RESTDIR\
					"File Mask"	"$RESTMSK"
				IFS=$SAVIFS
				RESTDIR=`AssignUEV 1`
				RESTMSK=`AssignUEV 2`
				if [ "$RESTDIR" = "EsCaPeD" ]
				then
					exit 1
				fi
				
				ask_newer_only

				ask_list_names
			fi
			RESTMSK=`DeWild "$RESTMSK"`
			if [ `SubString "@" "$RESTMSK"` -eq 0 ]
			then
				FIL=`CopyString "$RESTMSK" 1 255`
				RESTMSK=`cat $FIL`
				RESTMSK=`DeWild "$RESTMSK"`
			fi
			SAVDIR=`pwd`
			cd $RESTDIR
			echo "Restoring $RD_TYPE backup from /dev/rmt/$TAPEDEV"
			eval\
			cpio -icdm${NEWONLY}"${CPIOLVL}"${NAMONLY} -C $BLKSIZE \
			     -I/dev/rmt/$TAPEDEV $RESTMSK 2>&1 |\
			grep -v ' blocks$'
			cd $SAVDIR
		fi

		I=`expr $I + 1`
		if [ $I -ne $RD_SETS ]
		then
			tape_space 1
			TOCSKIP=`expr $TOCSKIP + 1`
		fi
	done
	rm /tmp/tbackup$1.contents
}

#
# perform the actual readback
#
do_readback()
{
	clear

	TOCSKIP=0
	tape_rewind

	for I in $ARCHIVE
	do
		tape_readback $I
	done

	TOCSKIP=0
	tape_rewind
}

#
# find out what to restore
#
restore()
{
	ask_tapedev

	clear

	read_TOCs

	if [ $UNATTEN -eq 1 ]
	then
		do_readback
		return 0
	fi

	case $BUPTYPE in
		1	) AWKFIND="File Backup";;
		2	) AWKFIND="Volume Backup";;
		3	) AWKFIND="Volume Backup|File Backup";;
	esac

	I=0
	ARCHIVES=""
	ARCHNUMS=""
	while [ $I -lt $N_ARCHS ]
	do
		ARCHTYPE=`awk  "/$AWKFIND/ { print;\
					     exit }"\
			 </tmp/tbackup$I.contents`
		if [ "$ARCHTYPE" != "" ]
		then
			ARCHIVES="$ARCHIVES^$ARCHTYPE"
			ARCHDATE=`awk '/backed up at/ { print $4,$5,$6,$7,$9;\
							exit }'\
				 </tmp/tbackup$I.contents`
			ARCHIVES="$ARCHIVES $ARCHDATE"
			ARCHNUMS="$ARCHNUMS $I"
		fi
		I=`expr $I + 1`
	done	

	if [ "$ARCHNUMS" = "" ]
	then
		clear
		echo "\007No Archives found to restore !"
		exit 1
	fi

	SAVIFS=$IFS
	IFS='^	\
'
	UserSelectMultiple	-n	-h"Select backup to restore"\
					$ARCHIVES

	IFS=$SAVIFS

	ARCHSELS=`AssignUSM`
	if [ "$ARCHSELS" = "EsCaPeD" ]
	then
		exit 1
	fi
	ARCHIVE=""
	for I in $ARCHSELS
	do
		ARCHIVE="$ARCHIVE `index_parm $I $ARCHNUMS`"
	done

	do_readback
}

#
# Start of main program
#
clear
echo "TRestore Version $VERSION (c) Stichting ZCS "

while getopts bdfnuva:C:L:t: c
do
	case $c in
	b	)	BUPTYPE=3;;
	d	)	NEWONLY="";;
	f	) 	BUPTYPE=1;;
	n	)	NAMONLY=t;;
	u	)	UNATTEN=1
			BUPTYPE=3;;
	v	) 	BUPTYPE=2;;
	a	)	ARCHIVE=$OPTARG;;
	C	)	BLKSIZE=$OPTARG;;
	L	)	CPIOLVL=$OPTARG;;
	t	)	TAPEDEV=$OPTARG;;
	*	)	usage;;
	esac
done
shift `expr $OPTIND - 1`

if [ $BUPTYPE -eq 0 ]
then
	ask_vol_or_files
fi

restore "$@"

