3e5a88e04cae137fab1472b534336cb18bb407c5
[debian/amanda] / server-src / amrmtape.sh
1 #!@SHELL@
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 amlibexecdir="@amlibexecdir@"
38 . "${amlibexecdir}/amanda-sh-lib.sh"
39
40 ConfigDir=@CONFIG_DIR@
41
42 # add sbin and ucb dirs
43 PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
44 export PATH
45
46 USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
47 if test "$USE_VERSION_SUFFIXES" = "yes"; then
48         SUF="-@VERSION@"
49 else
50         SUF=
51 fi
52
53 Program=`basename $0`
54
55 CleanTapelist () {
56   [ "xyes" = "x${DebugMode}" ] && set -x
57
58   #
59   # Check if the configuration directory exists.  Make sure that the
60   # necessary files can be found, such as amanda.conf and tapelist.
61   #
62   if [ ! -d ${ConfigDir}/${Config} ]; then
63     log `_ '%s: configuration directory %s does not exist.' "$0" "${ConfigDir}/${Config}"`
64     return 1
65   fi
66   (cd ${ConfigDir}/${Config} >/dev/null 2>&1) || return $?
67   cd ${ConfigDir}/${Config}
68   if [ ! -r amanda.conf ]; then
69     log `_ '%s: amanda.conf not found or is not readable in %s.' "$0" "${ConfigDir}"`
70     return 1
71   fi
72
73   dumpuser=`amgetconf$SUF dumpuser`
74   runuser=`whoami`
75   if [ $runuser != $dumpuser ]; then
76     log `_ '%s: must be run as user %s' "$0" "$dumpuser"`
77     return 1
78   fi
79
80   # Get the location and name of the tapelist filename.  If tapelist is not
81   # specified in the amanda.conf file, then use tapelist in the config
82   # directory.
83   TapeList=`amgetconf${SUF} tapelist`
84   if [ ! "$TapeList" ]; then
85     TapeList="$ConfigDir/$Config/tapelist"
86   fi
87   if [ ! -r $TapeList ]; then
88     log `_ '%s: %s not found or is not readable.' "$0" "$TapeList"`
89     return 1
90   fi
91
92   # Get the location and name of the database filename.
93   InfoFile=`amgetconf${SUF} infofile`
94   if [ ! "$InfoFile" ]; then
95     log `_ '%s: unable to find name of infofile from %s.' "$0" "${ConfigDir}/${Config}/amanda.conf"`
96     return 1
97   fi
98   VarDir=`echo "$InfoFile" | sed -e 's%^[^/]*$%.%' -e 's%/[^/]*$%%'`
99
100   # Check that the database directory and files really exist.
101   if [ ! -d "${VarDir}" ]; then
102     log `_ '%s: %s does not exist or is not a directory.' "$0" "${VarDir}"`
103     return 1
104   fi
105   if [ ! -r "${InfoFile}" ] && [ ! -d "${InfoFile}" ]; then
106     log `_ '%s: %s does not exist or is not readable.' "${Program}" "${InfoFile}"`
107     return 1
108   fi
109
110   if [ ! -d @AMANDA_TMPDIR@ ]; then
111     log `_ '%s: directory %s does not exist.' "$0" "@AMANDA_TMPDIR@"`
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 `_ '%s: remove label %s.' "$0" "${Tape}"`
136     else
137       log `_ '%s: no such tape: %s.' "$0" "${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 `_ '%s: preserving original database in %s (exported).' "$0" "${TmpSrc}"`
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 `_ '%s: unexpected number of fields in "stats" entry for %s.' "${Program}" "${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: "%s"' "${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 `_ '%s [-n] [-v] [-q] [-d] <configuration> <label>' "${Program}"`
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 backup tape within the Amanda current tape database.  This is meant
231 as a recovery mecanism for when a good backup is damaged either by
232 faulty hardware or user error, i.e. the tape is eaten by the tape drive,
233 or 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 $?