Imported Upstream version 2.4.5
[debian/amanda] / server-src / amverify.sh.in
1 #! /bin/sh
2 #
3 #       $Id: amverify.sh.in,v 1.7.2.13.4.5.2.6.2.2 2004/11/19 18:12:30 martinea Exp $
4 #
5 # (C) 1996 by ICEM Systems GmbH
6 # Author: Axel Zinser (fifi@icem.de)
7 #
8 # amverify: check amanda tapes and report errors
9 #
10
11 prefix=@prefix@
12 exec_prefix=@exec_prefix@
13 sbindir=@sbindir@
14 libexecdir=@libexecdir@
15
16 PATH=$sbindir:$libexecdir:/usr/bin:/bin:/usr/sbin:/sbin:/usr/ucb
17 export PATH
18
19 USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
20 if [ "$USE_VERSION_SUFFIXES" = "yes" ]; then
21         SUF="-@VERSION@"
22 else
23         SUF=
24 fi
25
26 # If the shell/system echo support \r and \c, use them to write some
27 # status messages over the top of each other as things progress, otherwise
28 # use a normal echo and let them go on new lines.  Define $Echoe to be
29 # an echo that goes to stderr.  In the code, $Echoe is used and it may
30 # be either echoe or echone, the latter being code that knows about echon.
31
32 t=`echo "abc\r\c" | wc -c`
33 if [ $t -eq 4 ]; then
34         Echon=echon
35 else
36         Echon=echo
37 fi
38 Echoe=echoe
39 elen=0
40 echoe() {
41         echo "$@" >&2
42         Echoe=echoe
43 }
44 echon() {
45         newelen=`expr "$1" : '.*'`
46         blanks=
47         while [ $newelen -lt $elen ]; do
48                 blanks="$blanks "
49                 elen=`expr $elen - 1`
50         done
51         echo "$1""$blanks\r\c"
52         elen=$newelen
53         Echoe=echone
54 }
55 echone() {
56         echon
57         echoe "$@"
58         Echoe=echoe
59 }
60
61 report() {
62         $Echoe "$@"
63         echo "$@" >> $REPORT
64 }
65
66 getparm() {
67         $AMGETCONF $CONFIG $1 2>/dev/null | grep -v BUGGY
68 }
69
70 sendreport() {
71         if [ -f $REPORT -a X"$REPORTTO" != X"" ]; then
72                 (
73                 echo "Tapes: $TAPELIST"
74                 if [ -s $DEFECTS ]; then
75                         echo "Errors found: "
76                         cat $DEFECTS
77                 else
78                         echo "No errors found!"
79                 fi
80                 echo
81
82                 [ -s $REPORT ] \
83                         && cat $REPORT
84                 ) | $MAIL -s "$ORG AMANDA VERIFY REPORT FOR$TAPELIST" $REPORTTO
85         fi
86 }
87
88 ###
89 # This function is called to process one dump image.  Standard input is
90 # the dump image.  We parse the header and decide if it is a GNU tar
91 # dump or a system dump.  Then we do a catalog operation to /dev/null
92 # and finally a "cat" to /dev/null to soak up whatever data is still in
93 # the pipeline.
94 #
95 # In the case of a system restore catalogue, this does not fully check
96 # the integrity of the dump image because system restore programs stop
97 # as soon as they are done with the directories, which are all at the
98 # beginning.  But the trailing cat will at least make sure the whole
99 # image is readable.
100 ###
101
102 doonefile() {
103
104         ###
105         # The goal here is to collect the first 32 KBytes and save the
106         # first line.  But the pipe size coming in to us from amrestore
107         # is highly system dependent and "dd" does not do reblocking.
108         # So we pick a block size that is likely to always be available in
109         # the pipe and a count to take it up to 32 KBytes.  Worst case,
110         # this could be changed to "bs=1 count=32k".  We also have to
111         # soak up the rest of the output after the "head" so an EPIPE
112         # does not go back and terminate the "dd" early.
113         ###
114
115         HEADER=`$DD bs=512 count=64 | ( sed 1q ; cat > /dev/null )`
116         CMD=
117         result=1
118         if [ X"$HEADER" = X"" ]; then
119                 echo "** No header" > $TEMP/errors
120         else
121                 set X $HEADER
122                 shift
123                 shift 9
124                 if [ X"$1" = X"program" -a X"$2" != X"" ]; then
125                         if [ X"$TAR" != X"" \
126                              -a \( X"`basename $2`" = X"`basename $TAR`" \
127                                    -o X"`basename $2`" = X"gtar" \
128                                    -o X"`basename $2`" = X"gnutar" \
129                                    -o X"`basename $2`" = X"tar" \) ]; then
130                                 CMD=$TAR
131                                 ARGS="tf -"
132                         elif [ X"$TAR" != X"" \
133                                -a X"$SAMBA_CLIENT" != X"" \
134                                -a X"$2" = X"$SAMBA_CLIENT" ]; then
135                                 CMD=$TAR
136                                 ARGS="tf -"
137                         elif [ X"$DUMP" != X"" -a X"$2" = X"$DUMP" ]; then
138                                 CMD=$RESTORE
139                                 if [ $IS_AIX -eq 1 ]; then
140                                         ARGS=-tB
141                                 else
142                                         ARGS="tbf 2 -"
143                                 fi
144                         elif [ X"$VDUMP" != X"" -a X"$2" = X"$VDUMP" ]; then
145                                 CMD=$VRESTORE
146                                 ARGS="tf -"
147                         elif [ X"$VXDUMP" != X"" -a X"$2" = X"$VXDUMP" ]; then
148                                 CMD=$VXRESTORE
149                                 ARGS="tbf 2 -"
150                         elif [ X"$XFSDUMP" != X"" -a X"$2" = X"$XFSDUMP" ]; then
151                                 CMD=$XFSRESTORE
152                                 ARGS="-t -v silent -"
153                         else
154                                 echo "** Cannot do $2 dumps" > $TEMP/errors
155                                 result=999      # flag as not really an error
156                         fi
157                 else
158                         echo "** Cannot find dump type" > $TEMP/errors
159                 fi
160         fi
161         if [ X"$CMD" != X"" ]; then
162                 if [ -x $CMD ]; then
163                         $CMD $ARGS > /dev/null 2> $TEMP/errors
164                         result=$?
165                 else
166                         echo "** Cannot execute $CMD" > $TEMP/errors
167                 fi
168         fi
169         cat >/dev/null                          # soak up the rest of the image
170         echo $result
171 }
172
173 #
174 # some paths
175 #
176 #       CONFIG_DIR      directory in which the config file resides
177 #       AMRESTORE       full path name of amrestore
178 #       AMGETCONF       full path name of amgetconf
179 #       AMTAPE          full path name of amtape
180 #       TAR             ditto for GNU-tar
181 #       SAMBA_CLIENT    ditto for smbclient
182 #       DUMP            ditto for the system dump program
183 #       RESTORE         ditto for the system restore program
184 #       VDUMP           ditto for the system dump program
185 #       VRESTORE        ditto for the system restore program
186 #       VXDUMP          ditto for the system dump program
187 #       VXRESTORE       ditto for the system restore program
188 #       XFSDUMP         ditto for the system dump program
189 #       XFSRESTORE      ditto for the system restore program
190 #       DD              ditto for dd
191 #       MT              ditto for mt
192 #       MTF             flag given to MT to specify tape device: -f or -t
193 #       MAIL            mail program
194 #       IS_AIX          true if this is an AIX system
195
196 CONFIG_DIR=@CONFIG_DIR@
197 libexecdir=$libexecdir
198 sbindir=$sbindir
199 AMRESTORE=$sbindir/amrestore$SUF
200 AMGETCONF=$sbindir/amgetconf$SUF
201 AMTAPE=$sbindir/amtape$SUF
202 TAR=@GNUTAR@
203 SAMBA_CLIENT=@SAMBA_CLIENT@
204 DUMP=@DUMP@
205 RESTORE=@RESTORE@
206 VDUMP=@VDUMP@
207 VRESTORE=@VRESTORE@
208 VXDUMP=@VXDUMP@
209 VXRESTORE=@VXRESTORE@
210 XFSDUMP=@XFSDUMP@
211 XFSRESTORE=@XFSRESTORE@
212 if [ -x $sbindir/ammt$SUF ]; then
213         MT=$sbindir/ammt$SUF
214         MTF=-f
215 elif [ -x "@MT@" ]; then
216         MT=@MT@
217         MTF=@MT_FILE_FLAG@
218 else
219         $Echoe "amverify$SUF mt program not found"
220         exit 1
221 fi
222 if [ -x $sbindir/amdd$SUF ]; then
223         DD=$sbindir/amdd$SUF
224 elif [ -x "@DD@" ]; then
225         DD=@DD@
226 else
227         $Echoe "amverify$SUF dd program not found"
228         exit 1
229 fi
230 MAIL=@MAILER@
231 if [ X"`/bin/uname -s 2>/dev/null`" = X"AIX" ]; then
232         IS_AIX=1
233
234         # The AIX "mt stat" function does not really do anything w.r.t.
235         # checking the drive for ready, and in fact, will fail under
236         # some conditions (e.g. if the tape "file" is a symlink to the
237         # real device).  We let the rewind do the equivalent since all
238         # we use this for is to wait for device ready.
239
240         DEVICE_READY=:
241 else
242         IS_AIX=0
243         DEVICE_READY='$MT $MTF $DEVICE stat'
244 fi
245
246 #
247 # config file
248 #
249 SLOT=0
250 CONFIG=$1
251 [ X"$CONFIG" = X"" ] \
252         && $Echoe "usage: amverify$SUF <config> [slot [ runtapes ] ]" \
253         && exit 1
254
255 AMCONFIG=$CONFIG_DIR/$CONFIG/amanda.conf
256 [ ! -f $AMCONFIG ] \
257         && $Echoe "Cannot find config file $AMCONFIG" \
258         && exit 1
259
260 TPCHANGER=`getparm tpchanger`
261 if [ X"$TPCHANGER" = X"" ]; then
262         $Echoe "No tape changer..."
263         DEVICE=`getparm tapedev`
264         [ X"$DEVICE" = X"" ] \
265                 && $Echoe "No tape device..." \
266                 && exit 1
267         $Echoe "Tape device is $DEVICE..."
268         SLOTS=1
269 else
270         CHANGER_SLOT=${2:-current}
271         $Echoe "Tape changer is $TPCHANGER..."
272         SLOTS=${3:-`getparm runtapes`}
273         [ X"$SLOTS" = X"" ] && SLOTS=1
274         if [ $SLOTS -eq 1 ]; then
275                 p=""
276         else
277                 p=s
278         fi
279         $Echoe "$SLOTS slot${p}..."
280         MAXRETRIES=2
281 fi
282
283 #
284 # check the accessability
285 #
286 [ X"$TAR" != X"" -a ! -x "$TAR" ] \
287         && $Echoe "GNU tar not found: $TAR"
288 [ X"$DUMP" != X"" -a \( X"$RESTORE" = X"" -o ! -x "$RESTORE" \) ] \
289         && $Echoe "System restore program not found: $RESTORE"
290 [ X"$VDUMP" != X"" -a \( X"$VRESTORE" = X"" -o ! -x "$VRESTORE" \) ] \
291         && $Echoe "System restore program not found: $VRESTORE"
292 [ X"$VXDUMP" != X"" -a \( X"$VXRESTORE" = X"" -o ! -x "$VXRESTORE" \) ] \
293         && $Echoe "System restore program not found: $VXRESTORE"
294 [ X"$XFSDUMP" != X"" -a \( X"$XFSRESTORE" = X"" -o ! -x "$XFSRESTORE" \) ] \
295         && $Echoe "System restore program not found: $XFSRESTORE"
296 [ ! -x $AMRESTORE ] \
297         && $Echoe "amrestore not found: $AMRESTORE" \
298         && exit 1
299
300 REPORTTO=`getparm mailto`
301 if [ X"$REPORTTO" = X"" ]; then
302         $Echoe "No notification by mail!"
303 else
304         $Echoe "Verify summary to $REPORTTO"
305 fi
306
307 ORG=`getparm org`
308 if [ X"$ORG" = X"" ]; then
309         $Echoe "No org in amanda.conf -- using $CONFIG"
310         ORG=$CONFIG
311 fi
312
313 #
314 # ok, let's do it
315 #
316 #       TEMP            directory for temporary tar archives and stderr
317 #       DEFECTS         defect list
318 #       REPORT          report for mail
319
320 if [ ! -d @AMANDA_TMPDIR@ ]; then
321   $Echoe "amverify: directory @AMANDA_TMPDIR@ does not exist."
322   exit 1
323 fi
324
325 cd @AMANDA_TMPDIR@ || exit 1
326
327 TEMP=@AMANDA_TMPDIR@/amverify.$$
328 trap 'rm -fr $TEMP' 0
329 if ( umask 077 ; mkdir $TEMP ) ; then
330         :
331 else
332         $Echoe "Cannot create $TEMP"
333         exit 1
334 fi
335 DEFECTS=$TEMP/defects; rm -f $DEFECTS
336 REPORT=$TEMP/report; rm -f $REPORT
337 TAPELIST=
338 EXITSTAT=$TEMP/amrecover.exit; rm -rf $EXITSTAT
339
340 trap 'report "aborted!"; echo "aborted!" >> $DEFECTS; sendreport; rm -fr $TEMP; exit 1' 1 2 3 4 5 6 7 8 10 12 13 14 15
341
342 $Echoe "Defects file is $DEFECTS"
343 report "amverify $CONFIG"
344 report "`date`"
345 report ""
346
347 # ----------------------------------------------------------------------------
348
349 while [ $SLOT -lt $SLOTS ]; do
350         SLOT=`expr $SLOT + 1`
351         #
352         # Tape Changer: dial slot
353         #
354         if [ X"$TPCHANGER" != X"" ]; then
355                 report "Loading ${CHANGER_SLOT} slot..."
356                 $AMTAPE $CONFIG slot $CHANGER_SLOT > $TEMP/amtape.out 2>&1
357                 THIS_SLOT=$CHANGER_SLOT
358                 CHANGER_SLOT=next
359                 RESULT=`grep "changed to slot" $TEMP/amtape.out`
360                 [ X"$RESULT" = X"" ] \
361                         && report "** Error loading slot $THIS_SLOT" \
362                         && report "`cat $TEMP/amtape.out`" \
363                         && cat $TEMP/amtape.out >> $DEFECTS \
364                         && continue
365                 DEVICE=`$AMTAPE $CONFIG device`
366         fi
367         report "Using device $DEVICE"
368         $Echon "Waiting for device to go ready..."
369         until eval $DEVICE_READY >/dev/null 2>&1; do
370                 sleep 3
371         done
372         $Echon "Rewinding..."
373         ERRORS=0
374         until $MT $MTF $DEVICE rewind > $TEMP/ammt.out 2>&1; do
375                 RESULT=`grep "No medium found" $TEMP/ammt.out`
376                 [ X"$RESULT" != X"" ] \
377                         && report "** Error rewinding tape" \
378                         && report "`cat $TEMP/ammt.out`" \
379                         && cat $TEMP/ammt.out >> $DEFECTS \
380                         && break
381                 ERRORS=`expr $ERRORS + 1`
382                 [ $ERRORS -gt 100 ] \
383                         && report "** Error rewinding tape" \
384                         && report "`cat $TEMP/ammt.out`" \
385                         && cat $TEMP/ammt.out >> $DEFECTS \
386                         && break
387                 sleep 3
388         done
389         $Echon "Processing label..."
390         $DD if=$DEVICE count=1 bs=@MAXTAPEBLOCKSIZE@k 2> $TEMP/errors > $TEMP/header
391         [ ! -s $TEMP/header ] \
392                 && report "** Error reading label on tape" \
393                 && cat $TEMP/errors >> $DEFECTS \
394                 && continue
395         TAPENDATE=`sed 1q < $TEMP/header | grep '^AMANDA: TAPESTART'`
396         [ X"$TAPENDATE" = X"" ] \
397                 && report "** No amanda tape in slot" \
398                 && continue
399         set X $TAPENDATE
400         shift
401         shift                   # "AMANDA:"
402         shift                   # "TAPESTART"
403         VOLUME=$4
404         DWRITTEN=$2
405         report "Volume $VOLUME, Date $DWRITTEN"
406         [ X"$DWRITTEN" = X"0" -o X"$DWRITTEN" = X"X" ] \
407                 && report "Fresh tape. Skipping..." \
408                 && continue
409         TAPELIST="$TAPELIST $VOLUME"
410         $Echon "Rewinding..."
411         until $MT $MTF $DEVICE rewind; do
412                 sleep 3
413         done
414         ERG=0
415         ERRORS=0
416         while [ $ERG = 0 ]; do
417                 if [ $Echon = echon ]; then
418                         $Echon "Waiting for device to go ready..."
419                 fi
420                 until eval $DEVICE_READY >/dev/null 2>&1; do
421                         sleep 3
422                 done
423                 if [ $Echon = echon ]; then
424                         $Echon "Reading..."
425                 fi
426                 RESULT=`$AMRESTORE -h -p $DEVICE 2> $TEMP/amrestore.out \
427                         | doonefile 2> $TEMP/onefile.errors`
428                 FILE=`grep restoring $TEMP/amrestore.out \
429                         | sed 's/^.*restoring //'`
430                 EOF=`grep "reached end of tape" $TEMP/amrestore.out`
431                 EOI=`grep "reached end of information" $TEMP/amrestore.out`
432                 # amrestore:   0: restoring sundae._mnt_sol1_usr.19961127.1
433                 if [ X"$FILE" != X"" -a X"$RESULT" = X"0" ]; then
434                         report "Checked $FILE"
435                 elif [ X"$FILE" != X"" -a X"$RESULT" = X"999" ]; then
436                         report "Skipped $FILE (`cat $TEMP/errors`)"
437                 elif [ -n "$EOF" ]; then
438                         report "End-of-Tape detected."
439                         break
440                 elif [ -n "$EOI" ]; then
441                         report "End-of-Information detected."
442                         break
443                 else
444                         report "** Error detected ($FILE)"
445                         echo "$VOLUME ($FILE):" >>$DEFECTS
446                         [ -s $TEMP/amrestore.out ] \
447                                 && report "`cat $TEMP/amrestore.out`" \
448                                 && cat $TEMP/amrestore.out >>$DEFECTS
449                         [ -s $TEMP/errors ] \
450                                 && report "`cat $TEMP/errors`" \
451                                 && cat $TEMP/errors >>$DEFECTS
452                         [ -s $TEMP/onefile.errors ] \
453                                 && report "`cat $TEMP/onefile.errors`" \
454                                 && cat $TEMP/onefile.errors >>$DEFECTS
455                         ERRORS=`expr $ERRORS + 1`
456                         [ $ERRORS -gt 5 ] \
457                                 && report "Too many errors." \
458                                 && break
459                 fi
460         done
461         $Echon "Rewinding..."
462         until $MT $MTF $DEVICE rewind; do
463                 sleep 3
464         done
465         rm -f $TEMP/header \
466               $TEMP/amtape.out \
467               $TEMP/amrestore.out \
468               $TEMP/errors \
469               $TEMP/onefile.errors
470 done
471
472 [ -s $DEFECTS ] \
473         && $Echoe "Errors found: " \
474         && cat $DEFECTS
475
476 sendreport
477
478 exit 0