/etc/bacula/scripts/disk-changer is in bacula-sd 9.0.6-1build1.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | #!/bin/sh
#
# Bacula interface to virtual autoloader using disk storage
#
# Written by Kern Sibbald
#
# Bacula(R) - The Network Backup Solution
#
# Copyright (C) 2000-2016 Kern Sibbald
#
# The original author of Bacula is Kern Sibbald, with contributions
# from many others, a complete list can be found in the file AUTHORS.
#
# You may use this file and others of this release according to the
# license defined in the LICENSE file, which includes the Affero General
# Public License, v3.0 ("AGPLv3") and some additional permissions and
# terms pursuant to its AGPLv3 Section 7.
#
# This notice must be preserved when any source code is
# conveyed and/or propagated.
#
# Bacula(R) is a registered trademark of Kern Sibbald.
# 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. Note, the Volume name is not always
# included.
#
# disk-changer "changer-device" "command" "slot" "archive-device" "drive-index" "volume"
# $1 $2 $3 $4 $5 $6
#
# 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 TestVol001
#
# 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.
#
# Modified 8 June 2010 to accept Volume names from the calling program as arg 6.
# In this case, rather than storing the data in slotn, it is stored in the
# Volume name. Note: for this to work, Volume names may not include spaces.
#
wd=/var/lib/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."
echo " You must create it."
exit 1
fi
}
#
# Get the Volume name from the call line, or directly from
# the volslotn information.
#
get_vol() {
havevol=0
debug "vol=$volume"
if test "x$volume" != x && test "x$volume" != "x*NONE*" ; then
debug "touching $dir/$volume"
touch $dir/$volume
echo "$volume" >$dir/volslot${slot}
havevol=1
elif [ -f $dir/volslot${slot} ]; then
volume=`cat $dir/volslot${slot}`
havevol=1
fi
}
# Setup arguments
ctl=$1
cmd="$2"
slot=$3
device=$4
drive=$5
volume=$6
# 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|listall)
check_parm_count $# 2
;;
slots)
check_parm_count $# 2
;;
transfer)
check_parm_count $# 4
if [ $slot -gt $maxslot ]; then
echo "Slot ($slot) out of range (1-$maxslot)"
debug "Error: Slot ($slot) out of range (1-$maxslot)"
exit 1
fi
;;
*)
check_parm_count $# 5
if [ $drive -gt $maxdrive ]; then
echo "Drive ($drive) out of range (0-$maxdrive)"
debug "Error: Drive ($drive) out of range (0-$maxdrive)"
exit 1
fi
if [ $slot -gt $maxslot ]; then
echo "Slot ($slot) out of range (1-$maxslot)"
debug "Error: Slot ($slot) out of range (1-$maxslot)"
exit 1
fi
;;
esac
debug "Parms: $ctl $cmd $slot $device $drive $volume $havevol"
case $cmd in
unload)
debug "Doing disk -f $ctl unload $slot $device $drive $volume"
get_dir
if [ -f $dir/loaded${drive} ]; then
ld=`cat $dir/loaded${drive}`
else
echo "Storage Element $slot is Already Full"
debug "Unload error: $dir/loaded${drive} is already unloaded"
exit 1
fi
if [ $slot -eq $ld ]; then
echo "0" >$dir/loaded${drive}
unlink $device 2>/dev/null >/dev/null
unlink ${device}.add 2>/dev/null >/dev/null
rm -f ${device} ${device}.add
else
echo "Storage Element $slot is Already Full"
debug "Unload error: $dir/loaded${drive} slot=$ld is already unloaded"
exit 1
fi
;;
load)
debug "Doing disk $ctl load $slot $device $drive $volume"
get_dir
i=0
# Check if slot already in a drive
while [ $i -le $maxdrive ]; do
if [ -f $dir/loaded${i} ]; then
ld=`cat $dir/loaded${i}`
else
ld=0
fi
if [ $ld -eq $slot ]; then
echo "Drive ${i} Full (Storage element ${ld} loaded)"
debug "Load error: Cannot load Slot=${ld} in drive=$drive. Already in drive=${i}"
exit 1
fi
i=`expr $i + 1`
done
# Check if we have a Volume name
get_vol
if [ $havevol -eq 0 ]; then
# check if slot exists
if [ ! -f $dir/slot${slot} ] ; then
echo "source Element Address $slot is Empty"
debug "Load error: source Element Address $slot is Empty"
exit 1
fi
fi
if [ -f $dir/loaded${drive} ]; then
ld=`cat $dir/loaded${drive}`
else
ld=0
fi
if [ $ld -ne 0 ]; then
echo "Drive ${drive} Full (Storage element ${ld} loaded)"
echo "Load error: Drive ${drive} Full (Storage element ${ld} loaded)"
exit 1
fi
echo "0" >$dir/loaded${drive}
unlink $device 2>/dev/null >/dev/null
unlink ${device}.add 2>/dev/null >/dev/null
rm -f ${device} ${device}.add
if [ $havevol -ne 0 ]; then
ln -s $dir/$volume $device
ln -s $dir/${volume}.add ${device}.add
rtn=$?
else
ln -s $dir/slot${slot} $device
ln -s $dir/slot${slot}.add ${device}.add
rtn=$?
fi
if [ $rtn -eq 0 ]; then
echo $slot >$dir/loaded${drive}
fi
exit $rtn
;;
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
slot=$i
volume=
get_vol
if [ $havevol -eq 0 ]; then
echo "$i:"
else
echo "$i:$volume"
fi
i=`expr $i + 1`
done
fi
exit 0
;;
listall)
# ***FIXME*** must add new Volume stuff
make_temp_file
debug "Doing disk -f $ctl -- to list volumes"
get_dir
if [ ! -f $dir/barcodes ]; then
exit 0
fi
# we print drive content seen by autochanger
# and we also remove loaded media from the barcode list
i=0
while [ $i -le $maxdrive ]; do
if [ -f $dir/loaded${i} ]; then
ld=`cat $dir/loaded${i}`
v=`awk -F: "/^$ld:/"' { print $2 }' $dir/barcodes`
echo "D:$i:F:$ld:$v"
echo "^$ld:" >> $TMPFILE
fi
i=`expr $i + 1`
done
# Empty slots are not in barcodes file
# When we detect a gap, we print missing rows as empty
# At the end, we fill the gap between the last entry and maxslot
grep -v -f $TMPFILE $dir/barcodes | sort -n | \
perl -ne 'BEGIN { $cur=1 }
if (/(\d+):(.+)?/) {
if ($cur == $1) {
print "S:$1:F:$2\n"
} else {
while ($cur < $1) {
print "S:$cur:E\n";
$cur++;
}
}
$cur++;
}
END { while ($cur < '"$maxslot"') { print "S:$cur:E\n"; $cur++; } } '
rm -f $TMPFILE
exit 0
;;
transfer)
# ***FIXME*** must add new Volume stuff
get_dir
make_temp_file
slotdest=$device
if [ -f $dir/slot{$slotdest} ]; then
echo "destination Element Address $slot is Full"
exit 1
fi
if [ ! -f $dir/slot${slot} ] ; then
echo "source Element Address $slot is Empty"
exit 1
fi
echo "Transfering $slot to $slotdest"
mv $dir/slot${slot} $dir/slot{$slotdest}
mv $dir/slot${slot}.add $dir/slot{$slotdest}.add
if [ -f $dir/barcodes ]; then
sed "s/^$slot:/$slotdest:/" > $TMPFILE
sort -n $TMPFILE > $dir/barcodes
fi
exit 0
;;
loaded)
debug "Doing disk -f $ctl $drive -- to find what is loaded"
get_dir
if [ -f $dir/loaded${drive} ]; then
a=`cat $dir/loaded${drive}`
else
a="0"
fi
debug "Loaded: drive=$drive is $a"
echo $a
exit
;;
slots)
debug "Doing disk -f $ctl -- to get count of slots"
echo $maxslot
;;
esac
|