Imported Upstream version 2.6.1
[debian/amanda] / changer-src / chg-zd-mtx.sh
index 464c07519537bdc4053e16dde5b0b92f11e124f9..dd26273daf9cdc607b6a35c0d3f2eb55d62c4f4f 100644 (file)
 # initial_poll_delay=NN            #### initial delay after load before polling for
 #                          #### readiness
 #
+# slotinfofile=FILENAME            #### record slot information to this file, in
+#                          #### the line-based format "SLOT LABEL\n"
+#
 ####
 
 ####
@@ -376,7 +379,7 @@ Exit() {
        if [ $call_type = Return ]; then
                return $code
        fi
-       amgetconf dbclose.$argv0:$DBGFILE > /dev/null 2>&1
+       amgetconf dbclose.$myname:$DBGFILE > /dev/null 2>&1
        exit $code
 }
 
@@ -411,7 +414,7 @@ Run() {
 
 IsNumeric() {
        test -z "$1" && return 1
-       x="`expr "$1" : '\([-0-9][0-9]*\)' 2>/dev/null`"
+       x="`expr -- "$1" : "\([-0-9][0-9]*\)" 2>/dev/null`"
        return `expr X"$1" != X"$x"`
 }
 
@@ -431,6 +434,11 @@ get_mtx_status() {
        if [ $status -eq 0 ]; then
                mtx_status_valid=1
        fi
+
+       # shim this in here so that we get a completely new slotinfofile
+       # every time we run mtx status
+       regenerate_slotinfo_from_mtx
+
        return $status
 }
 
@@ -443,6 +451,12 @@ get_mtx_status() {
 get_loaded_info() {
        test -n "$DEBUG" && set -x
        get_mtx_status
+       if [ $mtx_status_valid -eq 0 ]; then
+               Exit 2 \
+                    `_ '<none>'` \
+                    `head -1 $mtx_status`
+               return $?
+       fi
 
        set x `sed -n '
 /^Data Transfer Element:Empty/                          {
@@ -560,6 +574,12 @@ get_slot_list() {
                return
        fi
        get_mtx_status
+       if [ $mtx_status_valid -eq 0 ]; then
+               Exit 2 \
+                    `_ '<none>'` \
+                    `head -1 $mtx_status`
+               return $?
+       fi
        slot_list=`sed -n '
 /^Data Transfer Element:Full (Storage Element \([0-9][0-9]*\) Loaded)/ {
     s/.*(Storage Element \([0-9][0-9]*\) Loaded).*/\1/p
@@ -628,7 +648,195 @@ get_slot_list() {
        slot_list="$amanda_slot_list"
 }
 
-DBGFILE=`amgetconf dbopen.$argv0 2>/dev/null`
+###
+# Read the labelfile and scan for a particular entry.
+###
+
+read_labelfile() {
+       labelfile_entry_found=0
+       labelfile_label=
+       labelfile_barcode=
+
+       lbl_search=$1
+       bc_search=$2
+
+       line=0
+       while read lbl bc junk; do
+               line=`expr $line + 1`
+               if [ -z "$lbl" -o -z "$bc" -o -n "$junk" ]; then
+                       Log       `_ 'ERROR    -> Line %s malformed: %s %s %s' "$line" "$lbl" "$bc" "$junk"`
+                       LogAppend `_ '         -> Remove %s and run "%s %s update"' "$labelfile" "$sbindir/amtape" "$config"`
+                       Exit 2 \
+                            `_ '<none>'` \
+                            `_ 'Line %s malformed in %s: %s %s %s' "$line" "$labelfile" "$lbl" "$bc" "$junk"`
+                       return $?               # in case we are internal
+               fi
+               if [ $lbl = "$lbl_search" -o $bc = "$bc_search" ]; then
+                       if [ $labelfile_entry_found -ne 0 ]; then
+                               Log       `_ 'ERROR    -> Duplicate entries: %s line %s' "$labelfile" "$line"`
+                               LogAppend `_ '         -> Remove %s and run "%s %s update"' "$labelfile" "$sbindir/amtape" "$config"`
+                               Exit 2 \
+                                    `_ '<none>'` \
+                                    `_ 'Duplicate entries: %s line %s' "$labelfile" "$line"`
+                               return $?       # in case we are internal
+                       fi
+                       labelfile_entry_found=1
+                       labelfile_label=$lbl
+                       labelfile_barcode=$bc
+               fi
+       done
+}
+
+lookup_label_by_barcode() {
+    [ -z "$1" ] && return
+    read_labelfile "" "$1" < $labelfile
+    echo "$labelfile_label"
+}
+
+lookup_barcode_by_label() {
+    [ -z "$1" ] && return
+    read_labelfile "$1" "" < $labelfile
+    echo "$labelfile_barcode"
+}
+
+remove_from_labelfile() {
+       labelfile=$1
+       lbl_search=$2
+       bc_search=$3
+
+       internal_remove_from_labelfile "$lbl_search" "$bc_search" < $labelfile >$labelfile.new
+       if [ $labelfile_entry_found -ne 0 ]; then
+               mv -f $labelfile.new $labelfile
+               LogAppend `_ 'Removed Entry "%s %s" from barcode database' "$labelfile_label" "$labelfile_barcode"`
+       fi
+}
+
+internal_remove_from_labelfile() {
+       labelfile_entry_found=0
+       labelfile_label=
+       labelfile_barcode=
+
+       lbl_search=$1
+       bc_search=$2
+
+       line=0
+       while read lbl bc junk; do
+               line=`expr $line + 1`
+               if [ -z "$lbl" -o -z "$bc" -o -n "$junk" ]; then
+                       Log       `_ 'ERROR    -> Line %s malformed: %s %s %s' "$line" "$lbl" "$bc" "$junk"`
+                       LogAppend `_ '         -> Remove %s and run "%s %s update"' "$labelfile" "$sbindir/amtape" "$config"`
+                       Exit 2 \
+                            `_ '<none>'` \
+                            `_ 'Line %s malformed in %s: %s %s %s' "$line" "$labelfile" "$lbl" "$bc" "$junk"`
+                       return $?               # in case we are internal
+               fi
+               if [ $lbl = "$lbl_search" -o $bc = "$bc_search" ]; then
+                       if [ $labelfile_entry_found -ne 0 ]; then
+                               Log       `_ 'ERROR    -> Duplicate entries: %s line %s' "$labelfile" "$line"`
+                               LogAppend `_ '         -> Remove %s and run "%s %s update"' "$labelfile" "$sbindir/amtape" "$config"`
+                               Exit 2 \
+                                    `_ '<none>'` \
+                                    `_ 'Duplicate entries: %s line %s' "$labelfile" "$line"`
+                               return $?       # in case we are internal
+                       fi
+                       labelfile_entry_found=1
+                       labelfile_label=$lbl
+                       labelfile_barcode=$bc
+               else
+                       echo $lbl $bc
+               fi
+       done
+}
+
+###
+# Add a new slot -> label correspondance to the slotinfo file, removing any previous
+# information about that slot.
+###
+
+record_label_in_slot() {
+    [ -z "$slotinfofile" ] && return
+    newlabel="$1"
+    newslot="$2"
+
+    (
+       if [ -f "$slotinfofile" ]; then
+               grep -v "^$newslot " < "$slotinfofile"
+       fi
+       echo "$newslot $newlabel"
+    ) > "$slotinfofile~"
+    mv "$slotinfofile~" "$slotinfofile"
+}
+
+###
+# Remove a slot from the slotinfo file
+###
+
+remove_slot_from_slotinfo() {
+    [ -z "$slotinfofile" ] && return
+    emptyslot="$1"
+
+    (
+       if [ -f "$slotinfofile" ]; then
+               grep -v "^$emptyslot " < "$slotinfofile"
+       fi
+    ) > "$slotinfofile~"
+    mv "$slotinfofile~" "$slotinfofile"
+}
+
+###
+# Assuming get_mtx_status has been run,
+# - if we have barcodes, regenerate the slotinfo file completely by
+#   mapping barcodes in the status into labels using the labelfile
+# - otherwise, remove all empty slots from the slotinfo file
+###
+
+regenerate_slotinfo_from_mtx() {
+    [ -z "$slotinfofile" ] && return
+    [ "$mtx_status_valid" = "1" ] || return
+
+    if [ "$havereader" = "1" ]; then
+       # rewrite slotinfo entirely based on the status, since it has barcodes
+       :> "$slotinfofile~"
+       sed -n '/.*Storage Element \([0-9][0-9]*\).*VolumeTag *= *\([^ ]*\) *$/{
+s/.*Storage Element \([0-9][0-9]*\).*VolumeTag *= *\([^ ]*\) *$/\1 \2/
+p
+}' < $mtx_status | while read newslot newbarcode; do
+               newlabel=`lookup_label_by_barcode "$newbarcode"`
+               if [ -n "$newlabel" ]; then
+                   echo "$newslot $newlabel" >> "$slotinfofile~"
+               fi
+           done
+       mv "$slotinfofile~" "$slotinfofile"
+    else
+       # just remove empty slots from slotinfo
+
+       # first determine which slots are not really empty, but are
+       # loaded into a data transfer element
+loadedslots=`sed -n '/.*(Storage Element \([0-9][0-9]*\) Loaded).*/{
+s/.*(Storage Element \([0-9][0-9]*\) Loaded).*/\1/g
+p
+}' < $mtx_status`
+
+       # now look for any slots which are empty, but which aren't
+       # in the set of loaded slots
+       sed -n '/.*Storage Element \([0-9][0-9]*\): *Empty.*/{
+s/.*Storage Element \([0-9][0-9]*\): *Empty.*/\1/g
+p
+}' < $mtx_status | while read emptyslot; do
+           reallyempty=1
+           if [ -n "$loadedslots" ]; then
+               for loadedslot in $loadedslots; do
+                   [ "$loadedslot" = "$emptyslot" ] && reallyempty=0
+               done
+           fi
+           if [ "$reallyempty" = "1" ]; then
+               remove_slot_from_slotinfo "$emptyslot"
+           fi
+       done
+    fi
+}
+
+DBGFILE=`amgetconf dbopen.$myname 2>/dev/null`
 if [ -z "$DBGFILE" ]
 then
        DBGFILE=/dev/null                       # will try this again below
@@ -698,6 +906,7 @@ cleanfile=$changerfile-clean
 accessfile=$changerfile-access
 slotfile=$changerfile-slot
 labelfile=$changerfile-barcodes
+slotinfofile=""
 [ ! -s $cleanfile ] && echo 0 > $cleanfile
 [ ! -s $accessfile ] && echo 0 > $accessfile
 [ ! -s $slotfile ] && echo -1 > $slotfile
@@ -723,6 +932,7 @@ varlist="$varlist driveslot"
 varlist="$varlist poll_drive_ready"
 varlist="$varlist initial_poll_delay"
 varlist="$varlist max_drive_wait"
+varlist="$varlist slotinfofile"
 
 for var in $varlist
 do
@@ -797,7 +1007,7 @@ initial_poll_delay=${initial_poll_delay:-'0'}              # default: zero zeconds
 max_drive_wait=${max_drive_wait:-'120'}                        # default: two minutes
 
 # check MT and MTX for sanity
-if test "${MTX:0:1}" = "/"; then
+if test "${MTX%${MTX#?}}" = "/"; then
     if ! test -f "${MTX}"; then
        Exit 2 \
            `_ '<none>'` \
@@ -831,6 +1041,8 @@ for var in $varlist; do
                continue                        # old name
        elif [ $var = "AUTOCLEAN" ]; then
                continue                        # old name
+       elif [ $var = "slotinfofile" ]; then
+               continue                        # not numeric
        fi
        eval val=\"'$'$var\"
        if [ -z "$val" ]; then
@@ -1132,7 +1344,7 @@ loadslot() {
                waittime=`expr $waittime + $poll_drive_ready`
        done
        if [ $ready -eq 0 ]; then
-               Exit 2 "$loadslot" `_ 'Drive not ready after %s seconds, rewind said "%s"' "$max_drive_wait" "$result"`
+               Exit 2 "$loadslot" `_ 'Drive not ready after %s seconds: %s' "$max_drive_wait" "$amdevcheck_message"`
                return $?                       # in case we are internal
        fi
 
@@ -1179,45 +1391,6 @@ info() {
        return $?                               # in case we are internal
 }
 
-###
-# Read the labelfile and scan for a particular entry.
-###
-
-read_labelfile() {
-       labelfile_entry_found=0
-       labelfile_label=
-       labelfile_barcode=
-
-       lbl_search=$1
-       bc_search=$2
-
-       line=0
-       while read lbl bc junk; do
-               line=`expr $line + 1`
-               if [ -z "$lbl" -o -z "$bc" -o -n "$junk" ]; then
-                       Log       `_ 'ERROR    -> Line %s malformed: %s %s %s' "$line" "$lbl" "$bc" "$junk"`
-                       LogAppend `_ '         -> Remove %s and run "%s %s update"' "$labelfile" "$sbindir/amtape" "$config"`
-                       Exit 2 \
-                            `_ '<none>'` \
-                            `_ 'Line %s malformed in %s: %s %s %s' "$line" "$labelfile" "$lbl" "$bc" "$junk"`
-                       return $?               # in case we are internal
-               fi
-               if [ $lbl = "$lbl_search" -o $bc = "$bc_search" ]; then
-                       if [ $labelfile_entry_found -ne 0 ]; then
-                               Log       `_ 'ERROR    -> Duplicate entries: %s line %s' "$labelfile" "$line"`
-                               LogAppend `_ '         -> Remove %s and run "%s %s update"' "$labelfile" "$sbindir/amtape" "$config"`
-                               Exit 2 \
-                                    `_ '<none>'` \
-                                    `_ 'Duplicate entries: %s line %s' "$labelfile" "$line"`
-                               return $?       # in case we are internal
-                       fi
-                       labelfile_entry_found=1
-                       labelfile_label=$lbl
-                       labelfile_barcode=$bc
-               fi
-       done
-}
-
 ###
 # Adds the label and barcode for the currently loaded tape to the
 # barcode file.  Return an error if the database is messed up.
@@ -1230,15 +1403,16 @@ addlabel() {
                return $?                       # in case we are internal
        fi
         tapelabel=$1
-       if [ $havereader -eq 0 ]; then
-               Exit 2 `_ '<none>'` `_ 'Not configured with barcode reader'`
-               return $?                       # in case we are internal
-       fi
         get_loaded_info
        if [ $loadedslot -lt 0 ]; then
                Exit 1 `_ '<none>'` `_ 'No tape currently loaded'`
                return $?                       # in case we are internal
        fi
+       record_label_in_slot "$tapelabel" "$loadedslot"
+       if [ $havereader -eq 0 ]; then
+               Exit 0 "$loadedslot" "$rawtape" # that's all we needed
+               return $?                       # in case we are internal
+       fi
        if [ -z "$loadedbarcode" ]; then
                Exit 1 `_ '<none>'` `_ 'No barcode found for tape %s.' $tapelabel`
                return $?                       # in case we are internal
@@ -1261,14 +1435,16 @@ addlabel() {
                        new_val=$tapelabel
                fi
                if [ -n "$lf_val" ]; then
-                       LogAppend `_ 'ERROR    -> !!! Label database corrupted !!!'`
-                       LogAppend `_ '         -> "%s" conflicts with new %s "%s" for %s "%s"' "$old_val" "$val_type" "$new_val" "$lf_type" "$lf_val"`
-                       Exit 2 \
-                            `_ '<none>'` \
-                            `_ '%s: "%s" conflicts with new %s "%s" for %s "%s"' "$tapelabel" "$old_val" "$val_type" "$new_val" "$lf_type" "$lf_val"`
-                       return $?               # in case we are internal
+                       if [ "$val_type" = "barcode" ]; then
+                               remove_from_labelfile $labelfile "" "$old_val"
+                       else
+                               remove_from_labelfile $labelfile "$old_val" ""
+                       fi
+                       echo "$tapelabel $loadedbarcode" >> $labelfile
+                       LogAppend `_ '         -> appended %s entry: %s %s' "$labelfile" "$tapelabel" "$loadedbarcode"`
+               else
+                       LogAppend `_ "         -> already synced"`
                fi
-               LogAppend `_ "         -> already synced"`
        else
                echo "$tapelabel $loadedbarcode" >> $labelfile
                LogAppend `_ '         -> appended %s entry: %s %s' "$labelfile" "$tapelabel" "$loadedbarcode"`
@@ -1305,6 +1481,12 @@ searchtape() {
        fi
        LogAppend `_ '         -> barcode is "%s"' "$labelfile_barcode"`
        get_mtx_status
+       if [ $mtx_status_valid -eq 0 ]; then
+               Exit 2 \
+                    `_ '<none>'` \
+                    `head -1 $mtx_status`
+               return $?
+       fi
        foundslot=`sed -n '
 /VolumeTag *= *'$labelfile_barcode' *$/                        {
        s/.*Storage Element \([0-9][0-9]*\).*/\1/p