]> git.sur5r.net Git - bacula/bacula/blob - bacula/scripts/disk-changer.in
97b0ebac591fd6a4551cfb2fa1044e8a04bea0b2
[bacula/bacula] / bacula / scripts / disk-changer.in
1 #!/bin/sh
2 #
3 # Bacula interface to virtual autoloader using disk storage
4 #
5 #  Written by Kern Sibbald
6 #
7 #  Bacula® - The Network Backup Solution
8 #
9 #  Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
10 #
11 #  The main author of Bacula is Kern Sibbald, with contributions from many
12 #  others, a complete list can be found in the file AUTHORS.
13 #
14 #  You may use this file and others of this release according to the
15 #  license defined in the LICENSE file, which includes the Affero General
16 #  Public License, v3.0 ("AGPLv3") and some additional permissions and
17 #  terms pursuant to its AGPLv3 Section 7.
18 #
19 #  Bacula® is a registered trademark of Kern Sibbald.
20 #
21 #
22 #  If you set in your Device resource
23 #
24 #  Changer Command = "path-to-this-script/disk-changer %c %o %S %a %d"
25 #    you will have the following input to this script:
26 #
27 #  So Bacula will always call with all the following arguments, even though
28 #    in come cases, not all are used. Note, the Volume name is not always
29 #    included.
30 #
31 #  disk-changer "changer-device" "command" "slot" "archive-device" "drive-index" "volume"
32 #                   $1              $2       $3        $4               $5         $6
33 #
34 # By default the autochanger has 10 Volumes and 1 Drive.
35 #
36 # Note: For this script to work, you *must" specify
37 #    Device Type = File
38 # in each of the Devices associated with your AutoChanger resource.
39 #
40 # changer-device is the name of a file that overrides the default
41 #   volumes and drives.  It may have:
42 #        maxslot=n   where n is one based (default 10)
43 #        maxdrive=m  where m is zero based (default 1 -- i.e. 2 drives)
44 #
45 #   This code can also simulate barcodes. You simply put
46 #   a list of the slots and barcodes in the "base" directory/barcodes.
47 #   See below for the base directory definition.  Example of a
48 #   barcodes file:
49 #      /var/bacula/barcodes
50 #      1:Vol001
51 #      2:Vol002
52 #      ...
53 #
54 # archive-device is the name of the base directory where you want the
55 #  Volumes stored appended with /drive0 for the first drive; /drive1
56 #  for the second drive, ... For example, you might use
57 #  /var/bacula/drive0  Note: you must not have a trailing slash, and
58 #  the string (e.g. /drive0) must be unique, and it must not match
59 #  any other part of the directory name. These restrictions could be
60 #  easily removed by any clever script jockey.
61 #
62 #  Full example: disk-changer /var/bacula/conf load 1 /var/bacula/drive0 0 TestVol001
63 #
64 # The Volumes will be created with names slot1, slot2, slot3, ... maxslot in the
65 #  base directory. In the above example the base directory is /var/bacula.
66 #  However, as with tapes, their Bacula Volume names will be stored inside the
67 #  Volume label. In addition to the Volumes (e.g. /var/bacula/slot1,
68 #  /var/bacula/slot3, ...) this script will create a /var/bacula/loadedn
69 #  file to keep track of what Slot is loaded. You should not change this file.
70 #
71 # Modified 8 June 2010 to accept Volume names from the calling program as arg 6.
72 #  In this case, rather than storing the data in slotn, it is stored in the
73 #  Volume name.  Note: for this to work, Volume names may not include spaces.
74 #
75
76 wd=@working_dir@
77
78 #
79 # log whats done
80 #
81 # to turn on logging, uncomment the following line
82 #touch $wd/disk-changer.log
83 #
84 dbgfile="$wd/disk-changer.log"
85 debug() {
86     if test -f $dbgfile; then
87         echo "`date +\"%Y%m%d-%H:%M:%S\"` $*" >> $dbgfile
88     fi
89 }
90
91
92 #
93 # Create a temporary file
94 #
95 make_temp_file() {
96   TMPFILE=`mktemp -t mtx.XXXXXXXXXX`
97   if test x${TMPFILE} = x; then
98      TMPFILE="$wd/disk-changer.$$"
99      if test -f ${TMPFILE}; then
100         echo "Temp file security problem on: ${TMPFILE}"
101         exit 1
102      fi
103   fi
104 }
105
106 # check parameter count on commandline
107 #
108 check_parm_count() {
109     pCount=$1
110     pCountNeed=$2
111     if test $pCount -lt $pCountNeed; then
112         echo "usage: disk-changer ctl-device command [slot archive-device drive-index]"
113         echo "  Insufficient number of arguments arguments given."
114         if test $pCount -lt 2; then
115             echo "  Mimimum usage is first two arguments ..."
116         else
117             echo "  Command expected $pCountNeed arguments"
118         fi
119         exit 1
120     fi
121 }
122
123 #
124 # Strip off the final name in order to get the Directory ($dir)
125 #  that we are dealing with.
126 #
127 get_dir() {
128    bn=`basename $device`
129    dir=`echo "$device" | sed -e s%/$bn%%g`
130    if [ ! -d $dir ]; then
131       echo "ERROR: Autochanger directory \"$dir\" does not exist."
132       echo "       You must create it."
133       exit 1
134    fi
135 }
136
137 #
138 # Get the Volume name from the call line, or directly from
139 #  the volslotn information.
140 #
141 get_vol() {
142    havevol=0
143    debug "vol=$volume"
144    if test "x$volume" != x && test "x$volume" != "x*NONE*" ; then
145       debug "touching $dir/$volume"
146       touch $dir/$volume
147       echo "$volume" >$dir/volslot${slot}
148       havevol=1
149    elif [ -f $dir/volslot${slot} ]; then
150       volume=`cat $dir/volslot${slot}`
151       havevol=1
152    fi
153 }
154
155
156 # Setup arguments
157 ctl=$1
158 cmd="$2"
159 slot=$3
160 device=$4
161 drive=$5
162 volume=$6
163
164 # set defaults
165 maxdrive=1
166 maxslot=10
167
168 # Pull in conf file
169 if [ -f $ctl ]; then
170    . $ctl
171 fi
172
173
174 # Check for special cases where only 2 arguments are needed,
175 #  all others are a minimum of 5
176 #
177 case $2 in
178     list|listall)
179         check_parm_count $# 2
180         ;;
181     slots)
182         check_parm_count $# 2
183         ;;
184     transfer)
185         check_parm_count $# 4
186         if [ $slot -gt $maxslot ]; then
187            echo "Slot ($slot) out of range (1-$maxslot)"
188            debug "Error: Slot ($slot) out of range (1-$maxslot)"
189            exit 1
190         fi
191         ;;
192     *)
193         check_parm_count $# 5
194         if [ $drive -gt $maxdrive ]; then
195            echo "Drive ($drive) out of range (0-$maxdrive)"
196            debug "Error: Drive ($drive) out of range (0-$maxdrive)"
197            exit 1
198         fi
199         if [ $slot -gt $maxslot ]; then
200            echo "Slot ($slot) out of range (1-$maxslot)"
201            debug "Error: Slot ($slot) out of range (1-$maxslot)"
202            exit 1
203         fi
204         ;;
205 esac
206
207
208 debug "Parms: $ctl $cmd $slot $device $drive $volume $havevol"
209
210 case $cmd in
211    unload)
212       debug "Doing disk -f $ctl unload $slot $device $drive $volume"
213       get_dir
214       if [ -f $dir/loaded${drive} ]; then
215          ld=`cat $dir/loaded${drive}`
216       else
217          echo "Storage Element $slot is Already Full"
218          debug "Unload error: $dir/loaded${drive} is already unloaded"
219          exit 1
220       fi
221       if [ $slot -eq $ld ]; then
222          echo "0" >$dir/loaded${drive}
223          unlink $device 2>/dev/null >/dev/null
224       else
225          echo "Storage Element $slot is Already Full"
226          debug "Unload error: $dir/loaded${drive} slot=$ld is already unloaded"
227          exit 1
228       fi
229       ;;
230
231    load)
232       debug "Doing disk $ctl load $slot $device $drive $volume"
233       get_dir
234       i=0
235       # Check if slot already in a drive
236       while [ $i -le $maxdrive ]; do
237          if [ -f $dir/loaded${i} ]; then
238             ld=`cat $dir/loaded${i}`
239          else   
240             ld=0
241          fi
242          if [ $ld -eq $slot ]; then
243             echo "Drive ${i} Full (Storage element ${ld} loaded)"
244             debug "Load error: Cannot load Slot=${ld} in drive=$drive. Already in drive=${i}"
245             exit 1
246          fi
247          i=`expr $i + 1`
248       done
249       # Check if we have a Volume name
250       get_vol
251       if [ $havevol -eq 0 ]; then
252          # check if slot exists
253          if [ ! -f $dir/slot${slot} ] ; then
254             echo "source Element Address $slot is Empty"
255             debug "Load error: source Element Address $slot is Empty"
256             exit 1
257          fi
258       fi
259       if [ -f $dir/loaded${drive} ]; then
260          ld=`cat $dir/loaded${drive}`
261       else
262          ld=0
263       fi
264       if [ $ld -ne 0 ]; then
265          echo "Drive ${drive} Full (Storage element ${ld} loaded)"
266          echo "Load error: Drive ${drive} Full (Storage element ${ld} loaded)"
267          exit 1
268       fi
269       echo "0" >$dir/loaded${drive}
270       unlink $device 2>/dev/null >/dev/null
271       if [ $havevol -ne 0 ]; then
272          ln -s $dir/$volume $device
273          rtn=$?
274       else
275          ln -s $dir/slot${slot} $device
276          rtn=$?
277       fi
278       if [ $rtn -eq 0 ]; then
279          echo $slot >$dir/loaded${drive}
280       fi
281       exit $rtn
282       ;;
283
284    list)
285       debug "Doing disk -f $ctl -- to list volumes"
286       get_dir
287       if [ -f $dir/barcodes ]; then
288          cat $dir/barcodes
289       else
290          i=1
291          while [ $i -le $maxslot ]; do
292             slot=$i
293             volume=
294             get_vol
295             if [ $havevol -eq 0 ]; then
296                echo "$i:"
297             else
298                echo "$i:$volume"
299             fi
300             i=`expr $i + 1`
301          done
302       fi
303       exit 0
304       ;;
305
306    listall)
307       # ***FIXME*** must add new Volume stuff
308       make_temp_file
309       debug "Doing disk -f $ctl -- to list volumes"
310       get_dir
311       if [ ! -f $dir/barcodes ]; then
312           exit 0
313       fi
314
315       # we print drive content seen by autochanger
316       # and we also remove loaded media from the barcode list
317       i=0
318       while [ $i -le $maxdrive ]; do
319          if [ -f $dir/loaded${i} ]; then
320              ld=`cat $dir/loaded${i}`
321              v=`awk -F: "/^$ld:/"' { print $2 }' $dir/barcodes`
322              echo "D:$i:F:$ld:$v"
323              echo "^$ld:" >> $TMPFILE
324          fi
325          i=`expr $i + 1`
326       done
327
328       # Empty slots are not in barcodes file
329       # When we detect a gap, we print missing rows as empty
330       # At the end, we fill the gap between the last entry and maxslot
331       grep -v -f $TMPFILE $dir/barcodes | sort -n | \
332       perl -ne 'BEGIN { $cur=1 }
333        if (/(\d+):(.+)?/) {
334          if ($cur == $1) {
335            print "S:$1:F:$2\n"
336          } else {
337            while ($cur < $1) {
338               print "S:$cur:E\n";
339               $cur++;
340            }
341          }
342          $cur++;
343        }
344        END { while ($cur < '"$maxslot"') { print "S:$cur:E\n"; $cur++; } } '
345
346       rm -f $TMPFILE
347       exit 0
348       ;;
349    transfer)
350       #  ***FIXME*** must add new Volume stuff
351       get_dir
352       make_temp_file
353       slotdest=$device
354       if [ -f $dir/slot{$slotdest} ]; then
355          echo "destination Element Address $slot is Full"
356          exit 1
357       fi
358       if [ ! -f $dir/slot${slot} ] ; then
359          echo "source Element Address $slot is Empty"
360          exit 1
361       fi
362
363       echo "Transfering $slot to $slotdest"
364       mv $dir/slot${slot} $dir/slot{$slotdest}
365
366       if [ -f $dir/barcodes ]; then
367          sed "s/^$slot:/$slotdest:/" >  $TMPFILE
368          sort -n $TMPFILE > $dir/barcodes
369       fi
370       exit 0
371       ;;
372    loaded)
373       debug "Doing disk -f $ctl $drive -- to find what is loaded"
374       get_dir
375       if [ -f $dir/loaded${drive} ]; then
376          a=`cat $dir/loaded${drive}`
377       else
378          a="0"
379       fi
380       debug "Loaded: drive=$drive is $a"
381       echo $a
382       exit
383       ;;
384
385    slots)
386       debug "Doing disk -f $ctl -- to get count of slots"
387       echo $maxslot
388       ;;
389 esac