Imported Debian patch 2.5.1p3-1
[debian/amanda] / changer-src / chg-zd-mtx.sh.in
1 #!@SHELL@ 
2 #
3 # Exit Status:
4 # 0 Alles Ok
5 # 1 Illegal Request
6 # 2 Fatal Error
7 #
8 # Contributed by Eric DOUTRELEAU <Eric.Doutreleau@int-evry.fr>
9 # This is supposed to work with Zubkoff/Dandelion version of mtx
10 #
11 # Modified by Joe Rhett <jrhett@isite.net>
12 # to work with MTX 1.2.9 by Eric Lee Green http://mtx.sourceforge.net
13 #
14 # Modified by Jason Hollinden <jhollind@sammg.com> on 13-Feb-2001
15 # to work with MTX 1.2.10, >9 slots, has barcode support, and works with
16 # multiple configs at once.
17 # NOTE:  Only tested the 2 additions with an ADIC Scalar 100.
18
19 ################################################################################
20 # Here are the things you need to do and know to configure this script:
21 #
22 #   * Figure out what the robot device name is and what the tape drive
23 #     device name is.  They will be different!
24 #
25 #     You cannot send robot commands to a tape drive and vice versa.
26 #     Both should respond to "mtx -f /dev/... inquiry".  Hopefully,
27 #     that output will make it obvious which is which.
28 #
29 #     For instance, here is what mtx has to say about my current robot:
30 #
31 #       Product Type: Medium Changer
32 #       Vendor ID: 'ATL     '
33 #       Product ID: 'ACL2640 206     '
34 #       Revision: '2A5A'
35 #       Attached Changer: No
36 #
37 #     and here is what it says about a tape drive:
38 #
39 #       Product Type: Tape Drive
40 #       Vendor ID: 'Quantum '
41 #       Product ID: 'DLT4000         '
42 #       Revision: 'CD50'
43 #       Attached Changer: No
44 #
45 #     Note the "Product Type" value makes it clear which is which.
46 #
47 #     If it is not obvious, "mf -f /dev/... rewind" should be happy when
48 #     talking to a (loaded) tape drive but the changer should give some
49 #     kind of error.  Similarly, "mtx -f /dev/... status" should show good
50 #     results with the changer but fail with a tape drive device name.
51 #
52 #     Once you have this figured out, set "changerdev" in amanda.conf
53 #     to the changer device and "tapedev" to the tape device.
54 #
55 #   * Find out what the first and last storage slots are.  Running
56 #     "mtx -f /dev/... status" should give you something like this
57 #     (although the output will vary widely based on the version of mtx
58 #     and the specifics of your robot):
59 #
60 #         Storage Changer /dev/changer:1 Drives, 9 Slots ( 0 Import/Export )
61 #       Data Transfer Element 0:Empty
62 #             Storage Element 1:Full :VolumeTag=SR0001
63 #             Storage Element 2:Full :VolumeTag=SR0002
64 #             Storage Element 3:Full :VolumeTag=SR0003
65 #             Storage Element 4:Full :VolumeTag=SR0004
66 #             Storage Element 5:Full :VolumeTag=SR0005
67 #             Storage Element 6:Full :VolumeTag=SR0006
68 #             Storage Element 7:Full :VolumeTag=SR0007
69 #             Storage Element 8:Full :VolumeTag=SR0008
70 #             Storage Element 9:Full :VolumeTag=SR0009
71 #             Storage Element 10 IMPORT/EXPORT:Full :VolumeTag=SR0009
72 #
73 #     This says the first storage slot (element) is "1" and the last
74 #     is "9".  If you allocate the entire robot to Amanda, you do not need
75 #     to set the "firstslot" or "lastslot" configuration file variables --
76 #     the script will compute these values for you.
77 #
78 #     You do not have to allocate all of the slots for Amanda use,
79 #     but whatever slots you use must be contiguous (i.e. 4 through 9
80 #     in the above would be OK but 1, 2, 5, 6, 9 would not).  The one
81 #     exception to this is that if one of the slots contains a cleaning
82 #     cartridge, it may be in any slot (Amanda will just skip over it if
83 #     it is between firstslot and lastslot).
84 #
85 #   * Speaking of cleaning cartridges, if you have a storage slot dedicated
86 #     to one, figure out what slot it is in.  That slot number will go in
87 #     the "cleanslot" variable.
88 #
89 #     Also, decide if you want the changer script to automatically run
90 #     the cleaning tape through the drive after every so many mounts,
91 #     and how many mounts you want to do between cleanings.  If you
92 #     want the script to do this, set the "autoclean" variable to 1 and
93 #     the "autocleancount" to the number of mounts between cleanings.
94 #     If you do not want to do automatic cleanings (including not having
95 #     a cleaning cartridge in the robot), set "autoclean" to 0.
96 #
97 #     Note that only a count of mounts is used to determine when it is
98 #     time to clean.  The script does not try to detect if the drive is
99 #     requesting cleaning, or how much the drive was used on a given
100 #     mount.
101 #
102 #   * If you tell Amanda about a cleaning cartridge, whether for automatic
103 #     operation or manual (amtape <config> clean), you must also tell
104 #     the script how long it takes to run the cleaning cycle.  It is
105 #     impossible for the script to determine when the cleaning operation
106 #     is done, so the "cleancycle" variable is the number of seconds
107 #     the longest cleaning operation takes (you'll just have to figure
108 #     this out by watching it a few times, or maybe finding it in a tape
109 #     drive hardware manual).  The script will sleep for this length of
110 #     time whenever the cleaning tape is referenced.  The default is 120
111 #     seconds (two minutes).
112 #
113 #   * Figure out the drive slot number.  By default, it is set to 0.
114 #     In the example above, the tape drive ("Data Transfer Element")
115 #     is in slot 0. If your drive slot is not 0, you
116 #     need to set the drive slot number with the "driveslot" variable.
117 #
118 #   * Figure out whether your robot has a barcode reader and whether
119 #     your version of mtx supports it.  If you see "VolumeTag" entries
120 #     in the "mtx -f /dev/xxx status" output you did above, you have
121 #     a reader and mtx can work with it, so you may set the "havereader"
122 #     variable to 1.  The default is 0 (do not use a reader).
123 #
124 #   * Pick any tape to load and then determine if the robot can put it
125 #     away directly or whether an "offline" must be done first.
126 #
127 #     With the tape still mounted and ready, try to put the tape away
128 #     with "mtx".  If you get some kind of error, which is the most
129 #     common response, try "mt -f /dev/... offline", wait for the drive
130 #     to unload and make sure the robot takes no action on its own to
131 #     store the tape.  Assuming it does not, try the "mtx" command again
132 #     to store the tape.
133 #
134 #     If you had to issue the "mt -f /dev/... offline" before you could
135 #     use "mtx" to store the tape, set the "offline_before_unload"
136 #     variable to 1.  If "mtx" unloaded the drive and put the tape away
137 #     all by itself, set it to 0.
138 #
139 #   * Some drives and robots require a small delay between unloading the
140 #     tape and instructing the robot to move it back to storage.
141 #     For instance, if you try to grab the tape too soon on an ATL robot
142 #     with DLT tape drives, it will rip the leader out of the drive and
143 #     require sincerely painful hardware maintenance.
144 #
145 #     If you need a little delay, set the "unloadpause" variable to
146 #     the number of seconds to wait before trying to take a tape from
147 #     a drive back to storage.  The default is 0.
148 #
149 #   * Some drives also require a short pause after loading, or the drive
150 #     will return an I/O error during a test to see if it's online (which
151 #     this script uses "mt rewind" to test).  My drives don't recover from
152 #     this, and must be reloaded before they will come online after failing
153 #     such a test.  For this reason there is an "initial_poll_delay"
154 #     variable which will pause for a certain number of seconds before
155 #     looping through the online test for the first time.  The default is 0.
156 ####
157
158 ####
159 # Now you are ready to set up the variables in the changer configuration
160 # file.
161 #
162 # All variables are in "changerfile".conf where "changerfile" is set
163 # in amanda.conf.  For example, if amanda.conf has:
164 #
165 #       changerfile="/etc/amanda/Dailyset1/CHANGER"
166 #    or changerfile="/etc/amanda/Dailyset1/CHANGER.conf"
167 #
168 # the variables must be in "/etc/amanda/Dailyset1/CHANGER.conf".
169 # The ".conf" is appended only if it's not there".
170 #
171 # If "changerfile" is a relative path, it is relative to the directory
172 # that contains amanda.conf.  That also happens to be the directory Amanda
173 # makes current before running this script.
174 #
175 # Here is a commented out example file with all the variables and showing
176 # their default value (if any):
177 ####
178 # firstslot=?               #### First storage slot (element) -- required
179 # lastslot=?                #### Last storage slot (element) -- required
180 # cleanslot=-1              #### Slot with cleaner tape -- default is "-1"
181 #                           #### Set negative to indicate no cleaner available
182 # driveslot=0               #### Drive slot number.  Defaults to 0
183 #                           #### Use the 'Data Transfer Element' you want
184 #
185 #   # Do you want to clean the drive after a certain number of accesses?
186 #   # NOTE - This is unreliable, since 'accesses' aren't 'uses', and we
187 #   #        have no reliable way to count this.  A single amcheck could
188 #   #        generate as many accesses as slots you have, plus 1.
189 #   # ALSO NOTE - many modern tape loaders handle this automatically.
190 #
191 # autoclean=0               #### Set to '1' or greater to enable
192 #
193 # autocleancount=99         #### Number of access before a clean.
194 #
195 # cleancycle=120            #### Time (seconds) to clean drive (default 120)
196 #
197 # havereader=0              #### If you have a barcode reader, set to 1.
198 #
199 # offline_before_unload=0   #### Does your robot require an
200 #                           #### 'mt offline' before mtx unload?
201 #
202 # poll_drive_ready=NN       #### Time (seconds) between tests to see if
203 #                           #### the tape drive has gone ready (default: 3).
204 #
205 # max_drive_wait=NN         #### Maximum time (seconds) to wait for the
206 #                           #### tape drive to become ready (default: 120).
207 #
208 # initial_poll_delay=NN     #### initial delay after load before polling for
209 #                           #### readiness
210 ####
211
212 ####
213 # Now it is time to test the setup.  Do all of the following in the
214 # directory that contains the amanda.conf file, and do all of it as
215 # the Amanda user.
216 #
217 #   * Run this:
218 #
219 #       .../chg-zd-mtx -info
220 #       echo $?             #### (or "echo $status" if you use csh/tcsh)
221 #
222 #     You should get a single line from the script like this (the actual
223 #     numbers will vary):
224 #
225 #       5 9 1 1
226 #
227 #     The first number (5) is the "current" slot.  This may or may not be
228 #     the slot actually loaded at the moment (if any).  It is the slot
229 #     Amanda will try to use next.
230 #
231 #     The second number (9) is the number of slots.
232 #
233 #     The third number will always be "1" and indicates the changer is
234 #     capable of going backward.
235 #
236 #     The fourth number is optional.  If you set $havereader to 1, it
237 #     will be "1", otherwise it will not be present.
238 #
239 #     The exit code ($? or $status) should be zero.
240 #
241 #   * Run this:
242 #
243 #       .../chg-zd-mtx -reset
244 #       echo $?
245 #
246 #     The script should output a line like this:
247 #
248 #       1 /dev/rmt/0mn
249 #
250 #     The number at the first should match $firstslot.  The device name
251 #     after that should be your tape device.
252 #
253 #     The exit code ($? or $status) should be zero.
254 #
255 #   * Run this:
256 #
257 #       .../chg-zd-mtx -slot next
258 #       echo $?
259 #
260 #     The script should output a line like this:
261 #
262 #       2 /dev/rmt/0mn
263 #
264 #     The number at the first should be one higher than $firstslot.
265 #     The device name after that should be your tape device.
266 #
267 #     The exit code ($? or $status) should be zero.
268 #
269 #   * Run this:
270 #
271 #       .../chg-zd-mtx -slot current
272 #       echo $?
273 #
274 #     Assuming the tape is still loaded from the previous test, the
275 #     robot should not move and the script should report the same thing
276 #     the previous command did.
277 #
278 #   * If you continue to run "-slot next" commands, the robot should load
279 #     each tape in turn then wrap back around to the first when it
280 #     reaches $lasttape.  If $cleanslot is within the $firstslot to
281 #     $lastslot range, the script will skip over that entry.
282 #
283 #   * Finally, try some of the amtape commands and make sure they work:
284 #
285 #       amtape <config> reset
286 #       amtape <config> slot next
287 #       amtape <config> slot current
288 #
289 #   * If you set $havereader non-zero, now would be a good time to create
290 #     the initial barcode database:
291 #
292 #       amtape <config> update
293 ####
294
295 ################################################################################
296 # To debug this script, first look in @AMANDA_DBGDIR@.  The script
297 # uses one of two log files there, depending on what version of Amanda
298 # is calling it.  It may be chg-zd-mtx.YYYYMMDD*.debug, or it may be
299 # changer.debug.driveN where 'N' is the drive number.
300 #
301 # If the log file does not help, try running the script, **as the Amanda
302 # user**, in the amanda.conf directory with whatever set of args the log
303 # said were used when you had a problem.  If nothing else useful shows up
304 # in the output, try running the script with the DEBUG environment variable
305 # set non-null, e.g.:
306 #
307 #       env DEBUG=yes .../chg-zd-mtx ...
308 ################################################################################
309
310 ################################################################################
311 # You may need to customize these things
312 ################################################################################
313
314 MT=@MT@
315 MTF=@MT_FILE_FLAG@
316 MTX=@MTX@
317
318 ################################################################################
319 # No user-level customization should be required beyond this point.
320 ################################################################################
321
322 test -n "$DEBUG" && set -x
323 TMPDIR="@AMANDA_TMPDIR@"
324 DBGDIR="@AMANDA_DBGDIR@"
325
326 argv0=$0
327 myname=`expr "$argv0" : '.*/\(.*\)'`
328
329 config=`pwd 2>/dev/null`
330 config=`expr "$config" : '.*/\(.*\)'`
331
332 ###
333 # Functions to write a new log file entry and append more log information.
334 ###
335
336 ds=`date '+%H:%M:%S' 2>/dev/null`
337 if [ $? -eq 0  -a  -n "$ds" ]; then
338         logprefix=`echo "$ds" | sed 's/./ /g'`
339 else
340         logprefix=""
341 fi
342
343 LogAppend() {
344         if [ -z "$logprefix" ]; then
345                 echo "$@" >> $DBGFILE
346         else
347                 echo "$logprefix" "$@" >> $DBGFILE
348         fi
349 }
350
351 Log() {
352         if [ -z "$logprefix" ]; then
353                 echo "===" "`date`" "===" >> $DBGFILE
354                 echo "$@" >> $DBGFILE
355         else
356                 ds=`date '+%H:%M:%S' 2>/dev/null`
357                 echo "$ds" "$@" >> $DBGFILE
358         fi
359 }
360
361 ###
362 # Common exit function.
363 #
364 #   $1 = exit code
365 #   $2 = slot result
366 #   $3 = additional information (error message, tape devive, etc)
367 ###
368
369 internal_call=0
370 Exit() {
371         if [ $internal_call -gt 0 ]; then
372                 call_type=Return
373         else
374                 call_type=Exit
375         fi
376         code=$1
377         shift
378         exit_slot=$1
379         shift
380         exit_answer="$@"
381         Log $call_type "($code)" "->" "$exit_slot" "$@"
382         echo "$exit_slot" "$@"
383         if [ $call_type = Return ]; then
384                 return $code
385         fi
386         amgetconf$SUF dbclose.$argv0:$DBGFILE > /dev/null 2>&1
387         exit $code
388 }
389
390 ###
391 # Function to run another command and log it.
392 ###
393
394 Run() {
395         Log Running: "$@"
396         rm -f $stdout $stderr
397         "$@" > $stdout 2> $stderr
398         exitcode=$?
399         Log Exit code: $exitcode
400         if [ -s $stdout ]
401         then
402                 LogAppend Stdout:
403                 cat $stdout >> $DBGFILE
404         fi
405         if [ -s $stderr ]
406         then
407                 LogAppend Stderr:
408                 cat $stderr >> $DBGFILE
409         fi
410         cat $stdout
411         cat $stderr 1>&2
412         return $exitcode
413 }
414
415 ###
416 # Return success if the arg is numeric.
417 ###
418
419 IsNumeric() {
420         test -z "$1" && return 1
421         x="`expr "$1" : '\([-0-9][0-9]*\)' 2>/dev/null`"
422         return `expr X"$1" != X"$x"`
423 }
424
425 ###
426 # Run $MTX status unless the previous output is still valid.
427 ###
428
429 mtx_status_valid=0
430 get_mtx_status() {
431         test -n "$DEBUG" && set -x
432         if [ $mtx_status_valid -ne 0 ]; then
433                 return 0
434         fi
435         rm -f $mtx_status
436         Run $MTX status > $mtx_status 2>&1
437         status=$?
438         if [ $status -eq 0 ]; then
439                 mtx_status_valid=1
440         fi
441         return $status
442 }
443
444 ###
445 # Determine the slot currently loaded.  Set $loadedslot to the slot
446 # currently loaded, or "-1", and $loadedbarcode to the corresponding
447 # barcode (or nothing).
448 ###
449
450 get_loaded_info() {
451         test -n "$DEBUG" && set -x
452         get_mtx_status
453
454         set x `sed -n '
455 /^Data Transfer Element:Empty/                          {
456     s/.*/-1/p
457     q
458 }
459 /^Data Transfer Element '$driveslot':Empty/             {
460     s/.*/-1/p
461     q
462 }
463 /^Data Transfer Element:Full (Storage Element \([0-9][0-9]*\) Loaded):VolumeTag *= *\([^     ]*\)/               {
464     s/.*(Storage Element \([0-9][0-9]*\) Loaded):VolumeTag *= *\([^     ]*\)/\1 \2/p
465     q
466 }
467 /^Data Transfer Element '$driveslot':Full (Storage Element \([0-9][0-9]*\) Loaded):VolumeTag *= *\([^     ]*\)/  {
468     s/.*(Storage Element \([0-9][0-9]*\) Loaded):VolumeTag *= *\([^     ]*\)/\1 \2/p
469     q
470 }
471 /^Data Transfer Element '$driveslot':Full (Unknown Storage Element Loaded):VolumeTag *= *\([^     ]*\)/ {
472     s/.*:VolumeTag *= *\([^     ]*\)/-2 \1/p
473     q
474 }
475 /^Data Transfer Element:Full (Storage Element \([0-9][0-9]*\) Loaded)/                           {
476     s/.*(Storage Element \([0-9][0-9]*\) Loaded).*/\1/p
477     q
478 }
479 /^Data Transfer Element '$driveslot':Full (Storage Element \([0-9][0-9]*\) Loaded)/              {
480     s/.*Storage Element \([0-9][0-9]*\) Loaded.*/\1/p
481     q
482 }
483 /^Data Transfer Element '$driveslot':Full (Unknown Storage Element Loaded)/     {
484     s/.*/-2/p
485     q
486 }
487 ' < $mtx_status 2>&1`
488         shift                                   # get rid of the "x"
489         loadedslot=$1
490         loadedbarcode=$2
491         if [ -z "$loadedslot" ]; then
492                 Exit 2 "<none>" "could not determine current slot, are you sure your drive slot is $driveslot"
493                 return $?                       # in case we are internal
494         fi
495
496         #Use the current slot if it's empty and we don't know which slot is loaded'
497         if [ $loadedslot -eq -2 ]; then
498                 set x `sed -n '
499 {
500     /^.*Storage Element '$currentslot':Empty/ {
501         s/.*Storage Element \([0-9][0-9]*\):Empty/\1/p
502         q
503     }
504     /^.*Storage Element '$currentslot':Full/ {
505         s/.*Storage Element \([0-9][0-9]*\):Full/-2/p
506         q
507     }
508     /^.*Storage Element '$currentslot' IMPORT\/EXPORT:Empty/ {
509         s/.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Empty/\1/p
510         q
511     }
512     /^.*Storage Element '$currentslot' IMPORT\/EXPORT:Full/ {
513         s/.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Full/-2/p
514         q
515     }
516 }
517 ' < $mtx_status 2>& 1`
518                 shift                           # get rid of the "x"
519                 loadedslotx=$1
520                 if [ ! -z $loadedslotx ]; then
521                         loadedslot=$loadedslotx
522                 fi
523         fi
524
525         #Use the first empty slot if we don't know which slot is loaded'
526         if [ $loadedslot -eq -2 ]; then
527                 set x `sed -n '
528 {
529     /^.*Storage Element \([0-9][0-9]*\):Empty/ {
530         s/.*Storage Element \([0-9][0-9]*\):Empty/\1/p
531         q
532     }
533     /^.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Empty/ {
534         s/.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Empty/\1/p
535         q
536     }
537 }
538 ' < $mtx_status 2>& 1`
539                 shift                           # get rid of the "x"
540                 loadedslot=$1
541         fi
542
543         if IsNumeric "$loadedslot" ; then
544                 :
545         else
546                 Exit 2 \
547                      "<none>" \
548                      "currently loaded slot ($loadedslot) not numeric"
549                 return $?                       # in case we are internal
550         fi
551         Log       "STATUS   -> currently loaded slot = $loadedslot"
552         LogAppend "         -> currently loaded barcode = \"$loadedbarcode\""
553 }
554
555 ###
556 # Get a list of slots between $firstslot and $lastslot, if they are set.
557 # If they are not set, set them to the first and last slot seen on the
558 # assumption the entire robot is to be used (???).
559 ###
560
561 slot_list=
562 get_slot_list() {
563         test -n "$DEBUG" && set -x
564         if [ -n "$slot_list" ]; then
565                 return
566         fi
567         get_mtx_status
568         slot_list=`sed -n '
569 /^Data Transfer Element:Full (Storage Element \([0-9][0-9]*\) Loaded)/ {
570     s/.*(Storage Element \([0-9][0-9]*\) Loaded).*/\1/p
571 }
572 /^Data Transfer Element '$driveslot':Full (Storage Element \([0-9][0-9]*\) Loaded)/ {
573     s/.*Storage Element \([0-9][0-9]*\) Loaded.*/\1/p
574 }
575 /^Data Transfer Element '$driveslot':Full (Unknown Storage Element Loaded)/ {
576     : loop
577     n
578     /^.*Storage Element \([0-9][0-9]*\):Full/ {
579         s/.*Storage Element \([0-9][0-9]*\):Full.*/\1/p
580         b loop
581     }
582     /^.*Storage Element \([0-9][0-9]*\):Empty/ {
583         s/.*Storage Element \([0-9][0-9]*\):Empty/\1/p
584     }
585 }
586 /^.*Storage Element \([0-9][0-9]*\):Full/ {
587     s/.*Storage Element \([0-9][0-9]*\):Full.*/\1/p
588 }
589 /^.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Full/ {
590     s/.*Storage Element \([0-9][0-9]*\) IMPORT\/EXPORT:Full.*/\1/p
591 }
592 ' < $mtx_status 2>&1 | grep -v "^${cleanslot}\$" | sort -n`
593         slot_list=`echo $slot_list`             # remove the newlines
594         if [ $firstslot -lt 0 -o $lastslot -lt 0 ]; then
595                 last=$lastslot
596                 for slot in $slot_list; do
597                         if [ $firstslot -lt 0 ]; then
598                                 Log "SLOTLIST -> firstslot set to $slot"
599                                 firstslot=$slot
600                         fi
601                         if [ $lastslot -lt 0 ]; then
602                                 last=$slot
603                         fi
604                 done
605                 if [ $lastslot -lt 0 -a $last -ge 0 ]; then
606                         Log "SLOTLIST -> lastslot set to $last"
607                         lastslot=$last
608                 fi
609                 if [ $firstslot -lt 0 ]; then
610                         Exit 2 \
611                              "<none>" \
612                              "cannot determine first slot"
613                         return $?               # in case we are internal
614                 elif [ $lastslot -lt 0 ]; then
615                         Exit 2 \
616                              "<none>" \
617                              "cannot determine last slot"
618                         return $?               # in case we are internal
619                 fi
620         fi
621         amanda_slot_list=
622         for slot in $slot_list; do
623                 if [ $slot -ge $firstslot -a $slot -le $lastslot ]; then
624                         amanda_slot_list="$amanda_slot_list $slot"
625                 fi
626         done
627         if [ -z "$amanda_slot_list" ]; then
628                 Exit 2 \
629                      "<none>" \
630                      "no slots available"
631                 return $?                       # in case we are internal
632         fi
633         slot_list="$amanda_slot_list"
634 }
635
636 # Paths
637 prefix=@prefix@
638 exec_prefix=@exec_prefix@
639 sbindir=@sbindir@
640 libexecdir=@libexecdir@
641
642 # try to hit all the possibilities here
643 PATH=$sbindir:$libexecdir:/usr/bin:/bin:/usr/sbin:/sbin:/usr/ucb:/usr/local/bin
644 export PATH
645
646 USE_VERSION_SUFFIXES="@USE_VERSION_SUFFIXES@"
647 if test "$USE_VERSION_SUFFIXES" = "yes"; then
648         SUF="-@VERSION@"
649 else
650         SUF=
651 fi
652
653 DBGFILE=`amgetconf$SUF dbopen.$argv0 2>/dev/null`
654 if [ -z "$DBGFILE" ]
655 then
656         DBGFILE=/dev/null                       # will try this again below
657 fi
658
659 changerfile=`amgetconf$SUF changerfile 2>/dev/null`
660 if [ -z "$changerfile" ]; then
661         Exit 2 \
662              "<none>" \
663              "changerfile must be specified in amanda.conf"
664 fi
665
666 tape=`amgetconf$SUF tapedev 2>/dev/null`
667 if [ -z "$tape" ]; then
668         Exit 2 \
669              "<none>" \
670              "tapedev may not be empty"
671 elif [ $tape = "/dev/null" -o `expr "$tape" : 'null:'` -eq 5 ]; then
672         Exit 2 \
673              "<none>" \
674              "tapedev ($tape) may not be the null device"
675 fi
676 TAPE=`amgetconf$SUF changerdev 2>/dev/null`
677 if [ -z "$TAPE" ]; then
678         Exit 2 \
679              "<none>" \
680              "changerdev may not be empty"
681 elif [ $TAPE = "/dev/null" ]; then
682         Exit 2 \
683              "<none>" \
684              "changerdev ($TAPE) may not be the null device"
685 fi
686 export TAPE                                     # for mtx command
687
688 CHANGER=$TAPE
689 export CHANGER                                  # for mtx command
690
691 #### Set up the various config files.
692
693 conf_match=`expr "$changerfile" : .\*\.conf\$`
694 if [ $conf_match -ge 6 ]; then
695         configfile=$changerfile
696         changerfile=`echo $changerfile | sed 's/.conf$//g'`
697 else
698         configfile=$changerfile.conf
699 fi
700
701 cleanfile=$changerfile-clean
702 accessfile=$changerfile-access
703 slotfile=$changerfile-slot
704 labelfile=$changerfile-barcodes
705 [ ! -s $cleanfile ] && echo 0 > $cleanfile
706 [ ! -s $accessfile ] && echo 0 > $accessfile
707 [ ! -s $slotfile ] && echo -1 > $slotfile
708 [ ! -f $labelfile ] && > $labelfile
709 cleancount=`cat $cleanfile`
710 accesscount=`cat $accessfile`
711
712 test -z "$MT" && Exit 2 "<none>" "No mt command defined"
713 test ! -f "$MT" && Exit 2 "<none>" "mt command ($MT) doesn't exist"
714 test -z "$MTX" && Exit 2 "<none>" "No mtx command defined"
715 test ! -f "$MTX" && Exit 2 "<none>" "mtx command ($MTX) doesn't exist"
716
717 #### Dig out of the config file what is needed
718
719 varlist=
720 varlist="$varlist firstslot"
721 varlist="$varlist lastslot"
722 varlist="$varlist cleanslot"
723 varlist="$varlist cleancycle"
724 varlist="$varlist OFFLINE_BEFORE_UNLOAD"        # old name
725 varlist="$varlist offline_before_unload"
726 varlist="$varlist unloadpause"
727 varlist="$varlist AUTOCLEAN"                    # old name
728 varlist="$varlist autoclean"
729 varlist="$varlist autocleancount"
730 varlist="$varlist havereader"
731 varlist="$varlist driveslot"
732 varlist="$varlist poll_drive_ready"
733 varlist="$varlist initial_poll_delay"
734 varlist="$varlist max_drive_wait"
735
736 for var in $varlist
737 do
738         val="`cat $configfile 2>/dev/null | sed -n '
739 # Ignore comment lines (anything starting with a #).
740 /^[     ]*#/d
741 # Find the first var=val line in the file, print the value and quit.
742 /^[     ]*'$var'[       ]*=[    ]*\([^  ][^     ]*\).*/ {
743         s/^[    ]*'$var'[       ]*=[    ]*\([^  ][^     ]*\).*/\1/p
744         q
745 }
746 '`"
747         eval $var=\"$val\"
748 done
749
750 # Deal with driveslot first so we can get DBGFILE set if we are still
751 # using the old amgetconf.
752
753 if [ -z "$driveslot" ]; then
754         driveslot=0;
755 fi
756
757 # Get DBGFILE set if it is not already.
758
759 if [ $DBGFILE = /dev/null ]; then
760         if [ -d "$DBGDIR" ]; then
761                 DBGFILE=$DBGDIR/changer.debug.drive$driveslot
762         else
763                 DBGFILE=/dev/null
764         fi
765         Log === Start "`date`" ===
766 fi
767 if [ -z "$driveslot" ]; then
768         Exit 2 \
769              "<none>" \
770              "cannot determine drive slot from $tape"
771 fi
772
773 stdout=$TMPDIR/$myname.1.$$
774 stderr=$TMPDIR/$myname.2.$$
775 mtx_status=$TMPDIR/$myname.status.$$
776 trap "rm -f $stdout $stderr $mtx_status" 0      # exit cleanup
777
778 Log "Using config file $configfile"
779
780 # Log the argument list.
781
782 Log "Arg info:"
783 LogAppend "\$# = $#"
784 i=0
785 LogAppend "\$$i = \"$argv0\""
786 for arg in "$@"; do
787         i=`expr $i + 1`
788         LogAppend "\$$i = \"$arg\""
789 done
790
791 # Set the default config values for those not in the file.  Log the
792 # results and make sure each is valid (numeric).
793
794 firstslot=${firstslot:-'-1'}                            # default: mtx status
795 lastslot=${lastslot:-'-1'}                              # default: mtx status
796 cleanslot=${cleanslot:-'-1'}                            # default: -1
797 cleancycle=${cleancycle:-'120'}                         # default: two minutes
798 if [ -z "$offline_before_unload" -a -n "$OFFLINE_BEFORE_UNLOAD" ]; then
799         offline_before_unload=$OFFLINE_BEFORE_UNLOAD    # (old name)
800 fi
801 offline_before_unload=${offline_before_unload:-'0'}     # default: 0
802 unloadpause=${unloadpause:-'0'}                         # default: 0
803 if [ -z "$autoclean" -a -n "$AUTOCLEAN" ]; then
804         autoclean=$AUTOCLEAN                            # (old name)
805 fi
806 autoclean=${autoclean:-'0'}                             # default: 0
807 autocleancount=${autocleancount:-'99'}                  # default: 99
808 havereader=${havereader:-'0'}                           # default: 0
809 poll_drive_ready=${poll_drive_ready:-'3'}               # default: three seconds
810 initial_poll_delay=${initial_poll_delay:-'0'}           # default: zero zeconds
811 max_drive_wait=${max_drive_wait:-'120'}                 # default: two minutes
812
813 get_slot_list
814
815 Log "Config info:"
816 for var in $varlist; do
817         if [ $var = "OFFLINE_BEFORE_UNLOAD" ]; then
818                 continue                        # old name
819         elif [ $var = "AUTOCLEAN" ]; then
820                 continue                        # old name
821         fi
822         eval val=\"'$'$var\"
823         if [ -z "$val" ]; then
824                 Exit 2 \
825                      "<none>" \
826                      "$var missing in $configfile"
827         fi
828         if IsNumeric "$val" ; then
829                 :
830         else
831                 Exit 2 \
832                      "<none>" \
833                      "$var ($val) not numeric in $configfile"
834         fi
835         LogAppend $var = \"$val\"
836 done
837
838 # Run the rest of the config file sanity checks.
839
840 if [ $firstslot -gt $lastslot ]; then
841         Exit 2 \
842              "<none>" \
843              "firstslot ($firstslot) greater than" \
844              "lastslot ($lastslot) in $configfile"
845 fi
846 if [ $autoclean -ne 0 -a $cleanslot -lt 0 ]; then
847         Exit 2 \
848              "<none>" \
849              "autoclean set but cleanslot not valid ($cleanslot)"
850 fi
851
852 # Set up the current slot
853
854 currentslot=`cat $slotfile`
855 if IsNumeric "$currentslot" ; then
856         if [ $currentslot -lt $firstslot ]; then
857                 Log "SETUP    -> current slot $currentslot" \
858                                  "less than $firstslot ..." \
859                                  "resetting to $firstslot"
860                 currentslot=$firstslot
861         elif [ $currentslot -gt $lastslot ]; then
862                 Log "SETUP    -> current slot $currentslot" \
863                                  "greater than $lastslot ..." \
864                                  "resetting to $lastslot"
865                 currentslot=$lastslot
866         fi
867 else
868         Log "SETUP    -> contents of $slotfile ($currentslot) invalid," \
869                          "setting current slot to first slot ($firstslot)"
870         currentslot=$firstslot
871 fi
872
873 found_current=0
874 first_slot_in_list=-1
875 next_slot_after_current=-1
876 for slot in $slot_list; do
877         if [ $first_slot_in_list -lt 0 ]; then
878                 first_slot_in_list=$slot        # in case $firstslot is missing
879         fi
880         if [ $slot -eq $currentslot ]; then
881                 found_current=1
882                 break
883         elif [ $slot -gt $currentslot ]; then
884                 next_slot_after_current=$slot   # $currentslot is missing
885                 break
886         fi
887 done
888 if [ $found_current -eq 0 ]; then
889         if [ $next_slot_after_current -lt 0 ]; then
890                 new_currentslot=$first_slot_in_list
891         else
892                 new_currentslot=$next_slot_after_current
893         fi
894         Log "WARNING  -> current slot $currentslot not available," \
895                          "setting current slot to next slot ($new_currentslot)"
896         currentslot=$new_currentslot
897 fi
898
899 # More routines.
900
901 ###
902 # Eject the current tape and put it away.
903 ###
904
905 eject() {
906         test -n "$DEBUG" && set -x
907         Log "EJECT    -> ejecting tape from $tape"
908         get_loaded_info 
909         if [ $loadedslot -gt 0 ]; then
910                 Log "EJECT    -> moving tape from drive $driveslot" \
911                                  "to storage slot $loadedslot"
912                 if [ $offline_before_unload -ne 0 ]; then
913                         Run $MT $MTF $tape offline > /dev/null 2>&1
914                 fi
915                 sleep $unloadpause
916                 result=`Run $MTX unload $loadedslot $driveslot 2>&1`
917                 status=$?
918                 Log "         -> status $status, result \"$result\""
919                 mtx_status_valid=0
920                 if [ $status -ne 0 ]; then
921                         answer="$result"
922                         code=2
923                 else
924                         answer="$tape"
925                         code=0
926                 fi
927         else
928                 answer="Drive was not loaded"
929                 code=1
930         fi
931         Exit $code "$loadedslot" "$answer"
932         return $?                               # in case we are internal
933 }
934
935 ###
936 # Reset the robot back to the first slot.
937 ###
938
939 reset() {
940         test -n "$DEBUG" && set -x
941         Log "RESET    -> loading tape from slot $firstslot" \
942                          "to drive $driveslot ($tape)"
943         # Call loadslot without doing it as an internal and let it finish
944         # things up.
945         loadslot $firstslot
946         # NOTREACHED
947         Exit 2 "<none>" "reset: should not get here"
948         return $?                               # in case we are internal
949 }
950
951 ###
952 # Unload the current tape (if necessary) and load a new one (unless
953 # "advance").  If no tape is loaded, get the value of "current" from
954 # $slotfile.
955 ###
956
957 loadslot() {
958         test -n "$DEBUG" && set -x
959         if [ $# -lt 1 ]; then
960                 Exit 2 "<none>" "Missing -slot argument"
961                 return $?                       # in case we are internal
962         fi
963         whichslot=$1
964         Log "LOADSLOT -> load drive $driveslot ($tape) from slot $whichslot"
965
966         numeric=`echo $whichslot | sed 's/[^0-9]//g'`
967         case $whichslot in
968         current|prev|next|advance)
969                 find_slot=$currentslot
970                 ;;
971         first)
972                 find_slot=$firstslot
973                 ;;
974         last)
975                 find_slot=$lastslot
976                 ;;
977         $numeric)
978                 find_slot=$numeric
979                 ;;
980         clean)
981                 find_slot=$cleanslot
982                 ;;
983         *)
984                 Exit 2 "<none>" "Illegal slot: \"$whichslot\""
985                 return $?                       # in case we are internal
986                 ;;
987         esac
988
989         # Find the requested slot in the slot list.  By loading the "set"
990         # command with multiple copies, we guarantee that if the slot is
991         # found, we can look both forward and backward without running
992         # off the end.  Putting $cleanslot at the end allows us to find
993         # that slot since it is not in $slot_list.
994         get_slot_list
995         set x $slot_list $slot_list $slot_list $cleanslot
996         shift                                   # get rid of the "x"
997         prev_slot=$1
998         shift
999         while [ $# -gt 0 ]; do
1000                 if [ $1 -eq $find_slot ]; then
1001                         break
1002                 fi
1003                 prev_slot=$1
1004                 shift
1005         done
1006         if [ $# -le 0 ]; then
1007                 Exit 2 \
1008                      "<none>" \
1009                      "Cannot find slot $find_slot" \
1010                      "in slot list ($slot_list)"
1011                 return $?                       # in case we are internal
1012         fi
1013
1014         # Determine the slot to load.
1015         case $whichslot in
1016         next|advance)
1017                 shift
1018                 loadslot=$1
1019                 ;;
1020         prev)
1021                 loadslot=$prev_slot
1022                 ;;
1023         *)
1024                 loadslot=$find_slot
1025         esac
1026
1027         # If the desired slot is already loaded, we are done.  Only update
1028         # current slot if this is not the cleaning slot.
1029         get_loaded_info
1030         if [ $loadslot = $loadedslot ]; then
1031                 if [ $loadslot -ne $cleanslot ]; then
1032                         rm -f $slotfile
1033                         echo $loadslot > $slotfile
1034                 fi
1035                 Exit 0 "$loadedslot" "$tape"
1036                 return $?                       # in case we are internal
1037         fi
1038         if [ $loadedslot -eq -2 ]; then
1039                 Exit 0 "$loadedslot" "$tape"
1040                 return $?                       # in case we are internal
1041         fi
1042
1043         # If we are loading the cleaning tape, bump the cleaning count
1044         # and reset the access count.  Otherwise, bump the access count
1045         # and see if it is time to do a cleaning.
1046         if [ $loadslot = $cleanslot ]; then
1047                 rm -f $cleanfile $accessfile
1048                 expr $cleancount + 1 > $cleanfile
1049                 echo 0 > $accessfile
1050         else
1051                 rm -f $accessfile
1052                 expr $accesscount + 1 > $accessfile
1053                 if [ $autoclean -ne 0 -a $accesscount -gt $autocleancount ]
1054                 then
1055                         internal_call=`expr $internal_call + 1`
1056                         loadslot clean > /dev/null 2>&1
1057                         status=$?
1058                         internal_call=`expr $internal_call - 1`
1059                         if [ $status -ne 0 ]; then
1060                                 Exit $status "$loadslot" "$exit_answer"
1061                                 return $?       # in case we are internal
1062                         fi
1063
1064                         # Slot $cleanslot might contain an ordinary tape
1065                         # rather than a cleaning tape.  A cleaning tape
1066                         # *MIGHT* auto-eject; an ordinary tape does not.
1067                         # We therefore have to read the status again to
1068                         # check what actually happened.
1069                         mtx_status_valid=0
1070                         get_loaded_info
1071                 fi
1072         fi
1073
1074         # Unload whatever tape is in the drive.
1075         internal_call=`expr $internal_call + 1`
1076         eject > /dev/null 2>&1
1077         status=$?
1078         internal_call=`expr $internal_call - 1`
1079         if [ $status -gt 1 ]; then
1080                 Exit $status "$exit_slot" "$exit_answer"
1081                 return $?                       # in case we are internal
1082         fi
1083
1084         # If we were doing an "advance", we are done.
1085         if [ $whichslot = advance ]; then
1086                 if [ $loadslot -ne $cleanslot ]; then
1087                         rm -f $slotfile
1088                         echo $loadslot > $slotfile
1089                 fi
1090                 Exit 0 "$loadslot" "/dev/null"
1091                 return $?                       # in case we are internal
1092         fi
1093
1094         # Load the tape, finally!
1095         Log "LOADSLOT -> loading tape from slot $loadslot" \
1096                          "to drive $driveslot ($tape)"
1097         result=`Run $MTX load $loadslot $driveslot 2>&1`
1098         status=$?
1099         Log "         -> status $status, result \"$result\""
1100         mtx_status_valid=0
1101         if [ $status -ne 0 ]; then
1102                 Exit 2 "$loadslot" "$result"
1103                 return $?                       # in case we are internal
1104         fi
1105
1106         ###
1107         # Cleaning tapes never go "ready", so instead we just sit here
1108         # for "long enough" (as determined empirically by the user),
1109         # then return success.
1110         ###
1111         if [ $loadslot -eq $cleanslot ]; then
1112                 Run sleep $cleancycle
1113                 Exit 0 "$loadslot" "$tape"
1114                 return $?                       # in case we are internal
1115         fi
1116
1117         ###
1118         # Wait for the drive to go online.
1119         ###
1120         waittime=0
1121         ready=0
1122         sleep $initial_poll_delay
1123         while [ $waittime -lt $max_drive_wait ]; do
1124                 result=`Run $MT $MTF $tape rewind 2>&1`
1125                 if [ $? -eq 0 ]; then
1126                         ready=1
1127                         break
1128                 fi
1129                 sleep $poll_drive_ready
1130                 waittime=`expr $waittime + $poll_drive_ready`
1131         done
1132         if [ $ready -eq 0 ]; then
1133                 Exit 2 "$loadslot" "Drive not ready after" \
1134                                    "$max_drive_wait seconds," \
1135                                    "rewind said \"$result\""
1136                 return $?                       # in case we are internal
1137         fi
1138
1139         if [ $loadslot -ne $cleanslot ]; then
1140                 rm -f $slotfile
1141                 echo $loadslot > $slotfile
1142         fi
1143         Exit 0 "$loadslot" "$tape"
1144         return $?                               # in case we are internal
1145 }
1146
1147 ###
1148 # Return information about how the changer is configured and the current
1149 # state of the robot.
1150 ###
1151
1152 info() {
1153         test -n "$DEBUG" && set -x
1154         get_loaded_info
1155         get_slot_list
1156         Log       "INFO     -> first slot: $firstslot"
1157         LogAppend "         -> current slot: $currentslot"
1158         LogAppend "         -> loaded slot: $loadedslot"
1159         LogAppend "         -> last slot: $lastslot"
1160         LogAppend "         -> slot list: $slot_list"
1161         LogAppend "         -> can go backwards: 1"
1162         LogAppend "         -> havereader: $havereader"
1163
1164         ###
1165         # Check if a barcode reader is configured or not.  If so, it
1166         # passes the 4th item in the echo back to amtape signifying it
1167         # can search based on barcodes.
1168         ###
1169         reader=
1170         if [ $havereader -eq 1 ]; then
1171                 reader=1
1172         fi
1173
1174         if [ $currentslot -lt $firstslot -o $currentslot -gt $lastslot ]; then
1175                 currentslot=$firstslot          # what "current" will get
1176         fi
1177         numslots=`expr $lastslot - $firstslot + 1`
1178         Exit 0 "$currentslot" "$numslots 1 $reader"
1179         return $?                               # in case we are internal
1180 }
1181
1182 ###
1183 # Read the labelfile and scan for a particular entry.
1184 ###
1185
1186 read_labelfile() {
1187         labelfile_entry_found=0
1188         labelfile_label=
1189         labelfile_barcode=
1190
1191         lbl_search=$1
1192         bc_search=$2
1193
1194         line=0
1195         while read lbl bc junk; do
1196                 line=`expr $line + 1`
1197                 if [ -z "$lbl" -o -z "$bc" -o -n "$junk" ]; then
1198                         Log       "ERROR    -> Line $line malformed: $lbl $bc $junk"
1199                         LogAppend "         -> Remove $labelfile" \
1200                                                "and run" \
1201                                                "\"$sbindir/amtape $config update\""
1202                         Exit 2 \
1203                              "<none>" \
1204                              "Line $line malformed in $labelfile: $lbl $bc $junk"
1205                         return $?               # in case we are internal
1206                 fi
1207                 if [ $lbl = "$lbl_search" -o $bc = "$bc_search" ]; then
1208                         if [ $labelfile_entry_found -ne 0 ]; then
1209                                 Log       "ERROR    -> Duplicate entries: $labelfile line $line"
1210                                 LogAppend "         -> Remove $labelfile" \
1211                                                        "and run" \
1212                                                        "\"$sbindir/amtape $config update\""
1213                                 Exit 2 \
1214                                      "<none>" \
1215                                      "Duplicate entries: $labelfile line $line"
1216                                 return $?       # in case we are internal
1217                         fi
1218                         labelfile_entry_found=1
1219                         labelfile_label=$lbl
1220                         labelfile_barcode=$bc
1221                 fi
1222         done
1223 }
1224
1225 ###
1226 # Adds the label and barcode for the currently loaded tape to the
1227 # barcode file.  Return an error if the database is messed up.
1228 ###
1229
1230 addlabel() {
1231         test -n "$DEBUG" && set -x
1232         if [ $# -lt 1 ]; then
1233                 Exit 2 "<none>" "Missing -label argument"
1234                 return $?                       # in case we are internal
1235         fi
1236         tapelabel=$1
1237         if [ $havereader -eq 0 ]; then
1238                 Exit 2 "<none>" "Not configured with barcode reader"
1239                 return $?                       # in case we are internal
1240         fi
1241         get_loaded_info
1242         if [ $loadedslot -lt 0 ]; then
1243                 Exit 1 "<none>" "No tape currently loaded"
1244                 return $?                       # in case we are internal
1245         fi
1246         Log       "LABEL    -> Adding label \"$tapelabel\"" \
1247                                "with barcode \"$loadedbarcode\"" \
1248                                "for slot $loadedslot" \
1249                                "into $labelfile"
1250         read_labelfile "$tapelabel" "$loadedbarcode" < $labelfile
1251         if [ $labelfile_entry_found -ne 0 ]; then
1252                 lf_val=
1253                 if [ "$labelfile_barcode" != "$loadedbarcode" ]; then
1254                         lf_type=label
1255                         lf_val=$tapelabel
1256                         val_type=barcode
1257                         old_val=$labelfile_barcode
1258                         new_val=$loadedbarcode
1259                 elif [ "$labelfile_label" != "$tapelabel" ]; then
1260                         lf_type=barcode
1261                         lf_val=$loadedbarcode
1262                         val_type=label
1263                         old_val=$labelfile_label
1264                         new_val=$tapelabel
1265                 fi
1266                 if [ -n "$lf_val" ]; then
1267                         LogAppend "ERROR    -> !!! Label database corrupted !!!"
1268                         LogAppend "         -> \"$old_val\" conflicts with" \
1269                                                "new $val_type \"$new_val\"" \
1270                                                "for $lf_type \"$lf_val\""
1271                         LogAppend "         -> Remove $labelfile" \
1272                                                "and run" \
1273                                                "\"$sbindir/amtape $config update\""
1274                         Exit 2 \
1275                              "<none>" \
1276                              "$tapelabel: \"$old_val\" conflicts with" \
1277                              "new $val_type \"$new_val\"" \
1278                              "for $lf_type \"$lf_val\""
1279                         return $?               # in case we are internal
1280                 fi
1281                 LogAppend "         -> already synced"
1282         else
1283                 echo "$tapelabel $loadedbarcode" >> $labelfile
1284                 LogAppend "         -> appended $labelfile entry:" \
1285                                        "$tapelabel $loadedbarcode"
1286         fi
1287         Exit 0 "$loadedslot" "$tape"
1288         return $?                               # in case we are internal
1289 }
1290
1291 ###
1292 # Look for a label in the barcode file.  If found, locate the slot it's
1293 # in by looking for the barcode in the mtx output, then load that tape.
1294 ###
1295
1296 searchtape() {
1297         test -n "$DEBUG" && set -x
1298         if [ $# -lt 1 ]; then
1299                 Exit 2 "<none>" "Missing -search argument"
1300                 return $?                       # in case we are internal
1301         fi
1302         tapelabel=$1
1303         if [ $havereader -eq 0 ]; then
1304                 Exit 2 "<none>" "Not configured with barcode reader"
1305                 return $?                       # in case we are internal
1306         fi
1307         Log "SEARCH   -> Hunting for label \"$tapelabel\""
1308         read_labelfile "$tapelabel" "" < $labelfile
1309         if [ $labelfile_entry_found -eq 0 ]; then
1310                 LogAppend "         -> !!! label \"$tapelabel\" not found" \
1311                                        "in $labelfile !!!"
1312                 LogAppend "         -> Remove $labelfile" \
1313                                        "and run" \
1314                                        "\"$sbindir/amtape $config update\""
1315                 Exit 2 \
1316                      "<none>" \
1317                      "$tapelabel: label \"$tapelabel\" not found in $labelfile"
1318                 return $?                       # in case we are internal
1319         fi
1320         LogAppend "         -> barcode is \"$labelfile_barcode\""
1321         get_mtx_status
1322         foundslot=`sed -n '
1323 /VolumeTag *= *'$labelfile_barcode' *$/                 {
1324         s/.*Storage Element \([0-9][0-9]*\).*/\1/p
1325         q
1326 }
1327 ' < $mtx_status`
1328         LogAppend "         -> foundslot is $foundslot"
1329         if [ -z "$foundslot" ]; then
1330                 LogAppend "ERROR    -> !!! Could not find slot" \
1331                                        "for barcode \"$labelfile_barcode\"!!!"
1332                 LogAppend "         -> Remove $labelfile" \
1333                                        "and run" \
1334                                        "\"$sbindir/amtape $config update\""
1335                 Exit 2 \
1336                      "<none>" \
1337                      "barcode \"$labelfile_barcode\"" \
1338                      "not found in mtx status output"
1339                 return $?                       # in case we are internal
1340         fi
1341         # Call loadslot without doing it as an internal and let it finish
1342         # things up.
1343         loadslot $foundslot
1344         # NOTREACHED
1345         Exit 2 "<none>" "searchtape: should not get here"
1346         return $?                               # in case we are internal
1347 }
1348
1349 ###
1350 # Program invocation begins here
1351 ###
1352
1353 if [ $# -lt 1 ]; then
1354         Exit 2 "<none>" "Usage: $myname -command args"
1355 fi
1356 cmd=$1
1357 shift
1358 case "$cmd" in
1359 -slot)
1360         loadslot "$@"
1361         ;;
1362 -info)
1363         info "$@"
1364         ;;
1365 -reset)
1366         reset "$@"
1367         ;;
1368 -eject)
1369         eject "$@"
1370         ;;
1371 -label) 
1372         addlabel "$@"
1373         ;;
1374 -search)
1375         searchtape "$@"
1376         ;;
1377 -clean)
1378         loadslot clean
1379         ;;
1380 *)
1381         Exit 2 "<none>" "unknown option: $cmd"
1382         ;;
1383 esac
1384
1385 Exit 2 "<none>" "$myname: should not get here"