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