Need help updating my AIX shell script that uses IBM tape tool.

I have a shell script that interfaces with our tape library using IBM's Tape Diagnostic tool called "itdt".

The script does some basic stuff, it queries the tape library, loads tape to/from drive; it knows which inventory slot to pick the tape from based on SLOT=$(($BASESLOT + $TODAY)) .

The problem is, this only ever interacts with the first 7 tapes in a 24 tape library because TODAY=`date +%w ` is going to return values from 1-7 depending on the day of the week the script runs.

Using $TODAY is not ideal because it only ever loads/unloads the first 7 tapes in a 23 tape library.

Anyone able to give some pointers as to how I would update this script so that it fully utilizes all 23 tape slots. What other method could I use instead of..

TODAY=`date +%w`
BASESLOT=4096
SLOT=$(($BASESLOT + $TODAY))

to make use of all 23 slots.. below is full script..

inventory()
{
  echo "Tape Inventory"
  echo " "

  query_inventory
  query_drive

  echo "Slot  - Tape"
  i=0
  while [ $i -lt $MAXSLOTS ]
  do
    echo "$(($BASESLOT + $i))  - ${SLOTS[$i]}"
    ((i=$i+1))
  done

  echo " "
  echo "Drive - $TAPEINDRIVE"
  echo " "
}

load()
{
  query_inventory
  query_drive

  TAPEINSLOT=${SLOTS[$TODAY]}

  if [[ $TAPEINSLOT = " " ]]; then
    echo "Unable to load tape - today's slot is empty"
    exit
  fi

  if [[ $TAPEINDRIVE != "None" ]]; then
    echo "Unable to load tape - tape $TAPEINDRIVE is already in the drive"
    exit
  fi

  echo "Moving tape $TAPEINSLOT from slot $SLOT to drive"

  RETURN=`$ITDT -f $DEVICE move $SLOT $DRIVE`
  
}

query_drive()
{
  TAPEINDRIVE=`$ITDT -f $DEVICE inventory | \
    grep -p "Drive Address" | grep 'Volume Tag' | cut -c 34-42`

  [[ $TAPEINDRIVE = " " ]] && TAPEINDRIVE="None"
}

query_inventory()
{
  INVENTORY=$($ITDT -f $DEVICE inventory)

  i=0
  while [ $i -lt $MAXSLOTS ]
  do
    TMPSLOT=$(($BASESLOT+$i))
    SLOTS[$i]=`echo "$INVENTORY" | \
      grep -p "Slot Address ................... $TMPSLOT" | \
      grep 'Volume Tag' | cut -c 34-42`
    ((i=$i+1))
  done
}

unload()
{
  query_inventory
  query_drive

  if [[ $TAPEINDRIVE = "None" ]]; then
    echo "Drive is empty. There is nothing to unload!"
    exit
  fi

  if [[ ${SLOTS[$TODAY]} != " " ]]; then
    echo "Todays slot is occupied. Looking for available slot"
    SLOT="Occupied"
    i=0
    while [ $i -lt $MAXSLOTS ]
    do
      if [[ ${SLOTS[$i]} = " " ]]; then
        SLOT=$(($BASESLOT + $i))
        echo "Found available slot $SLOT"
        break
      fi
      ((i=$i+1))
    done
    if [[ $SLOT = "Occupied" ]]; then
      echo "Unable to find a free slot. Unable to unload tape"
      exit
    fi
  fi

  echo "Moving tape $TAPEINDRIVE from drive to slot $SLOT"

  RETURN=`$ITDT -f $DEVICE move $DRIVE $SLOT`


}

usage()
{
  echo "   usage: tapes load"
  echo "          tapes unload"
  echo "          tapes inventory"
  echo " "
}

if [ $# != 1 ]; then
  usage
  exit
fi

DEVICE=/dev/rmt0
ITDT=/usr/local/bin/itdt
DRIVE=256
TODAY=`date +%w`
BASESLOT=4096
SLOT=$(($BASESLOT + $TODAY))
MAXSLOTS=23
TAPEINDRIVE="None"

case "$1" in
  load) load; exit;;
  unload) unload; exit;;
  inventory) inventory; exit;;
  *) usage; exit;;
esac

If you're trying to use slots 4097 through 4119 approximately the same number of times in a round robin order based on the date (as opposed to keeping track of what had been used the last time your script was called), you could try something like:

DATE=$(date '+%j')	# Get Julian day of year.
DATE=${DATE#0}		# Strip leading zeros to guarantee decimal (rather
DATE=${DATE#0}		# than octal) evaluation of DATE when computing SLOT.
BASESLOT=4096
SLOT=$((BASESLOT + 1 + ((DATE - 1) % 23)))
1 Like

Should BASESLOT be included in the selection of slots, i.e. does 4096 address a correct tape? Then the + 1 needs to be omitted.
And, I guess DATE=${date#0} should read DATE=${DATE#0}

1 Like

Thanks for catching the date vs. DATE issue; that has now been fixed in my earlier post.

I don't think 4096 was intended to be included based on using date +%u (which returns 1-7; not 0-6) in the existing code. But, the original post also mentioned 23 a few times, but 24 once; and, it never mentioned the desired range of slot numbers to be assigned.

Thanks for the quick responses :slight_smile:

The tape library has 24 slots, the way they are counted is 23 slots + 1 tape head/drive slot.

The address of the first tape slot is 4096 and the address of the last (slot 23) is 4118; i'd like all of them to be used in a round robin kind of method. The idea is, this script gets called nightly to "change tapes" before the backup to tape happens. So every night it should be using a different tape (+1) until it reaches the 23rd tape (address 4118) then goes back to 1 (address 4096).

Sorry for the lack of information, I hope this is more complete now.

With the above changes you suggested, will it support this? When I made the above changes and ran the script, it loaded the tape from slot 4118... i'll try again tomorrow to see if it loads from 4096.

As I originally stated in post #2 in this thread:

so if you want to use slots 4096 through 4118, you should change:

SLOT=$((BASESLOT + 1 + ((DATE - 1) % 23)))

in that script to:

SLOT=$((BASESLOT + ((DATE - 1) % 23)))

Note that it will reset to SLOT 4096 on January 1st every year leaving a few tapes unused in the last rotation of the year.

I finally got around trying this, I was thinking it may be best we track this in a file instead of using something like DATE. The file could be incremented from 1 - 23 to determine $SLOT, then reset to 1 once it reaches 23 (would be easier to troubleshoot as well).

Any chance you could provide an example of doing this the alternate method you suggested (keeping track of it)?

You might be able to merge something like this into your code:

#!/bin/ksh
BASESLOT=4096
ConfigDir='/path/used/to/store/TapeSlotFile'
IAm=${0##*/}
TapeSlotFile="$ConfigDir/${IAm}_slot"

if [ ! -r "$TapeSlotFile" ]
then	printf '%s: Warning: Configuration file (%s) Not found.\n\t%s\n' \
	    "$IAm" "$TapeSlotFile" 'It is being created now.' >&2
	TAPE=0
	if ! echo "$TAPE" > "$TapeSlotFile"
	then	printf "%s: Error: Can't create tape slot file.\n\t%s\n" \
		    "$IAm" 'Terminating.' >&2
		exit 1
	fi
	# The following line is not needed if only root will run this script.
	chmod 664 "$TapeSlotFile"
else	read TAPE < "$TapeSlotFile"
	TAPE=$(((TAPE + 1) % 23))
	if ! echo "$TAPE" > "$TapeSlotFile"
	then	printf "%s: Error: Can't update tape slot file (%s).\n\t%s\n" \
		    "$IAm" "$TapeSlotFile" 'Terminating.' >&2
		exit 2
	fi
fi
SLOT=$((BASESLOT + TAPE))
printf 'Assigned tape slot: %d\n' "$SLOT"

Note that it is using $TAPE values 0 through 22 to select from $SLOT values 4096 through 4118. I'm sure you can make adjustments if the assigned slot range is off. You definitely need to set the ConfigDir variable (on the line shown in red in the script) to the name of a directory where anyone who should be running this script has permission to create files. And, if the users running the script don't all have the same user ID (such as root), they need to at least run with the same group ID.

1 Like

That worked great, implemented it in my script and I can manage all 23 slots with itdt now. Thank you!

I'm glad to hear that the code I suggested helped you.

Note that if one of the volunteers here submits a post that helps you learn how things work or helps you solve a problem you were having, hitting the :b: Thanks button at the lower left corner of that post is one way to convey your thanks.

Good to know, done that now.