#!/bin/sh
#datbkr
#boff!  Dave 'Kill a Cop' Cinege -- Pubic Lo Mein
#http://www.psychosis.com/datbkr/
VERSION=1999030301

#Evolving program to simplify local and remote ssh dat back-ups

#Cut and paste the user section into this file. It is sourced below
#and will override any of the 'hardcoded' variables in this script
CONFFILE="/etc/datbkr.conf"

###############################################################################
#Beginning of user config area.
###############################################################################

###
#Default global variables (BOOL)
###

VERBOSE=1			#verbose console output
AUTOEJECT=0			#eject tape after backup
AUTOPART=0			#make 10MB partition on unpartitioned tapes (otherwise fail)
PROMPT=1			#confirm backup
ESTSIZE=0			#estimate size and print

###
#Local machine variables.  (paths for this machine)
###

#default include listing for tar
INCLUDE="*"

#exclude listing for tar.
EXCLUDE="--exclude=cdrom --exclude=floppy --exclude=mnt --exclude=proc --exclude=tmp --exclude=*/lost+found"

CDTO="./"			#cd here before tar'ing

LOG="/root/tmp/tape.log"	#path and name of 'log' file. 
DIR="/root/tmp/tape.dir"	#path and name of 'dir' (index) file.

MAILTO="root"			#mail report to. Leave blank for no report.
RSH="/usr/bin/ssh"		#rsh command (ie ssh)
RSHUSR="dat"			#user to rsh in as

###
#DAT machine variables. (local or remote machine. paths for THAT machine)
###
 
TAPEHOST="dathost"		#Hostname of machine with dat drive.
TAPEDEV="/dev/tape"		#path to tape device
BLKSIZE=512			#tavedev block size (512 or 1024 typical)
MT="/usr/local/bin/mt-st"	#path to mt. MUST handle partitions (ie mt-st)

###############################################################################
#End of user config area
###############################################################################


#Source file to override these defaults
source () { . $@; }	#'source' is bash centric, '.' isn't
[ -f $CONFFILE ] && source $CONFFILE

###
#initilization
###

trap "cleanup;exit" 2 3 20	#INT QUIT TSTP

usage () {
	echo "datbkr $VERSION   call as: datbkr, datbkr-mt or datbkr-rshtar"
	echo ""
	echo "Usage: datbkr [OPTION]"
	echo ""
	echo "  -d CDTODIR 	change dir to    (defaults $CDTO)"
	echo "  -i INCLUDE 	tar include list (defaults $INCLUDE)"
	echo "  -b BLKSIZE	tape block size"
	echo "  -f TAPEDEV	tape device"
	echo "  -p		don't prompt to continue"
	echo "  -s		estimate size and print"
	echo "  -e		autoeject tape"
	echo "  -m		autopartition tape"
	echo "  -v		verbose console output"
	echo "  -q		suppress console output"
	echo ""
	echo "  -h		display this help and exit"
	echo ""
	echo "Usage: datbkr-mt [-b BLKSIZE] [-f TAPEDEV] mt-arg[, mt-arg2, ...]"
	echo
	echo "Usage: datbkr-rshtar -- internal use"
	echo ""

	exit
}

while getopts  d:i:b:f:hpemsvq opt ; do
	case "$opt" in
		d) CDTO="$OPTARG"  ;;
		i) INCLUDE="$OPTARG" ;;
		b) BLKSIZE="$OPTARG"  ;;
		f) TAPEDEV="$OPTARG"  ;;
		h) usage ;;
		p) PROMPT=0 ;;
		e) AUTOEJECT=1  ;;
		m) AUTOPART=1 ;;
		s) ESTSIZE=1  ;;
		v) VERBOSE=1  ;;
		q) VERBOSE=0  ;;
	esac
done

[ $OPTIND -gt 1 ] && shift $(expr $OPTIND - 1)

WRAPPER="$0-mt -f $TAPEDEV -b $BLKSIZE"
RSHTAR="$0-rshtar"
TARHOST="$TAPEHOST:"
RSHCMD="$RSH -l $RSHUSR $TAPEHOST"

if [ $VERBOSE -eq 1 ]
then	SE="/dev/tty"
else	SE="/dev/null"
fi


#See if tapehost is local (dat) machine or not. 
#Don't use rsh call if it is. Fix me?
LIP="$(host $TAPEHOST | grep '	A	' | cut -f 3)"
RIP="$(host $HOSTNAME | grep '	A	' | cut -f 3)"
[ "$LIP" = "$RIP" ] && RSHCMD="" && TARHOST=""

###
#END
###


###
#Functions
###
vb () { [ $VERBOSE -eq 1 ] && "$@" ; }

qt () { "$@" >/dev/null 2>&1 ; }

log () { "$@" >>$LOG 2>&1 ; }

tapefunc () { log $RSHCMD $WRAPPER "$@" ; }

cleanup () {

	#vb cat $LOG
	[ "$MAILTO" != "" ] && mail -s "Backup Report -- $HOSTNAME `date`" $MAILTO <$LOG

	qt rm $LOG
	qt rm $DIR
	qt rm $DIR.gz
	
	stty echo
}

checkacc () {
	if [ ${?} -ne 0 ]; then
		log echo "Device access error: $1"
		cleanup
		exit 1
	fi
}

rshtar () {
	$RSH -l $RSHUSR "$@"
	exit
}

mtwrapper () {

	#set blocksize, enable partitions
	qt $MT -f $TAPEDEV setblk $BLKSIZE
	qt $MT -f $TAPEDEV stoptions can-partitions
	
	OIFS=$IFS
	IFS=","
	set -- $@
	IFS=$OIFS
	while [ $# -gt 0 ] ; do
		#echo "arg: $1"
		$MT -f $TAPEDEV $1
		rc=${?}
		if [ $rc -ne 0 ]; then
			echo "$(basename $0) failure: $MT -f $TAPEDEV $1"
			exit $rc
		fi
		shift
	done

	#just in case
	qt $MT -f $TAPEDEV setblk $BLKSIZE
	exit
}

###
#END
###

##
#int main () {		#yes delusions of C
##

case "$(basename $0)" in 
	datbkr-mt)		mtwrapper "$@" ;;
	datbkr-rshtar)		rshtar "$@"  ;;
esac

#Create/clear status and index files
: > $LOG; chmod 600 $LOG
: > $DIR; chmod 600 $DIR

vb echo -n "Tape check: "
tapefunc tell, tell
checkacc "No tape in drive."
vb echo "OK"

if [ $PROMPT -eq 1 ]; then

	vb echo ""
	echo "All data will be erased on this tape!"
	echo -n "Proceed? (y/N) "
	read OPT
	case $OPT in
		y|Y)	;;
		""|*) cleanup; exit 1  ;;
	esac	
	vb echo ""
fi

#turn of echo
stty -echo

vb echo -n "Check for tape partitions: "
tapefunc setpart 1
	if [ ${?} -ne 0 ]; then
		if [ $AUTOPART -eq 1 ]; then		
			vb  echo "None. Making 10MB partition."
			log echo "Making 10MB partition."
			tapefunc mkpart 10
			checkacc "Make partition failed!"
		else
			vb echo "None. Failing."
			log echo "Tape not partitioned, failing."
			cleanup
			exit 1
		fi
	fi
vb echo "OK"

vb echo -n "Erase index partition: "
tapefunc setpart 1, rewind, status, erase, rewind
checkacc "Set 1"
vb echo "Done"

vb echo -n "Erase data partition: "
tapefunc setpart 0, rewind, status, erase, rewind
checkacc "Set 2"
vb echo "Done"

vb echo "Changing directory to: $CDTO"

CPWD=$(pwd)
cd $CDTO

vb [ $ESTSIZE -eq 1 ] && echo -n "Estimating size: "
vb [ $ESTSIZE -eq 1 ] && echo "$(du -csh $INCLUDE 2>/dev/null | sed -n /total/s/total//p)"

vb echo "Backing up: $INCLUDE"

log echo ""
log echo "Volume Information"
log echo "=========================================================================="
log echo "Timestamp:	`date +%Y%m%d-%H:%M`"
log echo "Hostname:	$HOSTNAME"
log echo "PWD:		$(pwd)"
log echo "Include:	$INCLUDE"
log echo "Exclude:	$(echo $EXCLUDE|sed s/--exclude=//g)"
log echo ""
log echo "Tar output:"

eval tar -cpvv --totals --rsh-command=$RSHTAR -C \$CDTO \$EXCLUDE -f "\$TARHOST""\$TAPEDEV" \$INCLUDE " 2>>\$LOG" " | tarblocks 2>\$SE >\$DIR"

log echo "=========================================================================="

cd $CPWD

vb echo "Back up complete."

vb echo -n "Change to index partition: "
tapefunc setpart 1
checkacc "Set 3"

vb echo -n "Compress index: "
gzip -9f $DIR

vb echo -n "Write index to tape: "

log echo ""
log echo "Index Information"
log echo "=========================================================================="

log tar -cvv --rsh-command=$RSHTAR -C $(dirname $LOG) -f "$TARHOST""$TAPEDEV" $(basename $LOG) "$(basename $DIR).gz"
checkacc "Problem writing index to tape"
log echo "=========================================================================="
vb echo "Done"


tapefunc rewind

if [ $AUTOEJECT -eq 1 ]; then
	vb echo -n "Ejecting tape: "
	log echo "Ejecting tape."
	tapefunc offline
	vb echo "Done"
fi

vb echo && echo "All Operations Finished."

cleanup

##
#}
##
