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