/bin/chio/chio.c
https://bitbucket.org/freebsd/freebsd-head/ · C · 1179 lines · 827 code · 190 blank · 162 comment · 196 complexity · 6f560a545faaab7a69baefab4f274f99 MD5 · raw file
- /* $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.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgements:
- * This product includes software developed by Jason R. Thorpe
- * for And Communications, http://www.and.com/
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * 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.
- * Addidional Copyright (c) 2000, by C. Stephen Gunn, Waterspout Communications
- */
- #if 0
- #ifndef lint
- static const char copyright[] =
- "@(#) Copyright (c) 1996 Jason R. Thorpe. All rights reserved.";
- #endif /* not lint */
- #endif
- #include <sys/cdefs.h>
- __FBSDID("$FreeBSD$");
- #include <sys/param.h>
- #include <sys/chio.h>
- #include <err.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include "defs.h"
- #include "pathnames.h"
- static void usage(void);
- static void cleanup(void);
- static u_int16_t parse_element_type(char *);
- static u_int16_t parse_element_unit(char *);
- static const char * element_type_name(int et);
- static int parse_special(char *);
- static int is_special(char *);
- static const char *bits_to_string(ces_status_flags, const char *);
- static void find_element(char *, uint16_t *, uint16_t *);
- static struct changer_element_status *get_element_status
- (unsigned int, unsigned int, int);
- static int do_move(const char *, int, char **);
- static int do_exchange(const char *, int, char **);
- static int do_position(const char *, int, char **);
- static int do_params(const char *, int, char **);
- static int do_getpicker(const char *, int, char **);
- static int do_setpicker(const char *, int, char **);
- static int do_status(const char *, int, char **);
- static int do_ielem(const char *, int, char **);
- static int do_return(const char *, int, char **);
- static int do_voltag(const char *, int, char **);
- #ifndef CHET_VT
- #define CHET_VT 10 /* Completely Arbitrary */
- #endif
- /* Valid changer element types. */
- static const struct element_type elements[] = {
- { "drive", CHET_DT },
- { "picker", CHET_MT },
- { "portal", CHET_IE },
- { "slot", CHET_ST },
- { "voltag", CHET_VT }, /* Select tapes by barcode */
- { NULL, 0 },
- };
- /* Valid commands. */
- static const struct changer_command commands[] = {
- { "exchange", do_exchange },
- { "getpicker", do_getpicker },
- { "ielem", do_ielem },
- { "move", do_move },
- { "params", do_params },
- { "position", do_position },
- { "setpicker", do_setpicker },
- { "status", do_status },
- { "return", do_return },
- { "voltag", do_voltag },
- { NULL, 0 },
- };
- /* Valid special words. */
- static const struct special_word specials[] = {
- { "inv", SW_INVERT },
- { "inv1", SW_INVERT1 },
- { "inv2", SW_INVERT2 },
- { NULL, 0 },
- };
- static int changer_fd;
- static const char *changer_name;
- int
- main(int argc, char **argv)
- {
- int ch, i;
- while ((ch = getopt(argc, argv, "f:")) != -1) {
- switch (ch) {
- case 'f':
- changer_name = optarg;
- break;
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
- if (argc == 0)
- usage();
- /* Get the default changer if not already specified. */
- if (changer_name == NULL)
- if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL)
- changer_name = _PATH_CH;
- /* Open the changer device. */
- if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1)
- err(1, "%s: open", changer_name);
- /* Register cleanup function. */
- if (atexit(cleanup))
- err(1, "can't register cleanup function");
- /* Find the specified command. */
- for (i = 0; commands[i].cc_name != NULL; ++i)
- if (strcmp(*argv, commands[i].cc_name) == 0)
- break;
- if (commands[i].cc_name == NULL) {
- /* look for abbreviation */
- for (i = 0; commands[i].cc_name != NULL; ++i)
- if (strncmp(*argv, commands[i].cc_name,
- strlen(*argv)) == 0)
- break;
- }
- if (commands[i].cc_name == NULL)
- errx(1, "unknown command: %s", *argv);
- exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv));
- /* NOTREACHED */
- }
- 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_exchange(const 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;
- }
- (void) memset(&cmd, 0, sizeof(cmd));
- /* <src ET> */
- cmd.ce_srctype = parse_element_type(*argv);
- ++argv; --argc;
- /* Check for voltag virtual type */
- if (CHET_VT == cmd.ce_srctype) {
- find_element(*argv, &cmd.ce_srctype, &cmd.ce_srcunit);
- } else {
- /* <from EU> */
- cmd.ce_srcunit = parse_element_unit(*argv);
- }
- ++argv; --argc;
- /* <dst1 ET> */
- cmd.ce_fdsttype = parse_element_type(*argv);
- ++argv; --argc;
- /* Check for voltag virtual type */
- if (CHET_VT == cmd.ce_fdsttype) {
- find_element(*argv, &cmd.ce_fdsttype, &cmd.ce_fdstunit);
- } else {
- /* <from 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;
- if (CHET_VT == cmd.ce_sdsttype)
- errx(1,"%s %s: voltag only makes sense as an element source",
- cname, *argv);
- /* <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:
- (void) fprintf(stderr,
- "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n"
- " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\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);
- }
- /* ARGSUSED */
- static int
- do_params(const char *cname, int argc, char **argv)
- {
- struct changer_params data;
- int picker;
- /* No arguments to this command. */
- ++argv; --argc;
- if (argc) {
- warnx("%s: no arguments expected", cname);
- goto usage;
- }
- /* Get params from changer and display them. */
- (void) memset(&data, 0, sizeof(data));
- if (ioctl(changer_fd, CHIOGPARAMS, &data))
- err(1, "%s: CHIOGPARAMS", changer_name);
- (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)
- (void) printf(", %d portal%s", data.cp_nportals,
- (data.cp_nportals > 1) ? "s" : "");
- /* Get current picker from changer and display it. */
- if (ioctl(changer_fd, CHIOGPICKER, &picker))
- err(1, "%s: CHIOGPICKER", changer_name);
- (void) printf("\n%s: current picker: %d\n", changer_name, picker);
- return (0);
- usage:
- (void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname);
- return (1);
- }
- /* ARGSUSED */
- static int
- do_getpicker(const 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, &picker))
- err(1, "%s: CHIOGPICKER", changer_name);
- (void) printf("%s: current picker: %d\n", changer_name, picker);
- return (0);
- usage:
- (void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname);
- return (1);
- }
- static int
- do_setpicker(const char *cname, int argc, char **argv)
- {
- int picker;
- ++argv; --argc;
- if (argc < 1) {
- warnx("%s: too few arguments", cname);
- goto usage;
- } else if (argc > 1) {
- warnx("%s: too many arguments", cname);
- goto usage;
- }
- picker = parse_element_unit(*argv);
- /* Set the changer picker. */
- if (ioctl(changer_fd, CHIOSPICKER, &picker))
- err(1, "%s: CHIOSPICKER", changer_name);
- return (0);
- usage:
- (void) fprintf(stderr, "usage: %s %s <picker>\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_ielem(const 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",
- getprogname(), 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 u_int16_t
- parse_element_type(char *cp)
- {
- int i;
- for (i = 0; elements[i].et_name != NULL; ++i)
- if (strcmp(elements[i].et_name, cp) == 0)
- return ((u_int16_t)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 u_int16_t
- parse_element_unit(char *cp)
- {
- int i;
- char *p;
- i = (int)strtol(cp, &p, 10);
- if ((i < 0) || (*p != '\0'))
- errx(1, "invalid unit number `%s'", cp);
- return ((u_int16_t)i);
- }
- static int
- parse_special(char *cp)
- {
- int val;
- val = is_special(cp);
- if (val)
- return (val);
- errx(1, "invalid modifier `%s'", cp);
- /* NOTREACHED */
- }
- static int
- is_special(char *cp)
- {
- int i;
- for (i = 0; specials[i].sw_name != NULL; ++i)
- if (strcmp(specials[i].sw_name, cp) == 0)
- return (specials[i].sw_value);
- return (0);
- }
- static const char *
- bits_to_string(ces_status_flags v, const char *cp)
- {
- const char *np;
- char f, sep, *bp;
- static char buf[128];
- bp = buf;
- (void) memset(buf, 0, sizeof(buf));
- for (sep = '<'; (f = *cp++) != 0; cp = np) {
- for (np = cp; *np >= ' ';)
- np++;
- if (((int)v & (1 << (f - 1))) == 0)
- continue;
- (void) snprintf(bp, sizeof(buf) - (size_t)(bp - &buf[0]),
- "%c%.*s", sep, (int)(long)(np - cp), cp);
- bp += strlen(bp);
- sep = ',';
- }
- if (sep != '<')
- *bp = '>';
- return (buf);
- }
- /*
- * do_return()
- *
- * Given an element reference, ask the changer/picker to move that
- * element back to its source slot.
- */
- static int
- do_return(const char *cname, int argc, char **argv)
- {
- struct changer_element_status *ces;
- struct changer_move cmd;
- uint16_t type, element;
- ++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;
- }
- type = parse_element_type(*argv);
- ++argv; --argc;
-
- /* Handle voltag virtual Changer Element Type */
- if (CHET_VT == type) {
- find_element(*argv, &type, &element);
- } else {
- element = parse_element_unit(*argv);
- }
- ++argv; --argc;
- /* Get the status */
- ces = get_element_status((unsigned int)type, (unsigned int)element,
- CHET_VT == type);
- if (NULL == ces)
- errx(1, "%s: null element status pointer", cname);
- if (!(ces->ces_flags & CES_SOURCE_VALID))
- errx(1, "%s: no source information", cname);
- (void) memset(&cmd, 0, sizeof(cmd));
- cmd.cm_fromtype = type;
- cmd.cm_fromunit = element;
- cmd.cm_totype = ces->ces_source_type;
- cmd.cm_tounit = ces->ces_source_addr;
- if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1)
- err(1, "%s: CHIOMOVE", changer_name);
- free(ces);
- return(0);
- usage:
- (void) fprintf(stderr, "usage: %s %s "
- "<from ET> <from EU>\n", getprogname(), cname);
- return(1);
- }
- /*
- * get_element_status()
- *
- * return a *cesr for the specified changer element. This
- * routing will malloc()/calloc() the memory. The caller
- * should free() it when done.
- */
- static struct changer_element_status *
- get_element_status(unsigned int type, unsigned int element, int use_voltags)
- {
- struct changer_element_status_request cesr;
- struct changer_element_status *ces;
-
- ces = (struct changer_element_status *)
- calloc((size_t)1, sizeof(struct changer_element_status));
- if (NULL == ces)
- errx(1, "can't allocate status storage");
- (void)memset(&cesr, 0, sizeof(cesr));
- cesr.cesr_element_type = (uint16_t)type;
- cesr.cesr_element_base = (uint16_t)element;
- cesr.cesr_element_count = 1; /* Only this one element */
- if (use_voltags)
- cesr.cesr_flags |= CESR_VOLTAGS; /* Grab voltags as well */
- cesr.cesr_element_status = ces;
- if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
- free(ces);
- err(1, "%s: CHIOGSTATUS", changer_name);
- /* NOTREACHED */
- }
- return ces;
- }
- /*
- * find_element()
- *
- * Given a <voltag> find the chager element and unit, or exit
- * with an error if it isn't found. We grab the changer status
- * and iterate until we find a match, or crap out.
- */
- static void
- find_element(char *voltag, uint16_t *et, uint16_t *eu)
- {
- struct changer_params cp;
- struct changer_element_status_request cesr;
- struct changer_element_status *ch_ces, *ces;
- int found = 0;
- size_t elem, total_elem;
- /*
- * Get the changer parameters, we're interested in the counts
- * for all types of elements to perform our search.
- */
- if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp))
- err(1, "%s: CHIOGPARAMS", changer_name);
- /* Allocate some memory for the results */
- total_elem = (cp.cp_nslots + cp.cp_ndrives
- + cp.cp_npickers + cp.cp_nportals);
-
- ch_ces = (struct changer_element_status *)
- calloc(total_elem, sizeof(struct changer_element_status));
- if (NULL == ch_ces)
- errx(1, "can't allocate status storage");
- ces = ch_ces;
- /* Read in the changer slots */
- if (cp.cp_nslots > 0) {
- (void) memset(&cesr, 0, sizeof(cesr));
- cesr.cesr_element_type = CHET_ST;
- cesr.cesr_element_base = 0;
- cesr.cesr_element_count = cp.cp_nslots;
- cesr.cesr_flags |= CESR_VOLTAGS;
- cesr.cesr_element_status = ces;
- if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
- free(ch_ces);
- err(1, "%s: CHIOGSTATUS", changer_name);
- }
- ces += cp.cp_nslots;
- }
- /* Read in the drive information */
- if (cp.cp_ndrives > 0 ) {
- (void) memset(&cesr, 0, sizeof(cesr));
- cesr.cesr_element_type = CHET_DT;
- cesr.cesr_element_base = 0;
- cesr.cesr_element_count = cp.cp_ndrives;
- cesr.cesr_flags |= CESR_VOLTAGS;
- cesr.cesr_element_status = ces;
- if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
- free(ch_ces);
- err(1, "%s: CHIOGSTATUS", changer_name);
- }
- ces += cp.cp_ndrives;
- }
- /* Read in the portal information */
- if (cp.cp_nportals > 0 ) {
- (void) memset(&cesr, 0, sizeof(cesr));
- cesr.cesr_element_type = CHET_IE;
- cesr.cesr_element_base = 0;
- cesr.cesr_element_count = cp.cp_nportals;
- cesr.cesr_flags |= CESR_VOLTAGS;
- cesr.cesr_element_status = ces;
- if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
- free(ch_ces);
- err(1, "%s: CHIOGSTATUS", changer_name);
- }
- ces += cp.cp_nportals;
- }
- /* Read in the picker information */
- if (cp.cp_npickers > 0) {
- (void) memset(&cesr, 0, sizeof(cesr));
- cesr.cesr_element_type = CHET_MT;
- cesr.cesr_element_base = 0;
- cesr.cesr_element_count = cp.cp_npickers;
- cesr.cesr_flags |= CESR_VOLTAGS;
- cesr.cesr_element_status = ces;
- if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) {
- free(ch_ces);
- err(1, "%s: CHIOGSTATUS", changer_name);
- }
- }
- /*
- * Now search the list the specified <voltag>
- */
- for (elem = 0; elem <= total_elem; ++elem) {
- ces = &ch_ces[elem];
- /* Make sure we have a tape in this element */
- if ((ces->ces_flags & (CES_STATUS_ACCESS|CES_STATUS_FULL))
- != (CES_STATUS_ACCESS|CES_STATUS_FULL))
- continue;
- /* Check to see if it is our target */
- if (strcasecmp(voltag,
- (const char *)ces->ces_pvoltag.cv_volid) == 0) {
- *et = ces->ces_type;
- *eu = ces->ces_addr;
- ++found;
- break;
- }
- }
- if (!found) {
- errx(1, "%s: unable to locate voltag: %s", changer_name,
- voltag);
- }
- free(ch_ces);
- return;
- }
- static void
- cleanup(void)
- {
- /* Simple enough... */
- (void)close(changer_fd);
- }
- static void
- usage(void)
- {
- (void)fprintf(stderr, "usage: %s [-f changer] command [-<flags>] "
- "arg1 arg2 [arg3 [...]]\n", getprogname());
- exit(1);
- }