diff options
Diffstat (limited to 'bin/chio/chio.c')
-rw-r--r-- | bin/chio/chio.c | 487 |
1 files changed, 361 insertions, 126 deletions
diff --git a/bin/chio/chio.c b/bin/chio/chio.c index 7488e7a..c2da513 100644 --- a/bin/chio/chio.c +++ b/bin/chio/chio.c @@ -1,3 +1,4 @@ +/* $NetBSD: chio.c,v 1.6 1998/01/04 23:53:58 thorpej Exp $ */ /* * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com> * All rights reserved. @@ -29,11 +30,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +/* + * Additional Copyright (c) 1997, by Matthew Jacob, for NASA/Ames Research Ctr. + */ +#include <sys/cdefs.h> #ifndef lint -static const char rcsid[] = - "$Id: chio.c,v 1.5 1998/05/06 06:49:56 charnier Exp $"; -#endif /* not lint */ +__COPYRIGHT("@(#) Copyright (c) 1996 Jason R. Thorpe. All rights reserved."); +__RCSID("$NetBSD: chio.c,v 1.6 1998/01/04 23:53:58 thorpej Exp $"); +#endif #include <sys/param.h> #include <sys/chio.h> @@ -47,21 +52,28 @@ static const char rcsid[] = #include "defs.h" #include "pathnames.h" -static void usage __P((void)); -static void cleanup __P((void)); -static int parse_element_type __P((char *)); -static int parse_element_unit __P((char *)); -static int parse_special __P((char *)); -static int is_special __P((char *)); -static char *bits_to_string __P((int, const char *)); - -static int do_move __P((char *, int, char **)); -static int do_exchange __P((char *, int, char **)); -static int do_position __P((char *, int, char **)); -static int do_params __P((char *, int, char **)); -static int do_getpicker __P((char *, int, char **)); -static int do_setpicker __P((char *, int, char **)); -static int do_status __P((char *, int, char **)); +extern char *__progname; /* from crt0.o */ +extern int optreset; /* from getopt.o */ + +int main(int, char *[]); +static void usage(void); +static void cleanup(void); +static int parse_element_type(char *); +static int parse_element_unit(char *); +static const char * element_type_name(int et); +static int parse_special(char *); +static int is_special(char *); +static char *bits_to_string(int, const char *); + +static int do_move(char *, int, char **); +static int do_exchange(char *, int, char **); +static int do_position(char *, int, char **); +static int do_params(char *, int, char **); +static int do_getpicker(char *, int, char **); +static int do_setpicker(char *, int, char **); +static int do_status(char *, int, char **); +static int do_ielem(char *, int, char **); +static int do_voltag(char *, int, char **); /* Valid changer element types. */ const struct element_type elements[] = { @@ -81,6 +93,8 @@ const struct changer_command commands[] = { { "getpicker", do_getpicker }, { "setpicker", do_setpicker }, { "status", do_status }, + { "ielem", do_ielem }, + { "voltag", do_voltag }, { NULL, 0 }, }; @@ -96,9 +110,7 @@ static int changer_fd; static char *changer_name; int -main(argc, argv) - int argc; - char **argv; +main(int argc, char *argv[]) { int ch, i; @@ -138,16 +150,12 @@ main(argc, argv) if (commands[i].cc_name == NULL) errx(1, "unknown command: %s", *argv); - /* Skip over the command name and call handler. */ - ++argv; --argc; - exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); + exit((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); + /* NOTREACHED */ } static int -do_move(cname, argc, argv) - char *cname; - int argc; - char **argv; +do_move(char *cname, int argc, char **argv) { struct changer_move cmd; int val; @@ -159,6 +167,9 @@ do_move(cname, argc, argv) * * where ET == element type and EU == element unit. */ + + ++argv; --argc; + if (argc < 4) { warnx("%s: too few arguments", cname); goto usage; @@ -166,7 +177,7 @@ do_move(cname, argc, argv) warnx("%s: too many arguments", cname); goto usage; } - bzero(&cmd, sizeof(cmd)); + (void) memset(&cmd, 0, sizeof(cmd)); /* <from ET> */ cmd.cm_fromtype = parse_element_type(*argv); @@ -200,22 +211,19 @@ do_move(cname, argc, argv) } /* Send command to changer. */ - if (ioctl(changer_fd, CHIOMOVE, (char *)&cmd)) + if (ioctl(changer_fd, CHIOMOVE, &cmd)) err(1, "%s: CHIOMOVE", changer_name); return (0); usage: - fprintf(stderr, "usage: chio %s " - "<from ET> <from EU> <to ET> <to EU> [inv]\n", cname); + (void) fprintf(stderr, "usage: %s %s " + "<from ET> <from EU> <to ET> <to EU> [inv]\n", __progname, cname); return (1); } static int -do_exchange(cname, argc, argv) - char *cname; - int argc; - char **argv; +do_exchange(char *cname, int argc, char **argv) { struct changer_exchange cmd; int val; @@ -227,6 +235,9 @@ do_exchange(cname, argc, argv) * * where ET == element type and EU == element unit. */ + + ++argv; --argc; + if (argc < 4) { warnx("%s: too few arguments", cname); goto usage; @@ -234,7 +245,7 @@ do_exchange(cname, argc, argv) warnx("%s: too many arguments", cname); goto usage; } - bzero(&cmd, sizeof(cmd)); + (void) memset(&cmd, 0, sizeof(cmd)); /* <src ET> */ cmd.ce_srctype = parse_element_type(*argv); @@ -293,23 +304,21 @@ do_exchange(cname, argc, argv) } /* Send command to changer. */ - if (ioctl(changer_fd, CHIOEXCHANGE, (char *)&cmd)) + if (ioctl(changer_fd, CHIOEXCHANGE, &cmd)) err(1, "%s: CHIOEXCHANGE", changer_name); return (0); usage: - fprintf(stderr, - "usage: chio %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n" - " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n", cname); + (void) 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_position(cname, argc, argv) - char *cname; - int argc; - char **argv; +do_position(char *cname, int argc, char **argv) { struct changer_position cmd; int val; @@ -321,6 +330,9 @@ do_position(cname, argc, argv) * * where ET == element type and EU == element unit. */ + + ++argv; --argc; + if (argc < 2) { warnx("%s: too few arguments", cname); goto usage; @@ -328,7 +340,7 @@ do_position(cname, argc, argv) warnx("%s: too many arguments", cname); goto usage; } - bzero(&cmd, sizeof(cmd)); + (void) memset(&cmd, 0, sizeof(cmd)); /* <to ET> */ cmd.cp_type = parse_element_type(*argv); @@ -354,87 +366,88 @@ do_position(cname, argc, argv) } /* Send command to changer. */ - if (ioctl(changer_fd, CHIOPOSITION, (char *)&cmd)) + if (ioctl(changer_fd, CHIOPOSITION, &cmd)) err(1, "%s: CHIOPOSITION", changer_name); return (0); usage: - fprintf(stderr, "usage: chio %s <to ET> <to EU> [inv]\n", cname); + (void) fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n", + __progname, cname); return (1); } +/* ARGSUSED */ static int -do_params(cname, argc, argv) - char *cname; - int argc; - char **argv; +do_params(char *cname, int argc, char **argv) { struct changer_params data; /* No arguments to this command. */ + + ++argv; --argc; + if (argc) { - warnx("%s: no arguments expected", cname); + warnx("%s: no arguements expected", cname); goto usage; } /* Get params from changer and display them. */ - bzero(&data, sizeof(data)); - if (ioctl(changer_fd, CHIOGPARAMS, (char *)&data)) + (void) memset(&data, 0, sizeof(data)); + if (ioctl(changer_fd, CHIOGPARAMS, &data)) err(1, "%s: CHIOGPARAMS", changer_name); - printf("%s: %d slot%s, %d drive%s, %d picker%s", + (void) printf("%s: %d slot%s, %d drive%s, %d picker%s", changer_name, data.cp_nslots, (data.cp_nslots > 1) ? "s" : "", data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "", data.cp_npickers, (data.cp_npickers > 1) ? "s" : ""); if (data.cp_nportals) - printf(", %d portal%s", data.cp_nportals, + (void) printf(", %d portal%s", data.cp_nportals, (data.cp_nportals > 1) ? "s" : ""); - printf("\n%s: current picker: %d\n", changer_name, data.cp_curpicker); return (0); usage: - fprintf(stderr, "usage: chio %s\n", cname); + (void) fprintf(stderr, "usage: %s %s\n", __progname, cname); return (1); } +/* ARGSUSED */ static int -do_getpicker(cname, argc, argv) - char *cname; - int argc; - char **argv; +do_getpicker(char *cname, int argc, char **argv) { int picker; /* No arguments to this command. */ + + ++argv; --argc; + if (argc) { warnx("%s: no arguments expected", cname); goto usage; } /* Get current picker from changer and display it. */ - if (ioctl(changer_fd, CHIOGPICKER, (char *)&picker)) + if (ioctl(changer_fd, CHIOGPICKER, &picker)) err(1, "%s: CHIOGPICKER", changer_name); - printf("%s: current picker: %d\n", changer_name, picker); + (void) printf("%s: current picker: %d\n", changer_name, picker); return (0); usage: - fprintf(stderr, "usage: chio %s\n", cname); + (void) fprintf(stderr, "usage: %s %s\n", __progname, cname); return (1); } static int -do_setpicker(cname, argc, argv) - char *cname; - int argc; - char **argv; +do_setpicker(char *cname, int argc, char **argv) { int picker; + ++argv; --argc; + if (argc < 1) { warnx("%s: too few arguments", cname); goto usage; @@ -446,42 +459,80 @@ do_setpicker(cname, argc, argv) picker = parse_element_unit(*argv); /* Set the changer picker. */ - if (ioctl(changer_fd, CHIOSPICKER, (char *)&picker)) + if (ioctl(changer_fd, CHIOSPICKER, &picker)) err(1, "%s: CHIOSPICKER", changer_name); return (0); usage: - fprintf(stderr, "usage: chio %s <picker>\n", cname); + (void) fprintf(stderr, "usage: %s %s <picker>\n", __progname, cname); return (1); } static int -do_status(cname, argc, argv) - char *cname; - int argc; - char **argv; +do_status(char *cname, int argc, char **argv) { - struct changer_element_status cmd; - struct changer_params data; - u_int8_t *statusp; - int i, count, chet, schet, echet; + struct changer_params cp; + struct changer_element_status_request cesr; + int i, count, base, chet, schet, echet; 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")) != EOF) { + 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("bad option", cname); + goto usage; + } + } + + argc -= optind; + argv += optind; + /* * On a status command, we expect the following: * - * [<ET>] + * [<ET> [<start> [<end>] ] ] * - * where ET == element type. + * 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 > 1) { + if (argc > 3) { warnx("%s: too many arguments", cname); goto usage; } @@ -490,38 +541,63 @@ do_status(cname, argc, argv) * Get params from changer. Specifically, we need the element * counts. */ - bzero(&data, sizeof(data)); - if (ioctl(changer_fd, CHIOGPARAMS, (char *)&data)) + if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) err(1, "%s: CHIOGPARAMS", changer_name); - if (argc) - schet = echet = parse_element_type(*argv); + if (argc > 0) + schet = echet = parse_element_type(argv[0]); else { schet = CHET_MT; echet = CHET_DT; } + if (argc > 1) { + base = atol(argv[1]); + count = 1; + } + if (argc > 2) + count = atol(argv[2]) - base + 1; + + if (base < 0 || count < 0) + errx(1, "bad arguments"); for (chet = schet; chet <= echet; ++chet) { switch (chet) { case CHET_MT: - count = data.cp_npickers; + 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: - count = data.cp_nslots; + 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: - count = data.cp_nportals; + 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: - count = data.cp_ndrives; + 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) { @@ -534,40 +610,193 @@ do_status(cname, argc, argv) } } - /* Allocate storage for the status bytes. */ - if ((statusp = (u_int8_t *)malloc(count)) == NULL) + 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 *) + malloc(count * sizeof(struct changer_element_status)); + + if (!cesr.cesr_element_status) errx(1, "can't allocate status storage"); - bzero(statusp, count); - bzero(&cmd, sizeof(cmd)); - - cmd.ces_type = chet; - cmd.ces_data = statusp; + if (avoltag || pvoltag) + cesr.cesr_flags |= CESR_VOLTAGS; - if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cmd)) { - free(statusp); + if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr)) { + free(cesr.cesr_element_status); err(1, "%s: CHIOGSTATUS", changer_name); } - /* Dump the status for each element of this type. */ + /* Dump the status for each reported element. */ for (i = 0; i < count; ++i) { - printf("%s %d: %s\n", description, i, - bits_to_string(statusp[i], CESTATUS_BITS)); + 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(statusp); + free(cesr.cesr_element_status); + count = 0; } return (0); usage: - fprintf(stderr, "usage: chio %s [<element type>]\n", cname); + (void) fprintf(stderr, "usage: %s %s [-vVsSbaA] [<element type> [<start-addr> [<end-addr>] ] ]\n", + __progname, cname); return (1); } static int -parse_element_type(cp) - char *cp; +do_ielem(char *cname, int argc, char **argv) +{ + int timeout = 0; + + if (argc == 2) { + timeout = atol(argv[1]); + } else if (argc > 1) { + warnx("%s: too many arguments", cname); + goto usage; + } + + if (ioctl(changer_fd, CHIOIELEM, &timeout)) + err(1, "%s: CHIOIELEM", changer_name); + + return (0); + + usage: + (void) fprintf(stderr, "usage: %s %s [<timeout>]\n", + __progname, cname); + return (1); +} + +static int +do_voltag(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")) != EOF) { + switch (c) { + case 'f': + force = 1; + break; + case 'c': + clear = 1; + break; + case 'a': + alternate = 1; + break; + default: + warnx("bad option", cname); + goto usage; + } + } + + argc -= optind; + argv += optind; + + if (argc < 2) { + warnx("missing element specification", cname); + goto usage; + } + + csvr.csvr_type = parse_element_type(argv[0]); + csvr.csvr_addr = atol(argv[1]); + + if (!clear) { + if (argc < 3 || argc > 4) { + warnx("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("volume label too long", cname); + goto usage; + } + + strncpy(csvr.csvr_voltag.cv_volid, argv[2], + sizeof(csvr.csvr_voltag.cv_volid)); + + if (argc == 4) { + csvr.csvr_voltag.cv_serial = atol(argv[3]); + } + } else { + if (argc != 2) { + warnx("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", + __progname, cname); + return 1; +} + +static int +parse_element_type(char *cp) { int i; @@ -576,11 +805,23 @@ parse_element_type(cp) return (elements[i].et_type); errx(1, "invalid element type `%s'", cp); + /* NOTREACHED */ +} + +static const char * +element_type_name(int et) +{ + int i; + + for (i = 0; elements[i].et_name != NULL; i++) + if (elements[i].et_type == et) + return elements[i].et_name; + + return "unknown"; } static int -parse_element_unit(cp) - char *cp; +parse_element_unit(char *cp) { int i; char *p; @@ -593,8 +834,7 @@ parse_element_unit(cp) } static int -parse_special(cp) - char *cp; +parse_special(char *cp) { int val; @@ -603,11 +843,11 @@ parse_special(cp) return (val); errx(1, "invalid modifier `%s'", cp); + /* NOTREACHED */ } static int -is_special(cp) - char *cp; +is_special(char *cp) { int i; @@ -619,24 +859,21 @@ is_special(cp) } static char * -bits_to_string(v, cp) - int v; - const char *cp; +bits_to_string(int v, const char *cp) { const char *np; char f, sep, *bp; static char buf[128]; bp = buf; - bzero(buf, sizeof(buf)); + (void) memset(buf, 0, sizeof(buf)); for (sep = '<'; (f = *cp++) != 0; cp = np) { for (np = cp; *np >= ' ';) np++; if ((v & (1 << (f - 1))) == 0) continue; - bp += snprintf(bp, sizeof(buf) - (bp - &buf[0]), - "%c%.*s", sep, np - cp, cp); + bp += sprintf(bp, "%c%.*s", sep, (int)(long)(np - cp), cp); sep = ','; } if (sep != '<') @@ -648,7 +885,6 @@ bits_to_string(v, cp) static void cleanup() { - /* Simple enough... */ (void)close(changer_fd); } @@ -656,12 +892,11 @@ cleanup() static void usage() { - int i; - fprintf(stderr, "usage: chio [-f changer] command [args ...]\n"); - fprintf(stderr, "commands:"); - for (i = 0; commands[i].cc_name; i++) - fprintf(stderr, " %s", commands[i].cc_name); - fprintf(stderr, "\n"); + (void) fprintf(stderr, "usage: %s command arg1 arg2 ...\n", __progname); + (void) fprintf(stderr, "Examples:\n"); + (void) fprintf(stderr, "\tchio -f /dev/ch0 move slot 1 drive 0\n"); + (void) fprintf(stderr, "\tchio ielem\n"); + (void) fprintf(stderr, "\tchio -f /dev/ch1 status\n"); exit(1); } |