#!/bin/sh
#
# amrmtape.sh
# Time-stamp: <96/10/23 12:07:21 adrian>
# Copyright 1996, Adrian Filipi-Martin
#
# amrmtape
#
# Summary:  This script allow you to invalidate the contents of an
# existing backup tape within the Amanda current tape database.  This
# is meant as a recovery mecanism for when a good backup is damaged
# either by faulty hardware or user error, i.e. the tape is eaten by
# the tape drive, or the tape has been overwritten.
#
# To remove a tape you must specify the Amanda configuration to
# operate upon as well as the name of the tape. e.g.
#
# amrmtape nvl NVL-006
#
# N.B.  amrmtape must be run as a user that can read the tape database
# files and rewrite them.
#
# Usage: amrmtape [-v] [-n] [-d] <configuration> <tape name>
#          -v Verbose mode.
#          -n Do nothing to orignal files, leave new ones in /tmp directory.
#          -d Enable debug tracing.
#
# Credits: The what-to-do algorithm was provided by Cedric Scott,
#          cedric.scott@sse.ie. 
#

prefix=/usr/local
exec_prefix=${prefix}
bindir=${exec_prefix}/bin
libexecdir=/usr/local/libexec/amanda

ConfigDir=/usr/local/etc/amanda

PATH=$libexecdir:$bindir:/usr/bin:/bin:/usr/sbin:/sbin:/usr/ucb
export PATH

USE_VERSION_SUFFIXES="no"
if test "$USE_VERSION_SUFFIXES" = "yes"; then
	SUF="-2.3.0.4"
else
	SUF=
fi

Program=`basename $0`

CleanTapelist () {
  [ "xyes" = "x${DebugMode}" ] && set -x

  #
  # Check if the configuration directory exists.  Make sure that the
  # necessary files are in there, such as amanda.conf and tapelist.
  #
  if [ ! -d ${ConfigDir}/${Config} ]; then
    log "${Program}: configuration directory ${ConfigDir}/${Config} does not exist."
    return 1
  fi
  (cd ${ConfigDir}/${Config} >/dev/null 2>&1) || return $?
  cd ${ConfigDir}/${Config}
  if [ ! -r amanda.conf ]; then
    log "${Program}: amanda.conf not found or is not readable in ${ConfigDir}."
    return 1
  fi
  if [ ! -r tapelist ]; then
    log "${Program}: tapelist not found or is not readable in ${ConfigDir}."
    return 1
  fi

  # Get the location and name of the database filename.
  exec < amanda.conf || return $?
  FoundInfoFile=no
  InfoFile=
  while read Line; do
    case $Line in
      infofile*)
        FoundInfoFile=yes
        set $Line
        eval InfoFile=$2
        ;;
      *)
        ;;
    esac
  done
  exec </dev/tty >/dev/tty
  if [ "xno" = "x${FoundInfoFile}" ]; then
    log "${Program}: no infofile line found in ${ConfigDir}/${Config}/amanda.conf."
    return 1
  fi
  if [ ! "$InfoFile" ]; then
    log "${Program}: unable to extract name of infofile from ${ConfigDir}/${Config}/amanda.conf."
    return 1
  fi
  VarDir=`dirname $InfoFile`

  # Check that the database directory and files really exist.
  if [ ! -d ${VarDir} ]; then
    log "${Program}: ${VarDir} does not exist or is not a directory."
    return 1
  fi
  if [ ! -r ${InfoFile}.pag ]; then
    log "${Program}: ${InfoFile}.pag does not exist or is not readable."
    return 1
  fi
  if [ ! -r ${InfoFile}.dir ]; then
    log "${Program}: ${InfoFile}.dir does not exist or is not readable."
    return 1
  fi

  NewTapelist=/tmp/tapelist
  rm -f ${NewTapelist}
  sed -e "/${Tape}/d" > ${NewTapelist} < tapelist || return $?
  if [ "xno" = "x${DoNothing}" ]; then
    lines=`wc -l tapelist`
    cp -p tapelist tapelist~ && (
      if test "$lines" -gt 1; then
        [ -s ${NewTapelist} ] &&
          cp ${NewTapelist} tapelist &&
          rm -f ${NewTapelist}
      else
        [ -f ${NewTapelist} ] &&
          cp ${NewTapelist} tapelist &&
          rm -f ${NewTapelist}
      fi
    )
  fi
  
  return $?
}


CleanCurinfo () {
  [ "xyes" = "x${DebugMode}" ] && set -x
  (cd ${VarDir}/${Config} >/dev/null 2>&1) || return $?
  cd ${VarDir}/${Config}

  TmpSrc=/tmp/amcurinfo.$$ 
  TmpDest=/tmp/amcurinfo.new.$$
  rm -f ${TmpSrc} ${TmpDest}
  amadmin${SUF} ${Config} export > ${TmpSrc} || return $?
  exec < ${TmpSrc} > ${TmpDest} || return $?
  DeadLevel=10
  while read Line; do
    case ${Line} in
      CURINFO*|"#"*|command*|full*|incr*)
	echo "${Line}"
        ;;
      host*)
	set ${Line}
        Host=$2
	echo "${Line}"
        ;;
      disk*)
	set ${Line}
        Disk=$2
	echo "${Line}"
        ;;
      stats*)
	set ${Line}
	if [ $# != 8 ]; then
	  log "${Program}: unexpected number of fields in 'stats' entry."
	  return 1
	fi
	Level=$2
	CurrentTape=$8
	if [ ${CurrentTape} = ${Tape} ]; then
	  DeadLevel=${Level}
	  ${Verbose} "Discarding Host: ${Host}, Disk: ${Disk}, Level: ${Level}"
	elif [ $Level -gt $DeadLevel ]; then
	  ${Verbose} "Discarding Host: ${Host}, Disk: ${Disk}, Level: ${Level}"
	else
	  echo "${Line}"
	fi
	;;
      //)
	echo "${Line}"
	DeadLevel=10
	;;
      *)
	log "Error: unrecognized line of input: \"${Line}\""
	return 1
    esac
  done
  exec < /dev/tty > /dev/tty

  if [ "xno" = "x${DoNothing}" ]; then
    if [ -r curinfo.db ]; then
      cp -p curinfo.db curinfo.db~ || exit 1
    else
      cp -p curinfo.dir curinfo.dir~ || exit 1
      cp -p curinfo.pag curinfo.pag~ || exit 1
    fi
    [ -s ${TmpDest} ] && 
    amadmin${SUF} ${Config} import < ${TmpDest} &&
    rm -f ${TmpSrc} ${TmpDest}
  fi

  return $?
}


log () {
  echo 1>&2 "$@"
  return 0
}


usage () {
  echo "${Program} [-v] [-n] [-d] <configuration> <tape name>"
  echo "  -v Verbose mode."
  echo "  -n Do nothing to orignal files, leave new ones in /tmp directory."
  echo "  -d Enable debug tracing."  
  echo "This program allows you to invalidate the contents of an existing"
  echo "backup tape within the Amanda current tape database.  This is meant as"
  echo "a recovery mecanism for when a good backup is damaged either by faulty"
  echo "hardware or user error, i.e. the tape is eaten by the tape drive, or"
  echo "the tape has been overwritten."
  return 0
}


Verbose=": "
DoNothing="no"
DebugMode="no"

set dummy "$@"
while shift 2>/dev/null; do
  case $1 in
    -v)
      Verbose="log "
      ;;
    -n)
      DoNothing="yes"
      ;;
    -d)
      DebugMode="yes"
      ;;
    *)
      if [ $# = 2 ]; then
        Config=$1
        Tape=$2
	break
      else
        usage 1>&2
	exit 1
      fi

  esac
done

( CleanTapelist && CleanCurinfo )
exit $?
