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

Reply via email to