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