chio.c revision 184484
148983Skris/* $NetBSD: chio.c,v 1.6 1998/01/04 23:53:58 thorpej Exp $ */ 2139969Simp/*- 323449Sjoerg * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com> 423449Sjoerg * All rights reserved. 523449Sjoerg * 623449Sjoerg * Redistribution and use in source and binary forms, with or without 723449Sjoerg * modification, are permitted provided that the following conditions 823449Sjoerg * are met: 923449Sjoerg * 1. Redistributions of source code must retain the above copyright 1023449Sjoerg * notice, this list of conditions and the following disclaimer. 1123449Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1223449Sjoerg * notice, this list of conditions and the following disclaimer in the 1323449Sjoerg * documentation and/or other materials provided with the distribution. 1423449Sjoerg * 3. All advertising materials mentioning features or use of this software 1523449Sjoerg * must display the following acknowledgements: 1623449Sjoerg * This product includes software developed by Jason R. Thorpe 1723449Sjoerg * for And Communications, http://www.and.com/ 1823449Sjoerg * 4. The name of the author may not be used to endorse or promote products 1923449Sjoerg * derived from this software without specific prior written permission. 2023449Sjoerg * 2123449Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2223449Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2323449Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2423449Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2523449Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2623449Sjoerg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2723449Sjoerg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2823449Sjoerg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2923449Sjoerg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3023449Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3123449Sjoerg * SUCH DAMAGE. 3223449Sjoerg */ 3339227Sgibbs/* 3439227Sgibbs * Additional Copyright (c) 1997, by Matthew Jacob, for NASA/Ames Research Ctr. 3566019Sken * Addidional Copyright (c) 2000, by C. Stephen Gunn, Waterspout Communications 3639227Sgibbs */ 3723449Sjoerg 38114433Sobrien#if 0 3935773Scharnier#ifndef lint 4048073Skrisstatic const char copyright[] = 4148073Skris "@(#) Copyright (c) 1996 Jason R. Thorpe. All rights reserved."; 4248073Skris#endif /* not lint */ 43114433Sobrien#endif 4435773Scharnier 4593101Smarkm#include <sys/cdefs.h> 4693101Smarkm__FBSDID("$FreeBSD: head/bin/chio/chio.c 184484 2008-10-30 19:51:02Z joerg $"); 4793101Smarkm 4836001Scharnier#include <sys/param.h> 4923449Sjoerg#include <sys/chio.h> 5023449Sjoerg#include <err.h> 5123449Sjoerg#include <fcntl.h> 5223449Sjoerg#include <stdio.h> 5391665Simp#include <stdint.h> 5423449Sjoerg#include <stdlib.h> 5523449Sjoerg#include <string.h> 5623449Sjoerg#include <unistd.h> 5723449Sjoerg 5823449Sjoerg#include "defs.h" 5923449Sjoerg#include "pathnames.h" 6023449Sjoerg 6190107Simpstatic void usage(void); 6290107Simpstatic void cleanup(void); 6391086Smarkmstatic u_int16_t parse_element_type(char *); 6491086Smarkmstatic u_int16_t parse_element_unit(char *); 6590107Simpstatic const char * element_type_name(int et); 6690107Simpstatic int parse_special(char *); 6790107Simpstatic int is_special(char *); 6890107Simpstatic const char *bits_to_string(ces_status_flags, const char *); 6923449Sjoerg 7091665Simpstatic void find_element(char *, uint16_t *, uint16_t *); 7179253Smikehstatic struct changer_element_status *get_element_status 72184484Sjoerg (unsigned int, unsigned int, int); 7366019Sken 7490107Simpstatic int do_move(const char *, int, char **); 7590107Simpstatic int do_exchange(const char *, int, char **); 7690107Simpstatic int do_position(const char *, int, char **); 7790107Simpstatic int do_params(const char *, int, char **); 7890107Simpstatic int do_getpicker(const char *, int, char **); 7990107Simpstatic int do_setpicker(const char *, int, char **); 8090107Simpstatic int do_status(const char *, int, char **); 8190107Simpstatic int do_ielem(const char *, int, char **); 8290107Simpstatic int do_return(const char *, int, char **); 8390107Simpstatic int do_voltag(const char *, int, char **); 8439227Sgibbs 8566019Sken#ifndef CHET_VT 8666019Sken#define CHET_VT 10 /* Completely Arbitrary */ 8766019Sken#endif 8866019Sken 8923449Sjoerg/* Valid changer element types. */ 9023449Sjoergconst struct element_type elements[] = { 9147816Skris { "drive", CHET_DT }, 9223449Sjoerg { "picker", CHET_MT }, 9347816Skris { "portal", CHET_IE }, 9423449Sjoerg { "slot", CHET_ST }, 9566019Sken { "voltag", CHET_VT }, /* Select tapes by barcode */ 9623449Sjoerg { NULL, 0 }, 9723449Sjoerg}; 9823449Sjoerg 9923449Sjoerg/* Valid commands. */ 10023449Sjoergconst struct changer_command commands[] = { 10147816Skris { "exchange", do_exchange }, 10247816Skris { "getpicker", do_getpicker }, 10347816Skris { "ielem", do_ielem }, 10423449Sjoerg { "move", do_move }, 10547816Skris { "params", do_params }, 10623449Sjoerg { "position", do_position }, 10723449Sjoerg { "setpicker", do_setpicker }, 10823449Sjoerg { "status", do_status }, 10966019Sken { "return", do_return }, 11039227Sgibbs { "voltag", do_voltag }, 11123449Sjoerg { NULL, 0 }, 11223449Sjoerg}; 11323449Sjoerg 11423449Sjoerg/* Valid special words. */ 11523449Sjoergconst struct special_word specials[] = { 11623449Sjoerg { "inv", SW_INVERT }, 11723449Sjoerg { "inv1", SW_INVERT1 }, 11823449Sjoerg { "inv2", SW_INVERT2 }, 11923449Sjoerg { NULL, 0 }, 12023449Sjoerg}; 12123449Sjoerg 12223449Sjoergstatic int changer_fd; 12348073Skrisstatic const char *changer_name; 12423449Sjoerg 12523449Sjoergint 12690107Simpmain(int argc, char **argv) 12723449Sjoerg{ 12823449Sjoerg int ch, i; 12923449Sjoerg 13023449Sjoerg while ((ch = getopt(argc, argv, "f:")) != -1) { 13123449Sjoerg switch (ch) { 13223449Sjoerg case 'f': 13323449Sjoerg changer_name = optarg; 13423449Sjoerg break; 13523449Sjoerg 13623449Sjoerg default: 13723449Sjoerg usage(); 13823449Sjoerg } 13923449Sjoerg } 14023449Sjoerg argc -= optind; 14123449Sjoerg argv += optind; 14223449Sjoerg 14323449Sjoerg if (argc == 0) 14423449Sjoerg usage(); 14523449Sjoerg 14623449Sjoerg /* Get the default changer if not already specified. */ 14723449Sjoerg if (changer_name == NULL) 14823449Sjoerg if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL) 14923449Sjoerg changer_name = _PATH_CH; 15023449Sjoerg 15123449Sjoerg /* Open the changer device. */ 15223449Sjoerg if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1) 15323449Sjoerg err(1, "%s: open", changer_name); 15423449Sjoerg 15523449Sjoerg /* Register cleanup function. */ 15623449Sjoerg if (atexit(cleanup)) 15723449Sjoerg err(1, "can't register cleanup function"); 15823449Sjoerg 15923449Sjoerg /* Find the specified command. */ 16023449Sjoerg for (i = 0; commands[i].cc_name != NULL; ++i) 16123449Sjoerg if (strcmp(*argv, commands[i].cc_name) == 0) 16223449Sjoerg break; 16347816Skris if (commands[i].cc_name == NULL) { 16447816Skris /* look for abbreviation */ 16547816Skris for (i = 0; commands[i].cc_name != NULL; ++i) 16647816Skris if (strncmp(*argv, commands[i].cc_name, 16747816Skris strlen(*argv)) == 0) 16847816Skris break; 16948073Skris } 17047816Skris 17123449Sjoerg if (commands[i].cc_name == NULL) 17223449Sjoerg errx(1, "unknown command: %s", *argv); 17323449Sjoerg 17448073Skris exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); 17539227Sgibbs /* NOTREACHED */ 17623449Sjoerg} 17723449Sjoerg 17823449Sjoergstatic int 17990107Simpdo_move(const char *cname, int argc, char **argv) 18023449Sjoerg{ 18123449Sjoerg struct changer_move cmd; 18223449Sjoerg int val; 18323449Sjoerg 18423449Sjoerg /* 18523449Sjoerg * On a move command, we expect the following: 18623449Sjoerg * 18723449Sjoerg * <from ET> <from EU> <to ET> <to EU> [inv] 18823449Sjoerg * 18923449Sjoerg * where ET == element type and EU == element unit. 19023449Sjoerg */ 19139227Sgibbs 19239227Sgibbs ++argv; --argc; 19339227Sgibbs 19423449Sjoerg if (argc < 4) { 19523449Sjoerg warnx("%s: too few arguments", cname); 19623449Sjoerg goto usage; 19723449Sjoerg } else if (argc > 5) { 19823449Sjoerg warnx("%s: too many arguments", cname); 19923449Sjoerg goto usage; 20023449Sjoerg } 20139227Sgibbs (void) memset(&cmd, 0, sizeof(cmd)); 20223449Sjoerg 20323449Sjoerg /* <from ET> */ 20423449Sjoerg cmd.cm_fromtype = parse_element_type(*argv); 20523449Sjoerg ++argv; --argc; 20623449Sjoerg 20766019Sken /* Check for voltag virtual type */ 20866019Sken if (CHET_VT == cmd.cm_fromtype) { 20966019Sken find_element(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit); 21066019Sken } else { 21166019Sken /* <from EU> */ 21266019Sken cmd.cm_fromunit = parse_element_unit(*argv); 21366019Sken } 21423449Sjoerg ++argv; --argc; 21523449Sjoerg 21623449Sjoerg /* <to ET> */ 21723449Sjoerg cmd.cm_totype = parse_element_type(*argv); 21823449Sjoerg ++argv; --argc; 21923449Sjoerg 22066019Sken /* Check for voltag virtual type, and report error */ 22166019Sken if (CHET_VT == cmd.cm_totype) 22266019Sken errx(1,"%s: voltag only makes sense as an element source", 22366019Sken cname); 22466019Sken 22523449Sjoerg /* <to EU> */ 22623449Sjoerg cmd.cm_tounit = parse_element_unit(*argv); 22723449Sjoerg ++argv; --argc; 22823449Sjoerg 22923449Sjoerg /* Deal with optional command modifier. */ 23023449Sjoerg if (argc) { 23123449Sjoerg val = parse_special(*argv); 23223449Sjoerg switch (val) { 23323449Sjoerg case SW_INVERT: 23423449Sjoerg cmd.cm_flags |= CM_INVERT; 23523449Sjoerg break; 23623449Sjoerg 23723449Sjoerg default: 23823449Sjoerg errx(1, "%s: inappropriate modifier `%s'", 23923449Sjoerg cname, *argv); 24023449Sjoerg /* NOTREACHED */ 24123449Sjoerg } 24223449Sjoerg } 24323449Sjoerg 24423449Sjoerg /* Send command to changer. */ 24539227Sgibbs if (ioctl(changer_fd, CHIOMOVE, &cmd)) 24623449Sjoerg err(1, "%s: CHIOMOVE", changer_name); 24723449Sjoerg 24823449Sjoerg return (0); 24923449Sjoerg 25023449Sjoerg usage: 25139227Sgibbs (void) fprintf(stderr, "usage: %s %s " 25293101Smarkm "<from ET> <from EU> <to ET> <to EU> [inv]\n", getprogname(), cname); 25323449Sjoerg return (1); 25423449Sjoerg} 25523449Sjoerg 25623449Sjoergstatic int 25790107Simpdo_exchange(const char *cname, int argc, char **argv) 25823449Sjoerg{ 25923449Sjoerg struct changer_exchange cmd; 26023449Sjoerg int val; 26123449Sjoerg 26223449Sjoerg /* 26323449Sjoerg * On an exchange command, we expect the following: 26423449Sjoerg * 26523449Sjoerg * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2] 26623449Sjoerg * 26723449Sjoerg * where ET == element type and EU == element unit. 26823449Sjoerg */ 26939227Sgibbs 27039227Sgibbs ++argv; --argc; 27139227Sgibbs 27223449Sjoerg if (argc < 4) { 27323449Sjoerg warnx("%s: too few arguments", cname); 27423449Sjoerg goto usage; 27523449Sjoerg } else if (argc > 8) { 27623449Sjoerg warnx("%s: too many arguments", cname); 27723449Sjoerg goto usage; 27823449Sjoerg } 27939227Sgibbs (void) memset(&cmd, 0, sizeof(cmd)); 28023449Sjoerg 28123449Sjoerg /* <src ET> */ 28223449Sjoerg cmd.ce_srctype = parse_element_type(*argv); 28323449Sjoerg ++argv; --argc; 28423449Sjoerg 28566019Sken /* Check for voltag virtual type */ 28666019Sken if (CHET_VT == cmd.ce_srctype) { 28766019Sken find_element(*argv, &cmd.ce_srctype, &cmd.ce_srcunit); 28866019Sken } else { 28966019Sken /* <from EU> */ 29066019Sken cmd.ce_srcunit = parse_element_unit(*argv); 29166019Sken } 29223449Sjoerg ++argv; --argc; 29323449Sjoerg 29423449Sjoerg /* <dst1 ET> */ 29523449Sjoerg cmd.ce_fdsttype = parse_element_type(*argv); 29623449Sjoerg ++argv; --argc; 29723449Sjoerg 29866019Sken /* Check for voltag virtual type */ 29966019Sken if (CHET_VT == cmd.ce_fdsttype) { 30066019Sken find_element(*argv, &cmd.ce_fdsttype, &cmd.ce_fdstunit); 30166019Sken } else { 30266019Sken /* <from EU> */ 30366019Sken cmd.ce_fdstunit = parse_element_unit(*argv); 30466019Sken } 30523449Sjoerg ++argv; --argc; 30623449Sjoerg 30723449Sjoerg /* 30823449Sjoerg * If the next token is a special word or there are no more 30923449Sjoerg * arguments, then this is a case of simple exchange. 31023449Sjoerg * dst2 == src. 31123449Sjoerg */ 31223449Sjoerg if ((argc == 0) || is_special(*argv)) { 31323449Sjoerg cmd.ce_sdsttype = cmd.ce_srctype; 31423449Sjoerg cmd.ce_sdstunit = cmd.ce_srcunit; 31523449Sjoerg goto do_special; 31623449Sjoerg } 31723449Sjoerg 31823449Sjoerg /* <dst2 ET> */ 31923449Sjoerg cmd.ce_sdsttype = parse_element_type(*argv); 32023449Sjoerg ++argv; --argc; 32123449Sjoerg 32266019Sken if (CHET_VT == cmd.ce_sdsttype) 32366019Sken errx(1,"%s %s: voltag only makes sense as an element source", 32466019Sken cname, *argv); 32566019Sken 32623449Sjoerg /* <dst2 EU> */ 32723449Sjoerg cmd.ce_sdstunit = parse_element_unit(*argv); 32823449Sjoerg ++argv; --argc; 32923449Sjoerg 33023449Sjoerg do_special: 33123449Sjoerg /* Deal with optional command modifiers. */ 33223449Sjoerg while (argc) { 33323449Sjoerg val = parse_special(*argv); 33423449Sjoerg ++argv; --argc; 33523449Sjoerg switch (val) { 33623449Sjoerg case SW_INVERT1: 33723449Sjoerg cmd.ce_flags |= CE_INVERT1; 33823449Sjoerg break; 33923449Sjoerg 34023449Sjoerg case SW_INVERT2: 34123449Sjoerg cmd.ce_flags |= CE_INVERT2; 34223449Sjoerg break; 34323449Sjoerg 34423449Sjoerg default: 34523449Sjoerg errx(1, "%s: inappropriate modifier `%s'", 34623449Sjoerg cname, *argv); 34723449Sjoerg /* NOTREACHED */ 34823449Sjoerg } 34923449Sjoerg } 35023449Sjoerg 35123449Sjoerg /* Send command to changer. */ 35239227Sgibbs if (ioctl(changer_fd, CHIOEXCHANGE, &cmd)) 35323449Sjoerg err(1, "%s: CHIOEXCHANGE", changer_name); 35423449Sjoerg 35523449Sjoerg return (0); 35623449Sjoerg 35723449Sjoerg usage: 35839227Sgibbs (void) fprintf(stderr, 35939227Sgibbs "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n" 36039227Sgibbs " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n", 36193101Smarkm getprogname(), cname); 36223449Sjoerg return (1); 36323449Sjoerg} 36423449Sjoerg 36523449Sjoergstatic int 36690107Simpdo_position(const char *cname, int argc, char **argv) 36723449Sjoerg{ 36823449Sjoerg struct changer_position cmd; 36923449Sjoerg int val; 37023449Sjoerg 37123449Sjoerg /* 37223449Sjoerg * On a position command, we expect the following: 37323449Sjoerg * 37423449Sjoerg * <to ET> <to EU> [inv] 37523449Sjoerg * 37623449Sjoerg * where ET == element type and EU == element unit. 37723449Sjoerg */ 37839227Sgibbs 37939227Sgibbs ++argv; --argc; 38039227Sgibbs 38123449Sjoerg if (argc < 2) { 38223449Sjoerg warnx("%s: too few arguments", cname); 38323449Sjoerg goto usage; 38423449Sjoerg } else if (argc > 3) { 38523449Sjoerg warnx("%s: too many arguments", cname); 38623449Sjoerg goto usage; 38723449Sjoerg } 38839227Sgibbs (void) memset(&cmd, 0, sizeof(cmd)); 38923449Sjoerg 39023449Sjoerg /* <to ET> */ 39123449Sjoerg cmd.cp_type = parse_element_type(*argv); 39223449Sjoerg ++argv; --argc; 39323449Sjoerg 39423449Sjoerg /* <to EU> */ 39523449Sjoerg cmd.cp_unit = parse_element_unit(*argv); 39623449Sjoerg ++argv; --argc; 39723449Sjoerg 39823449Sjoerg /* Deal with optional command modifier. */ 39923449Sjoerg if (argc) { 40023449Sjoerg val = parse_special(*argv); 40123449Sjoerg switch (val) { 40223449Sjoerg case SW_INVERT: 40323449Sjoerg cmd.cp_flags |= CP_INVERT; 40423449Sjoerg break; 40523449Sjoerg 40623449Sjoerg default: 40723449Sjoerg errx(1, "%s: inappropriate modifier `%s'", 40823449Sjoerg cname, *argv); 40923449Sjoerg /* NOTREACHED */ 41023449Sjoerg } 41123449Sjoerg } 41223449Sjoerg 41323449Sjoerg /* Send command to changer. */ 41439227Sgibbs if (ioctl(changer_fd, CHIOPOSITION, &cmd)) 41523449Sjoerg err(1, "%s: CHIOPOSITION", changer_name); 41623449Sjoerg 41723449Sjoerg return (0); 41823449Sjoerg 41923449Sjoerg usage: 42039227Sgibbs (void) fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n", 42193101Smarkm getprogname(), cname); 42223449Sjoerg return (1); 42323449Sjoerg} 42423449Sjoerg 42539227Sgibbs/* ARGSUSED */ 42623449Sjoergstatic int 42790107Simpdo_params(const char *cname, int argc, char **argv) 42823449Sjoerg{ 42923449Sjoerg struct changer_params data; 43039876Sken int picker; 43123449Sjoerg 43223449Sjoerg /* No arguments to this command. */ 43339227Sgibbs 43439227Sgibbs ++argv; --argc; 43539227Sgibbs 43623449Sjoerg if (argc) { 43741579Sbde warnx("%s: no arguments expected", cname); 43823449Sjoerg goto usage; 43923449Sjoerg } 44023449Sjoerg 44123449Sjoerg /* Get params from changer and display them. */ 44239227Sgibbs (void) memset(&data, 0, sizeof(data)); 44339227Sgibbs if (ioctl(changer_fd, CHIOGPARAMS, &data)) 44423449Sjoerg err(1, "%s: CHIOGPARAMS", changer_name); 44523449Sjoerg 44639227Sgibbs (void) printf("%s: %d slot%s, %d drive%s, %d picker%s", 44723449Sjoerg changer_name, 44823449Sjoerg data.cp_nslots, (data.cp_nslots > 1) ? "s" : "", 44923449Sjoerg data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "", 45023449Sjoerg data.cp_npickers, (data.cp_npickers > 1) ? "s" : ""); 45123449Sjoerg if (data.cp_nportals) 45239227Sgibbs (void) printf(", %d portal%s", data.cp_nportals, 45323449Sjoerg (data.cp_nportals > 1) ? "s" : ""); 45423449Sjoerg 45539876Sken /* Get current picker from changer and display it. */ 45639876Sken if (ioctl(changer_fd, CHIOGPICKER, &picker)) 45739876Sken err(1, "%s: CHIOGPICKER", changer_name); 45839876Sken 45939876Sken (void) printf("\n%s: current picker: %d\n", changer_name, picker); 46039876Sken 46123449Sjoerg return (0); 46223449Sjoerg 46323449Sjoerg usage: 46493101Smarkm (void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname); 46523449Sjoerg return (1); 46623449Sjoerg} 46723449Sjoerg 46839227Sgibbs/* ARGSUSED */ 46923449Sjoergstatic int 47090107Simpdo_getpicker(const char *cname, int argc, char **argv) 47123449Sjoerg{ 47223449Sjoerg int picker; 47323449Sjoerg 47423449Sjoerg /* No arguments to this command. */ 47539227Sgibbs 47639227Sgibbs ++argv; --argc; 47739227Sgibbs 47823449Sjoerg if (argc) { 47923449Sjoerg warnx("%s: no arguments expected", cname); 48023449Sjoerg goto usage; 48123449Sjoerg } 48223449Sjoerg 48323449Sjoerg /* Get current picker from changer and display it. */ 48439227Sgibbs if (ioctl(changer_fd, CHIOGPICKER, &picker)) 48523449Sjoerg err(1, "%s: CHIOGPICKER", changer_name); 48623449Sjoerg 48739227Sgibbs (void) printf("%s: current picker: %d\n", changer_name, picker); 48823449Sjoerg 48923449Sjoerg return (0); 49023449Sjoerg 49123449Sjoerg usage: 49293101Smarkm (void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname); 49323449Sjoerg return (1); 49423449Sjoerg} 49523449Sjoerg 49623449Sjoergstatic int 49790107Simpdo_setpicker(const char *cname, int argc, char **argv) 49823449Sjoerg{ 49923449Sjoerg int picker; 50023449Sjoerg 50139227Sgibbs ++argv; --argc; 50239227Sgibbs 50323449Sjoerg if (argc < 1) { 50423449Sjoerg warnx("%s: too few arguments", cname); 50523449Sjoerg goto usage; 50623449Sjoerg } else if (argc > 1) { 50723449Sjoerg warnx("%s: too many arguments", cname); 50823449Sjoerg goto usage; 50923449Sjoerg } 51023449Sjoerg 51123449Sjoerg picker = parse_element_unit(*argv); 51223449Sjoerg 51323449Sjoerg /* Set the changer picker. */ 51439227Sgibbs if (ioctl(changer_fd, CHIOSPICKER, &picker)) 51523449Sjoerg err(1, "%s: CHIOSPICKER", changer_name); 51623449Sjoerg 51723449Sjoerg return (0); 51823449Sjoerg 51923449Sjoerg usage: 52093101Smarkm (void) fprintf(stderr, "usage: %s %s <picker>\n", getprogname(), cname); 52123449Sjoerg return (1); 52223449Sjoerg} 52323449Sjoerg 52423449Sjoergstatic int 52590107Simpdo_status(const char *cname, int argc, char **argv) 52623449Sjoerg{ 52739227Sgibbs struct changer_params cp; 52839227Sgibbs struct changer_element_status_request cesr; 52991086Smarkm int i; 53091086Smarkm u_int16_t base, count, chet, schet, echet; 53179121Smikeh const char *description; 53239227Sgibbs int pvoltag = 0; 53339227Sgibbs int avoltag = 0; 53439227Sgibbs int sense = 0; 53539227Sgibbs int scsi = 0; 53639227Sgibbs int source = 0; 53739227Sgibbs int intaddr = 0; 53839227Sgibbs int c; 53923449Sjoerg 54026361Scharnier count = 0; 54139227Sgibbs base = 0; 54226361Scharnier description = NULL; 54326361Scharnier 54439227Sgibbs optind = optreset = 1; 54547442Simp while ((c = getopt(argc, argv, "vVsSbaI")) != -1) { 54639227Sgibbs switch (c) { 54739227Sgibbs case 'v': 54839227Sgibbs pvoltag = 1; 54939227Sgibbs break; 55039227Sgibbs case 'V': 55139227Sgibbs avoltag = 1; 55239227Sgibbs break; 55339227Sgibbs case 's': 55439227Sgibbs sense = 1; 55539227Sgibbs break; 55639227Sgibbs case 'S': 55739227Sgibbs source = 1; 55839227Sgibbs break; 55939227Sgibbs case 'b': 56039227Sgibbs scsi = 1; 56139227Sgibbs break; 56239227Sgibbs case 'I': 56339227Sgibbs intaddr = 1; 56439227Sgibbs break; 56539227Sgibbs case 'a': 56639227Sgibbs pvoltag = avoltag = source = sense = scsi = intaddr = 1; 56739227Sgibbs break; 56839227Sgibbs default: 56941579Sbde warnx("%s: bad option", cname); 57039227Sgibbs goto usage; 57139227Sgibbs } 57239227Sgibbs } 57339227Sgibbs 57439227Sgibbs argc -= optind; 57539227Sgibbs argv += optind; 57639227Sgibbs 57723449Sjoerg /* 57823449Sjoerg * On a status command, we expect the following: 57923449Sjoerg * 58039227Sgibbs * [<ET> [<start> [<end>] ] ] 58123449Sjoerg * 58239227Sgibbs * where ET == element type, start == first element to report, 58339227Sgibbs * end == number of elements to report 58423449Sjoerg * 58523449Sjoerg * If we get no arguments, we get the status of all 58623449Sjoerg * known element types. 58723449Sjoerg */ 58839227Sgibbs if (argc > 3) { 58923449Sjoerg warnx("%s: too many arguments", cname); 59023449Sjoerg goto usage; 59123449Sjoerg } 59223449Sjoerg 59323449Sjoerg /* 59423449Sjoerg * Get params from changer. Specifically, we need the element 59523449Sjoerg * counts. 59623449Sjoerg */ 59739227Sgibbs if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) 59823449Sjoerg err(1, "%s: CHIOGPARAMS", changer_name); 59923449Sjoerg 60039227Sgibbs if (argc > 0) 60139227Sgibbs schet = echet = parse_element_type(argv[0]); 60223449Sjoerg else { 60323449Sjoerg schet = CHET_MT; 60423449Sjoerg echet = CHET_DT; 60523449Sjoerg } 60639227Sgibbs if (argc > 1) { 60791086Smarkm base = (u_int16_t)atol(argv[1]); 60839227Sgibbs count = 1; 60939227Sgibbs } 61039227Sgibbs if (argc > 2) 61191086Smarkm count = (u_int16_t)atol(argv[2]) - base + 1; 61223449Sjoerg 61323449Sjoerg for (chet = schet; chet <= echet; ++chet) { 61423449Sjoerg switch (chet) { 61523449Sjoerg case CHET_MT: 61639227Sgibbs if (count == 0) 61739227Sgibbs count = cp.cp_npickers; 61839227Sgibbs else if (count > cp.cp_npickers) 61939227Sgibbs errx(1, "not that many pickers in device"); 62023449Sjoerg description = "picker"; 62123449Sjoerg break; 62223449Sjoerg 62323449Sjoerg case CHET_ST: 62439227Sgibbs if (count == 0) 62539227Sgibbs count = cp.cp_nslots; 62639227Sgibbs else if (count > cp.cp_nslots) 62739227Sgibbs errx(1, "not that many slots in device"); 62823449Sjoerg description = "slot"; 62923449Sjoerg break; 63023449Sjoerg 63123449Sjoerg case CHET_IE: 63239227Sgibbs if (count == 0) 63339227Sgibbs count = cp.cp_nportals; 63439227Sgibbs else if (count > cp.cp_nportals) 63539227Sgibbs errx(1, "not that many portals in device"); 63623449Sjoerg description = "portal"; 63723449Sjoerg break; 63823449Sjoerg 63923449Sjoerg case CHET_DT: 64039227Sgibbs if (count == 0) 64139227Sgibbs count = cp.cp_ndrives; 64239227Sgibbs else if (count > cp.cp_ndrives) 64339227Sgibbs errx(1, "not that many drives in device"); 64423449Sjoerg description = "drive"; 64523449Sjoerg break; 64639227Sgibbs 64739227Sgibbs default: 64839227Sgibbs /* To appease gcc -Wuninitialized. */ 64939227Sgibbs count = 0; 65039227Sgibbs description = NULL; 65123449Sjoerg } 65223449Sjoerg 65323449Sjoerg if (count == 0) { 65423449Sjoerg if (argc == 0) 65523449Sjoerg continue; 65623449Sjoerg else { 65723449Sjoerg printf("%s: no %s elements\n", 65823449Sjoerg changer_name, description); 65923449Sjoerg return (0); 66023449Sjoerg } 66123449Sjoerg } 66223449Sjoerg 66339227Sgibbs bzero(&cesr, sizeof(cesr)); 66439227Sgibbs cesr.cesr_element_type = chet; 66539227Sgibbs cesr.cesr_element_base = base; 66639227Sgibbs cesr.cesr_element_count = count; 66739227Sgibbs /* Allocate storage for the status structures. */ 66866019Sken cesr.cesr_element_status = 66966019Sken (struct changer_element_status *) 67079253Smikeh calloc((size_t)count, sizeof(struct changer_element_status)); 67139227Sgibbs 67239227Sgibbs if (!cesr.cesr_element_status) 67323449Sjoerg errx(1, "can't allocate status storage"); 67423449Sjoerg 67539227Sgibbs if (avoltag || pvoltag) 67639227Sgibbs cesr.cesr_flags |= CESR_VOLTAGS; 67723449Sjoerg 67839227Sgibbs if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr)) { 67939227Sgibbs free(cesr.cesr_element_status); 68023449Sjoerg err(1, "%s: CHIOGSTATUS", changer_name); 68123449Sjoerg } 68223449Sjoerg 68339227Sgibbs /* Dump the status for each reported element. */ 68423449Sjoerg for (i = 0; i < count; ++i) { 68539227Sgibbs struct changer_element_status *ces = 68639227Sgibbs &(cesr.cesr_element_status[i]); 68739227Sgibbs printf("%s %d: %s", description, ces->ces_addr, 68839227Sgibbs bits_to_string(ces->ces_flags, 68939227Sgibbs CESTATUS_BITS)); 69039227Sgibbs if (sense) 69139227Sgibbs printf(" sense: <0x%02x/0x%02x>", 69239227Sgibbs ces->ces_sensecode, 69339227Sgibbs ces->ces_sensequal); 69439227Sgibbs if (pvoltag) 69539227Sgibbs printf(" voltag: <%s:%d>", 69639227Sgibbs ces->ces_pvoltag.cv_volid, 69739227Sgibbs ces->ces_pvoltag.cv_serial); 69839227Sgibbs if (avoltag) 69939227Sgibbs printf(" avoltag: <%s:%d>", 70039227Sgibbs ces->ces_avoltag.cv_volid, 70139227Sgibbs ces->ces_avoltag.cv_serial); 70246073Simp if (source) { 70339227Sgibbs if (ces->ces_flags & CES_SOURCE_VALID) 70439227Sgibbs printf(" source: <%s %d>", 70539227Sgibbs element_type_name( 70639227Sgibbs ces->ces_source_type), 70739227Sgibbs ces->ces_source_addr); 70839227Sgibbs else 70939227Sgibbs printf(" source: <>"); 71046073Simp } 71139227Sgibbs if (intaddr) 71239227Sgibbs printf(" intaddr: <%d>", ces->ces_int_addr); 71339227Sgibbs if (scsi) { 71439227Sgibbs printf(" scsi: <"); 71539227Sgibbs if (ces->ces_flags & CES_SCSIID_VALID) 71639227Sgibbs printf("%d", ces->ces_scsi_id); 71739227Sgibbs else 71839227Sgibbs putchar('?'); 71939227Sgibbs putchar(':'); 72039227Sgibbs if (ces->ces_flags & CES_LUN_VALID) 72139227Sgibbs printf("%d", ces->ces_scsi_lun); 72239227Sgibbs else 72339227Sgibbs putchar('?'); 72439227Sgibbs putchar('>'); 72539227Sgibbs } 72639227Sgibbs putchar('\n'); 72723449Sjoerg } 72823449Sjoerg 72939227Sgibbs free(cesr.cesr_element_status); 73039227Sgibbs count = 0; 73123449Sjoerg } 73223449Sjoerg 73323449Sjoerg return (0); 73423449Sjoerg 73523449Sjoerg usage: 73639227Sgibbs (void) fprintf(stderr, "usage: %s %s [-vVsSbaA] [<element type> [<start-addr> [<end-addr>] ] ]\n", 73793101Smarkm getprogname(), cname); 73823449Sjoerg return (1); 73923449Sjoerg} 74023449Sjoerg 74123449Sjoergstatic int 74290107Simpdo_ielem(const char *cname, int argc, char **argv) 74323449Sjoerg{ 74439227Sgibbs int timeout = 0; 74539227Sgibbs 74639227Sgibbs if (argc == 2) { 74739227Sgibbs timeout = atol(argv[1]); 74839227Sgibbs } else if (argc > 1) { 74939227Sgibbs warnx("%s: too many arguments", cname); 75039227Sgibbs goto usage; 75139227Sgibbs } 75239227Sgibbs 75339227Sgibbs if (ioctl(changer_fd, CHIOIELEM, &timeout)) 75439227Sgibbs err(1, "%s: CHIOIELEM", changer_name); 75539227Sgibbs 75639227Sgibbs return (0); 75739227Sgibbs 75839227Sgibbs usage: 75939227Sgibbs (void) fprintf(stderr, "usage: %s %s [<timeout>]\n", 76093101Smarkm getprogname(), cname); 76139227Sgibbs return (1); 76239227Sgibbs} 76339227Sgibbs 76439227Sgibbsstatic int 76590107Simpdo_voltag(const char *cname, int argc, char **argv) 76639227Sgibbs{ 76739227Sgibbs int force = 0; 76839227Sgibbs int clear = 0; 76939227Sgibbs int alternate = 0; 77039227Sgibbs int c; 77139227Sgibbs struct changer_set_voltag_request csvr; 77239227Sgibbs 77339227Sgibbs bzero(&csvr, sizeof(csvr)); 77439227Sgibbs 77539227Sgibbs optind = optreset = 1; 77647442Simp while ((c = getopt(argc, argv, "fca")) != -1) { 77739227Sgibbs switch (c) { 77839227Sgibbs case 'f': 77939227Sgibbs force = 1; 78039227Sgibbs break; 78139227Sgibbs case 'c': 78239227Sgibbs clear = 1; 78339227Sgibbs break; 78439227Sgibbs case 'a': 78539227Sgibbs alternate = 1; 78639227Sgibbs break; 78739227Sgibbs default: 78841579Sbde warnx("%s: bad option", cname); 78939227Sgibbs goto usage; 79039227Sgibbs } 79139227Sgibbs } 79239227Sgibbs 79339227Sgibbs argc -= optind; 79439227Sgibbs argv += optind; 79539227Sgibbs 79639227Sgibbs if (argc < 2) { 79741579Sbde warnx("%s: missing element specification", cname); 79839227Sgibbs goto usage; 79939227Sgibbs } 80039227Sgibbs 80139227Sgibbs csvr.csvr_type = parse_element_type(argv[0]); 80291086Smarkm csvr.csvr_addr = (u_int16_t)atol(argv[1]); 80339227Sgibbs 80439227Sgibbs if (!clear) { 80539227Sgibbs if (argc < 3 || argc > 4) { 80641579Sbde warnx("%s: missing argument", cname); 80739227Sgibbs goto usage; 80839227Sgibbs } 80939227Sgibbs 81039227Sgibbs if (force) 81139227Sgibbs csvr.csvr_flags = CSVR_MODE_REPLACE; 81239227Sgibbs else 81339227Sgibbs csvr.csvr_flags = CSVR_MODE_SET; 81439227Sgibbs 81539227Sgibbs if (strlen(argv[2]) > sizeof(csvr.csvr_voltag.cv_volid)) { 81641579Sbde warnx("%s: volume label too long", cname); 81739227Sgibbs goto usage; 81839227Sgibbs } 81939227Sgibbs 82079253Smikeh strlcpy((char *)csvr.csvr_voltag.cv_volid, argv[2], 82139227Sgibbs sizeof(csvr.csvr_voltag.cv_volid)); 82239227Sgibbs 82339227Sgibbs if (argc == 4) { 82491086Smarkm csvr.csvr_voltag.cv_serial = (u_int16_t)atol(argv[3]); 82539227Sgibbs } 82639227Sgibbs } else { 82739227Sgibbs if (argc != 2) { 82841579Sbde warnx("%s: unexpected argument", cname); 82939227Sgibbs goto usage; 83039227Sgibbs } 83139227Sgibbs csvr.csvr_flags = CSVR_MODE_CLEAR; 83239227Sgibbs } 83339227Sgibbs 83439227Sgibbs if (alternate) { 83539227Sgibbs csvr.csvr_flags |= CSVR_ALTERNATE; 83639227Sgibbs } 83739227Sgibbs 83839227Sgibbs if (ioctl(changer_fd, CHIOSETVOLTAG, &csvr)) 83939227Sgibbs err(1, "%s: CHIOSETVOLTAG", changer_name); 84039227Sgibbs 84139227Sgibbs return 0; 84239227Sgibbs usage: 84339227Sgibbs (void) fprintf(stderr, 84439227Sgibbs "usage: %s %s [-fca] <element> [<voltag> [<vsn>] ]\n", 84593101Smarkm getprogname(), cname); 84639227Sgibbs return 1; 84739227Sgibbs} 84839227Sgibbs 84991086Smarkmstatic u_int16_t 85090107Simpparse_element_type(char *cp) 85139227Sgibbs{ 85223449Sjoerg int i; 85323449Sjoerg 85423449Sjoerg for (i = 0; elements[i].et_name != NULL; ++i) 85523449Sjoerg if (strcmp(elements[i].et_name, cp) == 0) 85691086Smarkm return ((u_int16_t)elements[i].et_type); 85723449Sjoerg 85823449Sjoerg errx(1, "invalid element type `%s'", cp); 85939227Sgibbs /* NOTREACHED */ 86023449Sjoerg} 86123449Sjoerg 86239227Sgibbsstatic const char * 86390107Simpelement_type_name(int et) 86439227Sgibbs{ 86539227Sgibbs int i; 86639227Sgibbs 86739227Sgibbs for (i = 0; elements[i].et_name != NULL; i++) 86839227Sgibbs if (elements[i].et_type == et) 86939227Sgibbs return elements[i].et_name; 87039227Sgibbs 87139227Sgibbs return "unknown"; 87239227Sgibbs} 87339227Sgibbs 87491086Smarkmstatic u_int16_t 87590107Simpparse_element_unit(char *cp) 87623449Sjoerg{ 87723449Sjoerg int i; 87823449Sjoerg char *p; 87923449Sjoerg 88023449Sjoerg i = (int)strtol(cp, &p, 10); 88123449Sjoerg if ((i < 0) || (*p != '\0')) 88223449Sjoerg errx(1, "invalid unit number `%s'", cp); 88323449Sjoerg 88491086Smarkm return ((u_int16_t)i); 88523449Sjoerg} 88623449Sjoerg 88723449Sjoergstatic int 88890107Simpparse_special(char *cp) 88923449Sjoerg{ 89023449Sjoerg int val; 89123449Sjoerg 89223449Sjoerg val = is_special(cp); 89323449Sjoerg if (val) 89423449Sjoerg return (val); 89523449Sjoerg 89623449Sjoerg errx(1, "invalid modifier `%s'", cp); 89739227Sgibbs /* NOTREACHED */ 89823449Sjoerg} 89923449Sjoerg 90023449Sjoergstatic int 90190107Simpis_special(char *cp) 90223449Sjoerg{ 90323449Sjoerg int i; 90423449Sjoerg 90523449Sjoerg for (i = 0; specials[i].sw_name != NULL; ++i) 90623449Sjoerg if (strcmp(specials[i].sw_name, cp) == 0) 90723449Sjoerg return (specials[i].sw_value); 90823449Sjoerg 90923449Sjoerg return (0); 91023449Sjoerg} 91123449Sjoerg 91248073Skrisstatic const char * 91390107Simpbits_to_string(ces_status_flags v, const char *cp) 91423449Sjoerg{ 91523449Sjoerg const char *np; 91623449Sjoerg char f, sep, *bp; 91723449Sjoerg static char buf[128]; 91823449Sjoerg 91923449Sjoerg bp = buf; 92039227Sgibbs (void) memset(buf, 0, sizeof(buf)); 92123449Sjoerg 92223449Sjoerg for (sep = '<'; (f = *cp++) != 0; cp = np) { 92323449Sjoerg for (np = cp; *np >= ' ';) 92423449Sjoerg np++; 92591086Smarkm if (((int)v & (1 << (f - 1))) == 0) 92623449Sjoerg continue; 92791086Smarkm (void) snprintf(bp, sizeof(buf) - (size_t)(bp - &buf[0]), 92848073Skris "%c%.*s", sep, (int)(long)(np - cp), cp); 92947816Skris bp += strlen(bp); 93023449Sjoerg sep = ','; 93123449Sjoerg } 93223449Sjoerg if (sep != '<') 93323449Sjoerg *bp = '>'; 93423449Sjoerg 93523449Sjoerg return (buf); 93623449Sjoerg} 93766019Sken/* 93866019Sken * do_return() 93966019Sken * 94066019Sken * Given an element reference, ask the changer/picker to move that 94166019Sken * element back to its source slot. 94266019Sken */ 94366019Skenstatic int 94490107Simpdo_return(const char *cname, int argc, char **argv) 94566019Sken{ 94666019Sken struct changer_element_status *ces; 94766019Sken struct changer_move cmd; 94891665Simp uint16_t type, element; 94923449Sjoerg 95066019Sken ++argv; --argc; 95166019Sken 95266019Sken if (argc < 2) { 95366019Sken warnx("%s: too few arguments", cname); 95466019Sken goto usage; 95566019Sken } else if (argc > 3) { 95666019Sken warnx("%s: too many arguments", cname); 95766019Sken goto usage; 95866019Sken } 95966019Sken 96066019Sken type = parse_element_type(*argv); 96166019Sken ++argv; --argc; 96266019Sken 96366019Sken /* Handle voltag virtual Changer Element Type */ 96466019Sken if (CHET_VT == type) { 96566019Sken find_element(*argv, &type, &element); 96666019Sken } else { 96766019Sken element = parse_element_unit(*argv); 96866019Sken } 96966019Sken ++argv; --argc; 97066019Sken 97179253Smikeh /* Get the status */ 972184484Sjoerg ces = get_element_status((unsigned int)type, (unsigned int)element, 973184484Sjoerg CHET_VT == type); 97466019Sken 97566019Sken if (NULL == ces) 97666019Sken errx(1, "%s: null element status pointer", cname); 97766019Sken 97866019Sken if (!(ces->ces_flags & CES_SOURCE_VALID)) 97966019Sken errx(1, "%s: no source information", cname); 98066019Sken 98166019Sken (void) memset(&cmd, 0, sizeof(cmd)); 98266019Sken 98366019Sken cmd.cm_fromtype = type; 98466019Sken cmd.cm_fromunit = element; 98566019Sken cmd.cm_totype = ces->ces_source_type; 98666019Sken cmd.cm_tounit = ces->ces_source_addr; 98766019Sken 98866019Sken if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1) 98966019Sken err(1, "%s: CHIOMOVE", changer_name); 99066019Sken free(ces); 99166019Sken 99266019Sken return(0); 99366019Sken 99466019Skenusage: 99566019Sken (void) fprintf(stderr, "usage: %s %s " 99693101Smarkm "<from ET> <from EU>\n", getprogname(), cname); 99766019Sken return(1); 99866019Sken} 99966019Sken 100066019Sken/* 100166019Sken * get_element_status() 100266019Sken * 100366019Sken * return a *cesr for the specified changer element. This 100466019Sken * routing will malloc()/calloc() the memory. The caller 100566019Sken * should free() it when done. 100666019Sken */ 100766019Skenstatic struct changer_element_status * 1008184484Sjoergget_element_status(unsigned int type, unsigned int element, int use_voltags) 100966019Sken{ 101066019Sken struct changer_element_status_request cesr; 101166019Sken struct changer_element_status *ces; 101266019Sken 101366019Sken ces = (struct changer_element_status *) 101479253Smikeh calloc((size_t)1, sizeof(struct changer_element_status)); 101566019Sken 101666019Sken if (NULL == ces) 101766019Sken errx(1, "can't allocate status storage"); 101866019Sken 101966019Sken (void)memset(&cesr, 0, sizeof(cesr)); 102066019Sken 102191665Simp cesr.cesr_element_type = (uint16_t)type; 102291665Simp cesr.cesr_element_base = (uint16_t)element; 102366019Sken cesr.cesr_element_count = 1; /* Only this one element */ 1024184484Sjoerg if (use_voltags) 1025184484Sjoerg cesr.cesr_flags |= CESR_VOLTAGS; /* Grab voltags as well */ 102666019Sken cesr.cesr_element_status = ces; 102766019Sken 102866019Sken if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 102966019Sken free(ces); 103066019Sken err(1, "%s: CHIOGSTATUS", changer_name); 103166019Sken /* NOTREACHED */ 103266019Sken } 103366019Sken 103466019Sken return ces; 103566019Sken} 103666019Sken 103766019Sken 103866019Sken/* 103966019Sken * find_element() 104066019Sken * 104166019Sken * Given a <voltag> find the chager element and unit, or exit 104266019Sken * with an error if it isn't found. We grab the changer status 104366019Sken * and iterate until we find a match, or crap out. 104466019Sken */ 104523449Sjoergstatic void 104691665Simpfind_element(char *voltag, uint16_t *et, uint16_t *eu) 104766019Sken{ 104866019Sken struct changer_params cp; 104966019Sken struct changer_element_status_request cesr; 105066019Sken struct changer_element_status *ch_ces, *ces; 105179253Smikeh int found = 0; 105279253Smikeh size_t elem, total_elem; 105366019Sken 105466019Sken /* 105566019Sken * Get the changer parameters, we're interested in the counts 105666019Sken * for all types of elements to perform our search. 105766019Sken */ 105866019Sken if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) 105966019Sken err(1, "%s: CHIOGPARAMS", changer_name); 106066019Sken 106166019Sken /* Allocate some memory for the results */ 106266019Sken total_elem = (cp.cp_nslots + cp.cp_ndrives 106366019Sken + cp.cp_npickers + cp.cp_nportals); 106466019Sken 106566019Sken ch_ces = (struct changer_element_status *) 106666019Sken calloc(total_elem, sizeof(struct changer_element_status)); 106766019Sken 106866019Sken if (NULL == ch_ces) 106966019Sken errx(1, "can't allocate status storage"); 107066019Sken 107166019Sken ces = ch_ces; 107266019Sken 107366019Sken /* Read in the changer slots */ 107466019Sken if (cp.cp_nslots > 0) { 107566019Sken cesr.cesr_element_type = CHET_ST; 107666019Sken cesr.cesr_element_base = 0; 107766019Sken cesr.cesr_element_count = cp.cp_nslots; 107866019Sken cesr.cesr_flags |= CESR_VOLTAGS; 107966019Sken cesr.cesr_element_status = ces; 108066019Sken 108166019Sken if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 108266019Sken free(ch_ces); 108366019Sken err(1, "%s: CHIOGSTATUS", changer_name); 108466019Sken } 108566019Sken ces += cp.cp_nslots; 108666019Sken } 108766019Sken 108866019Sken /* Read in the drive information */ 108966019Sken if (cp.cp_ndrives > 0 ) { 109066019Sken 109166019Sken (void) memset(&cesr, 0, sizeof(cesr)); 109266019Sken cesr.cesr_element_type = CHET_DT; 109366019Sken cesr.cesr_element_base = 0; 109466019Sken cesr.cesr_element_count = cp.cp_ndrives; 109566019Sken cesr.cesr_flags |= CESR_VOLTAGS; 109666019Sken cesr.cesr_element_status = ces; 109766019Sken 109866019Sken if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 109966019Sken free(ch_ces); 110066019Sken err(1, "%s: CHIOGSTATUS", changer_name); 110166019Sken } 110266019Sken ces += cp.cp_ndrives; 110366019Sken } 110466019Sken 110566019Sken /* Read in the portal information */ 110666019Sken if (cp.cp_nportals > 0 ) { 110766019Sken (void) memset(&cesr, 0, sizeof(cesr)); 110866019Sken cesr.cesr_element_type = CHET_IE; 110966019Sken cesr.cesr_element_base = 0; 111066019Sken cesr.cesr_element_count = cp.cp_nportals; 111166019Sken cesr.cesr_flags |= CESR_VOLTAGS; 111266019Sken cesr.cesr_element_status = ces; 111366019Sken 111466019Sken if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 111566019Sken free(ch_ces); 111666019Sken err(1, "%s: CHIOGSTATUS", changer_name); 111766019Sken } 111866019Sken ces += cp.cp_nportals; 111966019Sken } 112066019Sken 112166019Sken /* Read in the picker information */ 112266019Sken if (cp.cp_npickers > 0) { 112366019Sken (void) memset(&cesr, 0, sizeof(cesr)); 112466019Sken cesr.cesr_element_type = CHET_MT; 112566019Sken cesr.cesr_element_base = 0; 112666019Sken cesr.cesr_element_count = cp.cp_npickers; 112766019Sken cesr.cesr_flags |= CESR_VOLTAGS; 112866019Sken cesr.cesr_element_status = ces; 112966019Sken 113066019Sken if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 113166019Sken free(ch_ces); 113266019Sken err(1, "%s: CHIOGSTATUS", changer_name); 113366019Sken } 113466019Sken } 113566019Sken 113666019Sken /* 113766019Sken * Now search the list the specified <voltag> 113866019Sken */ 113966019Sken for (elem = 0; elem <= total_elem; ++elem) { 114066019Sken 114166019Sken ces = &ch_ces[elem]; 114266019Sken 114366019Sken /* Make sure we have a tape in this element */ 114466019Sken if ((ces->ces_flags & (CES_STATUS_ACCESS|CES_STATUS_FULL)) 114566019Sken != (CES_STATUS_ACCESS|CES_STATUS_FULL)) 114666019Sken continue; 114766019Sken 114866019Sken /* Check to see if it is our target */ 114979253Smikeh if (strcasecmp(voltag, 115079253Smikeh (const char *)ces->ces_pvoltag.cv_volid) == 0) { 115166019Sken *et = ces->ces_type; 115266019Sken *eu = ces->ces_addr; 115366019Sken ++found; 115466019Sken break; 115566019Sken } 115666019Sken } 115766019Sken if (!found) { 115866019Sken errx(1, "%s: unable to locate voltag: %s", changer_name, 115966019Sken voltag); 116066019Sken } 116166019Sken free(ch_ces); 116266019Sken return; 116366019Sken} 116466019Sken 116566019Skenstatic void 116690107Simpcleanup(void) 116723449Sjoerg{ 116823449Sjoerg /* Simple enough... */ 116923449Sjoerg (void)close(changer_fd); 117023449Sjoerg} 117123449Sjoerg 117223449Sjoergstatic void 117390107Simpusage(void) 117423449Sjoerg{ 117590107Simp (void)fprintf(stderr, "usage: %s [-f changer] command [-<flags>] " 117693101Smarkm "arg1 arg2 [arg3 [...]]\n", getprogname()); 117723449Sjoerg exit(1); 117823449Sjoerg} 1179