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