Difference between revisions of "Bacula and Bareos"

From Hack Sphere Labs Wiki
Jump to: navigation, search
(Configure On CentOS 6.5)
(Configure On CentOS 6.5)
Line 32: Line 32:
 
  nano /etc/bareos/vchanger
 
  nano /etc/bareos/vchanger
  
[[code|/etc/bareos/vchanger]]
+
</pre>
 +
 
 +
 
 +
#!/bin/sh
 +
#
 +
#  Bacula interface to virtual autochanger using removable disk drives
 +
#
 +
#  Based (somewhat) on the "disk-changer" script from bacula 1.39.26
 +
#
 +
#  Vchanger is a Bacula autochanger script that emulates a conventional
 +
#  magazine-based tape library device using removable disk drives.
 +
#  Partitions on the removable drives are used as virtual magazines,
 +
#  where each "magazine" contains the same number of virtual slots. Each
 +
#  "slot" holds one virtual tape, where a "tape" is a regular file that
 +
#  Bacula treats as a "Device Type = File" volume.
 +
#
 +
#  This script will be invoked by Bacula using the Bacula Autochanger
 +
#  Interface and will be passed the following arguments:
 +
#
 +
#  vchanger "changer-device" "command" "slot" "archive-device" "drive-index"
 +
#                $1            $2      $3          #4            #5
 +
#
 +
#  See the Bacula documentation and the Bacula Removable Disk Howto for
 +
#  further details.
 +
#
 +
#  Copyright (C) 2006 Josh Fisher
 +
#
 +
#  Permission to use, copy, modify, distribute, and sell this software
 +
#  and its documentation for any purpose is hereby granted without fee,
 +
#  provided that the above copyright notice appear in all copies.  This
 +
#  software is provided "as is" without express or implied warranty.
 +
#
 +
#  This software is distributed in the hope that it will be useful,
 +
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
 +
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 +
#
 +
# $Id: vchanger,v 0.7.4 2006/12/01 09:29:04 jfisher Exp $
 +
 
 +
#
 +
# log whats done
 +
#
 +
# to turn on logging, uncomment the following line
 +
#touch $wd/vchanger.log
 +
#
 +
 
 +
#
 +
# Write to a log file
 +
#    To log debugging info, create file /var/bacula/vchanger.log
 +
#    with write permission for bacula-sd user. To stop logging,
 +
#    delete file /var/bacula/vchanger.log
 +
#
 +
dbgfile="/var/bacula/vchanger.log"
 +
function debug()
 +
{
 +
    if test -e $dbgfile; then
 +
echo "`date +\"%Y%m%d-%H:%M:%S\"` $*" >> $dbgfile
 +
    fi
 +
}
 +
 
 +
#
 +
# Return length of string $1
 +
#
 +
if [ `uname` = "FreeBSD" ]
 +
then
 +
        function strlen ()
 +
        {
 +
                expr -- "$1" : ".*"
 +
        }
 +
else
 +
        function strlen ()
 +
        {
 +
                expr length $1
 +
        }
 +
fi
 +
 
 +
 
 +
#
 +
# Prepend zeros to $1 and return a string that is $2 characters long
 +
#
 +
function mklen ()
 +
{
 +
  o1=$1
 +
  while [ `eval strlen ${o1}` -lt ${2} ]; do
 +
      o1="0${o1}"
 +
  done
 +
  echo $o1
 +
}
 +
 
 +
#
 +
# Get uid of $1 (or current user if $1 empty)
 +
#
 +
function get_uid() {
 +
  id $1 2>/dev/null | cut -d ' ' -f 1 | sed "s/uid=//" | cut -d '(' -f 1
 +
}
 +
 
 +
 
 +
#
 +
# Initialize autochanger's state directory if not already initialized
 +
#
 +
function init_statedir() {
 +
  debug "Initializing $statedir"
 +
  # Create state directory if needed
 +
  if [ ! -d "${statedir}" ]; then
 +
      if [ "$su_uid" != "" ]; then
 +
        su -c "mkdir ${statedir} &>/dev/null" $su_uid
 +
      else
 +
        mkdir ${statedir} &>/dev/null
 +
      fi
 +
      if [ $? -ne 0 ]; then
 +
        echo "Could not create ${statedir}"
 +
        exit 1
 +
      fi
 +
      chmod 770 ${statedir} &>/dev/null
 +
      if [ $? -ne 0 ]; then
 +
        echo "Could not chmod ${statedir}"
 +
        exit 1
 +
      fi
 +
  fi
 +
  # Create nextmag file to hold max magazine index used
 +
  if [ ! -f "${statedir}/nextmag" ]; then
 +
      if [ "$su_uid" != "" ]; then
 +
        su -c "echo 0 >${statedir}/nextmag" $su_uid
 +
      else
 +
    echo 0 >${statedir}/nextmag
 +
      fi
 +
      if [ $? -ne 0 ]; then
 +
        echo "Could not create ${statedir}/nextmag"
 +
        exit 1
 +
      fi
 +
      chmod 660 ${statedir}/nextmag
 +
      if [ $? -ne 0 ]; then
 +
        echo "Could not chmod ${statedir}/nextmag"
 +
        exit 1
 +
      fi
 +
  fi
 +
  # Check nextmag value
 +
  nextmag=`cat "${statedir}/nextmag"`
 +
  if [ $? -ne 0 -o "${nextmag}" == "" -o $nextmag -lt 0 -o $nextmag -gt 99 ]; then
 +
      echo "${statedir}/nextmag has invalid value"
 +
      return 1
 +
  fi
 +
  # Create 'loaded' files for each virtual drive that hold the slot
 +
  # number currently loaded in that 'drive'
 +
  i=0
 +
  while [ $i -le $maxdrive ]; do
 +
      if [ ! -f "${statedir}/loaded${i}" ]; then
 +
        if [ "$su_uid" != "" ]; then
 +
            su -c "echo 0 >${statedir}/loaded${i}" $su_uid
 +
        else
 +
            echo 0 >${statedir}/loaded${i}
 +
        fi
 +
        if [ $? -ne 0 ]; then
 +
            echo "Could not create ${statedir}/loaded${i}"
 +
            exit 1
 +
        fi
 +
        if [ "$su_uid" != "" ]; then
 +
            su -c "chmod 660 ${statedir}/loaded${i}" $su_uid
 +
        else
 +
            chmod 660 ${statedir}/loaded${i}
 +
        fi
 +
        if [ $? -ne 0 ]; then
 +
            echo "Could not chmod ${statedir}/loaded${i}"
 +
            exit 1
 +
        fi
 +
      fi
 +
      i=`expr ${i} + 1`
 +
  done
 +
}
 +
 
 +
 
 +
#
 +
# Get magazine index of currently loaded magazine
 +
#
 +
function get_magazine() {
 +
  debug "Get magazine index"
 +
  # Check for mountpoint dir
 +
  if [ ! -d ${mountpoint} ]; then
 +
      echo "No magazine loaded at ${mountpoint}"
 +
      exit 1
 +
  fi
 +
  # Check magazine for existing index
 +
  if [ ! -f "${mountpoint}/index" ]; then
 +
      echo "00"
 +
      return 1
 +
  fi
 +
  mi=`cat "${mountpoint}/index"`
 +
  if [ $? -ne 0 ]; then
 +
      echo "Failed to read ${mountpoint}/index"
 +
      exit 1
 +
  fi
 +
  # must be 1-99
 +
  if [ $mi -lt 1 -o $mi -gt 99 ]; then
 +
      echo "Magazine has invalid index ${mi}"
 +
      exit 1
 +
  fi
 +
  # make magazine index 2 digits
 +
  eval mklen ${mi} 2
 +
  return 0
 +
}
 +
 
 +
#
 +
# Initialize magazine if not already initialized
 +
#
 +
function init_magazine() {
 +
  debug "Initializing magazine"
 +
  # Get max magazine index that has been used
 +
  nextmag=`cat "${statedir}/nextmag"`
 +
  if [ $? -ne 0 -o "${nextmag}" == "" ]; then
 +
      echo "Failed to read ${statedir}/nextmag"
 +
      exit 1
 +
  fi
 +
  # Check magazine for existing index
 +
  if [ -f "${mountpoint}/index" ]; then
 +
      # retrieve existing magazine index
 +
      mi=`cat "${mountpoint}/index"`
 +
      if [ $? -ne 0 ]; then
 +
        echo "Failed to read ${mountpoint}/index"
 +
        exit 1
 +
      fi
 +
      # must be 1-99
 +
      if [ $mi -lt 1 -o $mi -gt 99 ]; then
 +
        echo "Magazine has invalid index ${mi}"
 +
        exit 1
 +
      fi
 +
  else
 +
      # new magazine, so assign it the next avail index
 +
      mi=`expr ${nextmag} + 1`
 +
      if [ $mi -lt 0 -o $mi -gt 99 ]; then
 +
        echo "Max magazines exceeded"
 +
        exit 1
 +
      fi
 +
      if [ "$su_uid" != "" ]; then
 +
        su -c "echo ${mi} >${mountpoint}/index" $su_uid
 +
      else
 +
        echo ${mi} >${mountpoint}/index
 +
      fi
 +
      if [ $? -ne 0 ]; then
 +
        echo "Failed to write ${mountpoint}/index"
 +
        exit 1
 +
      fi
 +
      chmod 640 ${mountpoint}/index 2>/dev/null
 +
  fi
 +
  # make sure max index used is up to date
 +
  if [ $mi -gt $nextmag ]; then
 +
      echo $mi 2>/dev/null >"${statedir}/nextmag"
 +
      if [ $? -ne 0 ]; then
 +
        echo "Failed to update ${statedir}/nextmag"
 +
        exit 1
 +
      fi
 +
  fi
 +
  # make magazine index 2 digits
 +
  magindex=`eval mklen ${mi} 2`
 +
  # setup slot files (ie. virtual tapes)
 +
  i=1
 +
  while [ $i -le $magslots ]; do
 +
      s=`eval mklen ${i} 3`
 +
      f="${mountpoint}/m${magindex}s${s}"
 +
      if [ ! -f "${f}" ]; then
 +
        if [ "$su_uid" != "" ]; then
 +
            su -c "touch ${f} &>/dev/null" $su_uid
 +
        else
 +
            touch ${f} &>/dev/null
 +
        fi
 +
        if [ $? -ne 0 ]; then
 +
            echo "Failed to create ${f}"
 +
            exit 1
 +
        fi
 +
      fi
 +
      i=`expr ${i} + 1`
 +
  done
 +
  return 0
 +
}
 +
 
 +
 
 +
#
 +
# Get sd status with bconsole
 +
#
 +
function bconsole_sd_status() {
 +
  debug "Doing 'status storage' with bconsole"
 +
  $bconsole <<EOD_SDSTAT
 +
status storage=$baculasd
 +
quit
 +
EOD_SDSTAT
 +
}
 +
 
 +
 
 +
#
 +
# Delete volume with bconsole  param1 = slot
 +
#
 +
function bconsole_delete_volume() {
 +
  debug "Doing 'delete volume' with bconsole"
 +
  s=`eval mklen $1 3`
 +
  $bconsole <<EOD_DELVOL
 +
delete volume=m${magindex}s${s}
 +
yes
 +
quit
 +
EOD_DELVOL
 +
}
 +
 
 +
 
 +
#
 +
# Label volumes from barcodes with bconsole
 +
#
 +
function bconsole_label_barcodes() {
 +
  debug "Doing 'label barcodes' with bconsole"
 +
  $bconsole <<EOD_SDSTAT
 +
label storage=$baculasd pool=$purgepool drive=0 barcodes
 +
yes
 +
quit
 +
EOD_SDSTAT
 +
}
 +
 
 +
#
 +
# Checks if any of magazine's volumes are in use
 +
#
 +
function volumes_in_use() {
 +
  debug "Checking for in use volumes"
 +
  inuse=""
 +
  bconsole_sd_status | while read f; do
 +
      #echo $f
 +
      a=`echo ${f} | grep ^${magindex}`
 +
      if [ "$a" != "" -a "$inuse" == "" ]; then
 +
        inuse=`echo $f | cut -d ' ' -f 1`
 +
      fi
 +
  done
 +
  if [ "$inuse" != "" ]; then
 +
      echo $inuse
 +
  fi
 +
}
 +
 
 +
 
 +
#
 +
# Unload all drives
 +
#
 +
function unload_drives() {
 +
  debug "Unloading all drives"
 +
  vuse=`eval volumes_in_use`
 +
  if [ "${vuse}" != "" ]; then
 +
      return 1
 +
  fi
 +
  i=0
 +
  while [ $i -le $maxdrive ]; do
 +
      unlink "${statedir}/drive${i}" 2>/dev/null >/dev/null
 +
      echo "0" >"${statedir}/loaded${i}"
 +
      i=`expr ${i} + 1`
 +
  done
 +
  return 0
 +
}
 +
 
 +
 
 +
#
 +
# check parameter count on commandline
 +
#
 +
function check_parm_count() {
 +
    pCount=$1
 +
    pCountNeed=$2
 +
    if test $pCount -lt $pCountNeed; then
 +
echo "usage: vchanger 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
 +
}
 +
 
 +
# Setup arguments
 +
check_parm_count $# 2
 +
ctl=$1
 +
cmd=$2
 +
slot=$3
 +
device=$4
 +
drive=$5
 +
 
 +
# Setup default config values
 +
baculasd=
 +
baculasd_user=bacula
 +
bconsole="/etc/bacula/bconsole"
 +
magslots=10
 +
maxdrive=0
 +
mountpoint=
 +
purgepool="Scratch"
 +
statedir=
 +
 
 +
# Pull in conf file
 +
if [ -f $ctl ]; then
 +
  . $ctl
 +
else
 +
  echo "Config file ${ctl} not found"
 +
  exit 1
 +
fi
 +
 
 +
# When invoked by root, create files/dirs as bacula-sd user
 +
su_uid=
 +
myuid=`eval get_uid`
 +
if [ "$myuid" == "0" -a "$baculasd_user" != "" ]; then
 +
  buid=`eval get_uid $baculasd_user`
 +
  if [ "$buid" == "" ]; then
 +
      echo "bacula-sd user $baculasd_user not found"
 +
      exit 1
 +
  fi
 +
  if [ "$buid" != "0" ]; then
 +
      su_uid=baculasd_user
 +
  fi
 +
fi
 +
 
 +
# check for required config values
 +
if [ "${mountpoint}" == "" ]; then
 +
  echo "Required variable 'mountpoint' not defined in ${ctl}"
 +
  exit 1
 +
fi
 +
if [ "${baculasd}" == "" ]; then
 +
  echo "Required variable 'baculasd' not defined in ${ctl}"
 +
  exit 1
 +
fi
 +
if [ "${statedir}" == "" ]; then
 +
  echo "Required variable 'statedir' not defined in ${ctl}"
 +
  exit 1
 +
fi
 +
if [ "${magslots}" == "" -o $magslots -lt 1 -o $magslots -gt 999 ]; then
 +
  echo "Ivalid value for 'magslots' in ${ctl}"
 +
  exit 1
 +
fi
 +
if [ "${maxdrive}" == "" -o $maxdrive -lt 0 -o $maxdrive -ge $magslots ]; then
 +
  echo "Invalid value for 'maxdrive' in ${ctl}"
 +
  exit 1
 +
fi
 +
if [ "${bconsole}" == "" -o ! -f "${bconsole}" ]; then
 +
  echo "Ivalid value for 'bconsole' in ${ctl}"
 +
  exit 1
 +
fi
 +
if [ "${purgepool}" == "" ]; then
 +
  echo "Invalid value for 'purgepool' in ${ctl}"
 +
  exit 1
 +
fi
 +
 
 +
# attempt to set defaults for params not specified on command line
 +
if [ "${drive}" == "" ]; then
 +
  drive=0
 +
fi
 +
if [ "${device}" == "" ]; then
 +
  device="${statedir}/drive${drive}"
 +
fi
 +
 
 +
# make sure archive device makes sense
 +
if [ "${device}" != "${statedir}/drive${drive}" ]; then
 +
  echo "Param 4 (archive device) must be ${statedir}/driveN,"
 +
  echo "  where N is the drive number passed as param 5"
 +
  exit 1
 +
fi
 +
 
 +
# Initialize state directory for this autochanger
 +
init_statedir
 +
 
 +
debug "Parms: $ctl $cmd $slot $device $drive"
 +
 
 +
#
 +
#  Process command
 +
#
 +
case $cmd in
 +
  list)
 +
      check_parm_count $# 2
 +
      debug "Doing list command"
 +
      init_magazine
 +
      if [ $? -ne 0 ]; then
 +
        echo "Magazine Not Loaded"
 +
        exit 1
 +
      fi
 +
      i=1
 +
      while [ $i -le $magslots ]; do
 +
        s=`eval mklen ${i} 3`
 +
        echo "${i}:m${magindex}s${s}"
 +
        i=`expr ${i} + 1`
 +
      done
 +
      ;;
 +
  slots)
 +
      check_parm_count $# 2
 +
      debug "Doing slots command"
 +
      echo $magslots
 +
      ;;
 +
  load)
 +
      check_parm_count $# 5
 +
      debug "Doing load slot $slot into drive $drive"
 +
      if [ $drive -gt $maxdrive ]; then
 +
        echo "Drive ($drive) out of range (0-${maxdrive})"
 +
        exit 1
 +
      fi
 +
      if [ $slot -gt $magslots ]; then
 +
        echo "Slot ($slot) out of range (1-$magslots)"
 +
        exit 1
 +
      fi
 +
      ld=`cat "${statedir}/loaded${drive}"`
 +
      if [ $? -ne 0 ]; then
 +
        echo "Failed to read ${statedir}/loaded${drive}"
 +
        exit 1
 +
      fi
 +
      if [ $ld -eq 0 ]; then
 +
        unlink "${device}" &>/dev/null
 +
        # make sure slot is not loaded in another drive
 +
        i=0
 +
        while [ $i -le $maxdrive ]; do
 +
            if [ $i -ne $drive ]; then
 +
              ldi=`cat "${statedir}/loaded${i}"`
 +
              if [ $ldi -eq $slot ]; then
 +
                  echo "Storage Element ${slot} Empty (loaded in drive ${i})"
 +
                  exit 1
 +
              fi
 +
            fi
 +
            i=`expr ${i} + 1`
 +
        done
 +
        init_magazine
 +
        if [ $? -ne 0 ]; then
 +
            echo "Magazine Not Loaded"
 +
            exit 1
 +
        fi
 +
        s=`eval mklen ${slot} 3`
 +
        if [ "$su_uid" != "" ]; then
 +
            su -c "ln -s '${mountpoint}/m${magindex}s${s}' '${device}'" $su_uid
 +
        else
 +
            ln -s "${mountpoint}/m${magindex}s${s}" "${device}"
 +
        fi
 +
        echo $slot >"${statedir}/loaded${drive}"
 +
      else
 +
        echo "Drive ${drive} Full (Storage element ${ld} loaded)"
 +
        exit 1
 +
      fi
 +
      ;;
 +
  unload)
 +
      check_parm_count $# 5
 +
      debug "Doing unload drive $drive into slot $slot"
 +
      if [ $drive -gt $maxdrive ]; then
 +
        echo "Drive ($drive) out of range (0-${maxdrive})"
 +
        exit 1
 +
      fi
 +
      if [ $slot -gt $magslots ]; then
 +
        echo "Slot ($slot) out of range (1-$magslots)"
 +
        exit 1
 +
      fi
 +
      ld=`cat "${statedir}/loaded${drive}"`
 +
      if [ $? -ne 0 ]; then
 +
        echo "Failed to read ${statedir}/loaded${drive}"
 +
        exit 1
 +
      fi
 +
      if [ $slot -eq $ld ]; then
 +
        echo "0" >"${statedir}/loaded${drive}"
 +
        if [ $? -ne 0 ]; then
 +
            echo "Failed to write ${statedir}/loaded${drive}"
 +
            exit 1
 +
        fi
 +
        unlink "${device}" 2>/dev/null >/dev/null
 +
        exit 0
 +
      fi
 +
      if [ $ld -eq 0 ]; then
 +
        echo "Drive ${drive} Is Empty"
 +
        exit 1
 +
      else
 +
        echo "Storage Element ${slot} is Already Full"
 +
        exit 1
 +
      fi
 +
      ;;
 +
  loaded)
 +
      check_parm_count $# 5
 +
      debug "Doing loaded command for drive $drive"
 +
      if [ $drive -gt $maxdrive ]; then
 +
        echo "Drive ($drive) out of range (0-${maxdrive})"
 +
        exit 1
 +
      fi
 +
      if [ $slot -gt $magslots ]; then
 +
        echo "Slot ($slot) out of range (1-$magslots)"
 +
        exit 1
 +
      fi
 +
      cat "${statedir}/loaded${drive}"
 +
      ;;
 +
  purge)
 +
      check_parm_count $# 2
 +
      debug "Doing purge command"
 +
      magindex=`eval get_magazine`
 +
      if [ "$magazine" == "00" ]; then
 +
        echo No magazine loaded
 +
      fi
 +
      cm=""
 +
      while [ "$cm" != "y" -a "$cm" != "n" ]; do
 +
        echo -n "Purge all volumes on magazine $magindex (y/n)? "
 +
        read cm
 +
        if [ "$cm" == "Y" ]; then
 +
            cm="y"
 +
        fi
 +
        if [ "$cm" == "N" ]; then
 +
            cm="n"
 +
        fi
 +
      done
 +
      if [ "$cm" == "n" ]; then
 +
        exit 0
 +
      fi
 +
      echo "Unloading $baculasd drives"
 +
      unload_drives
 +
      if [ $? -ne 0 ]; then
 +
        echo Volume `eval volumes_in_use` in use...aborting
 +
        exit 1
 +
      fi
 +
      echo "Deleting magazine $magindex volumes"
 +
      i=1
 +
      while [ $i -le $magslots ]; do
 +
        bconsole_delete_volume $i &>/tmp/vclog
 +
        rm -f "${mountpoint}/m${magindex}s${s}"
 +
        echo "deleted volume m${magindex}s${s}"
 +
        i=`expr ${i} + 1`
 +
      done
 +
      echo "Doing 'label barcodes' to re-create magazine's volumes"
 +
      bconsole_label_barcodes | while read f; do
 +
        echo $f
 +
      done
 +
      ;;
 +
  *)
 +
      echo "Command not recognized"
 +
      exit 1
 +
      ;;
 +
esac
 +
 
 +
exit 0
 +
# eof
 +
</pre>

Revision as of 11:00, 3 March 2014

CentOS 6.5 Install

yum install mysql-server mysql-devel
service mysqld start
chkconfig mysqld on
mysqladmin -u root password Y0uR3l173P455w0rd


yum  install bareos-database-mysql
yum  install bareos


/usr/lib/bareos/scripts/create_bareos_database -u root -p
/usr/lib/bareos/scripts/make_bareos_tables -u root -p
/usr/lib/bareos/scripts/grant_bareos_privileges -u root -p


service bareos-dir start
service bareos-sd start
service bareos-fd start

Links

Archlinux GUI Admin

yaourt bareos-bat

Configure On CentOS 6.5

nano /etc/bareos/vchanger

</pre>


  1. !/bin/sh
  2. Bacula interface to virtual autochanger using removable disk drives
  3. Based (somewhat) on the "disk-changer" script from bacula 1.39.26
  4. Vchanger is a Bacula autochanger script that emulates a conventional
  5. magazine-based tape library device using removable disk drives.
  6. Partitions on the removable drives are used as virtual magazines,
  7. where each "magazine" contains the same number of virtual slots. Each
  8. "slot" holds one virtual tape, where a "tape" is a regular file that
  9. Bacula treats as a "Device Type = File" volume.
  10. This script will be invoked by Bacula using the Bacula Autochanger
  11. Interface and will be passed the following arguments:
  12. vchanger "changer-device" "command" "slot" "archive-device" "drive-index"
  13. $1 $2 $3 #4 #5
  14. See the Bacula documentation and the Bacula Removable Disk Howto for
  15. further details.
  16. Copyright (C) 2006 Josh Fisher
  17. Permission to use, copy, modify, distribute, and sell this software
  18. and its documentation for any purpose is hereby granted without fee,
  19. provided that the above copyright notice appear in all copies. This
  20. software is provided "as is" without express or implied warranty.
  21. This software is distributed in the hope that it will be useful,
  22. but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  24. $Id: vchanger,v 0.7.4 2006/12/01 09:29:04 jfisher Exp $
  1. log whats done
  2. to turn on logging, uncomment the following line
  3. touch $wd/vchanger.log
  1. Write to a log file
  2. To log debugging info, create file /var/bacula/vchanger.log
  3. with write permission for bacula-sd user. To stop logging,
  4. delete file /var/bacula/vchanger.log

dbgfile="/var/bacula/vchanger.log" function debug() {

   if test -e $dbgfile; then

echo "`date +\"%Y%m%d-%H:%M:%S\"` $*" >> $dbgfile

   fi

}

  1. Return length of string $1

if [ `uname` = "FreeBSD" ] then

       function strlen ()
       {
               expr -- "$1" : ".*"
       }

else

       function strlen ()
       {
               expr length $1
       }

fi


  1. Prepend zeros to $1 and return a string that is $2 characters long

function mklen () {

  o1=$1
  while [ `eval strlen ${o1}` -lt ${2} ]; do
     o1="0${o1}"
  done
  echo $o1

}

  1. Get uid of $1 (or current user if $1 empty)

function get_uid() {

  id $1 2>/dev/null | cut -d ' ' -f 1 | sed "s/uid=//" | cut -d '(' -f 1

}


  1. Initialize autochanger's state directory if not already initialized

function init_statedir() {

  debug "Initializing $statedir"
  # Create state directory if needed
  if [ ! -d "${statedir}" ]; then
     if [ "$su_uid" != "" ]; then
        su -c "mkdir ${statedir} &>/dev/null" $su_uid
     else
        mkdir ${statedir} &>/dev/null
     fi
     if [ $? -ne 0 ]; then
        echo "Could not create ${statedir}"
        exit 1
     fi
     chmod 770 ${statedir} &>/dev/null
     if [ $? -ne 0 ]; then
        echo "Could not chmod ${statedir}"
        exit 1
     fi
  fi
  # Create nextmag file to hold max magazine index used
  if [ ! -f "${statedir}/nextmag" ]; then
     if [ "$su_uid" != "" ]; then
        su -c "echo 0 >${statedir}/nextmag" $su_uid
     else

echo 0 >${statedir}/nextmag

     fi
     if [ $? -ne 0 ]; then
        echo "Could not create ${statedir}/nextmag"
        exit 1
     fi
     chmod 660 ${statedir}/nextmag
     if [ $? -ne 0 ]; then
        echo "Could not chmod ${statedir}/nextmag"
        exit 1
     fi
  fi
  # Check nextmag value
  nextmag=`cat "${statedir}/nextmag"`
  if [ $? -ne 0 -o "${nextmag}" == "" -o $nextmag -lt 0 -o $nextmag -gt 99 ]; then
     echo "${statedir}/nextmag has invalid value"
     return 1
  fi
  # Create 'loaded' files for each virtual drive that hold the slot
  # number currently loaded in that 'drive'
  i=0
  while [ $i -le $maxdrive ]; do
     if [ ! -f "${statedir}/loaded${i}" ]; then
        if [ "$su_uid" != "" ]; then
           su -c "echo 0 >${statedir}/loaded${i}" $su_uid
        else
           echo 0 >${statedir}/loaded${i}
        fi
        if [ $? -ne 0 ]; then
           echo "Could not create ${statedir}/loaded${i}"
           exit 1
        fi
        if [ "$su_uid" != "" ]; then
           su -c "chmod 660 ${statedir}/loaded${i}" $su_uid
        else
           chmod 660 ${statedir}/loaded${i}
        fi
        if [ $? -ne 0 ]; then
           echo "Could not chmod ${statedir}/loaded${i}"
           exit 1
        fi
     fi
     i=`expr ${i} + 1`
  done

}


  1. Get magazine index of currently loaded magazine

function get_magazine() {

  debug "Get magazine index"
  # Check for mountpoint dir
  if [ ! -d ${mountpoint} ]; then
     echo "No magazine loaded at ${mountpoint}"
     exit 1
  fi
  # Check magazine for existing index
  if [ ! -f "${mountpoint}/index" ]; then
     echo "00"
     return 1
  fi
  mi=`cat "${mountpoint}/index"`
  if [ $? -ne 0 ]; then
     echo "Failed to read ${mountpoint}/index"
     exit 1
  fi
  # must be 1-99
  if [ $mi -lt 1 -o $mi -gt 99 ]; then
     echo "Magazine has invalid index ${mi}"
     exit 1
  fi
  # make magazine index 2 digits
  eval mklen ${mi} 2
  return 0

}

  1. Initialize magazine if not already initialized

function init_magazine() {

  debug "Initializing magazine"
  # Get max magazine index that has been used
  nextmag=`cat "${statedir}/nextmag"`
  if [ $? -ne 0 -o "${nextmag}" == "" ]; then
     echo "Failed to read ${statedir}/nextmag"
     exit 1
  fi
  # Check magazine for existing index
  if [ -f "${mountpoint}/index" ]; then
     # retrieve existing magazine index
     mi=`cat "${mountpoint}/index"`
     if [ $? -ne 0 ]; then
        echo "Failed to read ${mountpoint}/index"
        exit 1
     fi
     # must be 1-99
     if [ $mi -lt 1 -o $mi -gt 99 ]; then
        echo "Magazine has invalid index ${mi}"
        exit 1
     fi
  else
     # new magazine, so assign it the next avail index
     mi=`expr ${nextmag} + 1`
     if [ $mi -lt 0 -o $mi -gt 99 ]; then
        echo "Max magazines exceeded"
        exit 1
     fi
     if [ "$su_uid" != "" ]; then
        su -c "echo ${mi} >${mountpoint}/index" $su_uid
     else
        echo ${mi} >${mountpoint}/index
     fi
     if [ $? -ne 0 ]; then
        echo "Failed to write ${mountpoint}/index"
        exit 1
     fi
     chmod 640 ${mountpoint}/index 2>/dev/null
  fi
  # make sure max index used is up to date
  if [ $mi -gt $nextmag ]; then
     echo $mi 2>/dev/null >"${statedir}/nextmag"
     if [ $? -ne 0 ]; then
        echo "Failed to update ${statedir}/nextmag"
        exit 1
     fi
  fi
  # make magazine index 2 digits
  magindex=`eval mklen ${mi} 2`
  # setup slot files (ie. virtual tapes)
  i=1
  while [ $i -le $magslots ]; do
     s=`eval mklen ${i} 3`
     f="${mountpoint}/m${magindex}s${s}"
     if [ ! -f "${f}" ]; then
        if [ "$su_uid" != "" ]; then
           su -c "touch ${f} &>/dev/null" $su_uid
        else
           touch ${f} &>/dev/null
        fi
        if [ $? -ne 0 ]; then
           echo "Failed to create ${f}"
           exit 1
        fi
     fi
     i=`expr ${i} + 1`
  done
  return 0

}


  1. Get sd status with bconsole

function bconsole_sd_status() {

  debug "Doing 'status storage' with bconsole"
  $bconsole <<EOD_SDSTAT

status storage=$baculasd quit EOD_SDSTAT }


  1. Delete volume with bconsole param1 = slot

function bconsole_delete_volume() {

  debug "Doing 'delete volume' with bconsole"
  s=`eval mklen $1 3`
  $bconsole <<EOD_DELVOL

delete volume=m${magindex}s${s} yes quit EOD_DELVOL }


  1. Label volumes from barcodes with bconsole

function bconsole_label_barcodes() {

  debug "Doing 'label barcodes' with bconsole"
  $bconsole <<EOD_SDSTAT

label storage=$baculasd pool=$purgepool drive=0 barcodes yes quit EOD_SDSTAT }

  1. Checks if any of magazine's volumes are in use

function volumes_in_use() {

  debug "Checking for in use volumes"
  inuse=""
  bconsole_sd_status | while read f; do
     #echo $f
     a=`echo ${f} | grep ^${magindex}`
     if [ "$a" != "" -a "$inuse" == "" ]; then
        inuse=`echo $f | cut -d ' ' -f 1`
     fi
  done
  if [ "$inuse" != "" ]; then
     echo $inuse
  fi

}


  1. Unload all drives

function unload_drives() {

  debug "Unloading all drives"
  vuse=`eval volumes_in_use`
  if [ "${vuse}" != "" ]; then
     return 1
  fi
  i=0
  while [ $i -le $maxdrive ]; do
     unlink "${statedir}/drive${i}" 2>/dev/null >/dev/null
     echo "0" >"${statedir}/loaded${i}"
     i=`expr ${i} + 1`
  done
  return 0

}


  1. check parameter count on commandline

function check_parm_count() {

   pCount=$1
   pCountNeed=$2
   if test $pCount -lt $pCountNeed; then

echo "usage: vchanger 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

}

  1. Setup arguments

check_parm_count $# 2 ctl=$1 cmd=$2 slot=$3 device=$4 drive=$5

  1. Setup default config values

baculasd= baculasd_user=bacula bconsole="/etc/bacula/bconsole" magslots=10 maxdrive=0 mountpoint= purgepool="Scratch" statedir=

  1. Pull in conf file

if [ -f $ctl ]; then

  . $ctl

else

  echo "Config file ${ctl} not found"
  exit 1

fi

  1. When invoked by root, create files/dirs as bacula-sd user

su_uid= myuid=`eval get_uid` if [ "$myuid" == "0" -a "$baculasd_user" != "" ]; then

  buid=`eval get_uid $baculasd_user`
  if [ "$buid" == "" ]; then
     echo "bacula-sd user $baculasd_user not found"
     exit 1
  fi
  if [ "$buid" != "0" ]; then
     su_uid=baculasd_user
  fi

fi

  1. check for required config values

if [ "${mountpoint}" == "" ]; then

  echo "Required variable 'mountpoint' not defined in ${ctl}"
  exit 1

fi if [ "${baculasd}" == "" ]; then

  echo "Required variable 'baculasd' not defined in ${ctl}"
  exit 1

fi if [ "${statedir}" == "" ]; then

  echo "Required variable 'statedir' not defined in ${ctl}"
  exit 1

fi if [ "${magslots}" == "" -o $magslots -lt 1 -o $magslots -gt 999 ]; then

  echo "Ivalid value for 'magslots' in ${ctl}"
  exit 1

fi if [ "${maxdrive}" == "" -o $maxdrive -lt 0 -o $maxdrive -ge $magslots ]; then

  echo "Invalid value for 'maxdrive' in ${ctl}"
  exit 1

fi if [ "${bconsole}" == "" -o ! -f "${bconsole}" ]; then

  echo "Ivalid value for 'bconsole' in ${ctl}"
  exit 1

fi if [ "${purgepool}" == "" ]; then

  echo "Invalid value for 'purgepool' in ${ctl}"
  exit 1

fi

  1. attempt to set defaults for params not specified on command line

if [ "${drive}" == "" ]; then

  drive=0

fi if [ "${device}" == "" ]; then

  device="${statedir}/drive${drive}"

fi

  1. make sure archive device makes sense

if [ "${device}" != "${statedir}/drive${drive}" ]; then

  echo "Param 4 (archive device) must be ${statedir}/driveN,"
  echo "   where N is the drive number passed as param 5"
  exit 1

fi

  1. Initialize state directory for this autochanger

init_statedir

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

  1. Process command

case $cmd in

  list)
     check_parm_count $# 2
     debug "Doing list command"
     init_magazine
     if [ $? -ne 0 ]; then
        echo "Magazine Not Loaded"
        exit 1
     fi
     i=1
     while [ $i -le $magslots ]; do
        s=`eval mklen ${i} 3`
        echo "${i}:m${magindex}s${s}"
        i=`expr ${i} + 1`
     done
     ;;
  slots)
     check_parm_count $# 2
     debug "Doing slots command"
     echo $magslots
     ;;
  load)
     check_parm_count $# 5
     debug "Doing load slot $slot into drive $drive"
     if [ $drive -gt $maxdrive ]; then
        echo "Drive ($drive) out of range (0-${maxdrive})"
        exit 1
     fi
     if [ $slot -gt $magslots ]; then
        echo "Slot ($slot) out of range (1-$magslots)"
        exit 1
     fi
     ld=`cat "${statedir}/loaded${drive}"`
     if [ $? -ne 0 ]; then
        echo "Failed to read ${statedir}/loaded${drive}"
        exit 1
     fi
     if [ $ld -eq 0 ]; then
        unlink "${device}" &>/dev/null
        # make sure slot is not loaded in another drive
        i=0
        while [ $i -le $maxdrive ]; do
           if [ $i -ne $drive ]; then
              ldi=`cat "${statedir}/loaded${i}"`
              if [ $ldi -eq $slot ]; then
                 echo "Storage Element ${slot} Empty (loaded in drive ${i})"
                 exit 1
              fi
           fi
           i=`expr ${i} + 1`
        done
        init_magazine
        if [ $? -ne 0 ]; then
           echo "Magazine Not Loaded"
           exit 1
        fi
        s=`eval mklen ${slot} 3`
        if [ "$su_uid" != "" ]; then
           su -c "ln -s '${mountpoint}/m${magindex}s${s}' '${device}'" $su_uid
        else
           ln -s "${mountpoint}/m${magindex}s${s}" "${device}"
        fi
        echo $slot >"${statedir}/loaded${drive}"
     else
        echo "Drive ${drive} Full (Storage element ${ld} loaded)"
        exit 1
     fi
     ;;
  unload)
     check_parm_count $# 5
     debug "Doing unload drive $drive into slot $slot"
     if [ $drive -gt $maxdrive ]; then
        echo "Drive ($drive) out of range (0-${maxdrive})"
        exit 1
     fi
     if [ $slot -gt $magslots ]; then
        echo "Slot ($slot) out of range (1-$magslots)"
        exit 1
     fi
     ld=`cat "${statedir}/loaded${drive}"`
     if [ $? -ne 0 ]; then
        echo "Failed to read ${statedir}/loaded${drive}"
        exit 1
     fi
     if [ $slot -eq $ld ]; then
        echo "0" >"${statedir}/loaded${drive}"
        if [ $? -ne 0 ]; then
           echo "Failed to write ${statedir}/loaded${drive}"
           exit 1
        fi
        unlink "${device}" 2>/dev/null >/dev/null
        exit 0
     fi
     if [ $ld -eq 0 ]; then
        echo "Drive ${drive} Is Empty"
        exit 1
     else
        echo "Storage Element ${slot} is Already Full"
        exit 1
     fi
     ;;
  loaded)
     check_parm_count $# 5
     debug "Doing loaded command for drive $drive"
     if [ $drive -gt $maxdrive ]; then
        echo "Drive ($drive) out of range (0-${maxdrive})"
        exit 1
     fi
     if [ $slot -gt $magslots ]; then
        echo "Slot ($slot) out of range (1-$magslots)"
        exit 1
     fi
     cat "${statedir}/loaded${drive}"
     ;;
  purge)
     check_parm_count $# 2
     debug "Doing purge command"
     magindex=`eval get_magazine`
     if [ "$magazine" == "00" ]; then
        echo No magazine loaded
     fi
     cm=""
     while [ "$cm" != "y" -a "$cm" != "n" ]; do
        echo -n "Purge all volumes on magazine $magindex (y/n)? "
        read cm
        if [ "$cm" == "Y" ]; then
           cm="y"
        fi
        if [ "$cm" == "N" ]; then
           cm="n"
        fi
     done
     if [ "$cm" == "n" ]; then
        exit 0
     fi
     echo "Unloading $baculasd drives"
     unload_drives
     if [ $? -ne 0 ]; then
        echo Volume `eval volumes_in_use` in use...aborting
        exit 1
     fi
     echo "Deleting magazine $magindex volumes"
     i=1
     while [ $i -le $magslots ]; do
        bconsole_delete_volume $i &>/tmp/vclog
        rm -f "${mountpoint}/m${magindex}s${s}"
        echo "deleted volume m${magindex}s${s}"
        i=`expr ${i} + 1`
     done
     echo "Doing 'label barcodes' to re-create magazine's volumes"
     bconsole_label_barcodes | while read f; do
        echo $f
     done
     ;;
  *)
     echo "Command not recognized"
     exit 1
     ;;

esac

exit 0

  1. eof

</pre>