static int do_status(char *cname, int argc, char *argv[]) { struct changer_element_status_request cmd; struct changer_params data; int i, chet, schet, echet, c; char *description; size_t count; #ifdef lint count = 0; description = NULL; #endif optreset = 1; optind = 1; while ((c = getopt(argc, argv, "vVa")) != -1) { switch (c) { case 'v': pvoltag = 1; break; case 'V': avoltag = 1; break; case 'a': pvoltag = avoltag = 1; break; default: goto usage; } } argc -= optind; argv += optind; /* * On a status command, we expect the following: * * [<ET>] * * where ET == element type. * * If we get no arguments, we get the status of all * known element types. */ if (argc > 1) { warnx("%s: too many arguments", cname); goto usage; } /* * Get params from changer. Specifically, we need the element * counts. */ bzero(&data, sizeof(data)); if (ioctl(changer_fd, CHIOGPARAMS, &data)) err(1, "%s: CHIOGPARAMS", changer_name); if (argc) schet = echet = parse_element_type(*argv); else { schet = CHET_MT; echet = CHET_DT; } for (chet = schet; chet <= echet; ++chet) { switch (chet) { case CHET_MT: count = data.cp_npickers; description = "picker"; break; case CHET_ST: count = data.cp_nslots; description = "slot"; break; case CHET_IE: count = data.cp_nportals; description = "portal"; break; case CHET_DT: count = data.cp_ndrives; description = "drive"; break; } if (count == 0) { if (argc == 0) continue; else { printf("%s: no %s elements\n", changer_name, description); return (0); } } bzero(&cmd, sizeof(cmd)); cmd.cesr_type = chet; /* Allocate storage for the status info. */ cmd.cesr_data = calloc(count, sizeof(*cmd.cesr_data)); if ((cmd.cesr_data) == NULL) errx(1, "can't allocate status storage"); if (avoltag || pvoltag) cmd.cesr_flags |= CESR_VOLTAGS; if (ioctl(changer_fd, CHIOGSTATUS, &cmd)) { free(cmd.cesr_data); err(1, "%s: CHIOGSTATUS", changer_name); } /* Dump the status for each element of this type. */ for (i = 0; i < count; ++i) { struct changer_element_status *ces = &(cmd.cesr_data[i]); printf("%s %d: %s", description, i, bits_to_string(ces->ces_flags, CESTATUS_BITS)); if (pvoltag) printf(" voltag: <%s:%d>", ces->ces_pvoltag.cv_volid, ces->ces_pvoltag.cv_serial); if (avoltag) printf(" avoltag: <%s:%d>", ces->ces_avoltag.cv_volid, ces->ces_avoltag.cv_serial); printf("\n"); } free(cmd.cesr_data); } return (0); usage: fprintf(stderr, "usage: %s %s [<element type>]\n", __progname, cname); return (1); }
static int do_move(char *cname, int argc, char *argv[]) { struct changer_move cmd; int val; /* * On a move command, we expect the following: * * <from ET> <from EU> <to ET> <to EU> [inv] * * where ET == element type and EU == element unit. */ ++argv; --argc; if (argc < 4) { warnx("%s: too few arguments", cname); goto usage; } else if (argc > 5) { warnx("%s: too many arguments", cname); goto usage; } bzero(&cmd, sizeof(cmd)); /* * Get the from ET and EU - we search for it if the ET is * "voltag", otherwise, we just use the ET and EU given to us. */ if (strcmp(*argv, "voltag") == 0) { ++argv; --argc; find_voltag(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit); ++argv; --argc; } else { cmd.cm_fromtype = parse_element_type(*argv); ++argv; --argc; cmd.cm_fromunit = parse_element_unit(*argv); ++argv; --argc; } if (cmd.cm_fromtype == CHET_DT) check_source_drive(cmd.cm_fromunit); /* * Don't allow voltag on the to ET, using a volume * as a destination makes no sense on a move */ cmd.cm_totype = parse_element_type(*argv); ++argv; --argc; cmd.cm_tounit = parse_element_unit(*argv); ++argv; --argc; /* Deal with optional command modifier. */ if (argc) { val = parse_special(*argv); switch (val) { case SW_INVERT: cmd.cm_flags |= CM_INVERT; break; default: errx(1, "%s: inappropriate modifier `%s'", cname, *argv); /* NOTREACHED */ } } /* Send command to changer. */ if (ioctl(changer_fd, CHIOMOVE, &cmd)) err(1, "%s: CHIOMOVE", changer_name); return (0); usage: fprintf(stderr, "usage: %s %s " "<from ET> <from EU> <to ET> <to EU> [inv]\n", __progname, cname); return (1); }
static int do_exchange(char *cname, int argc, char *argv[]) { struct changer_exchange cmd; int val; /* * On an exchange command, we expect the following: * * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2] * * where ET == element type and EU == element unit. */ ++argv; --argc; if (argc < 4) { warnx("%s: too few arguments", cname); goto usage; } else if (argc > 8) { warnx("%s: too many arguments", cname); goto usage; } bzero(&cmd, sizeof(cmd)); /* <src ET> */ cmd.ce_srctype = parse_element_type(*argv); ++argv; --argc; /* <src EU> */ cmd.ce_srcunit = parse_element_unit(*argv); ++argv; --argc; /* <dst1 ET> */ cmd.ce_fdsttype = parse_element_type(*argv); ++argv; --argc; /* <dst1 EU> */ cmd.ce_fdstunit = parse_element_unit(*argv); ++argv; --argc; /* * If the next token is a special word or there are no more * arguments, then this is a case of simple exchange. * dst2 == src. */ if ((argc == 0) || is_special(*argv)) { cmd.ce_sdsttype = cmd.ce_srctype; cmd.ce_sdstunit = cmd.ce_srcunit; goto do_special; } /* <dst2 ET> */ cmd.ce_sdsttype = parse_element_type(*argv); ++argv; --argc; /* <dst2 EU> */ cmd.ce_sdstunit = parse_element_unit(*argv); ++argv; --argc; do_special: /* Deal with optional command modifiers. */ while (argc) { val = parse_special(*argv); ++argv; --argc; switch (val) { case SW_INVERT1: cmd.ce_flags |= CE_INVERT1; break; case SW_INVERT2: cmd.ce_flags |= CE_INVERT2; break; default: errx(1, "%s: inappropriate modifier `%s'", cname, *argv); /* NOTREACHED */ } } /* Send command to changer. */ if (ioctl(changer_fd, CHIOEXCHANGE, &cmd)) err(1, "%s: CHIOEXCHANGE", changer_name); return (0); usage: fprintf(stderr, "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n" " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n", __progname, cname); return (1); }
static int do_voltag(const char *cname, int argc, char **argv) { int force = 0; int clear = 0; int alternate = 0; int c; struct changer_set_voltag_request csvr; bzero(&csvr, sizeof(csvr)); optind = optreset = 1; while ((c = getopt(argc, argv, "fca")) != -1) { switch (c) { case 'f': force = 1; break; case 'c': clear = 1; break; case 'a': alternate = 1; break; default: warnx("%s: bad option", cname); goto usage; } } argc -= optind; argv += optind; if (argc < 2) { warnx("%s: missing element specification", cname); goto usage; } csvr.csvr_type = parse_element_type(argv[0]); csvr.csvr_addr = (u_int16_t)atol(argv[1]); if (!clear) { if (argc < 3 || argc > 4) { warnx("%s: missing argument", cname); goto usage; } if (force) csvr.csvr_flags = CSVR_MODE_REPLACE; else csvr.csvr_flags = CSVR_MODE_SET; if (strlen(argv[2]) > sizeof(csvr.csvr_voltag.cv_volid)) { warnx("%s: volume label too long", cname); goto usage; } strlcpy((char *)csvr.csvr_voltag.cv_volid, argv[2], sizeof(csvr.csvr_voltag.cv_volid)); if (argc == 4) { csvr.csvr_voltag.cv_serial = (u_int16_t)atol(argv[3]); } } else { if (argc != 2) { warnx("%s: unexpected argument", cname); goto usage; } csvr.csvr_flags = CSVR_MODE_CLEAR; } if (alternate) { csvr.csvr_flags |= CSVR_ALTERNATE; } if (ioctl(changer_fd, CHIOSETVOLTAG, &csvr)) err(1, "%s: CHIOSETVOLTAG", changer_name); return 0; usage: (void) fprintf(stderr, "usage: %s %s [-fca] <element> [<voltag> [<vsn>] ]\n", getprogname(), cname); return 1; }
static int do_status(const char *cname, int argc, char **argv) { struct changer_params cp; struct changer_element_status_request cesr; int i; u_int16_t base, count, chet, schet, echet; const char *description; int pvoltag = 0; int avoltag = 0; int sense = 0; int scsi = 0; int source = 0; int intaddr = 0; int c; count = 0; base = 0; description = NULL; optind = optreset = 1; while ((c = getopt(argc, argv, "vVsSbaI")) != -1) { switch (c) { case 'v': pvoltag = 1; break; case 'V': avoltag = 1; break; case 's': sense = 1; break; case 'S': source = 1; break; case 'b': scsi = 1; break; case 'I': intaddr = 1; break; case 'a': pvoltag = avoltag = source = sense = scsi = intaddr = 1; break; default: warnx("%s: bad option", cname); goto usage; } } argc -= optind; argv += optind; /* * On a status command, we expect the following: * * [<ET> [<start> [<end>] ] ] * * where ET == element type, start == first element to report, * end == number of elements to report * * If we get no arguments, we get the status of all * known element types. */ if (argc > 3) { warnx("%s: too many arguments", cname); goto usage; } /* * Get params from changer. Specifically, we need the element * counts. */ if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) err(1, "%s: CHIOGPARAMS", changer_name); if (argc > 0) schet = echet = parse_element_type(argv[0]); else { schet = CHET_MT; echet = CHET_DT; } if (argc > 1) { base = (u_int16_t)atol(argv[1]); count = 1; } if (argc > 2) count = (u_int16_t)atol(argv[2]) - base + 1; for (chet = schet; chet <= echet; ++chet) { switch (chet) { case CHET_MT: if (count == 0) count = cp.cp_npickers; else if (count > cp.cp_npickers) errx(1, "not that many pickers in device"); description = "picker"; break; case CHET_ST: if (count == 0) count = cp.cp_nslots; else if (count > cp.cp_nslots) errx(1, "not that many slots in device"); description = "slot"; break; case CHET_IE: if (count == 0) count = cp.cp_nportals; else if (count > cp.cp_nportals) errx(1, "not that many portals in device"); description = "portal"; break; case CHET_DT: if (count == 0) count = cp.cp_ndrives; else if (count > cp.cp_ndrives) errx(1, "not that many drives in device"); description = "drive"; break; default: /* To appease gcc -Wuninitialized. */ count = 0; description = NULL; } if (count == 0) { if (argc == 0) continue; else { printf("%s: no %s elements\n", changer_name, description); return (0); } } bzero(&cesr, sizeof(cesr)); cesr.cesr_element_type = chet; cesr.cesr_element_base = base; cesr.cesr_element_count = count; /* Allocate storage for the status structures. */ cesr.cesr_element_status = (struct changer_element_status *) calloc((size_t)count, sizeof(struct changer_element_status)); if (!cesr.cesr_element_status) errx(1, "can't allocate status storage"); if (avoltag || pvoltag) cesr.cesr_flags |= CESR_VOLTAGS; if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr)) { free(cesr.cesr_element_status); err(1, "%s: CHIOGSTATUS", changer_name); } /* Dump the status for each reported element. */ for (i = 0; i < count; ++i) { struct changer_element_status *ces = &(cesr.cesr_element_status[i]); printf("%s %d: %s", description, ces->ces_addr, bits_to_string(ces->ces_flags, CESTATUS_BITS)); if (sense) printf(" sense: <0x%02x/0x%02x>", ces->ces_sensecode, ces->ces_sensequal); if (pvoltag) printf(" voltag: <%s:%d>", ces->ces_pvoltag.cv_volid, ces->ces_pvoltag.cv_serial); if (avoltag) printf(" avoltag: <%s:%d>", ces->ces_avoltag.cv_volid, ces->ces_avoltag.cv_serial); if (source) { if (ces->ces_flags & CES_SOURCE_VALID) printf(" source: <%s %d>", element_type_name( ces->ces_source_type), ces->ces_source_addr); else printf(" source: <>"); } if (intaddr) printf(" intaddr: <%d>", ces->ces_int_addr); if (scsi) { printf(" scsi: <"); if (ces->ces_flags & CES_SCSIID_VALID) printf("%d", ces->ces_scsi_id); else putchar('?'); putchar(':'); if (ces->ces_flags & CES_LUN_VALID) printf("%d", ces->ces_scsi_lun); else putchar('?'); putchar('>'); } putchar('\n'); } free(cesr.cesr_element_status); count = 0; } return (0); usage: (void) fprintf(stderr, "usage: %s %s [-vVsSbaA] [<element type> [<start-addr> [<end-addr>] ] ]\n", getprogname(), cname); return (1); }
static int do_move(const char *cname, int argc, char **argv) { struct changer_move cmd; int val; /* * On a move command, we expect the following: * * <from ET> <from EU> <to ET> <to EU> [inv] * * where ET == element type and EU == element unit. */ ++argv; --argc; if (argc < 4) { warnx("%s: too few arguments", cname); goto usage; } else if (argc > 5) { warnx("%s: too many arguments", cname); goto usage; } (void) memset(&cmd, 0, sizeof(cmd)); /* <from ET> */ cmd.cm_fromtype = parse_element_type(*argv); ++argv; --argc; /* Check for voltag virtual type */ if (CHET_VT == cmd.cm_fromtype) { find_element(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit); } else { /* <from EU> */ cmd.cm_fromunit = parse_element_unit(*argv); } ++argv; --argc; /* <to ET> */ cmd.cm_totype = parse_element_type(*argv); ++argv; --argc; /* Check for voltag virtual type, and report error */ if (CHET_VT == cmd.cm_totype) errx(1,"%s: voltag only makes sense as an element source", cname); /* <to EU> */ cmd.cm_tounit = parse_element_unit(*argv); ++argv; --argc; /* Deal with optional command modifier. */ if (argc) { val = parse_special(*argv); switch (val) { case SW_INVERT: cmd.cm_flags |= CM_INVERT; break; default: errx(1, "%s: inappropriate modifier `%s'", cname, *argv); /* NOTREACHED */ } } /* Send command to changer. */ if (ioctl(changer_fd, CHIOMOVE, &cmd)) err(1, "%s: CHIOMOVE", changer_name); return (0); usage: (void) fprintf(stderr, "usage: %s %s " "<from ET> <from EU> <to ET> <to EU> [inv]\n", getprogname(), cname); return (1); }
static int do_position(const char *cname, int argc, char **argv) { struct changer_position cmd; int val; /* * On a position command, we expect the following: * * <to ET> <to EU> [inv] * * where ET == element type and EU == element unit. */ ++argv; --argc; if (argc < 2) { warnx("%s: too few arguments", cname); goto usage; } else if (argc > 3) { warnx("%s: too many arguments", cname); goto usage; } (void) memset(&cmd, 0, sizeof(cmd)); /* <to ET> */ cmd.cp_type = parse_element_type(*argv); ++argv; --argc; /* <to EU> */ cmd.cp_unit = parse_element_unit(*argv); ++argv; --argc; /* Deal with optional command modifier. */ if (argc) { val = parse_special(*argv); switch (val) { case SW_INVERT: cmd.cp_flags |= CP_INVERT; break; default: errx(1, "%s: inappropriate modifier `%s'", cname, *argv); /* NOTREACHED */ } } /* Send command to changer. */ if (ioctl(changer_fd, CHIOPOSITION, &cmd)) err(1, "%s: CHIOPOSITION", changer_name); return (0); usage: (void) fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n", getprogname(), cname); return (1); }