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
11 echo "amverify is deprecated -- use amcheckdump" >& 2
14 exec_prefix="@exec_prefix@"
16 amlibexecdir="@amlibexecdir@"
17 . "${amlibexecdir}/amanda-sh-lib.sh"
19 # add sbin and ucb dirs
20 PATH="$PATH:/usr/sbin:/sbin:/usr/ucb"
23 USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
24 if [ "$USE_VERSION_SUFFIXES" = "yes" ]; then
30 # If the shell/system echo support \r and \c, use them to write some
31 # status messages over the top of each other as things progress, otherwise
32 # use a normal echo and let them go on new lines. Define $Echoe to be
33 # an echo that goes to stderr. In the code, $Echoe is used and it may
34 # be either echoe or echone, the latter being code that knows about echon.
36 t=`echo "abc\r\c" | wc -c`
49 newelen=`expr "$1" : '.*'`
51 while [ $newelen -lt $elen ]; do
55 echo "$1""$blanks\r\c"
71 $AMGETCONF $CONFIG $1 2>/dev/null
75 if [ -f $REPORT -a X"$REPORTTO" != X"" ]; then
77 echo `_ 'Tapes: %s' "$TAPELIST"`
78 if [ -s $DEFECTS ]; then
79 echo `_ 'Errors found:'`
82 echo `_ 'No errors found!'`
89 if test -n "$MAIL"; then
90 $MAIL -s "$ORG AMANDA VERIFY REPORT FOR$TAPELIST" $REPORTTO
99 # This function is called to process one dump image. Standard input is
100 # the dump image. We parse the header and decide if it is a GNU tar
101 # dump or a system dump. Then we do a catalog operation to /dev/null
102 # and finally a "cat" to /dev/null to soak up whatever data is still in
105 # In the case of a system restore catalogue, this does not fully check
106 # the integrity of the dump image because system restore programs stop
107 # as soon as they are done with the directories, which are all at the
108 # beginning. But the trailing cat will at least make sure the whole
115 # The goal here is to collect the first 32 KBytes and save the
116 # first line. But the pipe size coming in to us from amrestore
117 # is highly system dependent and "dd" does not do reblocking.
118 # So we pick a block size that is likely to always be available in
119 # the pipe and a count to take it up to 32 KBytes. Worst case,
120 # this could be changed to "bs=1 count=32k". We also have to
121 # soak up the rest of the output after the "head" so an EPIPE
122 # does not go back and terminate the "dd" early.
125 HEADER=`$DD bs=512 count=64 2>/dev/null | ( sed 1q ; cat > /dev/null )`
128 if [ X"$HEADER" = X"" ]; then
129 echo `_ '** No header'` > $TEMP/errors
132 # XXX meh, while[] is dangerous, what about a bad header?
133 while [ X"$1" != X"program" ]; do shift; done
134 if [ X"$1" = X"program" -a X"$2" != X"" ]; then
135 if [ X"$TAR" != X"" \
136 -a \( X"`basename $2`" = X"`basename $TAR`" \
137 -o X"`basename $2`" = X"gtar" \
138 -o X"`basename $2`" = X"gnutar" \
139 -o X"`basename $2`" = X"tar" \) ]; then
142 elif [ X"$TAR" != X"" \
143 -a X"$SAMBA_CLIENT" != X"" \
144 -a X"$2" = X"$SAMBA_CLIENT" ]; then
147 elif [ X"$DUMP" != X"" -a X"$2" = X"$DUMP" ]; then
149 if [ $IS_AIX -eq 1 ]; then
154 elif [ X"$VDUMP" != X"" -a X"$2" = X"$VDUMP" ]; then
157 elif [ X"$VXDUMP" != X"" -a X"$2" = X"$VXDUMP" ]; then
160 elif [ X"$XFSDUMP" != X"" -a X"$2" = X"$XFSDUMP" ]; then
162 ARGS="-t -v silent -"
164 echo `_ '** Cannot do %s dumps' "$2"` > $TEMP/errors
165 result=999 # flag as not really an error
168 echo `_ '** Cannot find dump type'` > $TEMP/errors
171 echo $CMD > $TEMP/onefile.cmd
172 if [ X"`echo $HEADER | grep '^AMANDA: SPLIT_FILE'`" != X"" ]; then
176 echo $1 | cut -f7 -d' ' > $TEMP/onefile.partnum
177 elif [ X"$CMD" != X"" ]; then
179 $CMD $ARGS > /dev/null 2> $TEMP/errors
182 echo `_ '** Cannot execute %s' "$CMD"` > $TEMP/errors
185 cat >/dev/null # soak up the rest of the image
192 # CONFIG_DIR directory in which the config file resides
193 # AMRESTORE full path name of amrestore
194 # AMGETCONF full path name of amgetconf
195 # AMTAPE full path name of amtape
196 # TAR ditto for GNU-tar
197 # SAMBA_CLIENT ditto for smbclient
198 # DUMP ditto for the system dump program
199 # RESTORE ditto for the system restore program
200 # VDUMP ditto for the system dump program
201 # VRESTORE ditto for the system restore program
202 # VXDUMP ditto for the system dump program
203 # VXRESTORE ditto for the system restore program
204 # XFSDUMP ditto for the system dump program
205 # XFSRESTORE ditto for the system restore program
208 # MTF flag given to MT to specify tape device: -f or -t
210 # IS_AIX true if this is an AIX system
212 CONFIG_DIR=@CONFIG_DIR@
213 amlibexecdir=$amlibexecdir
215 AMRESTORE=$sbindir/amrestore$SUF
216 AMGETCONF=$sbindir/amgetconf$SUF
217 AMTAPE=$sbindir/amtape$SUF
219 SAMBA_CLIENT=@SAMBA_CLIENT@
225 VXRESTORE=@VXRESTORE@
227 XFSRESTORE=@XFSRESTORE@
231 . ${amlibexecdir}/chg-lib.sh
238 [ X"$CONFIG" = X"" ] \
239 && $Echoe "usage: amverify$SUF <config> [slot [ runtapes ] ]" \
242 AMCONFIG=$CONFIG_DIR/$CONFIG/amanda.conf
244 && $Echoe "Cannot find config file $AMCONFIG" \
247 TPCHANGER=`getparm tpchanger`
248 if [ X"$TPCHANGER" = X"" ]; then
249 $Echoe "No tape changer..."
250 DEVICE=`getparm tapedev`
251 [ X"$DEVICE" = X"" ] \
252 && $Echoe "No tape device..." \
254 $Echoe "Tape device is $DEVICE..."
257 CHANGER_SLOT=${2:-current}
258 $Echoe "Tape changer is $TPCHANGER..."
259 SLOTS=${3:-`getparm runtapes`}
260 [ X"$SLOTS" = X"" ] && SLOTS=1
261 if [ $SLOTS -eq 1 ]; then
266 $Echoe "$SLOTS slot${p}..."
271 # check the accessability
273 [ X"$TAR" != X"" -a ! -x "$TAR" ] \
274 && $Echoe "GNU tar not found: $TAR"
275 [ X"$DUMP" != X"" -a \( X"$RESTORE" = X"" -o ! -x "$RESTORE" \) ] \
276 && $Echoe "System restore program not found: $RESTORE"
277 [ X"$VDUMP" != X"" -a \( X"$VRESTORE" = X"" -o ! -x "$VRESTORE" \) ] \
278 && $Echoe "System restore program not found: $VRESTORE"
279 [ X"$VXDUMP" != X"" -a \( X"$VXRESTORE" = X"" -o ! -x "$VXRESTORE" \) ] \
280 && $Echoe "System restore program not found: $VXRESTORE"
281 [ X"$XFSDUMP" != X"" -a \( X"$XFSRESTORE" = X"" -o ! -x "$XFSRESTORE" \) ] \
282 && $Echoe "System restore program not found: $XFSRESTORE"
283 [ ! -x $AMRESTORE ] \
284 && $Echoe "amrestore not found: $AMRESTORE" \
287 REPORTTO=`getparm mailto`
288 if [ X"$REPORTTO" = X"" ]; then
289 $Echoe "No notification by mail!"
291 $Echoe "Verify summary to $REPORTTO"
295 if [ X"$ORG" = X"" ]; then
296 $Echoe "No org in amanda.conf -- using $CONFIG"
303 # TEMP directory for temporary tar archives and stderr
304 # DEFECTS defect list
305 # REPORT report for mail
307 if [ ! -d @AMANDA_TMPDIR@ ]; then
308 $Echoe "amverify: directory @AMANDA_TMPDIR@ does not exist."
312 cd @AMANDA_TMPDIR@ || exit 1
314 TEMP=@AMANDA_TMPDIR@/amverify.$$
315 trap 'rm -fr $TEMP' EXIT
316 if ( umask 077 ; mkdir $TEMP ) ; then
319 $Echoe "Cannot create $TEMP"
322 DEFECTS=$TEMP/defects; rm -f $DEFECTS
323 REPORT=$TEMP/report; rm -f $REPORT
325 EXITSTAT=$TEMP/amrecover.exit; rm -rf $EXITSTAT
327 <<<<<<< HEAD:server-src/amverify.sh.in
328 trap 'report "aborted!"; echo "aborted!" >> $DEFECTS; sendreport; rm -fr $TEMP; exit 1' EXIT
330 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
331 >>>>>>> upstream:server-src/amverify.sh
333 $Echoe "Defects file is $DEFECTS"
334 report "amverify $CONFIG"
338 # ----------------------------------------------------------------------------
340 SPLIT_DUMPS= # this will keep track of split dumps that we'll tally later
341 while [ $SLOT -lt $SLOTS ]; do
342 SLOT=`expr $SLOT + 1`
344 # Tape Changer: dial slot
346 if [ X"$TPCHANGER" != X"" ]; then
347 report "Loading ${CHANGER_SLOT} slot..."
348 $AMTAPE $CONFIG slot $CHANGER_SLOT > $TEMP/amtape.out 2>&1
349 THIS_SLOT=$CHANGER_SLOT
351 RESULT=`grep "changed to slot" $TEMP/amtape.out`
352 [ X"$RESULT" = X"" ] \
353 && report "** Error loading slot $THIS_SLOT" \
354 && report "`cat $TEMP/amtape.out`" \
355 && cat $TEMP/amtape.out >> $DEFECTS \
357 DEVICE=`$AMTAPE $CONFIG device`
359 report "Using device $DEVICE"
360 $Echon "Waiting for device to go ready..."
362 <<<<<<< HEAD:server-src/amverify.sh.in
363 until eval $DEVICE_READY > $TEMP/ammt.out 2>&1; do
365 && report "Device not ready" \
366 && report "`cat $TEMP/ammt.out`" \
367 && report cat $TEMP/ammt.out >> $DEFECTS \
370 count=`expr $count - 3`
372 $Echon "Rewinding..."
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 \
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 \
390 amdevcheck_output="`amdevcheck $CONFIG $DEVICE`"
392 if [ $amdevcheck_status -eq 0 ]; then
395 if echo $amdevcheck_output | grep UNLABELED > /dev/null; then
396 if [ count -lt 0 ]; then
397 report "Device not ready"
401 count=`expr $count - 3`
403 report "Volume in $DEVICE unlabeled."
407 >>>>>>> upstream:server-src/amverify.sh
409 $Echon "Processing label..."
410 amtape_output="`amtape $CONFIG current 2>&1`";
411 if echo "$amtape_output" | \
412 egrep "^slot +[0-9]+: time [^ ]+ +label [^ ]+" > /dev/null; then
413 : # everything is fine
415 report "Error reading tape label using amtape."
420 until [ "$1" = "time" ]; do
426 report "Volume $VOLUME, Date $DWRITTEN"
427 [ X"$DWRITTEN" = X"0" -o X"$DWRITTEN" = X"X" ] \
428 && report "Fresh tape. Skipping..." \
430 TAPELIST="$TAPELIST $VOLUME"
435 while [ $ERG = 0 ]; do
436 <<<<<<< HEAD:server-src/amverify.sh.in
437 if [ $Echon = echon ]; then
438 $Echon "Waiting for device to go ready..."
441 until eval $DEVICE_READY > $TEMP/ammt.out 2>&1; do
443 && report "Device not ready" \
444 && report "`cat $TEMP/ammt.out`" \
445 && report cat $TEMP/ammt.out >> $DEFECTS \
448 count=`expr $count - 3`
450 if [ $Echon = echon ]; then
453 RESULT=`$AMRESTORE -h -p $DEVICE 2> $TEMP/amrestore.out \
454 | doonefile 2> $TEMP/onefile.errors`
455 FILE=`grep restoring $TEMP/amrestore.out \
456 | sed 's/^.*restoring //'`
457 EOF=`grep "reached end of tape" $TEMP/amrestore.out`
458 EOI=`grep "reached end of information" $TEMP/amrestore.out`
459 # amrestore: 0: restoring sundae._mnt_sol1_usr.19961127.1
461 FILENO=`expr $FILENO + 1`
462 # { cat <<EOF; dd if=/dev/zero bs=32k count=1; } | doonefile
463 #AMANDA: FILE 20070925205916 localhost /boot lev 0 comp N program /bin/tar
464 #To restore, position tape at start of file and run:
465 # dd if=<tape> bs=32k skip=1 | /bin/tar -xpGf - ...
467 RESULT=`$AMRESTORE -h -p -f $FILENO $DEVICE \
468 2> $TEMP/amrestore.out \
469 | doonefile 2> $TEMP/onefile.errors`
470 FILE=`grep restoring $TEMP/amrestore.out \
471 | sed 's/^.*restoring //'`
472 >>>>>>> upstream:server-src/amverify.sh
473 if [ X"$FILE" != X"" -a X"$RESULT" = X"0" ]; then
474 report "Checked $FILE"
475 elif [ X"$FILE" != X"" -a X"$RESULT" = X"500" ]; then
476 report "Skipped `cat $TEMP/onefile.cmd` check on partial dump $FILE"
477 dump="`echo $FILE | cut -d'.' -f'1,2,3,4'`"
478 cat $TEMP/onefile.partnum >> $TEMP/$dump.parts
479 if [ X"`echo $SPLIT_DUMPS | grep $dump`" = X"" ]; then
480 SPLIT_DUMPS="$dump $SPLIT_DUMPS"
482 elif [ X"$FILE" != X"" -a X"$RESULT" = X"999" ]; then
483 report "Skipped $FILE (`cat $TEMP/errors`)"
484 elif [ -z "$FILE" ]; then
485 # Unless we went over, there is no extra output.
486 report "End-of-Tape detected."
488 elif [ -n "$EOI" ]; then
489 report "End-of-Information detected."
492 report "** Error detected ($FILE)"
493 echo "$VOLUME ($FILE):" >>$DEFECTS
494 [ -s $TEMP/amrestore.out ] \
495 && report "`cat $TEMP/amrestore.out`" \
496 && cat $TEMP/amrestore.out >>$DEFECTS
497 [ -s $TEMP/errors ] \
498 && report "`cat $TEMP/errors`" \
499 && cat $TEMP/errors >>$DEFECTS
500 [ -s $TEMP/onefile.errors ] \
501 && report "`cat $TEMP/onefile.errors`" \
502 && cat $TEMP/onefile.errors >>$DEFECTS
503 ERRORS=`expr $ERRORS + 1`
505 && report "Too many errors." \
511 $TEMP/amrestore.out \
514 $TEMP/onefile.partnum \
519 && $Echoe "Errors found: " \
522 # Work out whether any split dumps we saw had all their parts
523 for dump in $SPLIT_DUMPS;do
530 for part in `cat $TEMP/$dump.parts`;do
531 cur="`echo $part | cut -d/ -f1`"
532 max="`echo $part | cut -d/ -f2`"
533 if [ $max != "UNKNOWN" ]; then
538 if [ $cur -gt $numparts ]; then
542 report "Split dump $dump should have $numparts total pieces"
543 if [ $max_known != 1 ]; then
544 report "NOTE: Header field for total pieces was UNKNOWN, $numparts is best guess"
547 while [ $part -lt $numparts ];do
548 part=`expr $part + 1`
549 if [ X"`grep \"^$part/\" $TEMP/$dump.parts`" = X"" ];then
550 report "Spanning chunk part $part is missing!"
551 missing=`expr $missing + 1`
554 if [ $missing = 0 ];then
555 report "All parts found"
557 rm -f $TEMP/$dump.parts