b0becf1878a513918546d2c0914cfe0cf91348c2
[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       history*)
193         set ${Line}
194         echo "${Line}"
195         ;;
196       //)
197         echo "${Line}"
198         DeadLevel=10
199         ;;
200       *)
201         log "Error: unrecognized line of input: \"${Line}\""
202         return 1
203     esac
204   done
205   exec < /dev/tty > /dev/tty
206
207   if [ "xno" = "x${DoNothing}" ]; then
208     [ -s ${TmpDest} ] && 
209     amadmin${SUF} ${Config} import < ${TmpDest} &&
210     rm -f ${TmpDest}
211   fi
212
213   return $?
214 }
215
216
217 log () {
218   echo 1>&2 "$@"
219   return 0
220 }
221
222
223 usage () {
224   echo "${Program} [-n] [-v] [-q] [-d] <configuration> <label>"
225   echo "  -n Do nothing to original files, leave new ones in database directory."
226   echo "  -v Verbose, list backups of hosts and disks that are being discarded."
227   echo "  -q Quiet, opposite of -v."
228   echo "  -d Enable debug tracing."  
229   echo "This program allows you to invalidate the contents of an existing"
230   echo "backup tape within the Amanda current tape database.  This is meant as"
231   echo "a recovery mecanism for when a good backup is damaged either by faulty"
232   echo "hardware or user error, i.e. the tape is eaten by the tape drive, or"
233   echo "the tape has been overwritten."
234   return 0
235 }
236
237
238 Verbose="log "
239 DoNothing="no"
240 DebugMode="no"
241
242 set dummy ${1+"$@"}
243 while shift 2>/dev/null; do
244   case "$1" in
245     -q)
246       Verbose=": "
247       ;;
248     -v)
249       Verbose="log "
250       ;;
251     -n)
252       DoNothing="yes"
253       ;;
254     -d)
255       DebugMode="yes"
256       ;;
257     *)
258       if [ $# = 2 ]; then
259         Config=$1
260         Tape=$2
261         break
262       else
263         usage 1>&2
264         exit 1
265       fi
266
267   esac
268 done
269
270 ( CleanTapelist && CleanCurinfo )
271 exit $?