Bacula and Bareos: Difference between revisions
| Line 32: | Line 32: | ||
nano /etc/bareos/vchanger | nano /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 12: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
- http://www.unixmen.com/install-and-configure-bacula-server-in-centos-6-4-rhel-6-4/
- http://www.bareos.org/en/documentation.html
- http://doc.bareos.org/master/html/bareos-manual-main-reference.html
Archlinux GUI Admin
yaourt bareos-bat
Configure On CentOS 6.5
nano /etc/bareos/vchanger
- !/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