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