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