3 # $Id: amverify.sh.in,v 1.38 2006/07/25 19:00:56 martinea Exp $
5 # (C) 1996 by ICEM Systems GmbH
6 # Author: Axel Zinser (fifi@icem.de)
8 # amverify: check amanda tapes and report errors
12 exec_prefix=@exec_prefix@
14 libexecdir=@libexecdir@
16 PATH=$sbindir:$libexecdir:/usr/bin:/bin:/usr/sbin:/sbin:/usr/ucb
19 USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
20 if [ "$USE_VERSION_SUFFIXES" = "yes" ]; then
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.
32 t=`echo "abc\r\c" | wc -c`
45 newelen=`expr "$1" : '.*'`
47 while [ $newelen -lt $elen ]; do
51 echo "$1""$blanks\r\c"
67 $AMGETCONF $CONFIG $1 2>/dev/null
71 if [ -f $REPORT -a X"$REPORTTO" != X"" ]; then
73 echo "Tapes: $TAPELIST"
74 if [ -s $DEFECTS ]; then
78 echo "No errors found!"
84 ) | $MAIL -s "$ORG AMANDA VERIFY REPORT FOR$TAPELIST" $REPORTTO
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
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
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.
115 HEADER=`$DD bs=512 count=64 | ( sed 1q ; cat > /dev/null )`
118 if [ X"$HEADER" = X"" ]; then
119 echo "** No header" > $TEMP/errors
122 # XXX meh, while[] is dangerous, what about a bad header?
123 while [ X"$1" != X"program" ]; do shift; done
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
132 elif [ X"$TAR" != X"" \
133 -a X"$SAMBA_CLIENT" != X"" \
134 -a X"$2" = X"$SAMBA_CLIENT" ]; then
137 elif [ X"$DUMP" != X"" -a X"$2" = X"$DUMP" ]; then
139 if [ $IS_AIX -eq 1 ]; then
144 elif [ X"$VDUMP" != X"" -a X"$2" = X"$VDUMP" ]; then
147 elif [ X"$VXDUMP" != X"" -a X"$2" = X"$VXDUMP" ]; then
150 elif [ X"$XFSDUMP" != X"" -a X"$2" = X"$XFSDUMP" ]; then
152 ARGS="-t -v silent -"
154 echo "** Cannot do $2 dumps" > $TEMP/errors
155 result=999 # flag as not really an error
158 echo "** Cannot find dump type" > $TEMP/errors
161 echo $CMD > $TEMP/onefile.cmd
162 if [ X"`echo $HEADER | grep '^AMANDA: SPLIT_FILE'`" != X"" ]; then
166 echo $1 | cut -f7 -d' ' > $TEMP/onefile.partnum
167 elif [ X"$CMD" != X"" ]; then
169 $CMD $ARGS > /dev/null 2> $TEMP/errors
172 echo "** Cannot execute $CMD" > $TEMP/errors
175 cat >/dev/null # soak up the rest of the image
182 # CONFIG_DIR directory in which the config file resides
183 # AMRESTORE full path name of amrestore
184 # AMGETCONF full path name of amgetconf
185 # AMTAPE full path name of amtape
186 # TAR ditto for GNU-tar
187 # SAMBA_CLIENT ditto for smbclient
188 # DUMP ditto for the system dump program
189 # RESTORE ditto for the system restore program
190 # VDUMP ditto for the system dump program
191 # VRESTORE ditto for the system restore program
192 # VXDUMP ditto for the system dump program
193 # VXRESTORE ditto for the system restore program
194 # XFSDUMP ditto for the system dump program
195 # XFSRESTORE ditto for the system restore program
198 # MTF flag given to MT to specify tape device: -f or -t
200 # IS_AIX true if this is an AIX system
202 CONFIG_DIR=@CONFIG_DIR@
203 libexecdir=$libexecdir
205 AMRESTORE=$sbindir/amrestore$SUF
206 AMGETCONF=$sbindir/amgetconf$SUF
207 AMTAPE=$sbindir/amtape$SUF
209 SAMBA_CLIENT=@SAMBA_CLIENT@
215 VXRESTORE=@VXRESTORE@
217 XFSRESTORE=@XFSRESTORE@
218 if [ -x $sbindir/ammt$SUF ]; then
221 elif [ -x "@MT@" ]; then
225 $Echoe "amverify$SUF mt program not found"
228 if [ -x $sbindir/amdd$SUF ]; then
230 elif [ -x "@DD@" ]; then
233 $Echoe "amverify$SUF dd program not found"
237 if [ X"`/bin/uname -s 2>/dev/null`" = X"AIX" ]; then
240 # The AIX "mt stat" function does not really do anything w.r.t.
241 # checking the drive for ready, and in fact, will fail under
242 # some conditions (e.g. if the tape "file" is a symlink to the
243 # real device). We let the rewind do the equivalent since all
244 # we use this for is to wait for device ready.
249 DEVICE_READY='$MT $MTF $DEVICE stat'
257 [ X"$CONFIG" = X"" ] \
258 && $Echoe "usage: amverify$SUF <config> [slot [ runtapes ] ]" \
261 AMCONFIG=$CONFIG_DIR/$CONFIG/amanda.conf
263 && $Echoe "Cannot find config file $AMCONFIG" \
266 TPCHANGER=`getparm tpchanger`
267 if [ X"$TPCHANGER" = X"" ]; then
268 $Echoe "No tape changer..."
269 DEVICE=`getparm tapedev`
270 [ X"$DEVICE" = X"" ] \
271 && $Echoe "No tape device..." \
273 $Echoe "Tape device is $DEVICE..."
276 CHANGER_SLOT=${2:-current}
277 $Echoe "Tape changer is $TPCHANGER..."
278 SLOTS=${3:-`getparm runtapes`}
279 [ X"$SLOTS" = X"" ] && SLOTS=1
280 if [ $SLOTS -eq 1 ]; then
285 $Echoe "$SLOTS slot${p}..."
290 # check the accessability
292 [ X"$TAR" != X"" -a ! -x "$TAR" ] \
293 && $Echoe "GNU tar not found: $TAR"
294 [ X"$DUMP" != X"" -a \( X"$RESTORE" = X"" -o ! -x "$RESTORE" \) ] \
295 && $Echoe "System restore program not found: $RESTORE"
296 [ X"$VDUMP" != X"" -a \( X"$VRESTORE" = X"" -o ! -x "$VRESTORE" \) ] \
297 && $Echoe "System restore program not found: $VRESTORE"
298 [ X"$VXDUMP" != X"" -a \( X"$VXRESTORE" = X"" -o ! -x "$VXRESTORE" \) ] \
299 && $Echoe "System restore program not found: $VXRESTORE"
300 [ X"$XFSDUMP" != X"" -a \( X"$XFSRESTORE" = X"" -o ! -x "$XFSRESTORE" \) ] \
301 && $Echoe "System restore program not found: $XFSRESTORE"
302 [ ! -x $AMRESTORE ] \
303 && $Echoe "amrestore not found: $AMRESTORE" \
306 REPORTTO=`getparm mailto`
307 if [ X"$REPORTTO" = X"" ]; then
308 $Echoe "No notification by mail!"
310 $Echoe "Verify summary to $REPORTTO"
314 if [ X"$ORG" = X"" ]; then
315 $Echoe "No org in amanda.conf -- using $CONFIG"
322 # TEMP directory for temporary tar archives and stderr
323 # DEFECTS defect list
324 # REPORT report for mail
326 if [ ! -d @AMANDA_TMPDIR@ ]; then
327 $Echoe "amverify: directory @AMANDA_TMPDIR@ does not exist."
331 cd @AMANDA_TMPDIR@ || exit 1
333 TEMP=@AMANDA_TMPDIR@/amverify.$$
334 trap 'rm -fr $TEMP' EXIT
335 if ( umask 077 ; mkdir $TEMP ) ; then
338 $Echoe "Cannot create $TEMP"
341 DEFECTS=$TEMP/defects; rm -f $DEFECTS
342 REPORT=$TEMP/report; rm -f $REPORT
344 EXITSTAT=$TEMP/amrecover.exit; rm -rf $EXITSTAT
346 trap 'report "aborted!"; echo "aborted!" >> $DEFECTS; sendreport; rm -fr $TEMP; exit 1' EXIT
348 $Echoe "Defects file is $DEFECTS"
349 report "amverify $CONFIG"
353 # ----------------------------------------------------------------------------
355 SPLIT_DUMPS= # this will keep track of split dumps that we'll tally later
356 while [ $SLOT -lt $SLOTS ]; do
357 SLOT=`expr $SLOT + 1`
359 # Tape Changer: dial slot
361 if [ X"$TPCHANGER" != X"" ]; then
362 report "Loading ${CHANGER_SLOT} slot..."
363 $AMTAPE $CONFIG slot $CHANGER_SLOT > $TEMP/amtape.out 2>&1
364 THIS_SLOT=$CHANGER_SLOT
366 RESULT=`grep "changed to slot" $TEMP/amtape.out`
367 [ X"$RESULT" = X"" ] \
368 && report "** Error loading slot $THIS_SLOT" \
369 && report "`cat $TEMP/amtape.out`" \
370 && cat $TEMP/amtape.out >> $DEFECTS \
372 DEVICE=`$AMTAPE $CONFIG device`
374 report "Using device $DEVICE"
375 $Echon "Waiting for device to go ready..."
377 until eval $DEVICE_READY > $TEMP/ammt.out 2>&1; do
379 && report "Device not ready" \
380 && report "`cat $TEMP/ammt.out`" \
381 && report cat $TEMP/ammt.out >> $DEFECTS \
384 count=`expr $count - 3`
386 $Echon "Rewinding..."
388 until $MT $MTF $DEVICE rewind > $TEMP/ammt.out 2>&1; do
389 RESULT=`grep "No medium found" $TEMP/ammt.out`
390 [ X"$RESULT" != X"" ] \
391 && report "** Error rewinding tape" \
392 && report "`cat $TEMP/ammt.out`" \
393 && cat $TEMP/ammt.out >> $DEFECTS \
395 ERRORS=`expr $ERRORS + 1`
396 [ $ERRORS -gt 100 ] \
397 && report "** Error rewinding tape" \
398 && report "`cat $TEMP/ammt.out`" \
399 && cat $TEMP/ammt.out >> $DEFECTS \
403 $Echon "Processing label..."
404 $DD if=$DEVICE count=1 bs=@MAXTAPEBLOCKSIZE@k 2> $TEMP/errors > $TEMP/header
405 [ ! -s $TEMP/header ] \
406 && report "** Error reading label on tape" \
407 && cat $TEMP/errors >> $DEFECTS \
409 TAPENDATE=`sed 1q < $TEMP/header | grep '^AMANDA: TAPESTART'`
410 [ X"$TAPENDATE" = X"" ] \
411 && report "** No amanda tape in slot" \
419 report "Volume $VOLUME, Date $DWRITTEN"
420 [ X"$DWRITTEN" = X"0" -o X"$DWRITTEN" = X"X" ] \
421 && report "Fresh tape. Skipping..." \
423 TAPELIST="$TAPELIST $VOLUME"
424 $Echon "Rewinding..."
425 until $MT $MTF $DEVICE rewind; do
430 while [ $ERG = 0 ]; do
431 if [ $Echon = echon ]; then
432 $Echon "Waiting for device to go ready..."
435 until eval $DEVICE_READY > $TEMP/ammt.out 2>&1; do
437 && report "Device not ready" \
438 && report "`cat $TEMP/ammt.out`" \
439 && report cat $TEMP/ammt.out >> $DEFECTS \
442 count=`expr $count - 3`
444 if [ $Echon = echon ]; then
447 RESULT=`$AMRESTORE -h -p $DEVICE 2> $TEMP/amrestore.out \
448 | doonefile 2> $TEMP/onefile.errors`
449 FILE=`grep restoring $TEMP/amrestore.out \
450 | sed 's/^.*restoring //'`
451 EOF=`grep "reached end of tape" $TEMP/amrestore.out`
452 EOI=`grep "reached end of information" $TEMP/amrestore.out`
453 # amrestore: 0: restoring sundae._mnt_sol1_usr.19961127.1
454 if [ X"$FILE" != X"" -a X"$RESULT" = X"0" ]; then
455 report "Checked $FILE"
456 elif [ X"$FILE" != X"" -a X"$RESULT" = X"500" ]; then
457 report "Skipped `cat $TEMP/onefile.cmd` check on partial dump $FILE"
458 dump="`echo $FILE | cut -d'.' -f'1,2,3,4'`"
459 cat $TEMP/onefile.partnum >> $TEMP/$dump.parts
460 if [ X"`echo $SPLIT_DUMPS | grep $dump`" = X"" ]; then
461 SPLIT_DUMPS="$dump $SPLIT_DUMPS"
463 elif [ X"$FILE" != X"" -a X"$RESULT" = X"999" ]; then
464 report "Skipped $FILE (`cat $TEMP/errors`)"
465 elif [ -n "$EOF" ]; then
466 report "End-of-Tape detected."
468 elif [ -n "$EOI" ]; then
469 report "End-of-Information detected."
472 report "** Error detected ($FILE)"
473 echo "$VOLUME ($FILE):" >>$DEFECTS
474 [ -s $TEMP/amrestore.out ] \
475 && report "`cat $TEMP/amrestore.out`" \
476 && cat $TEMP/amrestore.out >>$DEFECTS
477 [ -s $TEMP/errors ] \
478 && report "`cat $TEMP/errors`" \
479 && cat $TEMP/errors >>$DEFECTS
480 [ -s $TEMP/onefile.errors ] \
481 && report "`cat $TEMP/onefile.errors`" \
482 && cat $TEMP/onefile.errors >>$DEFECTS
483 ERRORS=`expr $ERRORS + 1`
485 && report "Too many errors." \
489 $Echon "Rewinding..."
490 until $MT $MTF $DEVICE rewind; do
495 $TEMP/amrestore.out \
498 $TEMP/onefile.partnum \
503 && $Echoe "Errors found: " \
506 # Work out whether any split dumps we saw had all their parts
507 for dump in $SPLIT_DUMPS;do
514 for part in `cat $TEMP/$dump.parts`;do
515 cur="`echo $part | cut -d/ -f1`"
516 max="`echo $part | cut -d/ -f2`"
517 if [ $max != "UNKNOWN" ]; then
522 if [ $cur -gt $numparts ]; then
526 report "Split dump $dump should have $numparts total pieces"
527 if [ $max_known != 1 ]; then
528 report "NOTE: Header field for total pieces was UNKNOWN, $numparts is best guess"
531 while [ $part -lt $numparts ];do
532 part=`expr $part + 1`
533 if [ X"`grep \"^$part/\" $TEMP/$dump.parts`" = X"" ];then
534 report "Spanning chunk part $part is missing!"
535 missing=`expr $missing + 1`
538 if [ $missing = 0 ];then
539 report "All parts found"
541 rm -f $TEMP/$dump.parts