Imported Upstream version 2.4.5
[debian/amanda] / changer-src / chg-multi.sh.in
1 #! /bin/sh
2 #
3 # Amanda, The Advanced Maryland Automatic Network Disk Archiver
4 # Copyright (c) 1991-1999 University of Maryland at College Park
5 # All Rights Reserved.
6 #
7 # Permission to use, copy, modify, distribute, and sell this software and its
8 # documentation for any purpose is hereby granted without fee, provided that
9 # the above copyright notice appear in all copies and that both that
10 # copyright notice and this permission notice appear in supporting
11 # documentation, and that the name of U.M. not be used in advertising or
12 # publicity pertaining to distribution of the software without specific,
13 # written prior permission.  U.M. makes no representations about the
14 # suitability of this software for any purpose.  It is provided "as is"
15 # without express or implied warranty.
16 #
17 # U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 #
24 # Author: James da Silva, Systems Design and Analysis Group
25 #                          Computer Science Department
26 #                          University of Maryland at College Park
27 #
28
29 #
30 # chg-multi.sh - generic tape changer script
31 #
32 # chg-multi is 'not' intended for use with tape changers or
33 # libraries.  It is primarily used to make several, individual
34 # tape drives appear to amanda as a single changer or library.
35 # The "multi" in the script name refers to multiple drives.
36 #
37
38 prefix=@prefix@
39 exec_prefix=@exec_prefix@
40 sbindir=@sbindir@
41 libexecdir=@libexecdir@
42
43 pname="chg-multi"
44
45 PATH=$sbindir:$libexecdir:/usr/bin:/bin:/usr/sbin:/sbin:/usr/ucb
46 export PATH
47
48 if [ -d "@AMANDA_DBGDIR@" ]; then
49         logfile=@AMANDA_DBGDIR@/changer.debug
50 else
51         logfile=/dev/null
52 fi
53
54 echo Args "->" "$@" >> $logfile
55
56 USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
57 if test "$USE_VERSION_SUFFIXES" = "yes"; then
58         SUF="-@VERSION@"
59 else
60         SUF=
61 fi
62
63 ourconf=`amgetconf$SUF changerfile`
64
65 if [ -x $sbindir/ammt$SUF ]; then
66         MT=$sbindir/ammt$SUF
67         MTF=-f
68 elif [ -x "@MT@" ]; then
69         MT=@MT@
70         MTF=@MT_FILE_FLAG@
71 else
72         answer="<none> $myname: mt program not found"
73         code=1
74         echo "Exit -> $answer" >> $logfile
75         echo "$answer"
76         exit $code
77 fi
78 echo MT "->" $MT $MTF >> $logfile
79
80 EXPR=expr
81 # EXPR=/usr/local/bin/expr # in case you need a more powerful expr...
82
83 # read in some config parameters
84
85 if [ ! -f "$ourconf" ]; then
86         answer="<none> $pname: $ourconf does not exist"
87         code=2
88         echo "Exit -> $answer" >> $logfile
89         echo "$answer"
90         exit $code
91 fi
92
93 firstslot=`awk '$1 == "firstslot" {print $2}' $ourconf 2>/dev/null`
94 if [ -z "$firstslot" ]; then
95         answer="<none> $pname: firstslot not specified in $ourconf"
96         code=2
97         echo "Exit -> $answer" >> $logfile
98         echo "$answer"
99         exit $code
100 fi
101
102 lastslot=`awk '$1 == "lastslot" {print $2}' $ourconf 2>/dev/null`
103 if [ -z "$lastslot" ]; then
104         answer="<none> $pname: lastslot not specified in $ourconf"
105         code=2
106         echo "Exit -> $answer" >> $logfile
107         echo "$answer"
108         exit $code
109 fi
110
111 nslots=`$EXPR $lastslot - $firstslot + 1`
112
113 gravity=`awk '$1 == "gravity" {print $2}' $ourconf 2>/dev/null`
114 if [ -z "$gravity" ]; then
115         answer="<none> $pname: gravity not specified in $ourconf"
116         code=2
117         echo "Exit -> $answer" >> $logfile
118         echo "$answer"
119         exit $code
120 fi
121
122 needeject=`awk '$1 == "needeject" {print $2}' $ourconf 2>/dev/null`
123 if [ -z "$needeject" ]; then
124         answer="<none> $pname: needeject not specified in $ourconf"
125         code=2
126         echo "Exit -> $answer" >> $logfile
127         echo "$answer"
128         exit $code
129 fi
130
131 multieject=`awk '$1 == "multieject" {print $2}' $ourconf 2>/dev/null`
132 if [ -z "$multieject" ]; then
133         echo "Note: setting multieject to a default of zero" >> $logfile
134         multieject=0
135 fi
136
137 ejectdelay=`awk '$1 == "ejectdelay" {print $2}' $ourconf 2>/dev/null`
138 if [ -z "$ejectdelay" ]; then
139         echo "Note: setting ejectdelay to a default of zero" >> $logfile
140         ejectdelay=0
141 fi
142
143 posteject=`awk '$1 == "posteject" {print $2}' $ourconf 2>/dev/null`
144 if [ -z "$posteject" ]; then
145         echo "Note: setting posteject to a default of \"true\"" >> $logfile
146         posteject=true
147 fi
148
149 ourstate=`awk '$1 == "statefile" {print $2}' $ourconf 2>/dev/null`
150 if [ -z "$ourstate" ]; then
151         answer="<none> $pname: statefile not specified in $ourconf"
152         code=2
153         echo "Exit -> $answer" >> $logfile
154         echo "$answer"
155         exit $code
156 fi
157
158 # needeject and multieject are incompatible
159 if [ $needeject -eq 1 ] && [ $multieject -eq 1 ] ; then
160         answer="<none> $pname: needeject and multieject cannot be both enabled in $ourconf"
161         code=2
162         echo "Exit -> $answer" >> $logfile
163         echo "$answer"
164         exit $code
165 fi
166
167 # read in state: only curslot and curloaded at the present time
168
169 curslot=`awk '$1 == "curslot" {print $2}' $ourstate 2>/dev/null`
170 if [ -z "$curslot" ]; then
171         curslot=$firstslot
172 fi
173
174 curloaded=`awk '$1 == "curloaded" {print $2}' $ourstate 2>/dev/null`
175 if [ -z "$curloaded" ]; then
176         curloaded=0
177 fi
178
179
180 # process the command-line
181
182 # control vars to avoid code duplication: not all shells have functions!
183 usage=0
184 checkgravity=0
185 ejectslot=0
186 loadslot=0
187 slotempty=0
188 ejectonly=0
189
190 if [ $# -ge 1 ]; then command=$1; else command="-usage"; fi
191
192 case "$command" in
193
194 -info) # return basic information about changer
195
196         backwards=`$EXPR 1 - $gravity`
197         answer="$curslot $nslots $backwards"
198         code=0
199         echo "Exit -> $answer" >> $logfile
200         echo "$answer"
201         exit $code
202         ;;
203
204 -reset) # reset changer. Actually, we only reset changer state. We
205         # trust that the operator has reloaded a stack and reset the
206         # hardware. In most cases, we do not want to actually do
207         # anything: if the operator has done something with the
208         # hardware, we have no way to know what the actual current
209         # slot is. If the hardware state has not changed, and what is
210         # really wanted is to load the first slot, use "slot first"
211         # instead 
212
213         checkgravity=0
214         loadslot=1
215         newslot=$firstslot
216         curslot=$firstslot
217         # XXX put changer-specific reset here, if applicable
218         ;;
219
220 -eject) # eject tape if loaded. Note that if multieject is set, this
221         # only can make sense if the position is last and gravity 1
222
223         checkgravity=0
224         loadslot=0
225         newslot=$curslot
226         ejectslot=1
227         ejectonly=1
228         if [ $multieject -eq 1 ] && \
229             ([ $gravity -eq 0 ] || [ $curslot -ne $lastslot ]) ; then 
230                 # Can't do this: if we eject, the stacker is going to
231                 # load the next tape, and our state will be botched
232                 answer="$curslot $pname: Cannot use -eject with multieject/nogravity/notlastslot"
233                 code=1
234                 echo "Exit -> $answer" >> $logfile
235                 echo "$answer"
236                 exit $code
237         fi    
238         if [ $curloaded -eq 0 ]; then
239                 answer="$curslot $pname: slot already empty"
240                 code=1
241                 echo "Exit -> $answer" >> $logfile
242                 echo "$answer"
243                 exit $code
244         fi
245         ;;
246
247 -slot)  # change to slot
248
249         checkgravity=1
250         loadslot=1
251
252         slotparm=$2
253         case "$slotparm" in
254         [0-9]*) 
255                 newslot=$slotparm
256                 if [ $newslot -gt $lastslot ] || \
257                      [ $newslot -lt $firstslot ] ; then
258                         answer="$newslot $pname: no slot $newslot: legal range is $firstslot ... $lastslot"
259                         code=1
260                         echo "Exit -> $answer" >> $logfile
261                         echo "$answer"
262                         exit $code
263                 fi
264                 ;;
265         current)
266                 newslot=$curslot
267                 ;;
268         first)
269                 newslot=$firstslot
270                 ;;
271         last)
272                 newslot=$lastslot
273                 ;;
274         next|advance)
275                 newslot=`$EXPR $curslot + 1`
276                 if [ $newslot -gt $lastslot ]; then
277                         newslot=$firstslot
278                 fi
279                 if [ $slotparm = advance ]; then
280                         loadslot=0
281                 fi
282                 ;;
283         prev)
284                 newslot=`$EXPR $curslot - 1`
285                 if [ $newslot -lt $firstslot ]; then
286                         newslot=$lastslot
287                 fi
288                 ;;
289         *)
290                 answer="<none> $pname: bad slot name \"$slotparm\""
291                 code=1
292                 echo "Exit -> $answer" >> $logfile
293                 echo "$answer"
294                 exit $code
295                 ;;
296         esac
297         ;;
298 *)
299         usage=1
300         ;;
301 esac
302
303
304 if [ $usage -eq 1 ]; then
305         answer="<none> usage: $pname {-reset | -slot [<slot-number>|current|next|prev|advance] | -info | -eject}"
306         code=2
307         echo "Exit -> $answer" >> $logfile
308         echo "$answer"
309         exit $code
310 fi
311
312
313 # check for legal move
314
315 if [ $checkgravity -eq 1 ] && [ $gravity -ne 0 ] ; then
316         if [ $newslot -lt $curslot ] || [ "$slotparm" = "prev" ] ; then
317                 answer="$newslot $pname: cannot go backwards in gravity stacker"
318                 code=1
319                 echo "Exit -> $answer" >> $logfile
320                 echo "$answer"
321                 exit $code
322         fi
323 fi
324
325 # Do the 'mt offline' style of stacker control if applicable
326 if [ $multieject -eq 1 ] && [ $loadslot -eq 1 ] && [ $newslot -ne $curslot ]
327 then
328         # XXX put changer-specific load command here, if applicable
329
330         curloaded=0             # unless something goes wrong
331         slotempty=0
332
333         while [ $curslot -ne $newslot ]; do
334             device=`awk '$1 == "slot" && $2 == '$curslot' {print $3}' $ourconf 2>/dev/null`
335             if [ "$device" = "" ]; then
336                 answer="$curslot $pname: slot $curslot device not specified in $ourconf"
337                 code=2
338                 echo "Exit -> $answer" >> $logfile
339                 echo "$answer"
340                 exit $code
341             fi
342             echo "     -> offline $device" >> $logfile
343             $MT $MTF $device offline >> $logfile 2>&1
344             if [ $? -ne 0 ]; then
345                 answer="$newslot $pname: $device: unable to change to slot $curslot"
346                 code=2
347                 echo "Exit -> $answer" >> $logfile
348                 echo "$answer"
349                 exit $code
350             fi
351             [ $ejectdelay -gt 0 ] && sleep $ejectdelay
352             echo "     -> running $posteject $device" >> $logfile
353             $posteject $device >> $logfile 2>&1
354             status=$?
355             if [ $status -ne 0 ]; then
356                 answer="$newslot $pname: $posteject $device failed: $status"
357                 code=2
358                 echo "Exit -> $answer" >> $logfile
359                 echo "$answer"
360                 exit $code
361             fi
362             curslot=`$EXPR $curslot + 1`
363             if [ $curslot -gt $lastslot ] ; then
364                 curslot=$firstslot
365             fi
366         done
367 fi
368
369 if [ $ejectonly -eq 1 ] \
370      || ([ $needeject -eq 1 ] \
371             && [ $loadslot -eq 1 ] \
372             && [ $curloaded -eq 1 ] \
373             && [ $newslot -ne $curslot ])
374 then
375         # XXX put changer-specific load command here, if applicable
376
377         curloaded=0             # unless something goes wrong
378         slotempty=0
379
380         # try to unload the current device
381         device=`awk '$1 == "slot" && $2 == '$curslot' {print $3}' $ourconf 2>/dev/null`
382         if [ "$device" = "" ]; then
383                 answer="$curslot $pname: slot $curslot device not specified in $ourconf"
384                 code=2
385                 echo "Exit -> $answer" >> $logfile
386                 echo "$answer"
387                 exit $code
388         fi
389         echo "     -> offline $device" >> $logfile
390         $MT $MTF $device offline >> $logfile 2>&1
391         if [ $? -ne 0 ]; then
392                 #
393                 # XXX if the changer-specific eject command can distinguish
394                 # betweeen "slot empty" and more serious errors, return 1
395                 # for the first case, 2 for the second case.  Generically,
396                 # we just presume an error signifies an empty slot.
397                 #
398                 slotempty=1
399         else
400                 [ $ejectonly -eq 0 ] && [ $ejectdelay -gt 0 ] && sleep $ejectdelay
401                 echo "     -> running $posteject $device" >> $logfile
402                 $posteject $device >> $logfile 2>&1
403                 status=$?
404                 if [ $status -ne 0 ]; then
405                         answer="$newslot $pname: $posteject $device failed: $status"
406                         code=2
407                         echo "Exit -> $answer" >> $logfile
408                         echo "$answer"
409                         exit $code
410                 fi
411         fi
412 fi
413
414 if [ $loadslot -eq 1 ]; then    # load the tape from the slot
415
416         # XXX put changer-specific load command here, if applicable
417
418         curloaded=1             # unless something goes wrong
419         slotempty=0
420         curslot=$newslot
421
422         # try to rewind the device
423         device=`awk '$1 == "slot" && $2 == '$curslot' {print $3}' $ourconf 2>/dev/null`
424         if [ "$device" = "" ]; then
425                 answer="$curslot $pname: slot $curslot device not specified in $ourconf"
426                 code=2
427                 echo "Exit -> $answer" >> $logfile
428                 echo "$answer"
429                 exit $code
430         fi
431         echo "     -> rewind $device" >> $logfile
432         $MT $MTF $device rewind >> $logfile 2>&1
433         if [ $? -ne 0 ]; then
434                 #
435                 # XXX if the changer-specific load command can distinguish
436                 # betweeen "slot empty" and more serious errors, return 1
437                 # for the first case, 2 for the second case.  Generically,
438                 # we just presume an error signifies an empty slot.
439                 #
440                 slotempty=1
441                 curloaded=0
442         fi
443 fi
444
445 # update state
446
447 echo "# multi-changer state cache: DO NOT EDIT!" >  $ourstate
448 echo curslot $newslot                            >> $ourstate
449 echo curloaded $curloaded                        >> $ourstate
450
451 # return slot info
452
453 if [ $slotempty -eq 1 ]; then
454         answer="$newslot $pname: slot is empty"
455         code=1
456         echo "Exit -> $answer" >> $logfile
457         echo "$answer"
458         exit $code
459 fi
460
461 if [ "$command" = -slot -a "$slotparm" = advance ]; then
462         device=/dev/null
463 fi
464
465 answer="$newslot $device"
466 code=0
467 echo "Exit -> $answer" >> $logfile
468 echo "$answer"
469 exit $code