As alluded to in previous messages, I've rewritten much of mtx-changer for my own needs. The goal was to make Bacula (2.2.8) interact nicely with my autochanger (16 slot Dell Powervault 124T) and OS (OpenBSD 4.4). It would be able to load tapes with no regard for actual slot numbers. All Bacula had to know was the barcode.
In other words, I have barcodes so I don't have to think about slots and such. I wanted Bacula to act accordingly. There were also quite a few problems between the existing mtx-changer and OpenBSD's chio command (didn't like output formatting, chio doesn't keep track of the tape's original slot, etc). For reference, here's the output of "chio status -v": --- picker 0: voltag: <:0> slot 0: <ACCESS,FULL> voltag: <000018L3:0> slot 1: <ACCESS,FULL> voltag: <000020L3:0> slot 2: <ACCESS,FULL> voltag: <000017L3:0> slot 3: <ACCESS,FULL> voltag: <000016L3:0> slot 4: <ACCESS> voltag: <:0> slot 5: <ACCESS> voltag: <:0> slot 6: <ACCESS> voltag: <:0> slot 7: <ACCESS> voltag: <:0> slot 8: <ACCESS> voltag: <:0> slot 9: <ACCESS> voltag: <:0> slot 10: <ACCESS> voltag: <:0> slot 11: <ACCESS> voltag: <:0> slot 12: <ACCESS> voltag: <:0> slot 13: <ACCESS> voltag: <:0> slot 14: <ACCESS> voltag: <:0> slot 15: <ACCESS> voltag: <:0> drive 0: <ACCESS,FULL> voltag: <000019L3:0> --- You can see most of how I did this from the mtx-changer output: --- # ./mtx-changer /dev/ch0 list 18:000018L3 20:000020L3 17:000017L3 16:000016L3 19:000019L3 # ./mtx-changer /dev/ch0 slots 20 # ./mtx-changer /dev/ch0 loaded 0 /dev/rst0 0 000019L3 # ./mtx-changer /dev/ch0 unload 0 /dev/rst0 0 # ./mtx-changer /dev/ch0 load 16 /dev/rst0 0 # ./mtx-changer /dev/ch0 loaded 0 /dev/rst0 0 000016L3 # --- In a nutshell, this script treats slots as if they're just the most relevant part of the barcode. If you tell it to load up slot 19, it figures you mean barcode 000019L3 and obeys. The number of slots reported to Bacula is always equivalent to the highest barcode in the autochanger (to avoid out-of-bounds problems). When told to unload the loaded tape, the script ignores the slot argument and just dumps the tape into the first empty slot it finds. Backups work nicely with this, though the autochanger test requires a bit of mucking about with the script to succeed (see commented section in "load" command). Keep in mind I've only used this on my very specific system, so your mileage will vary. -HKS #!/bin/sh # # Bacula interface to chio autoloader # # $Id: mtx-changer.in 5360 2007-08-16 13:01:19Z pbuschman $ # # If you set in your Device resource # # Changer Command = "path-to-this-script/mtx-changer %c %o %S %a %d" # you will have the following input to this script: # # So Bacula will always call with all the following arguments, even though # in come cases, not all are used. # # mtx-changer "changer-device" "command" "slot" "archive-device" "drive-index" # $1 $2 $3 $4 $5 # # for example: # # mtx-changer /dev/sg0 load 1 /dev/nst0 0 (on a Linux system) # # will request to load the first cartidge into drive 0, where # the SCSI control channel is /dev/sg0, and the read/write device # is /dev/nst0. # # The commands are: # Command Function # unload unload a given slot # load load a given slot # loaded which slot is loaded? # list list Volume names (requires barcode reader) # slots how many slots total? # # Slots are numbered from 1 ... # Drives are numbered from 0 ... # # # If you need to an offline, refer to the drive as $4 # e.g. mt -f $4 offline # # Many changers need an offline after the unload. Also many # changers need a sleep 60 after the chio load. # # N.B. If you change the script, take care to return either # the chio exit code or a 0. If the script exits with a non-zero # exit code, Bacula will assume the request failed. # # # Modified 2009-03-06 to accomodate OpenBSD 4.4 and, specifically, chio with a Powervault 124T # # The main purpose of these changes was to make the script slot-agnostic - we don't care what slot # a tape is in - that's why we have them labeled. # # Change notes by command: # unload - ignores the slot number you pass it and unloads the tape into the first empty slot it finds # load - treats the slot like it's a (possibly bastardized) barcode label and attempts to load the # tape with that label into the specified drive # loaded - returns the barcode label of the loaded tape # list - lists the barcode labels of all tapes in the changer. This isn't near as cool as the original # list, which printed "slot:volumetag" because this just prints "volumetag:volumetag", but since # everything else operates by volumetag, it doesn't really matter # slots - report a number equal to the highest numbered tape in the magazine # MTX=/bin/chio # mt status output # SunOS No Additional Sense # FreeBSD Current Driver State: at rest. # Linux ONLINE OS=`uname` case ${OS} in SunOS) ready="No Additional Sense" ;; FreeBSD) ready="Current Driver State: at rest." ;; OpenBSD) ready="Mounted|No medium found" ;; *) ready="ONLINE" ;; esac # # log whats done # # to turn on logging, uncomment the following line touch /var/bacula/mtx.log # dbgfile="/var/bacula/mtx.log" debug() { if test -f $dbgfile; then echo "`date +\"%Y%m%d-%H:%M:%S\"` $*" >> $dbgfile fi } # # Create a temporary file # make_temp_file() { TMPFILE=`mktemp /var/bacula/mtx.XXXXXXXXXX` if test x${TMPFILE} = x; then TMPFILE="/var/bacula/mtx.$$" if test -f ${TMPFILE}; then echo "Temp file security problem on: ${TMPFILE}" exit 1 fi fi } # # The purpose of this function to wait a maximum # time for the drive. It will # return as soon as the drive is ready, or after # waiting a maximum of 300 seconds. # Note, this is very system dependent, so if you are # not running on Linux, you will probably need to # re-write it, or at least change the grep target. # We've attempted to get the appropriate OS grep targets # in the code at the top of this script. # wait_for_drive() { i=0 while [ $i -le 300 ]; do # Wait max 300 seconds if mt -f $1 status 2>&1 | grep -E "${ready}" > /dev/null; then break fi debug "Device $1 - not ready, retrying..." sleep 1 i=`expr $i + 1` done } # check parameter count on commandline # check_parm_count() { pCount=$1 pCountNeed=$2 if test $pCount -lt $pCountNeed; then echo "usage: mtx-changer ctl-device command [slot archive-device drive-index]" echo " Insufficient number of arguments given." if test $pCount -lt 2; then echo " Mimimum usage is first two arguments ..." else echo " Command expected $pCountNeed arguments" fi exit 1 fi } # Check for special cases where only 2 arguments are needed, # all others are a minimum of 5 # case $2 in list) check_parm_count $# 2 ;; slots) check_parm_count $# 2 ;; *) check_parm_count $# 5 ;; esac # Setup arguments ctl=$1 cmd="$2" voltag=$3 device=$4 drive=$5 debug "Parms: $ctl $cmd $voltag $device $drive" # find the first empty slot in the autochanger # first_empty_slot() { debug "Doing chio -f $ctl status -- to find empty slots" # Don't think this is necessary - and it causes issues if the drive is offline but has a tape in it # wait_for_drive $device make_temp_file ${MTX} -f $ctl status -v >${TMPFILE} rtn=$? # find the first empty slot EMPTY_SLOT=`cat ${TMPFILE} | grep " *slot [0-9]*: <ACCESS> voltag: <:0>" | awk '{print $2}' | sed "s/:$//" | head -n 1` rm -f ${TMPFILE} >/dev/null 2>&1 if [ -z $EMPTY_SLOT ]; then echo "No empty slot found, aborting" exit 1 fi } # reformat voltag so it looks like a real voltag # format_voltag() { debug "Making voltag $voltag look like a real voltag" # we're expecting it in one of the following formats: # \d (1, 2, 3, etc) # \d\d (12, 13, etc) # 0000\d\dL3 (000011L3, 000002L3, etc -- this is the format we want it in. The L3 doesn't change, so that's hardcoded) tmpvar=`echo -n $voltag | perl -p -e "s/^0*([1-9]?\d)$/\1L3/"` voltag=`printf "%08s" $tmpvar` } case $cmd in unload) first_empty_slot debug "Doing mt -f $device offline to take the device offline" mt -f $device offline >/dev/null 2>&1 debug "Done with mt -f, sleeping 10 seconds" sleep 10 debug "Doing chio -f $ctl move drive $drive slot $EMPTY_SLOT" ${MTX} -f $ctl move drive $drive slot $EMPTY_SLOT ;; load) format_voltag # # TEMPORARILY CHANGING THIS AROUND TO MAKE BTAPE WORK! # voltag=`echo -n $voltag | perl -p -e "s/^000001L3$/000013L3/"` # voltag=`echo -n $voltag | perl -p -e "s/^000002L3$/000012L3/"` debug "Doing chio -f $ctl move voltag $voltag drive $drive" ${MTX} -f $ctl move voltag $voltag drive $drive rtn=$? wait_for_drive $device exit $rtn ;; list) # coming from this output: # $ chio status -v # picker 0: voltag: <:0> # slot 0: <ACCESS> voltag: <:0> # slot 1: <ACCESS,FULL> voltag: <000014L3:0> # slot 2: <ACCESS> voltag: <:0> # slot 3: <ACCESS> voltag: <:0> # slot 4: <ACCESS,FULL> voltag: <000013L3:0> # slot 5: <ACCESS,FULL> voltag: <000012L3:0> # slot 6: <ACCESS> voltag: <:0> # slot 7: <ACCESS,FULL> voltag: <000011L3:0> # slot 8: <ACCESS> voltag: <:0> # slot 9: <ACCESS> voltag: <:0> # slot 10: <ACCESS> voltag: <:0> # slot 11: <ACCESS> voltag: <:0> # slot 12: <ACCESS> voltag: <:0> # slot 13: <ACCESS> voltag: <:0> # slot 14: <ACCESS> voltag: <:0> # slot 15: <ACCESS> voltag: <:0> # drive 0: <ACCESS,FULL> voltag: <000015L3:0> # we want: # <slotnum>:<voltag> # # Since we're making this slot-agnostic, the slot output will look like: # <voltag-as-slotnum>:<voltag> debug "Doing chio -f $ctl status -- to list volumes" make_temp_file ${MTX} -f $ctl status -v >${TMPFILE} rtn=$? cat ${TMPFILE} | grep -E " *(slot|drive) [0-9]*: <ACCESS,.*FULL.*>" | awk '{printf "%s:%s\n", $5, $5}' | sed "s/<\([0-9]*L3\):0>/\1/g" | sed "s/^0*\([1-9]*[0-9]\)L3:/\1:/" rm -f ${TMPFILE} >/dev/null 2>&1 exit $rtn ;; loaded) debug "Doing chio -f $ctl status -- to find what is loaded" make_temp_file ${MTX} -f $ctl status -v >${TMPFILE} rtn=$? cat ${TMPFILE} | grep " *drive $drive: <.*FULL.*>" | awk '{print $5}' | sed "s/<\([0-9]*L3\):0>/\1/g" cat ${TMPFILE} | grep " *drive $drive: <.*FULL.*>" > /dev/null 2>&1 if [ $? != 0 ]; then echo 0; fi rm -f ${TMPFILE} >/dev/null 2>&1 exit $rtn ;; slots) # since bacula compares tape slot numbers to the number of slots reported by mtx-changer, it will # reject barcodes that are higher numbered than 16 in the 124T. So we change the slots command to # simply report the highest barcode number as the number of slots. debug "Doing chio -f $ctl status -- to get count of slots" ${MTX} -f $ctl status -v | grep -E '^slot.*<ACCESS,FULL>' | awk '{print $5}' | sed -e 's/<0*//' -e 's/L3:0>//' | sort -nr | head -n 1 ;; esac ------------------------------------------------------------------------------ Stay on top of everything new and different, both inside and around Java (TM) technology - register by April 22, and save $200 on the JavaOne (SM) conference, June 2-5, 2009, San Francisco. 300 plus technical and hands-on sessions. Register today. Use priority code J9JMT32. http://p.sf.net/sfu/p _______________________________________________ Bacula-users mailing list Bacula-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bacula-users