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