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$"); 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> 57252214Sken#include <langinfo.h> 58252214Sken#include <locale.h> 5923449Sjoerg 6023449Sjoerg#include "defs.h" 6123449Sjoerg#include "pathnames.h" 6223449Sjoerg 6390107Simpstatic void usage(void); 6490107Simpstatic void cleanup(void); 6591086Smarkmstatic u_int16_t parse_element_type(char *); 6691086Smarkmstatic u_int16_t parse_element_unit(char *); 6790107Simpstatic const char * element_type_name(int et); 6890107Simpstatic int parse_special(char *); 6990107Simpstatic int is_special(char *); 7090107Simpstatic const char *bits_to_string(ces_status_flags, const char *); 7123449Sjoerg 7291665Simpstatic void find_element(char *, uint16_t *, uint16_t *); 7379253Smikehstatic struct changer_element_status *get_element_status 74184484Sjoerg (unsigned int, unsigned int, int); 7566019Sken 7690107Simpstatic int do_move(const char *, int, char **); 7790107Simpstatic int do_exchange(const char *, int, char **); 7890107Simpstatic int do_position(const char *, int, char **); 7990107Simpstatic int do_params(const char *, int, char **); 8090107Simpstatic int do_getpicker(const char *, int, char **); 8190107Simpstatic int do_setpicker(const char *, int, char **); 8290107Simpstatic int do_status(const char *, int, char **); 8390107Simpstatic int do_ielem(const char *, int, char **); 8490107Simpstatic int do_return(const char *, int, char **); 8590107Simpstatic int do_voltag(const char *, int, char **); 86252214Skenstatic void print_designator(const char *, u_int8_t, u_int8_t); 8739227Sgibbs 8866019Sken#ifndef CHET_VT 8966019Sken#define CHET_VT 10 /* Completely Arbitrary */ 9066019Sken#endif 9166019Sken 9223449Sjoerg/* Valid changer element types. */ 9323449Sjoergconst struct element_type elements[] = { 9447816Skris { "drive", CHET_DT }, 9523449Sjoerg { "picker", CHET_MT }, 9647816Skris { "portal", CHET_IE }, 9723449Sjoerg { "slot", CHET_ST }, 9866019Sken { "voltag", CHET_VT }, /* Select tapes by barcode */ 9923449Sjoerg { NULL, 0 }, 10023449Sjoerg}; 10123449Sjoerg 10223449Sjoerg/* Valid commands. */ 10323449Sjoergconst struct changer_command commands[] = { 10447816Skris { "exchange", do_exchange }, 10547816Skris { "getpicker", do_getpicker }, 10647816Skris { "ielem", do_ielem }, 10723449Sjoerg { "move", do_move }, 10847816Skris { "params", do_params }, 10923449Sjoerg { "position", do_position }, 11023449Sjoerg { "setpicker", do_setpicker }, 11123449Sjoerg { "status", do_status }, 11266019Sken { "return", do_return }, 11339227Sgibbs { "voltag", do_voltag }, 11423449Sjoerg { NULL, 0 }, 11523449Sjoerg}; 11623449Sjoerg 11723449Sjoerg/* Valid special words. */ 11823449Sjoergconst struct special_word specials[] = { 11923449Sjoerg { "inv", SW_INVERT }, 12023449Sjoerg { "inv1", SW_INVERT1 }, 12123449Sjoerg { "inv2", SW_INVERT2 }, 12223449Sjoerg { NULL, 0 }, 12323449Sjoerg}; 12423449Sjoerg 12523449Sjoergstatic int changer_fd; 12648073Skrisstatic const char *changer_name; 12723449Sjoerg 12823449Sjoergint 12990107Simpmain(int argc, char **argv) 13023449Sjoerg{ 13123449Sjoerg int ch, i; 13223449Sjoerg 13323449Sjoerg while ((ch = getopt(argc, argv, "f:")) != -1) { 13423449Sjoerg switch (ch) { 13523449Sjoerg case 'f': 13623449Sjoerg changer_name = optarg; 13723449Sjoerg break; 13823449Sjoerg 13923449Sjoerg default: 14023449Sjoerg usage(); 14123449Sjoerg } 14223449Sjoerg } 14323449Sjoerg argc -= optind; 14423449Sjoerg argv += optind; 14523449Sjoerg 14623449Sjoerg if (argc == 0) 14723449Sjoerg usage(); 14823449Sjoerg 14923449Sjoerg /* Get the default changer if not already specified. */ 15023449Sjoerg if (changer_name == NULL) 15123449Sjoerg if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL) 15223449Sjoerg changer_name = _PATH_CH; 15323449Sjoerg 15423449Sjoerg /* Open the changer device. */ 15523449Sjoerg if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1) 15623449Sjoerg err(1, "%s: open", changer_name); 15723449Sjoerg 15823449Sjoerg /* Register cleanup function. */ 15923449Sjoerg if (atexit(cleanup)) 16023449Sjoerg err(1, "can't register cleanup function"); 16123449Sjoerg 16223449Sjoerg /* Find the specified command. */ 16323449Sjoerg for (i = 0; commands[i].cc_name != NULL; ++i) 16423449Sjoerg if (strcmp(*argv, commands[i].cc_name) == 0) 16523449Sjoerg break; 16647816Skris if (commands[i].cc_name == NULL) { 16747816Skris /* look for abbreviation */ 16847816Skris for (i = 0; commands[i].cc_name != NULL; ++i) 16947816Skris if (strncmp(*argv, commands[i].cc_name, 17047816Skris strlen(*argv)) == 0) 17147816Skris break; 17248073Skris } 17347816Skris 17423449Sjoerg if (commands[i].cc_name == NULL) 17523449Sjoerg errx(1, "unknown command: %s", *argv); 17623449Sjoerg 17748073Skris exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); 17839227Sgibbs /* NOTREACHED */ 17923449Sjoerg} 18023449Sjoerg 18123449Sjoergstatic int 18290107Simpdo_move(const char *cname, int argc, char **argv) 18323449Sjoerg{ 18423449Sjoerg struct changer_move cmd; 18523449Sjoerg int val; 18623449Sjoerg 18723449Sjoerg /* 18823449Sjoerg * On a move command, we expect the following: 18923449Sjoerg * 19023449Sjoerg * <from ET> <from EU> <to ET> <to EU> [inv] 19123449Sjoerg * 19223449Sjoerg * where ET == element type and EU == element unit. 19323449Sjoerg */ 19439227Sgibbs 19539227Sgibbs ++argv; --argc; 19639227Sgibbs 19723449Sjoerg if (argc < 4) { 19823449Sjoerg warnx("%s: too few arguments", cname); 19923449Sjoerg goto usage; 20023449Sjoerg } else if (argc > 5) { 20123449Sjoerg warnx("%s: too many arguments", cname); 20223449Sjoerg goto usage; 20323449Sjoerg } 20439227Sgibbs (void) memset(&cmd, 0, sizeof(cmd)); 20523449Sjoerg 20623449Sjoerg /* <from ET> */ 20723449Sjoerg cmd.cm_fromtype = parse_element_type(*argv); 20823449Sjoerg ++argv; --argc; 20923449Sjoerg 21066019Sken /* Check for voltag virtual type */ 21166019Sken if (CHET_VT == cmd.cm_fromtype) { 21266019Sken find_element(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit); 21366019Sken } else { 21466019Sken /* <from EU> */ 21566019Sken cmd.cm_fromunit = parse_element_unit(*argv); 21666019Sken } 21723449Sjoerg ++argv; --argc; 21823449Sjoerg 21923449Sjoerg /* <to ET> */ 22023449Sjoerg cmd.cm_totype = parse_element_type(*argv); 22123449Sjoerg ++argv; --argc; 22223449Sjoerg 22366019Sken /* Check for voltag virtual type, and report error */ 22466019Sken if (CHET_VT == cmd.cm_totype) 22566019Sken errx(1,"%s: voltag only makes sense as an element source", 22666019Sken cname); 22766019Sken 22823449Sjoerg /* <to EU> */ 22923449Sjoerg cmd.cm_tounit = parse_element_unit(*argv); 23023449Sjoerg ++argv; --argc; 23123449Sjoerg 23223449Sjoerg /* Deal with optional command modifier. */ 23323449Sjoerg if (argc) { 23423449Sjoerg val = parse_special(*argv); 23523449Sjoerg switch (val) { 23623449Sjoerg case SW_INVERT: 23723449Sjoerg cmd.cm_flags |= CM_INVERT; 23823449Sjoerg break; 23923449Sjoerg 24023449Sjoerg default: 24123449Sjoerg errx(1, "%s: inappropriate modifier `%s'", 24223449Sjoerg cname, *argv); 24323449Sjoerg /* NOTREACHED */ 24423449Sjoerg } 24523449Sjoerg } 24623449Sjoerg 24723449Sjoerg /* Send command to changer. */ 24839227Sgibbs if (ioctl(changer_fd, CHIOMOVE, &cmd)) 24923449Sjoerg err(1, "%s: CHIOMOVE", changer_name); 25023449Sjoerg 25123449Sjoerg return (0); 25223449Sjoerg 25323449Sjoerg usage: 25439227Sgibbs (void) fprintf(stderr, "usage: %s %s " 25593101Smarkm "<from ET> <from EU> <to ET> <to EU> [inv]\n", getprogname(), cname); 25623449Sjoerg return (1); 25723449Sjoerg} 25823449Sjoerg 25923449Sjoergstatic int 26090107Simpdo_exchange(const char *cname, int argc, char **argv) 26123449Sjoerg{ 26223449Sjoerg struct changer_exchange cmd; 26323449Sjoerg int val; 26423449Sjoerg 26523449Sjoerg /* 26623449Sjoerg * On an exchange command, we expect the following: 26723449Sjoerg * 26823449Sjoerg * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2] 26923449Sjoerg * 27023449Sjoerg * where ET == element type and EU == element unit. 27123449Sjoerg */ 27239227Sgibbs 27339227Sgibbs ++argv; --argc; 27439227Sgibbs 27523449Sjoerg if (argc < 4) { 27623449Sjoerg warnx("%s: too few arguments", cname); 27723449Sjoerg goto usage; 27823449Sjoerg } else if (argc > 8) { 27923449Sjoerg warnx("%s: too many arguments", cname); 28023449Sjoerg goto usage; 28123449Sjoerg } 28239227Sgibbs (void) memset(&cmd, 0, sizeof(cmd)); 28323449Sjoerg 28423449Sjoerg /* <src ET> */ 28523449Sjoerg cmd.ce_srctype = parse_element_type(*argv); 28623449Sjoerg ++argv; --argc; 28723449Sjoerg 28866019Sken /* Check for voltag virtual type */ 28966019Sken if (CHET_VT == cmd.ce_srctype) { 29066019Sken find_element(*argv, &cmd.ce_srctype, &cmd.ce_srcunit); 29166019Sken } else { 29266019Sken /* <from EU> */ 29366019Sken cmd.ce_srcunit = parse_element_unit(*argv); 29466019Sken } 29523449Sjoerg ++argv; --argc; 29623449Sjoerg 29723449Sjoerg /* <dst1 ET> */ 29823449Sjoerg cmd.ce_fdsttype = parse_element_type(*argv); 29923449Sjoerg ++argv; --argc; 30023449Sjoerg 30166019Sken /* Check for voltag virtual type */ 30266019Sken if (CHET_VT == cmd.ce_fdsttype) { 30366019Sken find_element(*argv, &cmd.ce_fdsttype, &cmd.ce_fdstunit); 30466019Sken } else { 30566019Sken /* <from EU> */ 30666019Sken cmd.ce_fdstunit = parse_element_unit(*argv); 30766019Sken } 30823449Sjoerg ++argv; --argc; 30923449Sjoerg 31023449Sjoerg /* 31123449Sjoerg * If the next token is a special word or there are no more 31223449Sjoerg * arguments, then this is a case of simple exchange. 31323449Sjoerg * dst2 == src. 31423449Sjoerg */ 31523449Sjoerg if ((argc == 0) || is_special(*argv)) { 31623449Sjoerg cmd.ce_sdsttype = cmd.ce_srctype; 31723449Sjoerg cmd.ce_sdstunit = cmd.ce_srcunit; 31823449Sjoerg goto do_special; 31923449Sjoerg } 32023449Sjoerg 32123449Sjoerg /* <dst2 ET> */ 32223449Sjoerg cmd.ce_sdsttype = parse_element_type(*argv); 32323449Sjoerg ++argv; --argc; 32423449Sjoerg 32566019Sken if (CHET_VT == cmd.ce_sdsttype) 32666019Sken errx(1,"%s %s: voltag only makes sense as an element source", 32766019Sken cname, *argv); 32866019Sken 32923449Sjoerg /* <dst2 EU> */ 33023449Sjoerg cmd.ce_sdstunit = parse_element_unit(*argv); 33123449Sjoerg ++argv; --argc; 33223449Sjoerg 33323449Sjoerg do_special: 33423449Sjoerg /* Deal with optional command modifiers. */ 33523449Sjoerg while (argc) { 33623449Sjoerg val = parse_special(*argv); 33723449Sjoerg ++argv; --argc; 33823449Sjoerg switch (val) { 33923449Sjoerg case SW_INVERT1: 34023449Sjoerg cmd.ce_flags |= CE_INVERT1; 34123449Sjoerg break; 34223449Sjoerg 34323449Sjoerg case SW_INVERT2: 34423449Sjoerg cmd.ce_flags |= CE_INVERT2; 34523449Sjoerg break; 34623449Sjoerg 34723449Sjoerg default: 34823449Sjoerg errx(1, "%s: inappropriate modifier `%s'", 34923449Sjoerg cname, *argv); 35023449Sjoerg /* NOTREACHED */ 35123449Sjoerg } 35223449Sjoerg } 35323449Sjoerg 35423449Sjoerg /* Send command to changer. */ 35539227Sgibbs if (ioctl(changer_fd, CHIOEXCHANGE, &cmd)) 35623449Sjoerg err(1, "%s: CHIOEXCHANGE", changer_name); 35723449Sjoerg 35823449Sjoerg return (0); 35923449Sjoerg 36023449Sjoerg usage: 36139227Sgibbs (void) fprintf(stderr, 36239227Sgibbs "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n" 36339227Sgibbs " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n", 36493101Smarkm getprogname(), cname); 36523449Sjoerg return (1); 36623449Sjoerg} 36723449Sjoerg 36823449Sjoergstatic int 36990107Simpdo_position(const char *cname, int argc, char **argv) 37023449Sjoerg{ 37123449Sjoerg struct changer_position cmd; 37223449Sjoerg int val; 37323449Sjoerg 37423449Sjoerg /* 37523449Sjoerg * On a position command, we expect the following: 37623449Sjoerg * 37723449Sjoerg * <to ET> <to EU> [inv] 37823449Sjoerg * 37923449Sjoerg * where ET == element type and EU == element unit. 38023449Sjoerg */ 38139227Sgibbs 38239227Sgibbs ++argv; --argc; 38339227Sgibbs 38423449Sjoerg if (argc < 2) { 38523449Sjoerg warnx("%s: too few arguments", cname); 38623449Sjoerg goto usage; 38723449Sjoerg } else if (argc > 3) { 38823449Sjoerg warnx("%s: too many arguments", cname); 38923449Sjoerg goto usage; 39023449Sjoerg } 39139227Sgibbs (void) memset(&cmd, 0, sizeof(cmd)); 39223449Sjoerg 39323449Sjoerg /* <to ET> */ 39423449Sjoerg cmd.cp_type = parse_element_type(*argv); 39523449Sjoerg ++argv; --argc; 39623449Sjoerg 39723449Sjoerg /* <to EU> */ 39823449Sjoerg cmd.cp_unit = parse_element_unit(*argv); 39923449Sjoerg ++argv; --argc; 40023449Sjoerg 40123449Sjoerg /* Deal with optional command modifier. */ 40223449Sjoerg if (argc) { 40323449Sjoerg val = parse_special(*argv); 40423449Sjoerg switch (val) { 40523449Sjoerg case SW_INVERT: 40623449Sjoerg cmd.cp_flags |= CP_INVERT; 40723449Sjoerg break; 40823449Sjoerg 40923449Sjoerg default: 41023449Sjoerg errx(1, "%s: inappropriate modifier `%s'", 41123449Sjoerg cname, *argv); 41223449Sjoerg /* NOTREACHED */ 41323449Sjoerg } 41423449Sjoerg } 41523449Sjoerg 41623449Sjoerg /* Send command to changer. */ 41739227Sgibbs if (ioctl(changer_fd, CHIOPOSITION, &cmd)) 41823449Sjoerg err(1, "%s: CHIOPOSITION", changer_name); 41923449Sjoerg 42023449Sjoerg return (0); 42123449Sjoerg 42223449Sjoerg usage: 42339227Sgibbs (void) fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n", 42493101Smarkm getprogname(), cname); 42523449Sjoerg return (1); 42623449Sjoerg} 42723449Sjoerg 42839227Sgibbs/* ARGSUSED */ 42923449Sjoergstatic int 43090107Simpdo_params(const char *cname, int argc, char **argv) 43123449Sjoerg{ 43223449Sjoerg struct changer_params data; 43339876Sken int picker; 43423449Sjoerg 43523449Sjoerg /* No arguments to this command. */ 43639227Sgibbs 43739227Sgibbs ++argv; --argc; 43839227Sgibbs 43923449Sjoerg if (argc) { 44041579Sbde warnx("%s: no arguments expected", cname); 44123449Sjoerg goto usage; 44223449Sjoerg } 44323449Sjoerg 44423449Sjoerg /* Get params from changer and display them. */ 44539227Sgibbs (void) memset(&data, 0, sizeof(data)); 44639227Sgibbs if (ioctl(changer_fd, CHIOGPARAMS, &data)) 44723449Sjoerg err(1, "%s: CHIOGPARAMS", changer_name); 44823449Sjoerg 44939227Sgibbs (void) printf("%s: %d slot%s, %d drive%s, %d picker%s", 45023449Sjoerg changer_name, 45123449Sjoerg data.cp_nslots, (data.cp_nslots > 1) ? "s" : "", 45223449Sjoerg data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "", 45323449Sjoerg data.cp_npickers, (data.cp_npickers > 1) ? "s" : ""); 45423449Sjoerg if (data.cp_nportals) 45539227Sgibbs (void) printf(", %d portal%s", data.cp_nportals, 45623449Sjoerg (data.cp_nportals > 1) ? "s" : ""); 45723449Sjoerg 45839876Sken /* Get current picker from changer and display it. */ 45939876Sken if (ioctl(changer_fd, CHIOGPICKER, &picker)) 46039876Sken err(1, "%s: CHIOGPICKER", changer_name); 46139876Sken 46239876Sken (void) printf("\n%s: current picker: %d\n", changer_name, picker); 46339876Sken 46423449Sjoerg return (0); 46523449Sjoerg 46623449Sjoerg usage: 46793101Smarkm (void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname); 46823449Sjoerg return (1); 46923449Sjoerg} 47023449Sjoerg 47139227Sgibbs/* ARGSUSED */ 47223449Sjoergstatic int 47390107Simpdo_getpicker(const char *cname, int argc, char **argv) 47423449Sjoerg{ 47523449Sjoerg int picker; 47623449Sjoerg 47723449Sjoerg /* No arguments to this command. */ 47839227Sgibbs 47939227Sgibbs ++argv; --argc; 48039227Sgibbs 48123449Sjoerg if (argc) { 48223449Sjoerg warnx("%s: no arguments expected", cname); 48323449Sjoerg goto usage; 48423449Sjoerg } 48523449Sjoerg 48623449Sjoerg /* Get current picker from changer and display it. */ 48739227Sgibbs if (ioctl(changer_fd, CHIOGPICKER, &picker)) 48823449Sjoerg err(1, "%s: CHIOGPICKER", changer_name); 48923449Sjoerg 49039227Sgibbs (void) printf("%s: current picker: %d\n", changer_name, picker); 49123449Sjoerg 49223449Sjoerg return (0); 49323449Sjoerg 49423449Sjoerg usage: 49593101Smarkm (void) fprintf(stderr, "usage: %s %s\n", getprogname(), cname); 49623449Sjoerg return (1); 49723449Sjoerg} 49823449Sjoerg 49923449Sjoergstatic int 50090107Simpdo_setpicker(const char *cname, int argc, char **argv) 50123449Sjoerg{ 50223449Sjoerg int picker; 50323449Sjoerg 50439227Sgibbs ++argv; --argc; 50539227Sgibbs 50623449Sjoerg if (argc < 1) { 50723449Sjoerg warnx("%s: too few arguments", cname); 50823449Sjoerg goto usage; 50923449Sjoerg } else if (argc > 1) { 51023449Sjoerg warnx("%s: too many arguments", cname); 51123449Sjoerg goto usage; 51223449Sjoerg } 51323449Sjoerg 51423449Sjoerg picker = parse_element_unit(*argv); 51523449Sjoerg 51623449Sjoerg /* Set the changer picker. */ 51739227Sgibbs if (ioctl(changer_fd, CHIOSPICKER, &picker)) 51823449Sjoerg err(1, "%s: CHIOSPICKER", changer_name); 51923449Sjoerg 52023449Sjoerg return (0); 52123449Sjoerg 52223449Sjoerg usage: 52393101Smarkm (void) fprintf(stderr, "usage: %s %s <picker>\n", getprogname(), cname); 52423449Sjoerg return (1); 52523449Sjoerg} 52623449Sjoerg 52723449Sjoergstatic int 52890107Simpdo_status(const char *cname, int argc, char **argv) 52923449Sjoerg{ 53039227Sgibbs struct changer_params cp; 53139227Sgibbs struct changer_element_status_request cesr; 53291086Smarkm int i; 53391086Smarkm u_int16_t base, count, chet, schet, echet; 53479121Smikeh const char *description; 53539227Sgibbs int pvoltag = 0; 53639227Sgibbs int avoltag = 0; 53739227Sgibbs int sense = 0; 53839227Sgibbs int scsi = 0; 53939227Sgibbs int source = 0; 54039227Sgibbs int intaddr = 0; 54139227Sgibbs int c; 54223449Sjoerg 54326361Scharnier count = 0; 54439227Sgibbs base = 0; 54526361Scharnier description = NULL; 54626361Scharnier 54739227Sgibbs optind = optreset = 1; 54847442Simp while ((c = getopt(argc, argv, "vVsSbaI")) != -1) { 54939227Sgibbs switch (c) { 55039227Sgibbs case 'v': 55139227Sgibbs pvoltag = 1; 55239227Sgibbs break; 55339227Sgibbs case 'V': 55439227Sgibbs avoltag = 1; 55539227Sgibbs break; 55639227Sgibbs case 's': 55739227Sgibbs sense = 1; 55839227Sgibbs break; 55939227Sgibbs case 'S': 56039227Sgibbs source = 1; 56139227Sgibbs break; 56239227Sgibbs case 'b': 56339227Sgibbs scsi = 1; 56439227Sgibbs break; 56539227Sgibbs case 'I': 56639227Sgibbs intaddr = 1; 56739227Sgibbs break; 56839227Sgibbs case 'a': 56939227Sgibbs pvoltag = avoltag = source = sense = scsi = intaddr = 1; 57039227Sgibbs break; 57139227Sgibbs default: 57241579Sbde warnx("%s: bad option", cname); 57339227Sgibbs goto usage; 57439227Sgibbs } 57539227Sgibbs } 57639227Sgibbs 57739227Sgibbs argc -= optind; 57839227Sgibbs argv += optind; 57939227Sgibbs 58023449Sjoerg /* 58123449Sjoerg * On a status command, we expect the following: 58223449Sjoerg * 58339227Sgibbs * [<ET> [<start> [<end>] ] ] 58423449Sjoerg * 58539227Sgibbs * where ET == element type, start == first element to report, 58639227Sgibbs * end == number of elements to report 58723449Sjoerg * 58823449Sjoerg * If we get no arguments, we get the status of all 58923449Sjoerg * known element types. 59023449Sjoerg */ 59139227Sgibbs if (argc > 3) { 59223449Sjoerg warnx("%s: too many arguments", cname); 59323449Sjoerg goto usage; 59423449Sjoerg } 59523449Sjoerg 59623449Sjoerg /* 59723449Sjoerg * Get params from changer. Specifically, we need the element 59823449Sjoerg * counts. 59923449Sjoerg */ 60039227Sgibbs if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) 60123449Sjoerg err(1, "%s: CHIOGPARAMS", changer_name); 60223449Sjoerg 60339227Sgibbs if (argc > 0) 60439227Sgibbs schet = echet = parse_element_type(argv[0]); 60523449Sjoerg else { 60623449Sjoerg schet = CHET_MT; 60723449Sjoerg echet = CHET_DT; 60823449Sjoerg } 60939227Sgibbs if (argc > 1) { 61091086Smarkm base = (u_int16_t)atol(argv[1]); 61139227Sgibbs count = 1; 61239227Sgibbs } 61339227Sgibbs if (argc > 2) 61491086Smarkm count = (u_int16_t)atol(argv[2]) - base + 1; 61523449Sjoerg 61623449Sjoerg for (chet = schet; chet <= echet; ++chet) { 61723449Sjoerg switch (chet) { 61823449Sjoerg case CHET_MT: 61939227Sgibbs if (count == 0) 62039227Sgibbs count = cp.cp_npickers; 62139227Sgibbs else if (count > cp.cp_npickers) 62239227Sgibbs errx(1, "not that many pickers in device"); 62323449Sjoerg description = "picker"; 62423449Sjoerg break; 62523449Sjoerg 62623449Sjoerg case CHET_ST: 62739227Sgibbs if (count == 0) 62839227Sgibbs count = cp.cp_nslots; 62939227Sgibbs else if (count > cp.cp_nslots) 63039227Sgibbs errx(1, "not that many slots in device"); 63123449Sjoerg description = "slot"; 63223449Sjoerg break; 63323449Sjoerg 63423449Sjoerg case CHET_IE: 63539227Sgibbs if (count == 0) 63639227Sgibbs count = cp.cp_nportals; 63739227Sgibbs else if (count > cp.cp_nportals) 63839227Sgibbs errx(1, "not that many portals in device"); 63923449Sjoerg description = "portal"; 64023449Sjoerg break; 64123449Sjoerg 64223449Sjoerg case CHET_DT: 64339227Sgibbs if (count == 0) 64439227Sgibbs count = cp.cp_ndrives; 64539227Sgibbs else if (count > cp.cp_ndrives) 64639227Sgibbs errx(1, "not that many drives in device"); 64723449Sjoerg description = "drive"; 64823449Sjoerg break; 64939227Sgibbs 65039227Sgibbs default: 65139227Sgibbs /* To appease gcc -Wuninitialized. */ 65239227Sgibbs count = 0; 65339227Sgibbs description = NULL; 65423449Sjoerg } 65523449Sjoerg 65623449Sjoerg if (count == 0) { 65723449Sjoerg if (argc == 0) 65823449Sjoerg continue; 65923449Sjoerg else { 66023449Sjoerg printf("%s: no %s elements\n", 66123449Sjoerg changer_name, description); 66223449Sjoerg return (0); 66323449Sjoerg } 66423449Sjoerg } 66523449Sjoerg 66639227Sgibbs bzero(&cesr, sizeof(cesr)); 66739227Sgibbs cesr.cesr_element_type = chet; 66839227Sgibbs cesr.cesr_element_base = base; 66939227Sgibbs cesr.cesr_element_count = count; 67039227Sgibbs /* Allocate storage for the status structures. */ 67166019Sken cesr.cesr_element_status = 67266019Sken (struct changer_element_status *) 67379253Smikeh calloc((size_t)count, sizeof(struct changer_element_status)); 67439227Sgibbs 67539227Sgibbs if (!cesr.cesr_element_status) 67623449Sjoerg errx(1, "can't allocate status storage"); 67723449Sjoerg 67839227Sgibbs if (avoltag || pvoltag) 67939227Sgibbs cesr.cesr_flags |= CESR_VOLTAGS; 68023449Sjoerg 68139227Sgibbs if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr)) { 68239227Sgibbs free(cesr.cesr_element_status); 68323449Sjoerg err(1, "%s: CHIOGSTATUS", changer_name); 68423449Sjoerg } 68523449Sjoerg 68639227Sgibbs /* Dump the status for each reported element. */ 68723449Sjoerg for (i = 0; i < count; ++i) { 68839227Sgibbs struct changer_element_status *ces = 68939227Sgibbs &(cesr.cesr_element_status[i]); 69039227Sgibbs printf("%s %d: %s", description, ces->ces_addr, 69139227Sgibbs bits_to_string(ces->ces_flags, 69239227Sgibbs CESTATUS_BITS)); 69339227Sgibbs if (sense) 69439227Sgibbs printf(" sense: <0x%02x/0x%02x>", 69539227Sgibbs ces->ces_sensecode, 69639227Sgibbs ces->ces_sensequal); 69739227Sgibbs if (pvoltag) 69839227Sgibbs printf(" voltag: <%s:%d>", 69939227Sgibbs ces->ces_pvoltag.cv_volid, 70039227Sgibbs ces->ces_pvoltag.cv_serial); 70139227Sgibbs if (avoltag) 70239227Sgibbs printf(" avoltag: <%s:%d>", 70339227Sgibbs ces->ces_avoltag.cv_volid, 70439227Sgibbs ces->ces_avoltag.cv_serial); 70546073Simp if (source) { 70639227Sgibbs if (ces->ces_flags & CES_SOURCE_VALID) 70739227Sgibbs printf(" source: <%s %d>", 70839227Sgibbs element_type_name( 70939227Sgibbs ces->ces_source_type), 71039227Sgibbs ces->ces_source_addr); 71139227Sgibbs else 71239227Sgibbs printf(" source: <>"); 71346073Simp } 71439227Sgibbs if (intaddr) 71539227Sgibbs printf(" intaddr: <%d>", ces->ces_int_addr); 71639227Sgibbs if (scsi) { 71739227Sgibbs printf(" scsi: <"); 71839227Sgibbs if (ces->ces_flags & CES_SCSIID_VALID) 71939227Sgibbs printf("%d", ces->ces_scsi_id); 72039227Sgibbs else 72139227Sgibbs putchar('?'); 72239227Sgibbs putchar(':'); 72339227Sgibbs if (ces->ces_flags & CES_LUN_VALID) 72439227Sgibbs printf("%d", ces->ces_scsi_lun); 72539227Sgibbs else 72639227Sgibbs putchar('?'); 72739227Sgibbs putchar('>'); 72839227Sgibbs } 729252214Sken if (ces->ces_designator_length > 0) 730252214Sken print_designator(ces->ces_designator, 731252214Sken ces->ces_code_set, 732252214Sken ces->ces_designator_length); 73339227Sgibbs putchar('\n'); 73423449Sjoerg } 73523449Sjoerg 73639227Sgibbs free(cesr.cesr_element_status); 73739227Sgibbs count = 0; 73823449Sjoerg } 73923449Sjoerg 74023449Sjoerg return (0); 74123449Sjoerg 74223449Sjoerg usage: 74339227Sgibbs (void) fprintf(stderr, "usage: %s %s [-vVsSbaA] [<element type> [<start-addr> [<end-addr>] ] ]\n", 74493101Smarkm getprogname(), cname); 74523449Sjoerg return (1); 74623449Sjoerg} 74723449Sjoerg 74823449Sjoergstatic int 74990107Simpdo_ielem(const char *cname, int argc, char **argv) 75023449Sjoerg{ 75139227Sgibbs int timeout = 0; 75239227Sgibbs 75339227Sgibbs if (argc == 2) { 75439227Sgibbs timeout = atol(argv[1]); 75539227Sgibbs } else if (argc > 1) { 75639227Sgibbs warnx("%s: too many arguments", cname); 75739227Sgibbs goto usage; 75839227Sgibbs } 75939227Sgibbs 76039227Sgibbs if (ioctl(changer_fd, CHIOIELEM, &timeout)) 76139227Sgibbs err(1, "%s: CHIOIELEM", changer_name); 76239227Sgibbs 76339227Sgibbs return (0); 76439227Sgibbs 76539227Sgibbs usage: 76639227Sgibbs (void) fprintf(stderr, "usage: %s %s [<timeout>]\n", 76793101Smarkm getprogname(), cname); 76839227Sgibbs return (1); 76939227Sgibbs} 77039227Sgibbs 77139227Sgibbsstatic int 77290107Simpdo_voltag(const char *cname, int argc, char **argv) 77339227Sgibbs{ 77439227Sgibbs int force = 0; 77539227Sgibbs int clear = 0; 77639227Sgibbs int alternate = 0; 77739227Sgibbs int c; 77839227Sgibbs struct changer_set_voltag_request csvr; 77939227Sgibbs 78039227Sgibbs bzero(&csvr, sizeof(csvr)); 78139227Sgibbs 78239227Sgibbs optind = optreset = 1; 78347442Simp while ((c = getopt(argc, argv, "fca")) != -1) { 78439227Sgibbs switch (c) { 78539227Sgibbs case 'f': 78639227Sgibbs force = 1; 78739227Sgibbs break; 78839227Sgibbs case 'c': 78939227Sgibbs clear = 1; 79039227Sgibbs break; 79139227Sgibbs case 'a': 79239227Sgibbs alternate = 1; 79339227Sgibbs break; 79439227Sgibbs default: 79541579Sbde warnx("%s: bad option", cname); 79639227Sgibbs goto usage; 79739227Sgibbs } 79839227Sgibbs } 79939227Sgibbs 80039227Sgibbs argc -= optind; 80139227Sgibbs argv += optind; 80239227Sgibbs 80339227Sgibbs if (argc < 2) { 80441579Sbde warnx("%s: missing element specification", cname); 80539227Sgibbs goto usage; 80639227Sgibbs } 80739227Sgibbs 80839227Sgibbs csvr.csvr_type = parse_element_type(argv[0]); 80991086Smarkm csvr.csvr_addr = (u_int16_t)atol(argv[1]); 81039227Sgibbs 81139227Sgibbs if (!clear) { 81239227Sgibbs if (argc < 3 || argc > 4) { 81341579Sbde warnx("%s: missing argument", cname); 81439227Sgibbs goto usage; 81539227Sgibbs } 81639227Sgibbs 81739227Sgibbs if (force) 81839227Sgibbs csvr.csvr_flags = CSVR_MODE_REPLACE; 81939227Sgibbs else 82039227Sgibbs csvr.csvr_flags = CSVR_MODE_SET; 82139227Sgibbs 82239227Sgibbs if (strlen(argv[2]) > sizeof(csvr.csvr_voltag.cv_volid)) { 82341579Sbde warnx("%s: volume label too long", cname); 82439227Sgibbs goto usage; 82539227Sgibbs } 82639227Sgibbs 82779253Smikeh strlcpy((char *)csvr.csvr_voltag.cv_volid, argv[2], 82839227Sgibbs sizeof(csvr.csvr_voltag.cv_volid)); 82939227Sgibbs 83039227Sgibbs if (argc == 4) { 83191086Smarkm csvr.csvr_voltag.cv_serial = (u_int16_t)atol(argv[3]); 83239227Sgibbs } 83339227Sgibbs } else { 83439227Sgibbs if (argc != 2) { 83541579Sbde warnx("%s: unexpected argument", cname); 83639227Sgibbs goto usage; 83739227Sgibbs } 83839227Sgibbs csvr.csvr_flags = CSVR_MODE_CLEAR; 83939227Sgibbs } 84039227Sgibbs 84139227Sgibbs if (alternate) { 84239227Sgibbs csvr.csvr_flags |= CSVR_ALTERNATE; 84339227Sgibbs } 84439227Sgibbs 84539227Sgibbs if (ioctl(changer_fd, CHIOSETVOLTAG, &csvr)) 84639227Sgibbs err(1, "%s: CHIOSETVOLTAG", changer_name); 84739227Sgibbs 84839227Sgibbs return 0; 84939227Sgibbs usage: 85039227Sgibbs (void) fprintf(stderr, 85139227Sgibbs "usage: %s %s [-fca] <element> [<voltag> [<vsn>] ]\n", 85293101Smarkm getprogname(), cname); 85339227Sgibbs return 1; 85439227Sgibbs} 85539227Sgibbs 85691086Smarkmstatic u_int16_t 85790107Simpparse_element_type(char *cp) 85839227Sgibbs{ 85923449Sjoerg int i; 86023449Sjoerg 86123449Sjoerg for (i = 0; elements[i].et_name != NULL; ++i) 86223449Sjoerg if (strcmp(elements[i].et_name, cp) == 0) 86391086Smarkm return ((u_int16_t)elements[i].et_type); 86423449Sjoerg 86523449Sjoerg errx(1, "invalid element type `%s'", cp); 86639227Sgibbs /* NOTREACHED */ 86723449Sjoerg} 86823449Sjoerg 86939227Sgibbsstatic const char * 87090107Simpelement_type_name(int et) 87139227Sgibbs{ 87239227Sgibbs int i; 87339227Sgibbs 87439227Sgibbs for (i = 0; elements[i].et_name != NULL; i++) 87539227Sgibbs if (elements[i].et_type == et) 87639227Sgibbs return elements[i].et_name; 87739227Sgibbs 87839227Sgibbs return "unknown"; 87939227Sgibbs} 88039227Sgibbs 88191086Smarkmstatic u_int16_t 88290107Simpparse_element_unit(char *cp) 88323449Sjoerg{ 88423449Sjoerg int i; 88523449Sjoerg char *p; 88623449Sjoerg 88723449Sjoerg i = (int)strtol(cp, &p, 10); 88823449Sjoerg if ((i < 0) || (*p != '\0')) 88923449Sjoerg errx(1, "invalid unit number `%s'", cp); 89023449Sjoerg 89191086Smarkm return ((u_int16_t)i); 89223449Sjoerg} 89323449Sjoerg 89423449Sjoergstatic int 89590107Simpparse_special(char *cp) 89623449Sjoerg{ 89723449Sjoerg int val; 89823449Sjoerg 89923449Sjoerg val = is_special(cp); 90023449Sjoerg if (val) 90123449Sjoerg return (val); 90223449Sjoerg 90323449Sjoerg errx(1, "invalid modifier `%s'", cp); 90439227Sgibbs /* NOTREACHED */ 90523449Sjoerg} 90623449Sjoerg 90723449Sjoergstatic int 90890107Simpis_special(char *cp) 90923449Sjoerg{ 91023449Sjoerg int i; 91123449Sjoerg 91223449Sjoerg for (i = 0; specials[i].sw_name != NULL; ++i) 91323449Sjoerg if (strcmp(specials[i].sw_name, cp) == 0) 91423449Sjoerg return (specials[i].sw_value); 91523449Sjoerg 91623449Sjoerg return (0); 91723449Sjoerg} 91823449Sjoerg 91948073Skrisstatic const char * 92090107Simpbits_to_string(ces_status_flags v, const char *cp) 92123449Sjoerg{ 92223449Sjoerg const char *np; 92323449Sjoerg char f, sep, *bp; 92423449Sjoerg static char buf[128]; 92523449Sjoerg 92623449Sjoerg bp = buf; 92739227Sgibbs (void) memset(buf, 0, sizeof(buf)); 92823449Sjoerg 92923449Sjoerg for (sep = '<'; (f = *cp++) != 0; cp = np) { 93023449Sjoerg for (np = cp; *np >= ' ';) 93123449Sjoerg np++; 93291086Smarkm if (((int)v & (1 << (f - 1))) == 0) 93323449Sjoerg continue; 93491086Smarkm (void) snprintf(bp, sizeof(buf) - (size_t)(bp - &buf[0]), 93548073Skris "%c%.*s", sep, (int)(long)(np - cp), cp); 93647816Skris bp += strlen(bp); 93723449Sjoerg sep = ','; 93823449Sjoerg } 93923449Sjoerg if (sep != '<') 94023449Sjoerg *bp = '>'; 94123449Sjoerg 94223449Sjoerg return (buf); 94323449Sjoerg} 94466019Sken/* 94566019Sken * do_return() 94666019Sken * 94766019Sken * Given an element reference, ask the changer/picker to move that 94866019Sken * element back to its source slot. 94966019Sken */ 95066019Skenstatic int 95190107Simpdo_return(const char *cname, int argc, char **argv) 95266019Sken{ 95366019Sken struct changer_element_status *ces; 95466019Sken struct changer_move cmd; 95591665Simp uint16_t type, element; 95623449Sjoerg 95766019Sken ++argv; --argc; 95866019Sken 95966019Sken if (argc < 2) { 96066019Sken warnx("%s: too few arguments", cname); 96166019Sken goto usage; 96266019Sken } else if (argc > 3) { 96366019Sken warnx("%s: too many arguments", cname); 96466019Sken goto usage; 96566019Sken } 96666019Sken 96766019Sken type = parse_element_type(*argv); 96866019Sken ++argv; --argc; 96966019Sken 97066019Sken /* Handle voltag virtual Changer Element Type */ 97166019Sken if (CHET_VT == type) { 97266019Sken find_element(*argv, &type, &element); 97366019Sken } else { 97466019Sken element = parse_element_unit(*argv); 97566019Sken } 97666019Sken ++argv; --argc; 97766019Sken 97879253Smikeh /* Get the status */ 979184484Sjoerg ces = get_element_status((unsigned int)type, (unsigned int)element, 980184484Sjoerg CHET_VT == type); 98166019Sken 98266019Sken if (NULL == ces) 98366019Sken errx(1, "%s: null element status pointer", cname); 98466019Sken 98566019Sken if (!(ces->ces_flags & CES_SOURCE_VALID)) 98666019Sken errx(1, "%s: no source information", cname); 98766019Sken 98866019Sken (void) memset(&cmd, 0, sizeof(cmd)); 98966019Sken 99066019Sken cmd.cm_fromtype = type; 99166019Sken cmd.cm_fromunit = element; 99266019Sken cmd.cm_totype = ces->ces_source_type; 99366019Sken cmd.cm_tounit = ces->ces_source_addr; 99466019Sken 99566019Sken if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1) 99666019Sken err(1, "%s: CHIOMOVE", changer_name); 99766019Sken free(ces); 99866019Sken 99966019Sken return(0); 100066019Sken 100166019Skenusage: 100266019Sken (void) fprintf(stderr, "usage: %s %s " 100393101Smarkm "<from ET> <from EU>\n", getprogname(), cname); 100466019Sken return(1); 100566019Sken} 100666019Sken 100766019Sken/* 100866019Sken * get_element_status() 100966019Sken * 101066019Sken * return a *cesr for the specified changer element. This 101166019Sken * routing will malloc()/calloc() the memory. The caller 101266019Sken * should free() it when done. 101366019Sken */ 101466019Skenstatic struct changer_element_status * 1015184484Sjoergget_element_status(unsigned int type, unsigned int element, int use_voltags) 101666019Sken{ 101766019Sken struct changer_element_status_request cesr; 101866019Sken struct changer_element_status *ces; 101966019Sken 102066019Sken ces = (struct changer_element_status *) 102179253Smikeh calloc((size_t)1, sizeof(struct changer_element_status)); 102266019Sken 102366019Sken if (NULL == ces) 102466019Sken errx(1, "can't allocate status storage"); 102566019Sken 102666019Sken (void)memset(&cesr, 0, sizeof(cesr)); 102766019Sken 102891665Simp cesr.cesr_element_type = (uint16_t)type; 102991665Simp cesr.cesr_element_base = (uint16_t)element; 103066019Sken cesr.cesr_element_count = 1; /* Only this one element */ 1031184484Sjoerg if (use_voltags) 1032184484Sjoerg cesr.cesr_flags |= CESR_VOLTAGS; /* Grab voltags as well */ 103366019Sken cesr.cesr_element_status = ces; 103466019Sken 103566019Sken if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 103666019Sken free(ces); 103766019Sken err(1, "%s: CHIOGSTATUS", changer_name); 103866019Sken /* NOTREACHED */ 103966019Sken } 104066019Sken 104166019Sken return ces; 104266019Sken} 104366019Sken 104466019Sken 104566019Sken/* 104666019Sken * find_element() 104766019Sken * 104866019Sken * Given a <voltag> find the chager element and unit, or exit 104966019Sken * with an error if it isn't found. We grab the changer status 105066019Sken * and iterate until we find a match, or crap out. 105166019Sken */ 105223449Sjoergstatic void 105391665Simpfind_element(char *voltag, uint16_t *et, uint16_t *eu) 105466019Sken{ 105566019Sken struct changer_params cp; 105666019Sken struct changer_element_status_request cesr; 105766019Sken struct changer_element_status *ch_ces, *ces; 105879253Smikeh int found = 0; 105979253Smikeh size_t elem, total_elem; 106066019Sken 106166019Sken /* 106266019Sken * Get the changer parameters, we're interested in the counts 106366019Sken * for all types of elements to perform our search. 106466019Sken */ 106566019Sken if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) 106666019Sken err(1, "%s: CHIOGPARAMS", changer_name); 106766019Sken 106866019Sken /* Allocate some memory for the results */ 106966019Sken total_elem = (cp.cp_nslots + cp.cp_ndrives 107066019Sken + cp.cp_npickers + cp.cp_nportals); 107166019Sken 107266019Sken ch_ces = (struct changer_element_status *) 107366019Sken calloc(total_elem, sizeof(struct changer_element_status)); 107466019Sken 107566019Sken if (NULL == ch_ces) 107666019Sken errx(1, "can't allocate status storage"); 107766019Sken 107866019Sken ces = ch_ces; 107966019Sken 108066019Sken /* Read in the changer slots */ 108166019Sken if (cp.cp_nslots > 0) { 1082208730Suqs (void) memset(&cesr, 0, sizeof(cesr)); 108366019Sken cesr.cesr_element_type = CHET_ST; 108466019Sken cesr.cesr_element_base = 0; 108566019Sken cesr.cesr_element_count = cp.cp_nslots; 108666019Sken cesr.cesr_flags |= CESR_VOLTAGS; 108766019Sken cesr.cesr_element_status = ces; 108866019Sken 108966019Sken if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 109066019Sken free(ch_ces); 109166019Sken err(1, "%s: CHIOGSTATUS", changer_name); 109266019Sken } 109366019Sken ces += cp.cp_nslots; 109466019Sken } 109566019Sken 109666019Sken /* Read in the drive information */ 109766019Sken if (cp.cp_ndrives > 0 ) { 109866019Sken 109966019Sken (void) memset(&cesr, 0, sizeof(cesr)); 110066019Sken cesr.cesr_element_type = CHET_DT; 110166019Sken cesr.cesr_element_base = 0; 110266019Sken cesr.cesr_element_count = cp.cp_ndrives; 110366019Sken cesr.cesr_flags |= CESR_VOLTAGS; 110466019Sken cesr.cesr_element_status = ces; 110566019Sken 110666019Sken if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 110766019Sken free(ch_ces); 110866019Sken err(1, "%s: CHIOGSTATUS", changer_name); 110966019Sken } 111066019Sken ces += cp.cp_ndrives; 111166019Sken } 111266019Sken 111366019Sken /* Read in the portal information */ 111466019Sken if (cp.cp_nportals > 0 ) { 111566019Sken (void) memset(&cesr, 0, sizeof(cesr)); 111666019Sken cesr.cesr_element_type = CHET_IE; 111766019Sken cesr.cesr_element_base = 0; 111866019Sken cesr.cesr_element_count = cp.cp_nportals; 111966019Sken cesr.cesr_flags |= CESR_VOLTAGS; 112066019Sken cesr.cesr_element_status = ces; 112166019Sken 112266019Sken if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 112366019Sken free(ch_ces); 112466019Sken err(1, "%s: CHIOGSTATUS", changer_name); 112566019Sken } 112666019Sken ces += cp.cp_nportals; 112766019Sken } 112866019Sken 112966019Sken /* Read in the picker information */ 113066019Sken if (cp.cp_npickers > 0) { 113166019Sken (void) memset(&cesr, 0, sizeof(cesr)); 113266019Sken cesr.cesr_element_type = CHET_MT; 113366019Sken cesr.cesr_element_base = 0; 113466019Sken cesr.cesr_element_count = cp.cp_npickers; 113566019Sken cesr.cesr_flags |= CESR_VOLTAGS; 113666019Sken cesr.cesr_element_status = ces; 113766019Sken 113866019Sken if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { 113966019Sken free(ch_ces); 114066019Sken err(1, "%s: CHIOGSTATUS", changer_name); 114166019Sken } 114266019Sken } 114366019Sken 114466019Sken /* 114566019Sken * Now search the list the specified <voltag> 114666019Sken */ 114766019Sken for (elem = 0; elem <= total_elem; ++elem) { 114866019Sken 114966019Sken ces = &ch_ces[elem]; 115066019Sken 115166019Sken /* Make sure we have a tape in this element */ 115266019Sken if ((ces->ces_flags & (CES_STATUS_ACCESS|CES_STATUS_FULL)) 115366019Sken != (CES_STATUS_ACCESS|CES_STATUS_FULL)) 115466019Sken continue; 115566019Sken 115666019Sken /* Check to see if it is our target */ 115779253Smikeh if (strcasecmp(voltag, 115879253Smikeh (const char *)ces->ces_pvoltag.cv_volid) == 0) { 115966019Sken *et = ces->ces_type; 116066019Sken *eu = ces->ces_addr; 116166019Sken ++found; 116266019Sken break; 116366019Sken } 116466019Sken } 116566019Sken if (!found) { 116666019Sken errx(1, "%s: unable to locate voltag: %s", changer_name, 116766019Sken voltag); 116866019Sken } 116966019Sken free(ch_ces); 117066019Sken return; 117166019Sken} 117266019Sken 117366019Skenstatic void 117490107Simpcleanup(void) 117523449Sjoerg{ 117623449Sjoerg /* Simple enough... */ 117723449Sjoerg (void)close(changer_fd); 117823449Sjoerg} 117923449Sjoerg 118023449Sjoergstatic void 118190107Simpusage(void) 118223449Sjoerg{ 118390107Simp (void)fprintf(stderr, "usage: %s [-f changer] command [-<flags>] " 118493101Smarkm "arg1 arg2 [arg3 [...]]\n", getprogname()); 118523449Sjoerg exit(1); 118623449Sjoerg} 1187252214Sken 1188252214Sken#define UTF8CODESET "UTF-8" 1189252214Sken 1190252214Skenstatic void 1191252214Skenprint_designator(const char *designator, u_int8_t code_set, 1192252214Sken u_int8_t designator_length) 1193252214Sken{ 1194252214Sken printf(" serial number: <"); 1195252214Sken switch (code_set) { 1196252214Sken case CES_CODE_SET_ASCII: { 1197252214Sken /* 1198252214Sken * The driver insures that the string is always NUL terminated. 1199252214Sken */ 1200252214Sken printf("%s", designator); 1201252214Sken break; 1202252214Sken } 1203252214Sken case CES_CODE_SET_UTF_8: { 1204252214Sken char *cs_native; 1205252214Sken 1206252214Sken setlocale(LC_ALL, ""); 1207252214Sken cs_native = nl_langinfo(CODESET); 1208252214Sken 1209252214Sken /* See if we can natively print UTF-8 */ 1210252214Sken if (strcmp(cs_native, UTF8CODESET) == 0) 1211252214Sken cs_native = NULL; 1212252214Sken 1213252214Sken if (cs_native == NULL) { 1214252214Sken /* We can natively print UTF-8, so use printf. */ 1215252214Sken printf("%s", designator); 1216252214Sken } else { 1217252214Sken int i; 1218252214Sken 1219252214Sken /* 1220252214Sken * We can't natively print UTF-8. We should 1221252214Sken * convert it to the terminal's codeset, but that 1222252214Sken * requires iconv(3) and FreeBSD doesn't have 1223252214Sken * iconv(3) in the base system yet. So we use %XX 1224252214Sken * notation for non US-ASCII characters instead. 1225252214Sken */ 1226252214Sken for (i = 0; i < designator_length && 1227252214Sken designator[i] != '\0'; i++) { 1228252214Sken if ((unsigned char)designator[i] < 0x80) 1229252214Sken printf("%c", designator[i]); 1230252214Sken else 1231252214Sken printf("%%%02x", 1232252214Sken (unsigned char)designator[i]); 1233252214Sken } 1234252214Sken } 1235252214Sken break; 1236252214Sken } 1237252214Sken case CES_CODE_SET_BINARY: { 1238252214Sken int i; 1239252214Sken 1240252214Sken for (i = 0; i < designator_length; i++) 1241252214Sken printf("%02X%s", designator[i], 1242252214Sken (i == designator_length - 1) ? "" : " "); 1243252214Sken break; 1244252214Sken } 1245252214Sken default: 1246252214Sken break; 1247252214Sken } 1248252214Sken printf(">"); 1249252214Sken} 1250