#!/bin/sh
#
# Bacula interface to virtual autoloader using disk storage
#
#  $Id: disk-changer.in 4982 2007-06-05 16:58:53Z kerns $
#
#  If you set in your Device resource
#
#  Changer Command = "path-to-this-script/disk-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.
#
#  disk-changer "changer-device" "command" "slot" "archive-device" "drive-index"
#		    $1		    $2	     $3        $4		$5
#
# By default the autochanger has 10 Volumes and 1 Drive.
#
# Note: For this script to work, you *must" specify
#    Device Type = File 
# in each of the Devices associated with your AutoChanger resource.
#
# changer-device is the name of a file that overrides the default
#   volumes and drives.  It may have:
#	 maxslot=n   where n is one based (default 10)
#	 maxdrive=m  where m is zero based (default 1 -- i.e. 2 drives)
#  
#   This code can also simulate barcodes. You simply put
#   a list of the slots and barcodes in the "base" directory/barcodes.
#   See below for the base directory definition.  Example of a 
#   barcodes file:
#      /var/bacula/barcodes
#      1:Vol001
#      2:Vol002
#      ...
# 
# archive-device is the name of the base directory where you want the
#  Volumes stored appended with /drive0 for the first drive; /drive1
#  for the second drive, ... For example, you might use
#  /var/bacula/drive0  Note: you must not have a trailing slash, and
#  the string (e.g. /drive0) must be unique, and it must not match
#  any other part of the directory name. These restrictions could be
#  easily removed by any clever script jockey.
#
#  Full example: disk-changer /var/bacula/conf load 1 /var/bacula/drive0 0
#
# The Volumes will be created with names slot1, slot2, slot3, ... maxslot in the
#  base directory. In the above example the base directory is /var/bacula.
#  However, as with tapes, their Bacula Volume names will be stored inside the
#  Volume label. In addition to the Volumes (e.g. /var/bacula/slot1, 
#  /var/bacula/slot3, ...) this script will create a /var/bacula/loadedn
#  file to keep track of what Slot is loaded. You should not change this file.
#
#

wd=/var/db/bacula

#
# log whats done
#
# to turn on logging, uncomment the following line
#touch $wd/disk-changer.log
#
dbgfile="$wd/disk-changer.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 -t mtx.XXXXXXXXXX`
  if test x${TMPFILE} = x; then
     TMPFILE="$wd/disk-changer.$$"
     if test -f ${TMPFILE}; then
	echo "Temp file security problem on: ${TMPFILE}"
	exit 1
     fi
  fi
}

# check parameter count on commandline
#
check_parm_count() {
    pCount=$1
    pCountNeed=$2
    if test $pCount -lt $pCountNeed; then
	echo "usage: disk-changer ctl-device command [slot archive-device drive-index]"
	echo "	Insufficient number of arguments 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
}

#
# Strip off the final name in order to get the Directory ($dir)
#  that we are dealing with.
#
get_dir() {
   bn=`basename $device`
   dir=`echo "$device" | sed -e s%/$bn%%g`
   if [ ! -d $dir ]; then
      echo "ERROR: Autochanger directory \"$dir\" does not exist.\n"
      echo "	   You must create it.\n"
      exit 1
   fi
}


# Setup arguments
ctl=$1
cmd="$2"
slot=$3
device=$4
drive=$5

# set defaults
maxdrive=1
maxslot=10

# Pull in conf file
if [ -f $ctl ]; then 
   . $ctl
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
	if [ $drive -gt $maxdrive ]; then
	   echo "Drive ($drive) out of range (0-$maxdrive)"
	   exit 1
	fi
	if [ $slot -gt $maxslot ]; then
	   echo "Slot ($slot) out of range (1-$maxslot)"
	   exit 1
	fi
	;;
esac



debug "Parms: $ctl $cmd $slot $device $drive"

case $cmd in 
   unload)
      debug "Doing disk -f $ctl unload $slot $device $drive"
      get_dir
      ld=`cat $dir/loaded${drive}`
      if [ $slot -eq $ld ]; then
	 echo "0" >$dir/loaded${drive}
	 unlink $device 2>/dev/null >/dev/null
	 rm -f $device
      else
	 echo "Storage Element $slot is Already Full"
	 exit 1
      fi
      ;;

   load)
      debug "Doing disk $ctl load $slot $device $drive"
      get_dir
      if [ -f $dir/loaded${drive} ]; then
	 ld=`cat $dir/loaded${drive}`
      else
	 ld=0
      fi
      if [ $ld -eq 0 ]; then
	 echo "0" >$dir/loaded${drive}
	 unlink $device 2>/dev/null >/dev/null
	 rm -f $device
	 ln -s $dir/slot${slot} $device
	 rtn=$?
	 if [ $rtn -eq 0 ]; then
	    echo $slot >$dir/loaded${drive}
	 fi
	 exit $rtn
      else
	 echo "Drive ${drive} Full (Storage element ${ld} loaded)"
	 exit 1
      fi
      ;;

   list) 
      debug "Doing disk -f $ctl -- to list volumes"
      get_dir 
      if [ -f $dir/barcodes ]; then
	 cat $dir/barcodes
      else
	 i=1
	 while [ $i -le $maxslot ]; do
	    echo "$i:"
	    i=`expr $i + 1`
	 done
      fi
      exit 0
      ;;

   loaded)
      debug "Doing disk -f $ctl $drive -- to find what is loaded"
      get_dir
      if [ -f $dir/loaded${drive} ]; then
	 cat $dir/loaded${drive}
      else
	 echo "0"
      fi
      exit
      ;;

   slots)
      debug "Doing disk -f $ctl -- to get count of slots"
      echo $maxslot
      ;;
esac
