chio.c revision 26361
1/* $Id: chio.c,v 1.1.1.1 1997/03/06 15:30:06 joerg Exp $ */ 2 3/* 4 * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgements: 17 * This product includes software developed by Jason R. Thorpe 18 * for And Communications, http://www.and.com/ 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/param.h> 36#include <sys/ioctl.h> 37#include <sys/chio.h> 38#include <err.h> 39#include <errno.h> 40#include <fcntl.h> 41#include <limits.h> 42#include <stdio.h> 43#include <stdlib.h> 44#include <string.h> 45#include <unistd.h> 46 47#include "defs.h" 48#include "pathnames.h" 49 50extern char *__progname; /* from crt0.o */ 51 52static void usage __P((void)); 53static void cleanup __P((void)); 54static int parse_element_type __P((char *)); 55static int parse_element_unit __P((char *)); 56static int parse_special __P((char *)); 57static int is_special __P((char *)); 58static char *bits_to_string __P((int, const char *)); 59 60static int do_move __P((char *, int, char **)); 61static int do_exchange __P((char *, int, char **)); 62static int do_position __P((char *, int, char **)); 63static int do_params __P((char *, int, char **)); 64static int do_getpicker __P((char *, int, char **)); 65static int do_setpicker __P((char *, int, char **)); 66static int do_status __P((char *, int, char **)); 67 68/* Valid changer element types. */ 69const struct element_type elements[] = { 70 { "picker", CHET_MT }, 71 { "slot", CHET_ST }, 72 { "portal", CHET_IE }, 73 { "drive", CHET_DT }, 74 { NULL, 0 }, 75}; 76 77/* Valid commands. */ 78const struct changer_command commands[] = { 79 { "move", do_move }, 80 { "exchange", do_exchange }, 81 { "position", do_position }, 82 { "params", do_params }, 83 { "getpicker", do_getpicker }, 84 { "setpicker", do_setpicker }, 85 { "status", do_status }, 86 { NULL, 0 }, 87}; 88 89/* Valid special words. */ 90const struct special_word specials[] = { 91 { "inv", SW_INVERT }, 92 { "inv1", SW_INVERT1 }, 93 { "inv2", SW_INVERT2 }, 94 { NULL, 0 }, 95}; 96 97static int changer_fd; 98static char *changer_name; 99 100int 101main(argc, argv) 102 int argc; 103 char **argv; 104{ 105 int ch, i; 106 107 while ((ch = getopt(argc, argv, "f:")) != -1) { 108 switch (ch) { 109 case 'f': 110 changer_name = optarg; 111 break; 112 113 default: 114 usage(); 115 } 116 } 117 argc -= optind; 118 argv += optind; 119 120 if (argc == 0) 121 usage(); 122 123 /* Get the default changer if not already specified. */ 124 if (changer_name == NULL) 125 if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL) 126 changer_name = _PATH_CH; 127 128 /* Open the changer device. */ 129 if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1) 130 err(1, "%s: open", changer_name); 131 132 /* Register cleanup function. */ 133 if (atexit(cleanup)) 134 err(1, "can't register cleanup function"); 135 136 /* Find the specified command. */ 137 for (i = 0; commands[i].cc_name != NULL; ++i) 138 if (strcmp(*argv, commands[i].cc_name) == 0) 139 break; 140 if (commands[i].cc_name == NULL) 141 errx(1, "unknown command: %s", *argv); 142 143 /* Skip over the command name and call handler. */ 144 ++argv; --argc; 145 exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); 146} 147 148static int 149do_move(cname, argc, argv) 150 char *cname; 151 int argc; 152 char **argv; 153{ 154 struct changer_move cmd; 155 int val; 156 157 /* 158 * On a move command, we expect the following: 159 * 160 * <from ET> <from EU> <to ET> <to EU> [inv] 161 * 162 * where ET == element type and EU == element unit. 163 */ 164 if (argc < 4) { 165 warnx("%s: too few arguments", cname); 166 goto usage; 167 } else if (argc > 5) { 168 warnx("%s: too many arguments", cname); 169 goto usage; 170 } 171 bzero(&cmd, sizeof(cmd)); 172 173 /* <from ET> */ 174 cmd.cm_fromtype = parse_element_type(*argv); 175 ++argv; --argc; 176 177 /* <from EU> */ 178 cmd.cm_fromunit = parse_element_unit(*argv); 179 ++argv; --argc; 180 181 /* <to ET> */ 182 cmd.cm_totype = parse_element_type(*argv); 183 ++argv; --argc; 184 185 /* <to EU> */ 186 cmd.cm_tounit = parse_element_unit(*argv); 187 ++argv; --argc; 188 189 /* Deal with optional command modifier. */ 190 if (argc) { 191 val = parse_special(*argv); 192 switch (val) { 193 case SW_INVERT: 194 cmd.cm_flags |= CM_INVERT; 195 break; 196 197 default: 198 errx(1, "%s: inappropriate modifier `%s'", 199 cname, *argv); 200 /* NOTREACHED */ 201 } 202 } 203 204 /* Send command to changer. */ 205 if (ioctl(changer_fd, CHIOMOVE, (char *)&cmd)) 206 err(1, "%s: CHIOMOVE", changer_name); 207 208 return (0); 209 210 usage: 211 fprintf(stderr, "usage: %s %s " 212 "<from ET> <from EU> <to ET> <to EU> [inv]\n", __progname, cname); 213 return (1); 214} 215 216static int 217do_exchange(cname, argc, argv) 218 char *cname; 219 int argc; 220 char **argv; 221{ 222 struct changer_exchange cmd; 223 int val; 224 225 /* 226 * On an exchange command, we expect the following: 227 * 228 * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2] 229 * 230 * where ET == element type and EU == element unit. 231 */ 232 if (argc < 4) { 233 warnx("%s: too few arguments", cname); 234 goto usage; 235 } else if (argc > 8) { 236 warnx("%s: too many arguments", cname); 237 goto usage; 238 } 239 bzero(&cmd, sizeof(cmd)); 240 241 /* <src ET> */ 242 cmd.ce_srctype = parse_element_type(*argv); 243 ++argv; --argc; 244 245 /* <src EU> */ 246 cmd.ce_srcunit = parse_element_unit(*argv); 247 ++argv; --argc; 248 249 /* <dst1 ET> */ 250 cmd.ce_fdsttype = parse_element_type(*argv); 251 ++argv; --argc; 252 253 /* <dst1 EU> */ 254 cmd.ce_fdstunit = parse_element_unit(*argv); 255 ++argv; --argc; 256 257 /* 258 * If the next token is a special word or there are no more 259 * arguments, then this is a case of simple exchange. 260 * dst2 == src. 261 */ 262 if ((argc == 0) || is_special(*argv)) { 263 cmd.ce_sdsttype = cmd.ce_srctype; 264 cmd.ce_sdstunit = cmd.ce_srcunit; 265 goto do_special; 266 } 267 268 /* <dst2 ET> */ 269 cmd.ce_sdsttype = parse_element_type(*argv); 270 ++argv; --argc; 271 272 /* <dst2 EU> */ 273 cmd.ce_sdstunit = parse_element_unit(*argv); 274 ++argv; --argc; 275 276 do_special: 277 /* Deal with optional command modifiers. */ 278 while (argc) { 279 val = parse_special(*argv); 280 ++argv; --argc; 281 switch (val) { 282 case SW_INVERT1: 283 cmd.ce_flags |= CE_INVERT1; 284 break; 285 286 case SW_INVERT2: 287 cmd.ce_flags |= CE_INVERT2; 288 break; 289 290 default: 291 errx(1, "%s: inappropriate modifier `%s'", 292 cname, *argv); 293 /* NOTREACHED */ 294 } 295 } 296 297 /* Send command to changer. */ 298 if (ioctl(changer_fd, CHIOEXCHANGE, (char *)&cmd)) 299 err(1, "%s: CHIOEXCHANGE", changer_name); 300 301 return (0); 302 303 usage: 304 fprintf(stderr, "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n" 305 " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n", 306 __progname, cname); 307 return (1); 308} 309 310static int 311do_position(cname, argc, argv) 312 char *cname; 313 int argc; 314 char **argv; 315{ 316 struct changer_position cmd; 317 int val; 318 319 /* 320 * On a position command, we expect the following: 321 * 322 * <to ET> <to EU> [inv] 323 * 324 * where ET == element type and EU == element unit. 325 */ 326 if (argc < 2) { 327 warnx("%s: too few arguments", cname); 328 goto usage; 329 } else if (argc > 3) { 330 warnx("%s: too many arguments", cname); 331 goto usage; 332 } 333 bzero(&cmd, sizeof(cmd)); 334 335 /* <to ET> */ 336 cmd.cp_type = parse_element_type(*argv); 337 ++argv; --argc; 338 339 /* <to EU> */ 340 cmd.cp_unit = parse_element_unit(*argv); 341 ++argv; --argc; 342 343 /* Deal with optional command modifier. */ 344 if (argc) { 345 val = parse_special(*argv); 346 switch (val) { 347 case SW_INVERT: 348 cmd.cp_flags |= CP_INVERT; 349 break; 350 351 default: 352 errx(1, "%s: inappropriate modifier `%s'", 353 cname, *argv); 354 /* NOTREACHED */ 355 } 356 } 357 358 /* Send command to changer. */ 359 if (ioctl(changer_fd, CHIOPOSITION, (char *)&cmd)) 360 err(1, "%s: CHIOPOSITION", changer_name); 361 362 return (0); 363 364 usage: 365 fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n", 366 __progname, cname); 367 return (1); 368} 369 370static int 371do_params(cname, argc, argv) 372 char *cname; 373 int argc; 374 char **argv; 375{ 376 struct changer_params data; 377 378 /* No arguments to this command. */ 379 if (argc) { 380 warnx("%s: no arguements expected", cname); 381 goto usage; 382 } 383 384 /* Get params from changer and display them. */ 385 bzero(&data, sizeof(data)); 386 if (ioctl(changer_fd, CHIOGPARAMS, (char *)&data)) 387 err(1, "%s: CHIOGPARAMS", changer_name); 388 389 printf("%s: %d slot%s, %d drive%s, %d picker%s", 390 changer_name, 391 data.cp_nslots, (data.cp_nslots > 1) ? "s" : "", 392 data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "", 393 data.cp_npickers, (data.cp_npickers > 1) ? "s" : ""); 394 if (data.cp_nportals) 395 printf(", %d portal%s", data.cp_nportals, 396 (data.cp_nportals > 1) ? "s" : ""); 397 printf("\n%s: current picker: %d\n", changer_name, data.cp_curpicker); 398 399 return (0); 400 401 usage: 402 fprintf(stderr, "usage: %s %s\n", __progname, cname); 403 return (1); 404} 405 406static int 407do_getpicker(cname, argc, argv) 408 char *cname; 409 int argc; 410 char **argv; 411{ 412 int picker; 413 414 /* No arguments to this command. */ 415 if (argc) { 416 warnx("%s: no arguments expected", cname); 417 goto usage; 418 } 419 420 /* Get current picker from changer and display it. */ 421 if (ioctl(changer_fd, CHIOGPICKER, (char *)&picker)) 422 err(1, "%s: CHIOGPICKER", changer_name); 423 424 printf("%s: current picker: %d\n", changer_name, picker); 425 426 return (0); 427 428 usage: 429 fprintf(stderr, "usage: %s %s\n", __progname, cname); 430 return (1); 431} 432 433static int 434do_setpicker(cname, argc, argv) 435 char *cname; 436 int argc; 437 char **argv; 438{ 439 int picker; 440 441 if (argc < 1) { 442 warnx("%s: too few arguments", cname); 443 goto usage; 444 } else if (argc > 1) { 445 warnx("%s: too many arguments", cname); 446 goto usage; 447 } 448 449 picker = parse_element_unit(*argv); 450 451 /* Set the changer picker. */ 452 if (ioctl(changer_fd, CHIOSPICKER, (char *)&picker)) 453 err(1, "%s: CHIOSPICKER", changer_name); 454 455 return (0); 456 457 usage: 458 fprintf(stderr, "usage: %s %s <picker>\n", __progname, cname); 459 return (1); 460} 461 462static int 463do_status(cname, argc, argv) 464 char *cname; 465 int argc; 466 char **argv; 467{ 468 struct changer_element_status cmd; 469 struct changer_params data; 470 u_int8_t *statusp; 471 int i, count, chet, schet, echet; 472 char *description; 473 474 count = 0; 475 description = NULL; 476 477 /* 478 * On a status command, we expect the following: 479 * 480 * [<ET>] 481 * 482 * where ET == element type. 483 * 484 * If we get no arguments, we get the status of all 485 * known element types. 486 */ 487 if (argc > 1) { 488 warnx("%s: too many arguments", cname); 489 goto usage; 490 } 491 492 /* 493 * Get params from changer. Specifically, we need the element 494 * counts. 495 */ 496 bzero(&data, sizeof(data)); 497 if (ioctl(changer_fd, CHIOGPARAMS, (char *)&data)) 498 err(1, "%s: CHIOGPARAMS", changer_name); 499 500 if (argc) 501 schet = echet = parse_element_type(*argv); 502 else { 503 schet = CHET_MT; 504 echet = CHET_DT; 505 } 506 507 for (chet = schet; chet <= echet; ++chet) { 508 switch (chet) { 509 case CHET_MT: 510 count = data.cp_npickers; 511 description = "picker"; 512 break; 513 514 case CHET_ST: 515 count = data.cp_nslots; 516 description = "slot"; 517 break; 518 519 case CHET_IE: 520 count = data.cp_nportals; 521 description = "portal"; 522 break; 523 524 case CHET_DT: 525 count = data.cp_ndrives; 526 description = "drive"; 527 break; 528 } 529 530 if (count == 0) { 531 if (argc == 0) 532 continue; 533 else { 534 printf("%s: no %s elements\n", 535 changer_name, description); 536 return (0); 537 } 538 } 539 540 /* Allocate storage for the status bytes. */ 541 if ((statusp = (u_int8_t *)malloc(count)) == NULL) 542 errx(1, "can't allocate status storage"); 543 544 bzero(statusp, count); 545 bzero(&cmd, sizeof(cmd)); 546 547 cmd.ces_type = chet; 548 cmd.ces_data = statusp; 549 550 if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cmd)) { 551 free(statusp); 552 err(1, "%s: CHIOGSTATUS", changer_name); 553 } 554 555 /* Dump the status for each element of this type. */ 556 for (i = 0; i < count; ++i) { 557 printf("%s %d: %s\n", description, i, 558 bits_to_string(statusp[i], CESTATUS_BITS)); 559 } 560 561 free(statusp); 562 } 563 564 return (0); 565 566 usage: 567 fprintf(stderr, "usage: %s %s [<element type>]\n", __progname, 568 cname); 569 return (1); 570} 571 572static int 573parse_element_type(cp) 574 char *cp; 575{ 576 int i; 577 578 for (i = 0; elements[i].et_name != NULL; ++i) 579 if (strcmp(elements[i].et_name, cp) == 0) 580 return (elements[i].et_type); 581 582 errx(1, "invalid element type `%s'", cp); 583} 584 585static int 586parse_element_unit(cp) 587 char *cp; 588{ 589 int i; 590 char *p; 591 592 i = (int)strtol(cp, &p, 10); 593 if ((i < 0) || (*p != '\0')) 594 errx(1, "invalid unit number `%s'", cp); 595 596 return (i); 597} 598 599static int 600parse_special(cp) 601 char *cp; 602{ 603 int val; 604 605 val = is_special(cp); 606 if (val) 607 return (val); 608 609 errx(1, "invalid modifier `%s'", cp); 610} 611 612static int 613is_special(cp) 614 char *cp; 615{ 616 int i; 617 618 for (i = 0; specials[i].sw_name != NULL; ++i) 619 if (strcmp(specials[i].sw_name, cp) == 0) 620 return (specials[i].sw_value); 621 622 return (0); 623} 624 625static char * 626bits_to_string(v, cp) 627 int v; 628 const char *cp; 629{ 630 const char *np; 631 char f, sep, *bp; 632 static char buf[128]; 633 634 bp = buf; 635 bzero(buf, sizeof(buf)); 636 637 for (sep = '<'; (f = *cp++) != 0; cp = np) { 638 for (np = cp; *np >= ' ';) 639 np++; 640 if ((v & (1 << (f - 1))) == 0) 641 continue; 642 bp += snprintf(bp, sizeof(buf) - (bp - &buf[0]), 643 "%c%.*s", sep, np - cp, cp); 644 sep = ','; 645 } 646 if (sep != '<') 647 *bp = '>'; 648 649 return (buf); 650} 651 652static void 653cleanup() 654{ 655 656 /* Simple enough... */ 657 (void)close(changer_fd); 658} 659 660static void 661usage() 662{ 663 int i; 664 665 fprintf(stderr, "usage: %s [-f changer] command [args ...]\n", __progname); 666 fprintf(stderr, "commands:"); 667 for (i = 0; commands[i].cc_name; i++) 668 fprintf(stderr, " %s", commands[i].cc_name); 669 fprintf(stderr, "\n"); 670 exit(1); 671} 672