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