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