1 /* 2 * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgements: 15 * This product includes software developed by Jason R. Thorpe 16 * for And Communications, http://www.and.com/ 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 27 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#) Copyright (c) 1996 Jason R. Thorpe. All rights reserved. 33 * $NetBSD: chio.c,v 1.6 1998/01/04 23:53:58 thorpej Exp $ 34 * $FreeBSD: src/bin/chio/chio.c,v 1.15.2.3 2001/07/28 19:22:01 mikeh Exp $ 35 */ 36 /* 37 * Additional Copyright (c) 1997, by Matthew Jacob, for NASA/Ames Research Ctr. 38 * Addidional Copyright (c) 2000, by C. Stephen Gunn, Waterspout Communications 39 */ 40 41 #include <sys/chio.h> 42 #include <sys/param.h> 43 44 #include <err.h> 45 #include <fcntl.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 51 #include "defs.h" 52 #include "pathnames.h" 53 54 extern char *__progname; /* from crt0.o */ 55 56 static void usage (void); 57 static void cleanup (void); 58 static int parse_element_type (char *); 59 static int parse_element_unit (char *); 60 static const char * element_type_name (int et); 61 static int parse_special (char *); 62 static int is_special (char *); 63 static const char *bits_to_string (ces_status_flags, const char *); 64 65 static void find_element (char *, u_int16_t *, u_int16_t *); 66 static struct changer_element_status *get_element_status 67 (unsigned int, unsigned int); 68 69 static int do_move (const char *, int, char **); 70 static int do_exchange (const char *, int, char **); 71 static int do_position (const char *, int, char **); 72 static int do_params (const char *, int, char **); 73 static int do_getpicker (const char *, int, char **); 74 static int do_setpicker (const char *, int, char **); 75 static int do_status (const char *, int, char **); 76 static int do_ielem (const char *, int, char **); 77 static int do_return (const char *, int, char **); 78 static int do_voltag (const char *, int, char **); 79 80 #ifndef CHET_VT 81 #define CHET_VT 10 /* Completely Arbitrary */ 82 #endif 83 84 /* Valid changer element types. */ 85 static const struct element_type elements[] = { 86 { "drive", CHET_DT }, 87 { "picker", CHET_MT }, 88 { "portal", CHET_IE }, 89 { "slot", CHET_ST }, 90 { "voltag", CHET_VT }, /* Select tapes by barcode */ 91 { NULL, 0 }, 92 }; 93 94 /* Valid commands. */ 95 static const struct changer_command commands[] = { 96 { "exchange", do_exchange }, 97 { "getpicker", do_getpicker }, 98 { "ielem", do_ielem }, 99 { "move", do_move }, 100 { "params", do_params }, 101 { "position", do_position }, 102 { "setpicker", do_setpicker }, 103 { "status", do_status }, 104 { "return", do_return }, 105 { "voltag", do_voltag }, 106 { NULL, 0 }, 107 }; 108 109 /* Valid special words. */ 110 static const struct special_word specials[] = { 111 { "inv", SW_INVERT }, 112 { "inv1", SW_INVERT1 }, 113 { "inv2", SW_INVERT2 }, 114 { NULL, 0 }, 115 }; 116 117 static int changer_fd; 118 static const char *changer_name; 119 120 int 121 main(int argc, char **argv) 122 { 123 int ch, i; 124 125 while ((ch = getopt(argc, argv, "f:")) != -1) { 126 switch (ch) { 127 case 'f': 128 changer_name = optarg; 129 break; 130 default: 131 usage(); 132 } 133 } 134 argc -= optind; 135 argv += optind; 136 137 if (argc == 0) 138 usage(); 139 140 /* Get the default changer if not already specified. */ 141 if (changer_name == NULL) 142 if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL) 143 changer_name = _PATH_CH; 144 145 /* Open the changer device. */ 146 if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1) 147 err(1, "%s: open", changer_name); 148 149 /* Register cleanup function. */ 150 if (atexit(cleanup)) 151 err(1, "can't register cleanup function"); 152 153 /* Find the specified command. */ 154 for (i = 0; commands[i].cc_name != NULL; ++i) 155 if (strcmp(*argv, commands[i].cc_name) == 0) 156 break; 157 if (commands[i].cc_name == NULL) { 158 /* look for abbreviation */ 159 for (i = 0; commands[i].cc_name != NULL; ++i) 160 if (strncmp(*argv, commands[i].cc_name, 161 strlen(*argv)) == 0) 162 break; 163 } 164 165 if (commands[i].cc_name == NULL) 166 errx(1, "unknown command: %s", *argv); 167 168 exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); 169 /* NOTREACHED */ 170 } 171 172 static int 173 do_move(const char *cname, int argc, char **argv) 174 { 175 struct changer_move cmd; 176 int val; 177 178 /* 179 * On a move command, we expect the following: 180 * 181 * <from ET> <from EU> <to ET> <to EU> [inv] 182 * 183 * where ET == element type and EU == element unit. 184 */ 185 186 ++argv; --argc; 187 188 if (argc < 4) { 189 warnx("%s: too few arguments", cname); 190 goto usage; 191 } else if (argc > 5) { 192 warnx("%s: too many arguments", cname); 193 goto usage; 194 } 195 memset(&cmd, 0, sizeof(cmd)); 196 197 /* <from ET> */ 198 cmd.cm_fromtype = parse_element_type(*argv); 199 ++argv; --argc; 200 201 /* Check for voltag virtual type */ 202 if (CHET_VT == cmd.cm_fromtype) { 203 find_element(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit); 204 } else { 205 /* <from EU> */ 206 cmd.cm_fromunit = parse_element_unit(*argv); 207 } 208 ++argv; --argc; 209 210 /* <to ET> */ 211 cmd.cm_totype = parse_element_type(*argv); 212 ++argv; --argc; 213 214 /* Check for voltag virtual type, and report error */ 215 if (CHET_VT == cmd.cm_totype) 216 errx(1,"%s: voltag only makes sense as an element source", 217 cname); 218 219 /* <to EU> */ 220 cmd.cm_tounit = parse_element_unit(*argv); 221 ++argv; --argc; 222 223 /* Deal with optional command modifier. */ 224 if (argc) { 225 val = parse_special(*argv); 226 switch (val) { 227 case SW_INVERT: 228 cmd.cm_flags |= CM_INVERT; 229 break; 230 231 default: 232 errx(1, "%s: inappropriate modifier `%s'", 233 cname, *argv); 234 /* NOTREACHED */ 235 } 236 } 237 238 /* Send command to changer. */ 239 if (ioctl(changer_fd, CHIOMOVE, &cmd)) 240 err(1, "%s: CHIOMOVE", changer_name); 241 242 return (0); 243 244 usage: 245 fprintf(stderr, "usage: %s %s " 246 "<from ET> <from EU> <to ET> <to EU> [inv]\n", __progname, cname); 247 return (1); 248 } 249 250 static int 251 do_exchange(const char *cname, int argc, char **argv) 252 { 253 struct changer_exchange cmd; 254 int val; 255 256 /* 257 * On an exchange command, we expect the following: 258 * 259 * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2] 260 * 261 * where ET == element type and EU == element unit. 262 */ 263 264 ++argv; --argc; 265 266 if (argc < 4) { 267 warnx("%s: too few arguments", cname); 268 goto usage; 269 } else if (argc > 8) { 270 warnx("%s: too many arguments", cname); 271 goto usage; 272 } 273 memset(&cmd, 0, sizeof(cmd)); 274 275 /* <src ET> */ 276 cmd.ce_srctype = parse_element_type(*argv); 277 ++argv; --argc; 278 279 /* Check for voltag virtual type */ 280 if (CHET_VT == cmd.ce_srctype) { 281 find_element(*argv, &cmd.ce_srctype, &cmd.ce_srcunit); 282 } else { 283 /* <from EU> */ 284 cmd.ce_srcunit = parse_element_unit(*argv); 285 } 286 ++argv; --argc; 287 288 /* <dst1 ET> */ 289 cmd.ce_fdsttype = parse_element_type(*argv); 290 ++argv; --argc; 291 292 /* Check for voltag virtual type */ 293 if (CHET_VT == cmd.ce_fdsttype) { 294 find_element(*argv, &cmd.ce_fdsttype, &cmd.ce_fdstunit); 295 } else { 296 /* <from EU> */ 297 cmd.ce_fdstunit = parse_element_unit(*argv); 298 } 299 ++argv; --argc; 300 301 /* 302 * If the next token is a special word or there are no more 303 * arguments, then this is a case of simple exchange. 304 * dst2 == src. 305 */ 306 if ((argc == 0) || is_special(*argv)) { 307 cmd.ce_sdsttype = cmd.ce_srctype; 308 cmd.ce_sdstunit = cmd.ce_srcunit; 309 goto do_special; 310 } 311 312 /* <dst2 ET> */ 313 cmd.ce_sdsttype = parse_element_type(*argv); 314 ++argv; --argc; 315 316 if (CHET_VT == cmd.ce_sdsttype) 317 errx(1,"%s %s: voltag only makes sense as an element source", 318 cname, *argv); 319 320 /* <dst2 EU> */ 321 cmd.ce_sdstunit = parse_element_unit(*argv); 322 ++argv; --argc; 323 324 do_special: 325 /* Deal with optional command modifiers. */ 326 while (argc) { 327 val = parse_special(*argv); 328 ++argv; --argc; 329 switch (val) { 330 case SW_INVERT1: 331 cmd.ce_flags |= CE_INVERT1; 332 break; 333 334 case SW_INVERT2: 335 cmd.ce_flags |= CE_INVERT2; 336 break; 337 338 default: 339 errx(1, "%s: inappropriate modifier `%s'", 340 cname, *argv); 341 /* NOTREACHED */ 342 } 343 } 344 345 /* Send command to changer. */ 346 if (ioctl(changer_fd, CHIOEXCHANGE, &cmd)) 347 err(1, "%s: CHIOEXCHANGE", changer_name); 348 349 return (0); 350 351 usage: 352 fprintf(stderr, 353 "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n" 354 " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n", 355 __progname, cname); 356 return (1); 357 } 358 359 static int 360 do_position(const char *cname, int argc, char **argv) 361 { 362 struct changer_position cmd; 363 int val; 364 365 /* 366 * On a position command, we expect the following: 367 * 368 * <to ET> <to EU> [inv] 369 * 370 * where ET == element type and EU == element unit. 371 */ 372 373 ++argv; --argc; 374 375 if (argc < 2) { 376 warnx("%s: too few arguments", cname); 377 goto usage; 378 } else if (argc > 3) { 379 warnx("%s: too many arguments", cname); 380 goto usage; 381 } 382 memset(&cmd, 0, sizeof(cmd)); 383 384 /* <to ET> */ 385 cmd.cp_type = parse_element_type(*argv); 386 ++argv; --argc; 387 388 /* <to EU> */ 389 cmd.cp_unit = parse_element_unit(*argv); 390 ++argv; --argc; 391 392 /* Deal with optional command modifier. */ 393 if (argc) { 394 val = parse_special(*argv); 395 switch (val) { 396 case SW_INVERT: 397 cmd.cp_flags |= CP_INVERT; 398 break; 399 400 default: 401 errx(1, "%s: inappropriate modifier `%s'", 402 cname, *argv); 403 /* NOTREACHED */ 404 } 405 } 406 407 /* Send command to changer. */ 408 if (ioctl(changer_fd, CHIOPOSITION, &cmd)) 409 err(1, "%s: CHIOPOSITION", changer_name); 410 411 return (0); 412 413 usage: 414 fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n", 415 __progname, cname); 416 return (1); 417 } 418 419 /* ARGSUSED */ 420 static int 421 do_params(const char *cname, int argc, char **argv) 422 { 423 struct changer_params data; 424 int picker; 425 426 /* No arguments to this command. */ 427 428 ++argv; --argc; 429 430 if (argc) { 431 warnx("%s: no arguments expected", cname); 432 goto usage; 433 } 434 435 /* Get params from changer and display them. */ 436 memset(&data, 0, sizeof(data)); 437 if (ioctl(changer_fd, CHIOGPARAMS, &data)) 438 err(1, "%s: CHIOGPARAMS", changer_name); 439 440 printf("%s: %d slot%s, %d drive%s, %d picker%s", 441 changer_name, 442 data.cp_nslots, (data.cp_nslots > 1) ? "s" : "", 443 data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "", 444 data.cp_npickers, (data.cp_npickers > 1) ? "s" : ""); 445 if (data.cp_nportals) 446 printf(", %d portal%s", data.cp_nportals, 447 (data.cp_nportals > 1) ? "s" : ""); 448 449 /* Get current picker from changer and display it. */ 450 if (ioctl(changer_fd, CHIOGPICKER, &picker)) 451 err(1, "%s: CHIOGPICKER", changer_name); 452 453 printf("\n%s: current picker: %d\n", changer_name, picker); 454 455 return (0); 456 457 usage: 458 fprintf(stderr, "usage: %s %s\n", __progname, cname); 459 return (1); 460 } 461 462 /* ARGSUSED */ 463 static int 464 do_getpicker(const char *cname, int argc, char **argv) 465 { 466 int picker; 467 468 /* No arguments to this command. */ 469 470 ++argv; --argc; 471 472 if (argc) { 473 warnx("%s: no arguments expected", cname); 474 goto usage; 475 } 476 477 /* Get current picker from changer and display it. */ 478 if (ioctl(changer_fd, CHIOGPICKER, &picker)) 479 err(1, "%s: CHIOGPICKER", changer_name); 480 481 printf("%s: current picker: %d\n", changer_name, picker); 482 483 return (0); 484 485 usage: 486 fprintf(stderr, "usage: %s %s\n", __progname, cname); 487 return (1); 488 } 489 490 static int 491 do_setpicker(const char *cname, int argc, char **argv) 492 { 493 int picker; 494 495 ++argv; --argc; 496 497 if (argc < 1) { 498 warnx("%s: too few arguments", cname); 499 goto usage; 500 } else if (argc > 1) { 501 warnx("%s: too many arguments", cname); 502 goto usage; 503 } 504 505 picker = parse_element_unit(*argv); 506 507 /* Set the changer picker. */ 508 if (ioctl(changer_fd, CHIOSPICKER, &picker)) 509 err(1, "%s: CHIOSPICKER", changer_name); 510 511 return (0); 512 513 usage: 514 fprintf(stderr, "usage: %s %s <picker>\n", __progname, cname); 515 return (1); 516 } 517 518 static int 519 do_status(const char *cname, int argc, char **argv) 520 { 521 struct changer_params cp; 522 struct changer_element_status_request cesr; 523 int i, count, base, chet, schet, echet; 524 const char *description; 525 int pvoltag = 0; 526 int avoltag = 0; 527 int sense = 0; 528 int scsi = 0; 529 int source = 0; 530 int intaddr = 0; 531 int c; 532 533 count = 0; 534 base = 0; 535 description = NULL; 536 537 optind = optreset = 1; 538 while ((c = getopt(argc, argv, "vVsSbaI")) != -1) { 539 switch (c) { 540 case 'v': 541 pvoltag = 1; 542 break; 543 case 'V': 544 avoltag = 1; 545 break; 546 case 's': 547 sense = 1; 548 break; 549 case 'S': 550 source = 1; 551 break; 552 case 'b': 553 scsi = 1; 554 break; 555 case 'I': 556 intaddr = 1; 557 break; 558 case 'a': 559 pvoltag = avoltag = source = sense = scsi = intaddr = 1; 560 break; 561 default: 562 warnx("%s: bad option", cname); 563 goto usage; 564 } 565 } 566 567 argc -= optind; 568 argv += optind; 569 570 /* 571 * On a status command, we expect the following: 572 * 573 * [<ET> [<start> [<end>] ] ] 574 * 575 * where ET == element type, start == first element to report, 576 * end == number of elements to report 577 * 578 * If we get no arguments, we get the status of all 579 * known element types. 580 */ 581 if (argc > 3) { 582 warnx("%s: too many arguments", cname); 583 goto usage; 584 } 585 586 /* 587 * Get params from changer. Specifically, we need the element 588 * counts. 589 */ 590 if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) 591 err(1, "%s: CHIOGPARAMS", changer_name); 592 593 if (argc > 0) 594 schet = echet = parse_element_type(argv[0]); 595 else { 596 schet = CHET_MT; 597 echet = CHET_DT; 598 } 599 if (argc > 1) { 600 base = atol(argv[1]); 601 count = 1; 602 } 603 if (argc > 2) 604 count = atol(argv[2]) - base + 1; 605 606 if (base < 0 || count < 0) 607 errx(1, "bad arguments"); 608 609 for (chet = schet; chet <= echet; ++chet) { 610 switch (chet) { 611 case CHET_MT: 612 if (count == 0) 613 count = cp.cp_npickers; 614 else if (count > cp.cp_npickers) 615 errx(1, "not that many pickers in device"); 616 description = "picker"; 617 break; 618 619 case CHET_ST: 620 if (count == 0) 621 count = cp.cp_nslots; 622 else if (count > cp.cp_nslots) 623 errx(1, "not that many slots in device"); 624 description = "slot"; 625 break; 626 627 case CHET_IE: 628 if (count == 0) 629 count = cp.cp_nportals; 630 else if (count > cp.cp_nportals) 631 errx(1, "not that many portals in device"); 632 description = "portal"; 633 break; 634 635 case CHET_DT: 636 if (count == 0) 637 count = cp.cp_ndrives; 638 else if (count > cp.cp_ndrives) 639 errx(1, "not that many drives in device"); 640 description = "drive"; 641 break; 642 643 default: 644 /* To appease gcc -Wuninitialized. */ 645 count = 0; 646 description = NULL; 647 } 648 649 if (count == 0) { 650 if (argc == 0) 651 continue; 652 else { 653 printf("%s: no %s elements\n", 654 changer_name, description); 655 return (0); 656 } 657 } 658 659 bzero(&cesr, sizeof(cesr)); 660 cesr.cesr_element_type = chet; 661 cesr.cesr_element_base = base; 662 cesr.cesr_element_count = count; 663 /* Allocate storage for the status structures. */ 664 cesr.cesr_element_status = 665 (struct changer_element_status *) 666 calloc((size_t)count, sizeof(struct changer_element_status)); 667 668 if (!cesr.cesr_element_status) 669 errx(1, "can't allocate status storage"); 670 671 if (avoltag || pvoltag) 672 cesr.cesr_flags |= CESR_VOLTAGS; 673 674 if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr)) { 675 free(cesr.cesr_element_status); 676 err(1, "%s: CHIOGSTATUS", changer_name); 677 } 678 679 /* Dump the status for each reported element. */ 680 for (i = 0; i < count; ++i) { 681 struct changer_element_status *ces = 682 &(cesr.cesr_element_status[i]); 683 printf("%s %d: %s", description, ces->ces_addr, 684 bits_to_string(ces->ces_flags, 685 CESTATUS_BITS)); 686 if (sense) 687 printf(" sense: <0x%02x/0x%02x>", 688 ces->ces_sensecode, 689 ces->ces_sensequal); 690 if (pvoltag) 691 printf(" voltag: <%s:%d>", 692 ces->ces_pvoltag.cv_volid, 693 ces->ces_pvoltag.cv_serial); 694 if (avoltag) 695 printf(" avoltag: <%s:%d>", 696 ces->ces_avoltag.cv_volid, 697 ces->ces_avoltag.cv_serial); 698 if (source) { 699 if (ces->ces_flags & CES_SOURCE_VALID) 700 printf(" source: <%s %d>", 701 element_type_name( 702 ces->ces_source_type), 703 ces->ces_source_addr); 704 else 705 printf(" source: <>"); 706 } 707 if (intaddr) 708 printf(" intaddr: <%d>", ces->ces_int_addr); 709 if (scsi) { 710 printf(" scsi: <"); 711 if (ces->ces_flags & CES_SCSIID_VALID) 712 printf("%d", ces->ces_scsi_id); 713 else 714 putchar('?'); 715 putchar(':'); 716 if (ces->ces_flags & CES_LUN_VALID) 717 printf("%d", ces->ces_scsi_lun); 718 else 719 putchar('?'); 720 putchar('>'); 721 } 722 putchar('\n'); 723 } 724 725 free(cesr.cesr_element_status); 726 count = 0; 727 } 728 729 return (0); 730 731 usage: 732 fprintf(stderr, "usage: %s %s [-vVsSbaA] [<element type> [<start-addr> [<end-addr>] ] ]\n", 733 __progname, cname); 734 return (1); 735 } 736 737 static int 738 do_ielem(const char *cname, int argc, char **argv) 739 { 740 int timeout = 0; 741 742 if (argc == 2) { 743 timeout = atol(argv[1]); 744 } else if (argc > 1) { 745 warnx("%s: too many arguments", cname); 746 goto usage; 747 } 748 749 if (ioctl(changer_fd, CHIOIELEM, &timeout)) 750 err(1, "%s: CHIOIELEM", changer_name); 751 752 return (0); 753 754 usage: 755 fprintf(stderr, "usage: %s %s [<timeout>]\n", 756 __progname, cname); 757 return (1); 758 } 759 760 static int 761 do_voltag(const char *cname, int argc, char **argv) 762 { 763 int force = 0; 764 int clear = 0; 765 int alternate = 0; 766 int c; 767 struct changer_set_voltag_request csvr; 768 769 bzero(&csvr, sizeof(csvr)); 770 771 optind = optreset = 1; 772 while ((c = getopt(argc, argv, "fca")) != -1) { 773 switch (c) { 774 case 'f': 775 force = 1; 776 break; 777 case 'c': 778 clear = 1; 779 break; 780 case 'a': 781 alternate = 1; 782 break; 783 default: 784 warnx("%s: bad option", cname); 785 goto usage; 786 } 787 } 788 789 argc -= optind; 790 argv += optind; 791 792 if (argc < 2) { 793 warnx("%s: missing element specification", cname); 794 goto usage; 795 } 796 797 csvr.csvr_type = parse_element_type(argv[0]); 798 csvr.csvr_addr = atol(argv[1]); 799 800 if (!clear) { 801 if (argc < 3 || argc > 4) { 802 warnx("%s: missing argument", cname); 803 goto usage; 804 } 805 806 if (force) 807 csvr.csvr_flags = CSVR_MODE_REPLACE; 808 else 809 csvr.csvr_flags = CSVR_MODE_SET; 810 811 if (strlen(argv[2]) > sizeof(csvr.csvr_voltag.cv_volid)) { 812 warnx("%s: volume label too long", cname); 813 goto usage; 814 } 815 816 strlcpy((char *)csvr.csvr_voltag.cv_volid, argv[2], 817 sizeof(csvr.csvr_voltag.cv_volid)); 818 819 if (argc == 4) { 820 csvr.csvr_voltag.cv_serial = atol(argv[3]); 821 } 822 } else { 823 if (argc != 2) { 824 warnx("%s: unexpected argument", cname); 825 goto usage; 826 } 827 csvr.csvr_flags = CSVR_MODE_CLEAR; 828 } 829 830 if (alternate) { 831 csvr.csvr_flags |= CSVR_ALTERNATE; 832 } 833 834 if (ioctl(changer_fd, CHIOSETVOLTAG, &csvr)) 835 err(1, "%s: CHIOSETVOLTAG", changer_name); 836 837 return 0; 838 usage: 839 fprintf(stderr, "usage: %s %s [-fca] <element> [<voltag> [<vsn>] ]\n", 840 __progname, cname); 841 return 1; 842 } 843 844 static int 845 parse_element_type(char *cp) 846 { 847 int i; 848 849 for (i = 0; elements[i].et_name != NULL; ++i) 850 if (strcmp(elements[i].et_name, cp) == 0) 851 return (elements[i].et_type); 852 853 errx(1, "invalid element type `%s'", cp); 854 /* NOTREACHED */ 855 } 856 857 static const char * 858 element_type_name(int et) 859 { 860 int i; 861 862 for (i = 0; elements[i].et_name != NULL; i++) 863 if (elements[i].et_type == et) 864 return elements[i].et_name; 865 866 return "unknown"; 867 } 868 869 static int 870 parse_element_unit(char *cp) 871 { 872 int i; 873 char *p; 874 875 i = (int)strtol(cp, &p, 10); 876 if ((i < 0) || (*p != '\0')) 877 errx(1, "invalid unit number `%s'", cp); 878 879 return (i); 880 } 881 882 static int 883 parse_special(char *cp) 884 { 885 int val; 886 887 val = is_special(cp); 888 if (val) 889 return (val); 890 891 errx(1, "invalid modifier `%s'", cp); 892 /* NOTREACHED */ 893 } 894 895 static int 896 is_special(char *cp) 897 { 898 int i; 899 900 for (i = 0; specials[i].sw_name != NULL; ++i) 901 if (strcmp(specials[i].sw_name, cp) == 0) 902 return (specials[i].sw_value); 903 904 return (0); 905 } 906 907 static const char * 908 bits_to_string(ces_status_flags v, const char *cp) 909 { 910 const char *np; 911 char f, sep, *bp; 912 static char buf[128]; 913 914 bp = buf; 915 memset(buf, 0, sizeof(buf)); 916 917 for (sep = '<'; (f = *cp++) != 0; cp = np) { 918 for (np = cp; *np >= ' ';) 919 np++; 920 if ((v & (1 << (f - 1))) == 0) 921 continue; 922 snprintf(bp, sizeof(buf) - (bp - &buf[0]), 923 "%c%.*s", sep, (int)(long)(np - cp), cp); 924 bp += strlen(bp); 925 sep = ','; 926 } 927 if (sep != '<') 928 *bp = '>'; 929 930 return (buf); 931 } 932 /* 933 * do_return() 934 * 935 * Given an element reference, ask the changer/picker to move that 936 * element back to its source slot. 937 */ 938 static int 939 do_return(const char *cname, int argc, char **argv) 940 { 941 struct changer_element_status *ces; 942 struct changer_move cmd; 943 u_int16_t type, element; 944 945 ++argv; --argc; 946 947 if (argc < 2) { 948 warnx("%s: too few arguments", cname); 949 goto usage; 950 } else if (argc > 3) { 951 warnx("%s: too many arguments", cname); 952 goto usage; 953 } 954 955 type = parse_element_type(*argv); 956 ++argv; --argc; 957 958 /* Handle voltag virtual Changer Element Type */ 959 if (CHET_VT == type) { 960 find_element(*argv, &type, &element); 961 } else { 962 element = parse_element_unit(*argv); 963 } 964 ++argv; --argc; 965 966 /* Get the status */ 967 ces = get_element_status((unsigned int)type, (unsigned int)element); 968 969 if (NULL == ces) 970 errx(1, "%s: null element status pointer", cname); 971 972 if (!(ces->ces_flags & CES_SOURCE_VALID)) 973 errx(1, "%s: no source information", cname); 974 975 memset(&cmd, 0, sizeof(cmd)); 976 977 cmd.cm_fromtype = type; 978 cmd.cm_fromunit = element; 979 cmd.cm_totype = ces->ces_source_type; 980 cmd.cm_tounit = ces->ces_source_addr; 981 982 if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1) 983 err(1, "%s: CHIOMOVE", changer_name); 984 free(ces); 985 986 return(0); 987 988 usage: 989 fprintf(stderr, "usage: %s %s " 990 "<from ET> <from EU>\n", __progname, cname); 991 return(1); 992 } 993 994 /* 995 * get_element_status() 996 * 997 * return a *cesr for the specified changer element. This 998 * routing will malloc()/calloc() the memory. The caller 999 * should free() it when done. 1000 */ 1001 static struct changer_element_status * 1002 get_element_status(unsigned int type, unsigned int element) 1003 { 1004 struct changer_element_status_request cesr; 1005 struct changer_element_status *ces; 1006 1007 ces = (struct changer_element_status *) 1008 calloc((size_t)1, sizeof(struct changer_element_status)); 1009 1010 if (NULL == ces) 1011 errx(1, "can't allocate status storage"); 1012 1013 memset(&cesr, 0, sizeof(cesr)); 1014 1015 cesr.cesr_element_type = (u_int16_t)type; 1016 cesr.cesr_element_base = (u_int16_t)element; 1017 cesr.cesr_element_count = 1; /* Only this one element */ 1018 cesr.cesr_flags |= CESR_VOLTAGS; /* Grab voltags as well */ 1019 cesr.cesr_element_status = ces; 1020 1021 if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 1022 free(ces); 1023 err(1, "%s: CHIOGSTATUS", changer_name); 1024 /* NOTREACHED */ 1025 } 1026 1027 return ces; 1028 } 1029 1030 1031 /* 1032 * find_element() 1033 * 1034 * Given a <voltag> find the chager element and unit, or exit 1035 * with an error if it isn't found. We grab the changer status 1036 * and iterate until we find a match, or crap out. 1037 */ 1038 static void 1039 find_element(char *voltag, u_int16_t *et, u_int16_t *eu) 1040 { 1041 struct changer_params cp; 1042 struct changer_element_status_request cesr = { .cesr_flags = 0 }; 1043 struct changer_element_status *ch_ces, *ces; 1044 int found = 0; 1045 size_t elem, total_elem; 1046 1047 /* 1048 * Get the changer parameters, we're interested in the counts 1049 * for all types of elements to perform our search. 1050 */ 1051 if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) 1052 err(1, "%s: CHIOGPARAMS", changer_name); 1053 1054 /* Allocate some memory for the results */ 1055 total_elem = (cp.cp_nslots + cp.cp_ndrives 1056 + cp.cp_npickers + cp.cp_nportals); 1057 1058 ch_ces = (struct changer_element_status *) 1059 calloc(total_elem, sizeof(struct changer_element_status)); 1060 1061 if (NULL == ch_ces) 1062 errx(1, "can't allocate status storage"); 1063 1064 ces = ch_ces; 1065 1066 /* Read in the changer slots */ 1067 if (cp.cp_nslots > 0) { 1068 cesr.cesr_element_type = CHET_ST; 1069 cesr.cesr_element_base = 0; 1070 cesr.cesr_element_count = cp.cp_nslots; 1071 cesr.cesr_flags |= CESR_VOLTAGS; 1072 cesr.cesr_element_status = ces; 1073 1074 if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 1075 free(ch_ces); 1076 err(1, "%s: CHIOGSTATUS", changer_name); 1077 } 1078 ces += cp.cp_nslots; 1079 } 1080 1081 /* Read in the drive information */ 1082 if (cp.cp_ndrives > 0 ) { 1083 1084 memset(&cesr, 0, sizeof(cesr)); 1085 cesr.cesr_element_type = CHET_DT; 1086 cesr.cesr_element_base = 0; 1087 cesr.cesr_element_count = cp.cp_ndrives; 1088 cesr.cesr_flags |= CESR_VOLTAGS; 1089 cesr.cesr_element_status = ces; 1090 1091 if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 1092 free(ch_ces); 1093 err(1, "%s: CHIOGSTATUS", changer_name); 1094 } 1095 ces += cp.cp_ndrives; 1096 } 1097 1098 /* Read in the portal information */ 1099 if (cp.cp_nportals > 0 ) { 1100 memset(&cesr, 0, sizeof(cesr)); 1101 cesr.cesr_element_type = CHET_IE; 1102 cesr.cesr_element_base = 0; 1103 cesr.cesr_element_count = cp.cp_nportals; 1104 cesr.cesr_flags |= CESR_VOLTAGS; 1105 cesr.cesr_element_status = ces; 1106 1107 if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 1108 free(ch_ces); 1109 err(1, "%s: CHIOGSTATUS", changer_name); 1110 } 1111 ces += cp.cp_nportals; 1112 } 1113 1114 /* Read in the picker information */ 1115 if (cp.cp_npickers > 0) { 1116 memset(&cesr, 0, sizeof(cesr)); 1117 cesr.cesr_element_type = CHET_MT; 1118 cesr.cesr_element_base = 0; 1119 cesr.cesr_element_count = cp.cp_npickers; 1120 cesr.cesr_flags |= CESR_VOLTAGS; 1121 cesr.cesr_element_status = ces; 1122 1123 if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 1124 free(ch_ces); 1125 err(1, "%s: CHIOGSTATUS", changer_name); 1126 } 1127 } 1128 1129 /* 1130 * Now search the list the specified <voltag> 1131 */ 1132 for (elem = 0; elem <= total_elem; ++elem) { 1133 1134 ces = &ch_ces[elem]; 1135 1136 /* Make sure we have a tape in this element */ 1137 if ((ces->ces_flags & (CES_STATUS_ACCESS|CES_STATUS_FULL)) 1138 != (CES_STATUS_ACCESS|CES_STATUS_FULL)) 1139 continue; 1140 1141 /* Check to see if it is our target */ 1142 if (strcasecmp(voltag, 1143 (const char *)ces->ces_pvoltag.cv_volid) == 0) { 1144 *et = ces->ces_type; 1145 *eu = ces->ces_addr; 1146 ++found; 1147 break; 1148 } 1149 } 1150 if (!found) { 1151 errx(1, "%s: unable to locate voltag: %s", changer_name, 1152 voltag); 1153 } 1154 free(ch_ces); 1155 return; 1156 } 1157 1158 static void 1159 cleanup(void) 1160 { 1161 /* Simple enough... */ 1162 close(changer_fd); 1163 } 1164 1165 static void 1166 usage(void) 1167 { 1168 fprintf(stderr, "usage: %s [-f changer] command [-<flags>] " 1169 "arg1 arg2 [arg3 [...]]\n", __progname); 1170 exit(1); 1171 } 1172