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