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 */ 36 37 #ifndef lint 38 static const char copyright[] = 39 "@(#) Copyright (c) 1996 Jason R. Thorpe. All rights reserved."; 40 static const char rcsid[] = 41 "$FreeBSD$"; 42 #endif /* not lint */ 43 44 #include <sys/param.h> 45 #include <sys/chio.h> 46 #include <err.h> 47 #include <fcntl.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <unistd.h> 52 53 #include "defs.h" 54 #include "pathnames.h" 55 56 extern char *__progname; /* from crt0.o */ 57 extern int optreset; /* from getopt.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((int, const char *)); 67 68 static int do_move __P((char *, int, char **)); 69 static int do_exchange __P((char *, int, char **)); 70 static int do_position __P((char *, int, char **)); 71 static int do_params __P((char *, int, char **)); 72 static int do_getpicker __P((char *, int, char **)); 73 static int do_setpicker __P((char *, int, char **)); 74 static int do_status __P((char *, int, char **)); 75 static int do_ielem __P((char *, int, char **)); 76 static int do_voltag __P((char *, int, char **)); 77 78 /* Valid changer element types. */ 79 const struct element_type elements[] = { 80 { "drive", CHET_DT }, 81 { "picker", CHET_MT }, 82 { "portal", CHET_IE }, 83 { "slot", CHET_ST }, 84 { NULL, 0 }, 85 }; 86 87 /* Valid commands. */ 88 const struct changer_command commands[] = { 89 { "exchange", do_exchange }, 90 { "getpicker", do_getpicker }, 91 { "ielem", do_ielem }, 92 { "move", do_move }, 93 { "params", do_params }, 94 { "position", do_position }, 95 { "setpicker", do_setpicker }, 96 { "status", do_status }, 97 { "voltag", do_voltag }, 98 { NULL, 0 }, 99 }; 100 101 /* Valid special words. */ 102 const struct special_word specials[] = { 103 { "inv", SW_INVERT }, 104 { "inv1", SW_INVERT1 }, 105 { "inv2", SW_INVERT2 }, 106 { NULL, 0 }, 107 }; 108 109 static int changer_fd; 110 static const char *changer_name; 111 112 int 113 main(argc, argv) 114 int argc; 115 char **argv; 116 { 117 int ch, i; 118 119 while ((ch = getopt(argc, argv, "f:")) != -1) { 120 switch (ch) { 121 case 'f': 122 changer_name = optarg; 123 break; 124 125 default: 126 usage(); 127 } 128 } 129 argc -= optind; 130 argv += optind; 131 132 if (argc == 0) 133 usage(); 134 135 /* Get the default changer if not already specified. */ 136 if (changer_name == NULL) 137 if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL) 138 changer_name = _PATH_CH; 139 140 /* Open the changer device. */ 141 if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1) 142 err(1, "%s: open", changer_name); 143 144 /* Register cleanup function. */ 145 if (atexit(cleanup)) 146 err(1, "can't register cleanup function"); 147 148 /* Find the specified command. */ 149 for (i = 0; commands[i].cc_name != NULL; ++i) 150 if (strcmp(*argv, commands[i].cc_name) == 0) 151 break; 152 if (commands[i].cc_name == NULL) { 153 /* look for abbreviation */ 154 for (i = 0; commands[i].cc_name != NULL; ++i) 155 if (strncmp(*argv, commands[i].cc_name, 156 strlen(*argv)) == 0) 157 break; 158 } 159 160 if (commands[i].cc_name == NULL) 161 errx(1, "unknown command: %s", *argv); 162 163 exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); 164 /* NOTREACHED */ 165 } 166 167 static int 168 do_move(cname, argc, argv) 169 char *cname; 170 int argc; 171 char **argv; 172 { 173 struct changer_move cmd; 174 int val; 175 176 /* 177 * On a move command, we expect the following: 178 * 179 * <from ET> <from EU> <to ET> <to EU> [inv] 180 * 181 * where ET == element type and EU == element unit. 182 */ 183 184 ++argv; --argc; 185 186 if (argc < 4) { 187 warnx("%s: too few arguments", cname); 188 goto usage; 189 } else if (argc > 5) { 190 warnx("%s: too many arguments", cname); 191 goto usage; 192 } 193 (void) memset(&cmd, 0, sizeof(cmd)); 194 195 /* <from ET> */ 196 cmd.cm_fromtype = parse_element_type(*argv); 197 ++argv; --argc; 198 199 /* <from EU> */ 200 cmd.cm_fromunit = parse_element_unit(*argv); 201 ++argv; --argc; 202 203 /* <to ET> */ 204 cmd.cm_totype = parse_element_type(*argv); 205 ++argv; --argc; 206 207 /* <to EU> */ 208 cmd.cm_tounit = parse_element_unit(*argv); 209 ++argv; --argc; 210 211 /* Deal with optional command modifier. */ 212 if (argc) { 213 val = parse_special(*argv); 214 switch (val) { 215 case SW_INVERT: 216 cmd.cm_flags |= CM_INVERT; 217 break; 218 219 default: 220 errx(1, "%s: inappropriate modifier `%s'", 221 cname, *argv); 222 /* NOTREACHED */ 223 } 224 } 225 226 /* Send command to changer. */ 227 if (ioctl(changer_fd, CHIOMOVE, &cmd)) 228 err(1, "%s: CHIOMOVE", changer_name); 229 230 return (0); 231 232 usage: 233 (void) fprintf(stderr, "usage: %s %s " 234 "<from ET> <from EU> <to ET> <to EU> [inv]\n", __progname, cname); 235 return (1); 236 } 237 238 static int 239 do_exchange(cname, argc, argv) 240 char *cname; 241 int argc; 242 char **argv; 243 { 244 struct changer_exchange cmd; 245 int val; 246 247 /* 248 * On an exchange command, we expect the following: 249 * 250 * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2] 251 * 252 * where ET == element type and EU == element unit. 253 */ 254 255 ++argv; --argc; 256 257 if (argc < 4) { 258 warnx("%s: too few arguments", cname); 259 goto usage; 260 } else if (argc > 8) { 261 warnx("%s: too many arguments", cname); 262 goto usage; 263 } 264 (void) memset(&cmd, 0, sizeof(cmd)); 265 266 /* <src ET> */ 267 cmd.ce_srctype = parse_element_type(*argv); 268 ++argv; --argc; 269 270 /* <src EU> */ 271 cmd.ce_srcunit = parse_element_unit(*argv); 272 ++argv; --argc; 273 274 /* <dst1 ET> */ 275 cmd.ce_fdsttype = parse_element_type(*argv); 276 ++argv; --argc; 277 278 /* <dst1 EU> */ 279 cmd.ce_fdstunit = parse_element_unit(*argv); 280 ++argv; --argc; 281 282 /* 283 * If the next token is a special word or there are no more 284 * arguments, then this is a case of simple exchange. 285 * dst2 == src. 286 */ 287 if ((argc == 0) || is_special(*argv)) { 288 cmd.ce_sdsttype = cmd.ce_srctype; 289 cmd.ce_sdstunit = cmd.ce_srcunit; 290 goto do_special; 291 } 292 293 /* <dst2 ET> */ 294 cmd.ce_sdsttype = parse_element_type(*argv); 295 ++argv; --argc; 296 297 /* <dst2 EU> */ 298 cmd.ce_sdstunit = parse_element_unit(*argv); 299 ++argv; --argc; 300 301 do_special: 302 /* Deal with optional command modifiers. */ 303 while (argc) { 304 val = parse_special(*argv); 305 ++argv; --argc; 306 switch (val) { 307 case SW_INVERT1: 308 cmd.ce_flags |= CE_INVERT1; 309 break; 310 311 case SW_INVERT2: 312 cmd.ce_flags |= CE_INVERT2; 313 break; 314 315 default: 316 errx(1, "%s: inappropriate modifier `%s'", 317 cname, *argv); 318 /* NOTREACHED */ 319 } 320 } 321 322 /* Send command to changer. */ 323 if (ioctl(changer_fd, CHIOEXCHANGE, &cmd)) 324 err(1, "%s: CHIOEXCHANGE", changer_name); 325 326 return (0); 327 328 usage: 329 (void) fprintf(stderr, 330 "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n" 331 " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n", 332 __progname, cname); 333 return (1); 334 } 335 336 static int 337 do_position(cname, argc, argv) 338 char *cname; 339 int argc; 340 char **argv; 341 { 342 struct changer_position cmd; 343 int val; 344 345 /* 346 * On a position command, we expect the following: 347 * 348 * <to ET> <to EU> [inv] 349 * 350 * where ET == element type and EU == element unit. 351 */ 352 353 ++argv; --argc; 354 355 if (argc < 2) { 356 warnx("%s: too few arguments", cname); 357 goto usage; 358 } else if (argc > 3) { 359 warnx("%s: too many arguments", cname); 360 goto usage; 361 } 362 (void) memset(&cmd, 0, sizeof(cmd)); 363 364 /* <to ET> */ 365 cmd.cp_type = parse_element_type(*argv); 366 ++argv; --argc; 367 368 /* <to EU> */ 369 cmd.cp_unit = parse_element_unit(*argv); 370 ++argv; --argc; 371 372 /* Deal with optional command modifier. */ 373 if (argc) { 374 val = parse_special(*argv); 375 switch (val) { 376 case SW_INVERT: 377 cmd.cp_flags |= CP_INVERT; 378 break; 379 380 default: 381 errx(1, "%s: inappropriate modifier `%s'", 382 cname, *argv); 383 /* NOTREACHED */ 384 } 385 } 386 387 /* Send command to changer. */ 388 if (ioctl(changer_fd, CHIOPOSITION, &cmd)) 389 err(1, "%s: CHIOPOSITION", changer_name); 390 391 return (0); 392 393 usage: 394 (void) fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n", 395 __progname, cname); 396 return (1); 397 } 398 399 /* ARGSUSED */ 400 static int 401 do_params(cname, argc, argv) 402 char *cname; 403 int argc; 404 char **argv; 405 { 406 struct changer_params data; 407 int picker; 408 409 /* No arguments to this command. */ 410 411 ++argv; --argc; 412 413 if (argc) { 414 warnx("%s: no arguments expected", cname); 415 goto usage; 416 } 417 418 /* Get params from changer and display them. */ 419 (void) memset(&data, 0, sizeof(data)); 420 if (ioctl(changer_fd, CHIOGPARAMS, &data)) 421 err(1, "%s: CHIOGPARAMS", changer_name); 422 423 (void) printf("%s: %d slot%s, %d drive%s, %d picker%s", 424 changer_name, 425 data.cp_nslots, (data.cp_nslots > 1) ? "s" : "", 426 data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "", 427 data.cp_npickers, (data.cp_npickers > 1) ? "s" : ""); 428 if (data.cp_nportals) 429 (void) printf(", %d portal%s", data.cp_nportals, 430 (data.cp_nportals > 1) ? "s" : ""); 431 432 /* Get current picker from changer and display it. */ 433 if (ioctl(changer_fd, CHIOGPICKER, &picker)) 434 err(1, "%s: CHIOGPICKER", changer_name); 435 436 (void) printf("\n%s: current picker: %d\n", changer_name, picker); 437 438 return (0); 439 440 usage: 441 (void) fprintf(stderr, "usage: %s %s\n", __progname, cname); 442 return (1); 443 } 444 445 /* ARGSUSED */ 446 static int 447 do_getpicker(cname, argc, argv) 448 char *cname; 449 int argc; 450 char **argv; 451 { 452 int picker; 453 454 /* No arguments to this command. */ 455 456 ++argv; --argc; 457 458 if (argc) { 459 warnx("%s: no arguments expected", cname); 460 goto usage; 461 } 462 463 /* Get current picker from changer and display it. */ 464 if (ioctl(changer_fd, CHIOGPICKER, &picker)) 465 err(1, "%s: CHIOGPICKER", changer_name); 466 467 (void) printf("%s: current picker: %d\n", changer_name, picker); 468 469 return (0); 470 471 usage: 472 (void) fprintf(stderr, "usage: %s %s\n", __progname, cname); 473 return (1); 474 } 475 476 static int 477 do_setpicker(cname, argc, argv) 478 char *cname; 479 int argc; 480 char **argv; 481 { 482 int picker; 483 484 ++argv; --argc; 485 486 if (argc < 1) { 487 warnx("%s: too few arguments", cname); 488 goto usage; 489 } else if (argc > 1) { 490 warnx("%s: too many arguments", cname); 491 goto usage; 492 } 493 494 picker = parse_element_unit(*argv); 495 496 /* Set the changer picker. */ 497 if (ioctl(changer_fd, CHIOSPICKER, &picker)) 498 err(1, "%s: CHIOSPICKER", changer_name); 499 500 return (0); 501 502 usage: 503 (void) fprintf(stderr, "usage: %s %s <picker>\n", __progname, cname); 504 return (1); 505 } 506 507 static int 508 do_status(cname, argc, argv) 509 char *cname; 510 int argc; 511 char **argv; 512 { 513 struct changer_params cp; 514 struct changer_element_status_request cesr; 515 int i, count, base, chet, schet, echet; 516 char *description; 517 int pvoltag = 0; 518 int avoltag = 0; 519 int sense = 0; 520 int scsi = 0; 521 int source = 0; 522 int intaddr = 0; 523 int c; 524 525 count = 0; 526 base = 0; 527 description = NULL; 528 529 optind = optreset = 1; 530 while ((c = getopt(argc, argv, "vVsSbaI")) != -1) { 531 switch (c) { 532 case 'v': 533 pvoltag = 1; 534 break; 535 case 'V': 536 avoltag = 1; 537 break; 538 case 's': 539 sense = 1; 540 break; 541 case 'S': 542 source = 1; 543 break; 544 case 'b': 545 scsi = 1; 546 break; 547 case 'I': 548 intaddr = 1; 549 break; 550 case 'a': 551 pvoltag = avoltag = source = sense = scsi = intaddr = 1; 552 break; 553 default: 554 warnx("%s: bad option", cname); 555 goto usage; 556 } 557 } 558 559 argc -= optind; 560 argv += optind; 561 562 /* 563 * On a status command, we expect the following: 564 * 565 * [<ET> [<start> [<end>] ] ] 566 * 567 * where ET == element type, start == first element to report, 568 * end == number of elements to report 569 * 570 * If we get no arguments, we get the status of all 571 * known element types. 572 */ 573 if (argc > 3) { 574 warnx("%s: too many arguments", cname); 575 goto usage; 576 } 577 578 /* 579 * Get params from changer. Specifically, we need the element 580 * counts. 581 */ 582 if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) 583 err(1, "%s: CHIOGPARAMS", changer_name); 584 585 if (argc > 0) 586 schet = echet = parse_element_type(argv[0]); 587 else { 588 schet = CHET_MT; 589 echet = CHET_DT; 590 } 591 if (argc > 1) { 592 base = atol(argv[1]); 593 count = 1; 594 } 595 if (argc > 2) 596 count = atol(argv[2]) - base + 1; 597 598 if (base < 0 || count < 0) 599 errx(1, "bad arguments"); 600 601 for (chet = schet; chet <= echet; ++chet) { 602 switch (chet) { 603 case CHET_MT: 604 if (count == 0) 605 count = cp.cp_npickers; 606 else if (count > cp.cp_npickers) 607 errx(1, "not that many pickers in device"); 608 description = "picker"; 609 break; 610 611 case CHET_ST: 612 if (count == 0) 613 count = cp.cp_nslots; 614 else if (count > cp.cp_nslots) 615 errx(1, "not that many slots in device"); 616 description = "slot"; 617 break; 618 619 case CHET_IE: 620 if (count == 0) 621 count = cp.cp_nportals; 622 else if (count > cp.cp_nportals) 623 errx(1, "not that many portals in device"); 624 description = "portal"; 625 break; 626 627 case CHET_DT: 628 if (count == 0) 629 count = cp.cp_ndrives; 630 else if (count > cp.cp_ndrives) 631 errx(1, "not that many drives in device"); 632 description = "drive"; 633 break; 634 635 default: 636 /* To appease gcc -Wuninitialized. */ 637 count = 0; 638 description = NULL; 639 } 640 641 if (count == 0) { 642 if (argc == 0) 643 continue; 644 else { 645 printf("%s: no %s elements\n", 646 changer_name, description); 647 return (0); 648 } 649 } 650 651 bzero(&cesr, sizeof(cesr)); 652 cesr.cesr_element_type = chet; 653 cesr.cesr_element_base = base; 654 cesr.cesr_element_count = count; 655 /* Allocate storage for the status structures. */ 656 cesr.cesr_element_status 657 = (struct changer_element_status *) 658 malloc(count * sizeof(struct changer_element_status)); 659 660 if (!cesr.cesr_element_status) 661 errx(1, "can't allocate status storage"); 662 663 if (avoltag || pvoltag) 664 cesr.cesr_flags |= CESR_VOLTAGS; 665 666 if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr)) { 667 free(cesr.cesr_element_status); 668 err(1, "%s: CHIOGSTATUS", changer_name); 669 } 670 671 /* Dump the status for each reported element. */ 672 for (i = 0; i < count; ++i) { 673 struct changer_element_status *ces = 674 &(cesr.cesr_element_status[i]); 675 printf("%s %d: %s", description, ces->ces_addr, 676 bits_to_string(ces->ces_flags, 677 CESTATUS_BITS)); 678 if (sense) 679 printf(" sense: <0x%02x/0x%02x>", 680 ces->ces_sensecode, 681 ces->ces_sensequal); 682 if (pvoltag) 683 printf(" voltag: <%s:%d>", 684 ces->ces_pvoltag.cv_volid, 685 ces->ces_pvoltag.cv_serial); 686 if (avoltag) 687 printf(" avoltag: <%s:%d>", 688 ces->ces_avoltag.cv_volid, 689 ces->ces_avoltag.cv_serial); 690 if (source) { 691 if (ces->ces_flags & CES_SOURCE_VALID) 692 printf(" source: <%s %d>", 693 element_type_name( 694 ces->ces_source_type), 695 ces->ces_source_addr); 696 else 697 printf(" source: <>"); 698 } 699 if (intaddr) 700 printf(" intaddr: <%d>", ces->ces_int_addr); 701 if (scsi) { 702 printf(" scsi: <"); 703 if (ces->ces_flags & CES_SCSIID_VALID) 704 printf("%d", ces->ces_scsi_id); 705 else 706 putchar('?'); 707 putchar(':'); 708 if (ces->ces_flags & CES_LUN_VALID) 709 printf("%d", ces->ces_scsi_lun); 710 else 711 putchar('?'); 712 putchar('>'); 713 } 714 putchar('\n'); 715 } 716 717 free(cesr.cesr_element_status); 718 count = 0; 719 } 720 721 return (0); 722 723 usage: 724 (void) fprintf(stderr, "usage: %s %s [-vVsSbaA] [<element type> [<start-addr> [<end-addr>] ] ]\n", 725 __progname, cname); 726 return (1); 727 } 728 729 static int 730 do_ielem(cname, argc, argv) 731 char *cname; 732 int argc; 733 char **argv; 734 { 735 int timeout = 0; 736 737 if (argc == 2) { 738 timeout = atol(argv[1]); 739 } else if (argc > 1) { 740 warnx("%s: too many arguments", cname); 741 goto usage; 742 } 743 744 if (ioctl(changer_fd, CHIOIELEM, &timeout)) 745 err(1, "%s: CHIOIELEM", changer_name); 746 747 return (0); 748 749 usage: 750 (void) fprintf(stderr, "usage: %s %s [<timeout>]\n", 751 __progname, cname); 752 return (1); 753 } 754 755 static int 756 do_voltag(cname, argc, argv) 757 char *cname; 758 int argc; 759 char **argv; 760 { 761 int force = 0; 762 int clear = 0; 763 int alternate = 0; 764 int c; 765 struct changer_set_voltag_request csvr; 766 767 bzero(&csvr, sizeof(csvr)); 768 769 optind = optreset = 1; 770 while ((c = getopt(argc, argv, "fca")) != -1) { 771 switch (c) { 772 case 'f': 773 force = 1; 774 break; 775 case 'c': 776 clear = 1; 777 break; 778 case 'a': 779 alternate = 1; 780 break; 781 default: 782 warnx("%s: bad option", cname); 783 goto usage; 784 } 785 } 786 787 argc -= optind; 788 argv += optind; 789 790 if (argc < 2) { 791 warnx("%s: missing element specification", cname); 792 goto usage; 793 } 794 795 csvr.csvr_type = parse_element_type(argv[0]); 796 csvr.csvr_addr = atol(argv[1]); 797 798 if (!clear) { 799 if (argc < 3 || argc > 4) { 800 warnx("%s: missing argument", cname); 801 goto usage; 802 } 803 804 if (force) 805 csvr.csvr_flags = CSVR_MODE_REPLACE; 806 else 807 csvr.csvr_flags = CSVR_MODE_SET; 808 809 if (strlen(argv[2]) > sizeof(csvr.csvr_voltag.cv_volid)) { 810 warnx("%s: volume label too long", cname); 811 goto usage; 812 } 813 814 strncpy(csvr.csvr_voltag.cv_volid, argv[2], 815 sizeof(csvr.csvr_voltag.cv_volid)); 816 817 if (argc == 4) { 818 csvr.csvr_voltag.cv_serial = atol(argv[3]); 819 } 820 } else { 821 if (argc != 2) { 822 warnx("%s: unexpected argument", cname); 823 goto usage; 824 } 825 csvr.csvr_flags = CSVR_MODE_CLEAR; 826 } 827 828 if (alternate) { 829 csvr.csvr_flags |= CSVR_ALTERNATE; 830 } 831 832 if (ioctl(changer_fd, CHIOSETVOLTAG, &csvr)) 833 err(1, "%s: CHIOSETVOLTAG", changer_name); 834 835 return 0; 836 usage: 837 (void) fprintf(stderr, 838 "usage: %s %s [-fca] <element> [<voltag> [<vsn>] ]\n", 839 __progname, cname); 840 return 1; 841 } 842 843 static int 844 parse_element_type(cp) 845 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(et) 859 int et; 860 { 861 int i; 862 863 for (i = 0; elements[i].et_name != NULL; i++) 864 if (elements[i].et_type == et) 865 return elements[i].et_name; 866 867 return "unknown"; 868 } 869 870 static int 871 parse_element_unit(cp) 872 char *cp; 873 { 874 int i; 875 char *p; 876 877 i = (int)strtol(cp, &p, 10); 878 if ((i < 0) || (*p != '\0')) 879 errx(1, "invalid unit number `%s'", cp); 880 881 return (i); 882 } 883 884 static int 885 parse_special(cp) 886 char *cp; 887 { 888 int val; 889 890 val = is_special(cp); 891 if (val) 892 return (val); 893 894 errx(1, "invalid modifier `%s'", cp); 895 /* NOTREACHED */ 896 } 897 898 static int 899 is_special(cp) 900 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(v, cp) 913 int v; 914 const char *cp; 915 { 916 const char *np; 917 char f, sep, *bp; 918 static char buf[128]; 919 920 bp = buf; 921 (void) memset(buf, 0, sizeof(buf)); 922 923 for (sep = '<'; (f = *cp++) != 0; cp = np) { 924 for (np = cp; *np >= ' ';) 925 np++; 926 if ((v & (1 << (f - 1))) == 0) 927 continue; 928 (void) snprintf(bp, sizeof(buf) - (bp - &buf[0]), 929 "%c%.*s", sep, (int)(long)(np - cp), cp); 930 bp += strlen(bp); 931 sep = ','; 932 } 933 if (sep != '<') 934 *bp = '>'; 935 936 return (buf); 937 } 938 939 static void 940 cleanup() 941 { 942 /* Simple enough... */ 943 (void)close(changer_fd); 944 } 945 946 static void 947 usage() 948 { 949 (void) fprintf(stderr, "usage: %s [-f changer] command [-<flags>] " 950 "arg1 arg2 [arg3 [...]]\n", __progname); 951 exit(1); 952 } 953