Imported Upstream version 2.4.4p3
[debian/amanda] / server-src / amrmtape.sh.in
1 #!/bin/sh
2 #
3 # amrmtape.sh
4 # Time-stamp: <96/10/23 12:07:21 adrian>
5 # Copyright 1996, Adrian Filipi-Martin
6 #
7 # amrmtape
8 #
9 # Summary:  This script allow you to invalidate the contents of an
10 # existing backup tape within the Amanda current tape database.  This
11 # is meant as a recovery mecanism for when a good backup is damaged
12 # either by faulty hardware or user error, i.e. the tape is eaten by
13 # the tape drive, or the tape has been overwritten.
14 #
15 # To remove a tape you must specify the Amanda configuration to
16 # operate upon as well as the name of the tape. e.g.
17 #
18 # amrmtape nvl NVL-006
19 #
20 # N.B.  amrmtape must be run as a user that can read the tape database
21 # files and rewrite them.
22 #
23 # Usage: amrmtape [-n] [-v] [-q] [-d] <configuration> <label>
24 #          -n Do nothing to original files, leave new ones in --with-tmpdir
25 #             directory.
26 #          -v Verbose mode.  Enabled by default.
27 #          -q Quiet (opposite of -v).
28 #          -d Enable debug tracing.
29 #
30 # Credits: The what-to-do algorithm was provided by Cedric Scott,
31 #          cedric.scott@sse.ie. 
32 #
33
34 prefix=@prefix@
35 exec_prefix=@exec_prefix@
36 sbindir=@sbindir@
37 libexecdir=@libexecdir@
38
39 ConfigDir=@CONFIG_DIR@
40
41 PATH=$sbindir:$libexecdir:/usr/bin:/bin:/usr/sbin:/sbin:/usr/ucb
42 export PATH
43
44 USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
45 if test "$USE_VERSION_SUFFIXES" = "yes"; then
46         SUF="-@VERSION@"
47 else
48         SUF=
49 fi
50
51 Program=`basename $0`
52
53 CleanTapelist () {
54   [ "xyes" = "x${DebugMode}" ] && set -x
55
56   #
57   # Check if the configuration directory exists.  Make sure that the
58   # necessary files can be found, such as amanda.conf and tapelist.
59   #
60   if [ ! -d ${ConfigDir}/${Config} ]; then
61     log "${Program}: configuration directory ${ConfigDir}/${Config} does not exist."
62     return 1
63   fi
64   (cd ${ConfigDir}/${Config} >/dev/null 2>&1) || return $?
65   cd ${ConfigDir}/${Config}
66   if [ ! -r amanda.conf ]; then
67     log "${Program}: amanda.conf not found or is not readable in ${ConfigDir}."
68     return 1
69   fi
70
71   dumpuser=`amgetconf$SUF dumpuser`
72   runuser=`whoami`
73   if [ $runuser != $dumpuser ]; then
74     log "${Program}: must be run as user $dumpuser"
75     return 1
76   fi
77
78   # Get the location and name of the tapelist filename.  If tapelist is not
79   # specified in the amanda.conf file, then use tapelist in the config
80   # directory.
81   TapeList=`amgetconf${SUF} tapelist`
82   if [ ! "$TapeList" ]; then
83     TapeList="$ConfigDir/$Config/tapelist"
84   fi
85   if [ ! -r $TapeList ]; then
86     log "${Program}: $TapeList not found or is not readable."
87     return 1
88   fi
89
90   # Get the location and name of the database filename.
91   InfoFile=`amgetconf${SUF} infofile`
92   if [ ! "$InfoFile" ]; then
93     log "${Program}: unable to find name of infofile from ${ConfigDir}/${Config}/amanda.conf."
94     return 1
95   fi
96   VarDir=`echo "$InfoFile" | sed -e 's%^[^/]*$%.%' -e 's%/[^/]*$%%'`
97
98   # Check that the database directory and files really exist.
99   if [ ! -d "${VarDir}" ]; then
100     log "${Program}: ${VarDir} does not exist or is not a directory."
101     return 1
102   fi
103   for dbext in @DB_EXT@; do
104     if [ ! -r ${InfoFile}${dbext} ] && [ ! -d ${InfoFile}${dbext} ]; then
105       log "${Program}: ${InfoFile}${dbext} does not exist or is not readable."
106       return 1
107     fi
108   done
109
110   if [ ! -d @AMANDA_TMPDIR@ ]; then
111     log "${Program}: directory @AMANDA_TMPDIR@ does not exist."
112     exit 1
113   fi
114
115   NewTapelist=@AMANDA_TMPDIR@/tapelist
116   rm -f ${NewTapelist}
117   awk "\$2 == \"${Tape}\" { next; } { print; }" \
118       > ${NewTapelist} < $TapeList ||
119   return $?
120   if [ "xno" = "x${DoNothing}" ]; then
121     lines=`wc -l < $TapeList`
122     linesafter=`wc -l < $NewTapelist`
123     if [ "$lines" -gt "$linesafter" ]; then
124       cp -p $TapeList ${TapeList}~ && (
125         if test "$lines" -gt 1; then
126           [ -s ${NewTapelist} ] &&
127             cp ${NewTapelist} $TapeList &&
128             rm -f ${NewTapelist}
129         else
130           [ -f ${NewTapelist} ] &&
131             cp ${NewTapelist} $TapeList &&
132             rm -f ${NewTapelist}
133         fi
134       )
135       log "${Program}: remove label ${Tape}."
136     else
137       log "${Program}: no such tape: ${Tape}."
138       return 1
139     fi
140   fi
141   
142   return $?
143 }
144
145
146 CleanCurinfo () {
147   [ "xyes" = "x${DebugMode}" ] && set -x
148   (cd ${VarDir} >/dev/null 2>&1) || return $?
149   cd ${VarDir}
150   InfoFileBase=`echo $InfoFile | sed -e 's%.*/%%g'`
151
152   TmpSrc=$InfoFileBase.orig.$$
153   TmpDest=$InfoFileBase.new.$$
154   rm -f ${TmpSrc} ${TmpDest}
155   amadmin${SUF} ${Config} export > ${TmpSrc} || return $?
156   log "${Program}: preserving original database in ${TmpSrc} (exported)."
157   exec < ${TmpSrc} > ${TmpDest} || return $?
158   DeadLevel=10
159   while read Line; do
160     case ${Line} in
161       CURINFO*|"#"*|command*|last_level*|consecutive_runs*|full*|incr*)
162         echo "${Line}"
163         ;;
164       host*)
165         set ${Line}
166         Host=$2
167         echo "${Line}"
168         ;;
169       disk*)
170         set ${Line}
171         Disk=$2
172         echo "${Line}"
173         ;;
174       stats*)
175         set ${Line}
176         if [ $# -lt 6 ] || [ $# -gt 8 ]; then
177           log "${Program}: unexpected number of fields in 'stats' entry for ${Host}:${Disk}."
178           log "${Line}"
179           return 1
180         fi
181         Level=$2
182         CurrentTape=$8
183         if [ "${CurrentTape}" = "${Tape}" ]; then
184           DeadLevel=${Level}
185           ${Verbose} "Discarding Host: ${Host}, Disk: ${Disk}, Level: ${Level}"
186         elif [ $Level -gt $DeadLevel ]; then
187           ${Verbose} "Discarding Host: ${Host}, Disk: ${Disk}, Level: ${Level}"
188         else
189           echo "${Line}"
190         fi
191         ;;
192       //)
193         echo "${Line}"
194         DeadLevel=10
195         ;;
196       *)
197         log "Error: unrecognized line of input: \"${Line}\""
198         return 1
199     esac
200   done
201   exec < /dev/tty > /dev/tty
202
203   if [ "xno" = "x${DoNothing}" ]; then
204     [ -s ${TmpDest} ] && 
205     amadmin${SUF} ${Config} import < ${TmpDest} &&
206     rm -f ${TmpDest}
207   fi
208
209   return $?
210 }
211
212
213 log () {
214   echo 1>&2 "$@"
215   return 0
216 }
217
218
219 usage () {
220   echo "${Program} [-n] [-v] [-q] [-d] <configuration> <label>"
221   echo "  -n Do nothing to original files, leave new ones in database directory."
222   echo "  -v Verbose, list backups of hosts and disks that are being discarded."
223   echo "  -q Quiet, opposite of -v."
224   echo "  -d Enable debug tracing."  
225   echo "This program allows you to invalidate the contents of an existing"
226   echo "backup tape within the Amanda current tape database.  This is meant as"
227   echo "a recovery mecanism for when a good backup is damaged either by faulty"
228   echo "hardware or user error, i.e. the tape is eaten by the tape drive, or"
229   echo "the tape has been overwritten."
230   return 0
231 }
232
233
234 Verbose="log "
235 DoNothing="no"
236 DebugMode="no"
237
238 set dummy ${1+"$@"}
239 while shift 2>/dev/null; do
240   case "$1" in
241     -q)
242       Verbose=": "
243       ;;
244     -v)
245       Verbose="log "
246       ;;
247     -n)
248       DoNothing="yes"
249       ;;
250     -d)
251       DebugMode="yes"
252       ;;
253     *)
254       if [ $# = 2 ]; then
255         Config=$1
256         Tape=$2
257         break
258       else
259         usage 1>&2
260         exit 1
261       fi
262
263   esac
264 done
265
266 ( CleanTapelist && CleanCurinfo )
267 exit $?