Note: This has only been tested on an ADIC Scalar 100. If you find something broken, or not clearly commented, tell me. Also, this is my 1st public showing of any code, so please, be gentle... ;) The attached file is a replacement for chg-zd-mtx. I have added support for barcode readers, and also for libraries between 1-999 slots (I would so love to hear from someone that has a honking big library like that say it works). All amanda utils can work with this for barcode database lookups (amcheck can load the appropriate tape all by itself, etc.) The main thing to do it be sure to update the barcode database after any new tapes are added, or removed from cycle. To do this, make a backup of the old barcodes file, then run 'amtape <conf> update'. This will cycle through all your tape slots, and put them in your barcodes file like this: <tape amlabel> <barcode> Be sure to modify the top part of the script to fit your needs, and also check out the comments on what 'mt status' should return for your tape device. Some changes to come: - make it completely independent of what slot the tapes are in, since certain loaders may unload to the wrong slot depending on circumstances. - Better error handling, which right now is crappy to say the least. - Anything brought ot my attention by you peoples Enjoy... -- Jason Hollinden SMG Systems Admin
#!/bin/sh # # Exit Status: # 0 Alles Ok # 1 Illegal Request # 2 Fatal Error # # Contributed by Eric DOUTRELEAU <[EMAIL PROTECTED]> # This is supposed to work with Zubkoff/Dandelion version of mtx # # Modified by Joe Rhett <[EMAIL PROTECTED]> # to work with MTX 1.2.9 by Eric Lee Green http://mtx.sourceforge.net # # Modified by Jason Hollinden <[EMAIL PROTECTED]> on 6-Feb-2001 # to work with MTX 1.2.10, up to 999 slots, and added barcode support. # NOTE: Only tested the 2 additions with an ADIC Scalar 100. # All my additions have a '#### Comment' close by. # You may need to customize these things MT=/bin/mt MTF=-f MTX=/sbin/mtx DD=/bin/dd firstslot=2 lastslot=9 #### Clean function just loads the tape, and may not necessarily eject it. #### If not, just issue an eject afterwards. cleanslot=31 accessbeforeclean=119 #### If you have a barcode reader, set to 1. Otherwise set to 0. havereader=1 #### Email of who should get severe library errors, and mailer to use. #### All other errors are in the $DBGFILE. [EMAIL PROTECTED] mailer=/bin/mail #### Check the 'readyError' section if mt acts differently for you #### as stated below. #### See the 'readstatus' section below if using a different drive than 0. ########## No (hopefully) user-level customized required beyond this point. # try to hit all the possibilities here prefix=/opt/amanda exec_prefix=${prefix} sbindir=${exec_prefix}/sbin libexecdir=${exec_prefix}/libexec PATH=$sbindir:$libexecdir:/usr/bin:/bin:/usr/sbin:/sbin:/usr/ucb:/usr/local/bin export PATH if [ -d "/tmp/amanda" ]; then DBGFILE=/tmp/amanda/changer.debug else DBGFILE=/dev/null fi USE_VERSION_SUFFIXES="no" if test "$USE_VERSION_SUFFIXES" = "yes"; then SUF="-2.4.2b2" else SUF= fi myname=$0 tape=`amgetconf$SUF tapedev` TAPE=`amgetconf$SUF changerdev`; export TAPE # for mtx command if [ "$tape" = "/dev/null" -o "$TAPE" = "/dev/null" ]; then echo "Both tapedev and changerdev must be specified in config file"; exit 2; fi changerfile=`amgetconf$SUF changerfile` cleanfile=$changerfile-clean accessfile=$changerfile-access slotfile=$changerfile-slot labelfile=$changerfile-barcodes [ ! -f $cleanfile ] && echo 0 > $cleanfile [ ! -f $accessfile ] && echo 0 > $accessfile [ ! -f $slotfile ] && echo 0 > $slotfile [ ! -f $labelfile ] && echo 0 > $labelfile cleancount=`cat $cleanfile` accesscount=`cat $accessfile` # Routines start here #### If using a different drive than /dev/nst0 (or whatever your OS #### calls the 0'th drive) change the 'Data Transfer Element 0' (there #### are 5 below) to 'Data Transfer Element #' where # = /dev/nst# #### (or whatever for your OS). readstatus() { tmpslot=`$MTX status | grep "Data Transfer Element 0"` #### The horrid sed statement below returns the slot number. #### The origional was in shell script, so I didn't want to change that, #### Which give the below puke for a number between 1-999. usedslot=`echo $tmpslot | sed -n 's/Data Transfer Element 0:Empty/-1/p;s/Data Transfer Element 0:Full (Storage Element \(\([1-9]\)\|\([1-9][0-9]\)\|\([1-9][0-9][0-9]\)\) Loaded)\(.*\)/\1/p'` barcode=`echo $tmpslot | sed -n 's/Data Transfer Element 0:Empty/-1/p;s/Data Transfer Element 0:Full (Storage Element \(.\) Loaded):VolumeTag = \(.*\)/\2/p'` if [ "$usedslot" -eq "-1" ]; then echo '-1' > $slotfile fi echo "STATUS -> currently loaded slot = $usedslot" >> $DBGFILE } eject() { readstatus echo "EJECT -> ejecting tape from slot $usedslot" >> $DBGFILE if [ $usedslot -gt 0 ]; then $MTX unload $usedslot 2>/dev/null echo "0 $tape" exit 0 else echo "0 Drive was not loaded" exit 1 fi } reset() { readstatus if [ $usedslot -gt 0 ]; then echo "RESET -> ejecting tape from slot $usedslot" >> $DBGFILE $MTX unload $usedslot 2>/dev/null fi echo "RESET -> loading tape from slot 1" >> $DBGFILE result=`$MTX load 1 2>&1` if [ $? -eq 0 ]; then echo "1 $tape" exit 0 else echo "1 $result" exit 1 fi } loadslot() { readstatus whichslot=$1 echo "LOADSLOT -> load tape from slot $whichslot" >> $DBGFILE case $whichslot in $[${whichslot}]) if [ $whichslot -gt $lastslot ] || [ $whichslot -lt $firstslot ]; then echo "0 Slot $whichslot is out of range ($firstslot - $lastslot)" exit 1 else loadslot=$whichslot fi ;; current) if [ $usedslot -lt 0 ]; then loadslot=$firstslot else echo "$usedslot $tape" exit 0 fi ;; next|advance) if [ $usedslot -lt 0 ]; then loadslot=$firstslot else loadslot=`expr $usedslot + 1` if [ $loadslot -gt $lastslot ]; then loadslot=$firstslot fi fi ;; prev) loadslot=`expr $usedslot - 1` if [ $loadslot -lt $firstslot ]; then loadslot=$lastslot fi ;; first) loadslot=$firstslot ;; last) loadslot=$lastslot ;; clean) loadslot=$cleanslot ;; *) echo "0 illegal request" exit 1 ;; esac # Is this already the current slot? if [ $loadslot = $usedslot ]; then echo "$usedslot $tape" exit 0 fi # Is this a cleaning request? if [ $loadslot = $cleanslot ]; then expr $cleancount + 1 > $cleanfile echo 0 > $accessfile else expr $accesscount + 1 > $accessfile if [ $accesscount -gt $accessbeforeclean ]; then $myname -slot clean >/dev/null # Slot $cleanslot might contain an ordinary tape rather than a cleaning # tape. A cleaning tape *MIGHT* auto-eject; an ordinary tape does not. # We therefore have to read the status again to check what actually happened. readstatus fi fi # Unload any previous tape if [ $usedslot -ne "-1" ]; then echo " -> unload $usedslot" >> $DBGFILE result=`$MTX unload $usedslot 2>&1` status=$? echo " -> status $status, result '$result'" >> $DBGFILE if [ $status -ne 0 ]; then echo "$loadslot $result" exit 2 fi fi # Load the tape, finally! echo " -> loading tape from slot $loadslot" >> $DBGFILE result=`$MTX load $loadslot 2>&1` status=$? echo " -> status $status, result '$result'" >> $DBGFILE # If there is an error, abort unless the slot is simply empty if [ $status -ne 0 ]; then empty=`echo $result | grep "Empty"` if [ -z "$empty" ]; then echo "$loadslot $result" exit 2 else loadslot next fi else #### The origional test if the drive is offline. This depends on what #### 'mt -f <device> status returns different between being offline and #### online. Aparently some drives report an 'offline' when offline, and #### it goes away when online. #readyError="offline" #while [ -n "$readyError" ]; do # readyStatus=`$MT $MTF $tape status 2>&1` # readyError=`echo $readyStatus | grep "offline"` #### ADIC doesn't report an 'offline', rather an 'ONLINE' when it's up. #### Don't assume the drive is ready until we get an ONLINE readyError="" while [ -z "$readyError" ]; do readyStatus=`$MT $MTF $tape status 2>&1` readyError=`echo $readyStatus | grep "ONLINE"` done echo " -> readyStatus = $readyStatus" >> $DBGFILE # Now rewind and check echo " -> rewind $loadslot" >> $DBGFILE $MT $MTF $tape rewind echo "$loadslot" > $slotfile echo "$loadslot $tape" exit 0 fi } info() { readstatus echo "INFO -> current slot $usedslot, last slot $lastslot, can go backwards 1" >> $DBGFILE #### Checks if you have a barcode reader or not. If so, it passes the 4th item in the echo #### back to amtape signifying it can search based on barcodes. if [ $havereader -eq 1 ]; then if [ $usedslot -lt 0 ]; then #### added a variable to the end of the following 2 echos. This indicates to amtape that #### it can/cannot read barcodes. echo "0 $lastslot 1 1" else echo "$usedslot $lastslot 1 1" fi exit 0 else if [ $usedslot -lt 0 ]; then echo "0 $lastslot 1" else echo "$usedslot $lastslot 1" fi exit 0 fi } #### Adds the amlabel and the barcode to the barcode file specified above. #### If the database is messed up, it kills amtape (rather abruptly) and #### dumps a message into changer.debug on what to do, then sends an email #### of the changer.debug to the above set email addr. addlabel() { readstatus tapelabel=$1 labelfilesize=`ls -l $labelfile | awk '{print $5}'` case $tapelabel in $tapelabel) echo "LABEL -> Adding Barcode $barcode and amlabel $tapelabel for Slot $usedslot into $labelfile" >> $DBGFILE if [ $labelfilesize -eq 2 ]; then echo "$tapelabel $barcode" > $labelfile echo "0 $usedslot $tape" else included=`grep $tapelabel $labelfile | awk '{print $1}'` if [ -z $included ]; then echo "$tapelabel $barcode" >> $labelfile echo "0 $usedslot $tape" else oldbarcode=`grep $tapelabel $labelfile | awk '{print $2}'` if [ $oldbarcode -eq $barcode ]; then echo " -> Barcode $barcode $oldbarcode already synced for $tapelabel" >> $DBGFILE echo "0 $usedslot $tape" else echo " -> WARNING!!! Label database corrupted!!!" >> $DBGFILE echo " -> $tapelabel $oldbarcode conflicts with new barcode $barcode" >> $DBGFILE echo " -> Remove file $labelfile and run /usr/sbin/amtape <config> update" >> $DBGFILE `cat $DBGFILE | $mailer -s "Error with barcode reader on \`date\`" $email` `killall amtape` fi fi fi ;; esac exit 0 } #### Looks for the amlabel in the barcode file. If found, it locates the #### slot it's in by looking for the barcode in the mtx output. It then #### loads that tape, and returns to amtape the device the tape is loaded in. #### If the amlabel is not found, it kills amtape and dumps a message to #### changer.debug on what to do, then sends an email of the changer.debug #### to the above set email addr. searchtape() { # readstatus tapelabel=$1 includedtag=`grep $tapelabel $labelfile | awk '{print $1}'` includedbar=`grep $tapelabel $labelfile | awk '{print $2}'` tmpincludedslot=`$MTX status | grep $includedbar` #### The horrid sed statement below returns the slot number. #### The origional was in shell script, so I didn't want to change that, #### Which give the below puke for a number between 1-999. includedslot=`echo $tmpincludedslot | sed -n 's/\(.*\)Storage Element \(\([1-9]\)\|\([1-9][0-9]\)\|\([1-9][0-9][0-9]\)\):\(.*\)/\2/p;s/Data Transfer Element 0:Full (Storage Element \(.\) Loaded)\(.*\)/\1/p'` case $tapelabel in $tapelabel) if [ $tapelabel == $includedtag ]; then shift loadslot $includedslot echo "$tape" else echo "SEARCH -> WARNING!!! $tapelabel not found in current ADIC-barcodes database." >> $DBGFILE echo " -> WARNING!!! Check your typing, and/or update the database." >> $DBGFILE `cat $DBGFILE | $mailer -s "Error with barcode reader on \`date\`" $email` `killall amtape` fi exit 0 esac } # Program invocation begins here echo "`date` Invoked with args '$@'" >> $DBGFILE while [ $# -ge 1 ];do case $1 in -slot) shift loadslot $* ;; -info) shift info ;; -reset) shift reset ;; -eject) shift eject ;; #### Added the below flags, for barcode support -label) shift addlabel $* ;; -search) shift searchtape $* ;; -clean) shift loadslot $cleanslot ;; *) echo "Unknown option $1" exit 2 ;; esac done
