1*c4a732d1Sbeck /* $OpenBSD: chio.c,v 1.16 2006/05/31 03:04:52 beck Exp $ */ 2c16b380fSderaadt /* $NetBSD: chio.c,v 1.1.1.1 1996/04/03 00:34:38 thorpej Exp $ */ 3c16b380fSderaadt 4c16b380fSderaadt /* 5c16b380fSderaadt * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com> 6c16b380fSderaadt * All rights reserved. 7c16b380fSderaadt * 8c16b380fSderaadt * Redistribution and use in source and binary forms, with or without 9c16b380fSderaadt * modification, are permitted provided that the following conditions 10c16b380fSderaadt * are met: 11c16b380fSderaadt * 1. Redistributions of source code must retain the above copyright 12c16b380fSderaadt * notice, this list of conditions and the following disclaimer. 13c16b380fSderaadt * 2. Redistributions in binary form must reproduce the above copyright 14c16b380fSderaadt * notice, this list of conditions and the following disclaimer in the 15c16b380fSderaadt * documentation and/or other materials provided with the distribution. 16c16b380fSderaadt * 3. All advertising materials mentioning features or use of this software 17d9248734Stodd * must display the following acknowledgments: 18c16b380fSderaadt * This product includes software developed by Jason R. Thorpe 19c16b380fSderaadt * for And Communications, http://www.and.com/ 20c16b380fSderaadt * 4. The name of the author may not be used to endorse or promote products 21c16b380fSderaadt * derived from this software without specific prior written permission. 22c16b380fSderaadt * 23c16b380fSderaadt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24c16b380fSderaadt * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25c16b380fSderaadt * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26c16b380fSderaadt * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27c16b380fSderaadt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28c16b380fSderaadt * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29c16b380fSderaadt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30c16b380fSderaadt * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31c16b380fSderaadt * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32c16b380fSderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33c16b380fSderaadt * SUCH DAMAGE. 34c16b380fSderaadt */ 35c16b380fSderaadt 36c16b380fSderaadt #include <sys/param.h> 37c16b380fSderaadt #include <sys/ioctl.h> 38b2b21931Sbeck #include <sys/mtio.h> 39c16b380fSderaadt #include <sys/chio.h> 40c16b380fSderaadt #include <err.h> 41c16b380fSderaadt #include <errno.h> 42c16b380fSderaadt #include <fcntl.h> 43c16b380fSderaadt #include <limits.h> 44c16b380fSderaadt #include <stdio.h> 45c16b380fSderaadt #include <stdlib.h> 46c16b380fSderaadt #include <string.h> 47c16b380fSderaadt #include <unistd.h> 48b2b21931Sbeck #include <util.h> 49c16b380fSderaadt 50c16b380fSderaadt #include "defs.h" 51c16b380fSderaadt #include "pathnames.h" 52c16b380fSderaadt 53b2b21931Sbeck #define _PATH_CH_CONF "/etc/chio.conf" 54b2b21931Sbeck extern char *parse_tapedev(const char *, const char *, int); /* parse.y */ 55c16b380fSderaadt extern char *__progname; /* from crt0.o */ 56c16b380fSderaadt 57c72b5b24Smillert static void usage(void); 58c72b5b24Smillert static int parse_element_type(char *); 59c72b5b24Smillert static int parse_element_unit(char *); 60c72b5b24Smillert static int parse_special(char *); 61c72b5b24Smillert static int is_special(char *); 62c72b5b24Smillert static char *bits_to_string(int, const char *); 63c16b380fSderaadt 64c72b5b24Smillert static int do_move(char *, int, char **); 65c72b5b24Smillert static int do_exchange(char *, int, char **); 66c72b5b24Smillert static int do_position(char *, int, char **); 67c72b5b24Smillert static int do_params(char *, int, char **); 68c72b5b24Smillert static int do_getpicker(char *, int, char **); 69c72b5b24Smillert static int do_setpicker(char *, int, char **); 70c72b5b24Smillert static int do_status(char *, int, char **); 71c16b380fSderaadt 72c16b380fSderaadt /* Valid changer element types. */ 73c16b380fSderaadt const struct element_type elements[] = { 74c16b380fSderaadt { "drive", CHET_DT }, 75b13cd761Sderaadt { "picker", CHET_MT }, 76b13cd761Sderaadt { "portal", CHET_IE }, 77b13cd761Sderaadt { "slot", CHET_ST }, 78c16b380fSderaadt { NULL, 0 }, 79c16b380fSderaadt }; 80c16b380fSderaadt 81c16b380fSderaadt /* Valid commands. */ 82c16b380fSderaadt const struct changer_command commands[] = { 83c16b380fSderaadt { "exchange", do_exchange }, 84c16b380fSderaadt { "getpicker", do_getpicker }, 85b13cd761Sderaadt { "move", do_move }, 86b13cd761Sderaadt { "params", do_params }, 87b13cd761Sderaadt { "position", do_position }, 88c16b380fSderaadt { "setpicker", do_setpicker }, 89c16b380fSderaadt { "status", do_status }, 90c16b380fSderaadt { NULL, 0 }, 91c16b380fSderaadt }; 92c16b380fSderaadt 93c16b380fSderaadt /* Valid special words. */ 94c16b380fSderaadt const struct special_word specials[] = { 95c16b380fSderaadt { "inv", SW_INVERT }, 96c16b380fSderaadt { "inv1", SW_INVERT1 }, 97c16b380fSderaadt { "inv2", SW_INVERT2 }, 98c16b380fSderaadt { NULL, 0 }, 99c16b380fSderaadt }; 100c16b380fSderaadt 101c16b380fSderaadt static int changer_fd; 102c16b380fSderaadt static char *changer_name; 103*c4a732d1Sbeck static int avoltag; 104*c4a732d1Sbeck static int pvoltag; 105c16b380fSderaadt 106c16b380fSderaadt int 107ab83b6d6Sderaadt main(int argc, char *argv[]) 108c16b380fSderaadt { 109c16b380fSderaadt int ch, i; 110c16b380fSderaadt 111*c4a732d1Sbeck while ((ch = getopt(argc, argv, "af:vV")) != -1) { 112c16b380fSderaadt switch (ch) { 113*c4a732d1Sbeck case 'v': 114*c4a732d1Sbeck pvoltag = 1; 115*c4a732d1Sbeck break; 116*c4a732d1Sbeck case 'V': 117*c4a732d1Sbeck avoltag = 1; 118*c4a732d1Sbeck break; 119c16b380fSderaadt case 'f': 120c16b380fSderaadt changer_name = optarg; 121c16b380fSderaadt break; 122*c4a732d1Sbeck case 'a': 123*c4a732d1Sbeck pvoltag = avoltag = 1; 124*c4a732d1Sbeck break; 125c16b380fSderaadt default: 126c16b380fSderaadt usage(); 127c16b380fSderaadt } 128c16b380fSderaadt } 129c16b380fSderaadt argc -= optind; 130c16b380fSderaadt argv += optind; 131c16b380fSderaadt 132c16b380fSderaadt if (argc == 0) 133c16b380fSderaadt usage(); 134c16b380fSderaadt 135c16b380fSderaadt /* Get the default changer if not already specified. */ 136c16b380fSderaadt if (changer_name == NULL) 137c16b380fSderaadt if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL) 138c16b380fSderaadt changer_name = _PATH_CH; 139c16b380fSderaadt 140c16b380fSderaadt /* Open the changer device. */ 141c16b380fSderaadt if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1) 142c16b380fSderaadt err(1, "%s: open", changer_name); 143c16b380fSderaadt 144c16b380fSderaadt /* Find the specified command. */ 145c16b380fSderaadt for (i = 0; commands[i].cc_name != NULL; ++i) 146c16b380fSderaadt if (strcmp(*argv, commands[i].cc_name) == 0) 147c16b380fSderaadt break; 148b13cd761Sderaadt if (commands[i].cc_name == NULL) { 149b13cd761Sderaadt /* look for abbreviation */ 150b13cd761Sderaadt for (i = 0; commands[i].cc_name != NULL; ++i) 151b13cd761Sderaadt if (strncmp(*argv, commands[i].cc_name, 152b13cd761Sderaadt strlen(*argv)) == 0) 153b13cd761Sderaadt break; 154b13cd761Sderaadt } 155c16b380fSderaadt if (commands[i].cc_name == NULL) 156c16b380fSderaadt errx(1, "unknown command: %s", *argv); 157c16b380fSderaadt 158c16b380fSderaadt /* Skip over the command name and call handler. */ 159c16b380fSderaadt ++argv; --argc; 160c16b380fSderaadt exit((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); 161c16b380fSderaadt } 162c16b380fSderaadt 163c16b380fSderaadt static int 164ab83b6d6Sderaadt do_move(char *cname, int argc, char *argv[]) 165c16b380fSderaadt { 166c16b380fSderaadt struct changer_move cmd; 167c16b380fSderaadt int val; 168c16b380fSderaadt 169c16b380fSderaadt /* 170c16b380fSderaadt * On a move command, we expect the following: 171c16b380fSderaadt * 172c16b380fSderaadt * <from ET> <from EU> <to ET> <to EU> [inv] 173c16b380fSderaadt * 174c16b380fSderaadt * where ET == element type and EU == element unit. 175c16b380fSderaadt */ 176c16b380fSderaadt if (argc < 4) { 177c16b380fSderaadt warnx("%s: too few arguments", cname); 178c16b380fSderaadt goto usage; 179c16b380fSderaadt } else if (argc > 5) { 180c16b380fSderaadt warnx("%s: too many arguments", cname); 181c16b380fSderaadt goto usage; 182c16b380fSderaadt } 183c16b380fSderaadt bzero(&cmd, sizeof(cmd)); 184c16b380fSderaadt 185c16b380fSderaadt /* <from ET> */ 186c16b380fSderaadt cmd.cm_fromtype = parse_element_type(*argv); 187c16b380fSderaadt ++argv; --argc; 188c16b380fSderaadt 189c16b380fSderaadt /* <from EU> */ 190c16b380fSderaadt cmd.cm_fromunit = parse_element_unit(*argv); 191c16b380fSderaadt ++argv; --argc; 192c16b380fSderaadt 193b2b21931Sbeck if (cmd.cm_fromtype == CHET_DT) { 194b2b21931Sbeck /* 195b2b21931Sbeck * from unit is a drive - make sure the tape 196b2b21931Sbeck * in it is unmounted before we attempt to move 197b2b21931Sbeck * it to avoid errors in "disconnected" type 198b2b21931Sbeck * pickers where the drive is on a seperate target 199b2b21931Sbeck * from the changer. 200b2b21931Sbeck */ 201b2b21931Sbeck int mtfd; 202b2b21931Sbeck struct mtop mtoffl = { MTOFFL, 1 }; 203252f0782Shenning char *tapedev = 204252f0782Shenning parse_tapedev(_PATH_CH_CONF, changer_name, cmd.cm_fromunit); 205b2b21931Sbeck mtfd = opendev(tapedev, O_RDONLY, OPENDEV_PART | OPENDEV_DRCT, 206b2b21931Sbeck NULL); 207b2b21931Sbeck if (mtfd == -1) 208b2b21931Sbeck err(1, "%s drive %d (%s): open", changer_name, 209b2b21931Sbeck cmd.cm_fromunit, tapedev); 210b2b21931Sbeck if (ioctl(mtfd, MTIOCTOP, &mtoffl) == -1) 211b2b21931Sbeck err(1, "%s drive %d (%s): rewoffl", changer_name, 212b2b21931Sbeck cmd.cm_fromunit, tapedev); 213b2b21931Sbeck close(mtfd); 214b2b21931Sbeck } 215b2b21931Sbeck 216c16b380fSderaadt /* <to ET> */ 217c16b380fSderaadt cmd.cm_totype = parse_element_type(*argv); 218c16b380fSderaadt ++argv; --argc; 219c16b380fSderaadt 220c16b380fSderaadt /* <to EU> */ 221c16b380fSderaadt cmd.cm_tounit = parse_element_unit(*argv); 222c16b380fSderaadt ++argv; --argc; 223c16b380fSderaadt 224c16b380fSderaadt /* Deal with optional command modifier. */ 225c16b380fSderaadt if (argc) { 226c16b380fSderaadt val = parse_special(*argv); 227c16b380fSderaadt switch (val) { 228c16b380fSderaadt case SW_INVERT: 229c16b380fSderaadt cmd.cm_flags |= CM_INVERT; 230c16b380fSderaadt break; 231c16b380fSderaadt 232c16b380fSderaadt default: 233c16b380fSderaadt errx(1, "%s: inappropriate modifier `%s'", 234c16b380fSderaadt cname, *argv); 235c16b380fSderaadt /* NOTREACHED */ 236c16b380fSderaadt } 237c16b380fSderaadt } 238c16b380fSderaadt 239c16b380fSderaadt /* Send command to changer. */ 240496bd962Sderaadt if (ioctl(changer_fd, CHIOMOVE, &cmd)) 241c16b380fSderaadt err(1, "%s: CHIOMOVE", changer_name); 242c16b380fSderaadt 243c16b380fSderaadt return (0); 244c16b380fSderaadt 245c16b380fSderaadt usage: 246c16b380fSderaadt fprintf(stderr, "usage: %s %s " 247c16b380fSderaadt "<from ET> <from EU> <to ET> <to EU> [inv]\n", __progname, cname); 248c16b380fSderaadt return (1); 249c16b380fSderaadt } 250c16b380fSderaadt 251c16b380fSderaadt static int 252ab83b6d6Sderaadt do_exchange(char *cname, int argc, char *argv[]) 253c16b380fSderaadt { 254c16b380fSderaadt struct changer_exchange cmd; 255c16b380fSderaadt int val; 256c16b380fSderaadt 257c16b380fSderaadt /* 258c16b380fSderaadt * On an exchange command, we expect the following: 259c16b380fSderaadt * 260c16b380fSderaadt * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2] 261c16b380fSderaadt * 262c16b380fSderaadt * where ET == element type and EU == element unit. 263c16b380fSderaadt */ 264c16b380fSderaadt if (argc < 4) { 265c16b380fSderaadt warnx("%s: too few arguments", cname); 266c16b380fSderaadt goto usage; 267c16b380fSderaadt } else if (argc > 8) { 268c16b380fSderaadt warnx("%s: too many arguments", cname); 269c16b380fSderaadt goto usage; 270c16b380fSderaadt } 271c16b380fSderaadt bzero(&cmd, sizeof(cmd)); 272c16b380fSderaadt 273c16b380fSderaadt /* <src ET> */ 274c16b380fSderaadt cmd.ce_srctype = parse_element_type(*argv); 275c16b380fSderaadt ++argv; --argc; 276c16b380fSderaadt 277c16b380fSderaadt /* <src EU> */ 278c16b380fSderaadt cmd.ce_srcunit = parse_element_unit(*argv); 279c16b380fSderaadt ++argv; --argc; 280c16b380fSderaadt 281c16b380fSderaadt /* <dst1 ET> */ 282c16b380fSderaadt cmd.ce_fdsttype = parse_element_type(*argv); 283c16b380fSderaadt ++argv; --argc; 284c16b380fSderaadt 285c16b380fSderaadt /* <dst1 EU> */ 286c16b380fSderaadt cmd.ce_fdstunit = parse_element_unit(*argv); 287c16b380fSderaadt ++argv; --argc; 288c16b380fSderaadt 289c16b380fSderaadt /* 290c16b380fSderaadt * If the next token is a special word or there are no more 291c16b380fSderaadt * arguments, then this is a case of simple exchange. 292c16b380fSderaadt * dst2 == src. 293c16b380fSderaadt */ 294c16b380fSderaadt if ((argc == 0) || is_special(*argv)) { 295c16b380fSderaadt cmd.ce_sdsttype = cmd.ce_srctype; 296c16b380fSderaadt cmd.ce_sdstunit = cmd.ce_srcunit; 297c16b380fSderaadt goto do_special; 298c16b380fSderaadt } 299c16b380fSderaadt 300c16b380fSderaadt /* <dst2 ET> */ 301c16b380fSderaadt cmd.ce_sdsttype = parse_element_type(*argv); 302c16b380fSderaadt ++argv; --argc; 303c16b380fSderaadt 304c16b380fSderaadt /* <dst2 EU> */ 305c16b380fSderaadt cmd.ce_sdstunit = parse_element_unit(*argv); 306c16b380fSderaadt ++argv; --argc; 307c16b380fSderaadt 308c16b380fSderaadt do_special: 309c16b380fSderaadt /* Deal with optional command modifiers. */ 310c16b380fSderaadt while (argc) { 311c16b380fSderaadt val = parse_special(*argv); 312c16b380fSderaadt ++argv; --argc; 313c16b380fSderaadt switch (val) { 314c16b380fSderaadt case SW_INVERT1: 315c16b380fSderaadt cmd.ce_flags |= CE_INVERT1; 316c16b380fSderaadt break; 317c16b380fSderaadt 318c16b380fSderaadt case SW_INVERT2: 319c16b380fSderaadt cmd.ce_flags |= CE_INVERT2; 320c16b380fSderaadt break; 321c16b380fSderaadt 322c16b380fSderaadt default: 323c16b380fSderaadt errx(1, "%s: inappropriate modifier `%s'", 324c16b380fSderaadt cname, *argv); 325c16b380fSderaadt /* NOTREACHED */ 326c16b380fSderaadt } 327c16b380fSderaadt } 328c16b380fSderaadt 329c16b380fSderaadt /* Send command to changer. */ 330496bd962Sderaadt if (ioctl(changer_fd, CHIOEXCHANGE, &cmd)) 331c16b380fSderaadt err(1, "%s: CHIOEXCHANGE", changer_name); 332c16b380fSderaadt 333c16b380fSderaadt return (0); 334c16b380fSderaadt 335c16b380fSderaadt usage: 336c16b380fSderaadt fprintf(stderr, "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n" 337c16b380fSderaadt " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n", 338c16b380fSderaadt __progname, cname); 339c16b380fSderaadt return (1); 340c16b380fSderaadt } 341c16b380fSderaadt 342c16b380fSderaadt static int 343ab83b6d6Sderaadt do_position(char *cname, int argc, char *argv[]) 344c16b380fSderaadt { 345c16b380fSderaadt struct changer_position cmd; 346c16b380fSderaadt int val; 347c16b380fSderaadt 348c16b380fSderaadt /* 349c16b380fSderaadt * On a position command, we expect the following: 350c16b380fSderaadt * 351c16b380fSderaadt * <to ET> <to EU> [inv] 352c16b380fSderaadt * 353c16b380fSderaadt * where ET == element type and EU == element unit. 354c16b380fSderaadt */ 355c16b380fSderaadt if (argc < 2) { 356c16b380fSderaadt warnx("%s: too few arguments", cname); 357c16b380fSderaadt goto usage; 358c16b380fSderaadt } else if (argc > 3) { 359c16b380fSderaadt warnx("%s: too many arguments", cname); 360c16b380fSderaadt goto usage; 361c16b380fSderaadt } 362c16b380fSderaadt bzero(&cmd, sizeof(cmd)); 363c16b380fSderaadt 364c16b380fSderaadt /* <to ET> */ 365c16b380fSderaadt cmd.cp_type = parse_element_type(*argv); 366c16b380fSderaadt ++argv; --argc; 367c16b380fSderaadt 368c16b380fSderaadt /* <to EU> */ 369c16b380fSderaadt cmd.cp_unit = parse_element_unit(*argv); 370c16b380fSderaadt ++argv; --argc; 371c16b380fSderaadt 372c16b380fSderaadt /* Deal with optional command modifier. */ 373c16b380fSderaadt if (argc) { 374c16b380fSderaadt val = parse_special(*argv); 375c16b380fSderaadt switch (val) { 376c16b380fSderaadt case SW_INVERT: 377c16b380fSderaadt cmd.cp_flags |= CP_INVERT; 378c16b380fSderaadt break; 379c16b380fSderaadt 380c16b380fSderaadt default: 381c16b380fSderaadt errx(1, "%s: inappropriate modifier `%s'", 382c16b380fSderaadt cname, *argv); 383c16b380fSderaadt /* NOTREACHED */ 384c16b380fSderaadt } 385c16b380fSderaadt } 386c16b380fSderaadt 387c16b380fSderaadt /* Send command to changer. */ 388496bd962Sderaadt if (ioctl(changer_fd, CHIOPOSITION, &cmd)) 389c16b380fSderaadt err(1, "%s: CHIOPOSITION", changer_name); 390c16b380fSderaadt 391c16b380fSderaadt return (0); 392c16b380fSderaadt 393c16b380fSderaadt usage: 394c16b380fSderaadt fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n", 395c16b380fSderaadt __progname, cname); 396c16b380fSderaadt return (1); 397c16b380fSderaadt } 398c16b380fSderaadt 399c16b380fSderaadt static int 400ab83b6d6Sderaadt do_params(char *cname, int argc, char *argv[]) 401c16b380fSderaadt { 402c16b380fSderaadt struct changer_params data; 403c16b380fSderaadt 404c16b380fSderaadt /* No arguments to this command. */ 405c16b380fSderaadt if (argc) { 406d9248734Stodd warnx("%s: no arguments expected", cname); 407c16b380fSderaadt goto usage; 408c16b380fSderaadt } 409c16b380fSderaadt 410c16b380fSderaadt /* Get params from changer and display them. */ 411c16b380fSderaadt bzero(&data, sizeof(data)); 412496bd962Sderaadt if (ioctl(changer_fd, CHIOGPARAMS, &data)) 413c16b380fSderaadt err(1, "%s: CHIOGPARAMS", changer_name); 414c16b380fSderaadt 415c16b380fSderaadt printf("%s: %d slot%s, %d drive%s, %d picker%s", 416c16b380fSderaadt changer_name, 417c16b380fSderaadt data.cp_nslots, (data.cp_nslots > 1) ? "s" : "", 418c16b380fSderaadt data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "", 419c16b380fSderaadt data.cp_npickers, (data.cp_npickers > 1) ? "s" : ""); 420c16b380fSderaadt if (data.cp_nportals) 421c16b380fSderaadt printf(", %d portal%s", data.cp_nportals, 422c16b380fSderaadt (data.cp_nportals > 1) ? "s" : ""); 423c16b380fSderaadt printf("\n%s: current picker: %d\n", changer_name, data.cp_curpicker); 424c16b380fSderaadt 425c16b380fSderaadt return (0); 426c16b380fSderaadt 427c16b380fSderaadt usage: 428c16b380fSderaadt fprintf(stderr, "usage: %s %s\n", __progname, cname); 429c16b380fSderaadt return (1); 430c16b380fSderaadt } 431c16b380fSderaadt 432c16b380fSderaadt static int 433ab83b6d6Sderaadt do_getpicker(char *cname, int argc, char *argv[]) 434c16b380fSderaadt { 435c16b380fSderaadt int picker; 436c16b380fSderaadt 437c16b380fSderaadt /* No arguments to this command. */ 438c16b380fSderaadt if (argc) { 439c16b380fSderaadt warnx("%s: no arguments expected", cname); 440c16b380fSderaadt goto usage; 441c16b380fSderaadt } 442c16b380fSderaadt 443c16b380fSderaadt /* Get current picker from changer and display it. */ 444496bd962Sderaadt if (ioctl(changer_fd, CHIOGPICKER, &picker)) 445c16b380fSderaadt err(1, "%s: CHIOGPICKER", changer_name); 446c16b380fSderaadt 447c16b380fSderaadt printf("%s: current picker: %d\n", changer_name, picker); 448c16b380fSderaadt 449c16b380fSderaadt return (0); 450c16b380fSderaadt 451c16b380fSderaadt usage: 452c16b380fSderaadt fprintf(stderr, "usage: %s %s\n", __progname, cname); 453c16b380fSderaadt return (1); 454c16b380fSderaadt } 455c16b380fSderaadt 456c16b380fSderaadt static int 457ab83b6d6Sderaadt do_setpicker(char *cname, int argc, char *argv[]) 458c16b380fSderaadt { 459c16b380fSderaadt int picker; 460c16b380fSderaadt 461c16b380fSderaadt if (argc < 1) { 462c16b380fSderaadt warnx("%s: too few arguments", cname); 463c16b380fSderaadt goto usage; 464c16b380fSderaadt } else if (argc > 1) { 465c16b380fSderaadt warnx("%s: too many arguments", cname); 466c16b380fSderaadt goto usage; 467c16b380fSderaadt } 468c16b380fSderaadt 469c16b380fSderaadt picker = parse_element_unit(*argv); 470c16b380fSderaadt 471c16b380fSderaadt /* Set the changer picker. */ 472496bd962Sderaadt if (ioctl(changer_fd, CHIOSPICKER, &picker)) 473c16b380fSderaadt err(1, "%s: CHIOSPICKER", changer_name); 474c16b380fSderaadt 475c16b380fSderaadt return (0); 476c16b380fSderaadt 477c16b380fSderaadt usage: 478c16b380fSderaadt fprintf(stderr, "usage: %s %s <picker>\n", __progname, cname); 479c16b380fSderaadt return (1); 480c16b380fSderaadt } 481c16b380fSderaadt 482c16b380fSderaadt static int 483ab83b6d6Sderaadt do_status(char *cname, int argc, char *argv[]) 484c16b380fSderaadt { 485*c4a732d1Sbeck struct changer_element_status_request cmd; 486c16b380fSderaadt struct changer_params data; 487496bd962Sderaadt int i, chet, schet, echet; 488764064c4Smickey char *description; 489496bd962Sderaadt size_t count; 490764064c4Smickey 491764064c4Smickey #ifdef lint 492764064c4Smickey count = 0; 493764064c4Smickey description = NULL; 494764064c4Smickey #endif 495c16b380fSderaadt 496c16b380fSderaadt /* 497c16b380fSderaadt * On a status command, we expect the following: 498c16b380fSderaadt * 499c16b380fSderaadt * [<ET>] 500c16b380fSderaadt * 501c16b380fSderaadt * where ET == element type. 502c16b380fSderaadt * 503c16b380fSderaadt * If we get no arguments, we get the status of all 504c16b380fSderaadt * known element types. 505c16b380fSderaadt */ 506c16b380fSderaadt if (argc > 1) { 507c16b380fSderaadt warnx("%s: too many arguments", cname); 508c16b380fSderaadt goto usage; 509c16b380fSderaadt } 510c16b380fSderaadt 511c16b380fSderaadt /* 512c16b380fSderaadt * Get params from changer. Specifically, we need the element 513c16b380fSderaadt * counts. 514c16b380fSderaadt */ 515c16b380fSderaadt bzero(&data, sizeof(data)); 516496bd962Sderaadt if (ioctl(changer_fd, CHIOGPARAMS, &data)) 517c16b380fSderaadt err(1, "%s: CHIOGPARAMS", changer_name); 518c16b380fSderaadt 519c16b380fSderaadt if (argc) 520c16b380fSderaadt schet = echet = parse_element_type(*argv); 521c16b380fSderaadt else { 522c16b380fSderaadt schet = CHET_MT; 523c16b380fSderaadt echet = CHET_DT; 524c16b380fSderaadt } 525c16b380fSderaadt 526c16b380fSderaadt for (chet = schet; chet <= echet; ++chet) { 527c16b380fSderaadt switch (chet) { 528c16b380fSderaadt case CHET_MT: 529c16b380fSderaadt count = data.cp_npickers; 530c16b380fSderaadt description = "picker"; 531c16b380fSderaadt break; 532c16b380fSderaadt 533c16b380fSderaadt case CHET_ST: 534c16b380fSderaadt count = data.cp_nslots; 535c16b380fSderaadt description = "slot"; 536c16b380fSderaadt break; 537c16b380fSderaadt 538c16b380fSderaadt case CHET_IE: 539c16b380fSderaadt count = data.cp_nportals; 540c16b380fSderaadt description = "portal"; 541c16b380fSderaadt break; 542c16b380fSderaadt 543c16b380fSderaadt case CHET_DT: 544c16b380fSderaadt count = data.cp_ndrives; 545c16b380fSderaadt description = "drive"; 546c16b380fSderaadt break; 547c16b380fSderaadt } 548c16b380fSderaadt 549c16b380fSderaadt if (count == 0) { 550c16b380fSderaadt if (argc == 0) 551c16b380fSderaadt continue; 552c16b380fSderaadt else { 553c16b380fSderaadt printf("%s: no %s elements\n", 554c16b380fSderaadt changer_name, description); 555c16b380fSderaadt return (0); 556c16b380fSderaadt } 557c16b380fSderaadt } 558c16b380fSderaadt 559c16b380fSderaadt bzero(&cmd, sizeof(cmd)); 560c16b380fSderaadt 561*c4a732d1Sbeck cmd.cesr_type = chet; 562*c4a732d1Sbeck /* Allocate storage for the status info. */ 563*c4a732d1Sbeck cmd.cesr_data = calloc(count, sizeof(*cmd.cesr_data)); 564*c4a732d1Sbeck if ((cmd.cesr_data) == NULL) 565*c4a732d1Sbeck errx(1, "can't allocate status storage"); 566*c4a732d1Sbeck if (avoltag || pvoltag) 567*c4a732d1Sbeck cmd.cesr_flags |= CESR_VOLTAGS; 568c16b380fSderaadt 569496bd962Sderaadt if (ioctl(changer_fd, CHIOGSTATUS, &cmd)) { 570*c4a732d1Sbeck free(cmd.cesr_data); 571c16b380fSderaadt err(1, "%s: CHIOGSTATUS", changer_name); 572c16b380fSderaadt } 573c16b380fSderaadt 574c16b380fSderaadt /* Dump the status for each element of this type. */ 575c16b380fSderaadt for (i = 0; i < count; ++i) { 576*c4a732d1Sbeck struct changer_element_status *ces = 577*c4a732d1Sbeck &(cmd.cesr_data[i]); 578*c4a732d1Sbeck printf("%s %d: %s", description, i, 579*c4a732d1Sbeck bits_to_string(ces->ces_flags, CESTATUS_BITS)); 580*c4a732d1Sbeck if (pvoltag) 581*c4a732d1Sbeck printf(" voltag: <%s:%d>", 582*c4a732d1Sbeck ces->ces_pvoltag.cv_volid, 583*c4a732d1Sbeck ces->ces_pvoltag.cv_serial); 584*c4a732d1Sbeck if (avoltag) 585*c4a732d1Sbeck printf(" avoltag: <%s:%d>", 586*c4a732d1Sbeck ces->ces_avoltag.cv_volid, 587*c4a732d1Sbeck ces->ces_avoltag.cv_serial); 588*c4a732d1Sbeck printf("\n"); 589c16b380fSderaadt } 590c16b380fSderaadt 591*c4a732d1Sbeck free(cmd.cesr_data); 592c16b380fSderaadt } 593c16b380fSderaadt 594c16b380fSderaadt return (0); 595c16b380fSderaadt 596c16b380fSderaadt usage: 597c16b380fSderaadt fprintf(stderr, "usage: %s %s [<element type>]\n", __progname, 598c16b380fSderaadt cname); 599c16b380fSderaadt return (1); 600c16b380fSderaadt } 601c16b380fSderaadt 602c16b380fSderaadt static int 603ab83b6d6Sderaadt parse_element_type(char *cp) 604c16b380fSderaadt { 605c16b380fSderaadt int i; 606c16b380fSderaadt 607c16b380fSderaadt for (i = 0; elements[i].et_name != NULL; ++i) 608c16b380fSderaadt if (strcmp(elements[i].et_name, cp) == 0) 609c16b380fSderaadt return (elements[i].et_type); 610c16b380fSderaadt 611c16b380fSderaadt errx(1, "invalid element type `%s'", cp); 612c16b380fSderaadt } 613c16b380fSderaadt 614c16b380fSderaadt static int 615ab83b6d6Sderaadt parse_element_unit(char *cp) 616c16b380fSderaadt { 617c16b380fSderaadt int i; 618c16b380fSderaadt char *p; 619c16b380fSderaadt 620c16b380fSderaadt i = (int)strtol(cp, &p, 10); 621c16b380fSderaadt if ((i < 0) || (*p != '\0')) 622c16b380fSderaadt errx(1, "invalid unit number `%s'", cp); 623c16b380fSderaadt 624c16b380fSderaadt return (i); 625c16b380fSderaadt } 626c16b380fSderaadt 627c16b380fSderaadt static int 628ab83b6d6Sderaadt parse_special(char *cp) 629c16b380fSderaadt { 630c16b380fSderaadt int val; 631c16b380fSderaadt 632c16b380fSderaadt val = is_special(cp); 633c16b380fSderaadt if (val) 634c16b380fSderaadt return (val); 635c16b380fSderaadt 636c16b380fSderaadt errx(1, "invalid modifier `%s'", cp); 637c16b380fSderaadt } 638c16b380fSderaadt 639c16b380fSderaadt static int 640ab83b6d6Sderaadt is_special(char *cp) 641c16b380fSderaadt { 642c16b380fSderaadt int i; 643c16b380fSderaadt 644c16b380fSderaadt for (i = 0; specials[i].sw_name != NULL; ++i) 645c16b380fSderaadt if (strcmp(specials[i].sw_name, cp) == 0) 646c16b380fSderaadt return (specials[i].sw_value); 647c16b380fSderaadt 648c16b380fSderaadt return (0); 649c16b380fSderaadt } 650c16b380fSderaadt 651c16b380fSderaadt static char * 652ab83b6d6Sderaadt bits_to_string(int v, const char *cp) 653c16b380fSderaadt { 654c16b380fSderaadt const char *np; 655c16b380fSderaadt char f, sep, *bp; 656c16b380fSderaadt static char buf[128]; 657c16b380fSderaadt 658c16b380fSderaadt bp = buf; 659c16b380fSderaadt bzero(buf, sizeof(buf)); 660c16b380fSderaadt 661c16b380fSderaadt for (sep = '<'; (f = *cp++) != 0; cp = np) { 662c16b380fSderaadt for (np = cp; *np >= ' ';) 663c16b380fSderaadt np++; 664c16b380fSderaadt if ((v & (1 << (f - 1))) == 0) 665c16b380fSderaadt continue; 6662f61c7c6Smillert (void)snprintf(bp, sizeof(buf) - (bp - &buf[0]), 667707c1213Sart "%c%.*s", sep, (int)(np - cp), cp); 6682f61c7c6Smillert bp += strlen(bp); 669c16b380fSderaadt sep = ','; 670c16b380fSderaadt } 671c16b380fSderaadt if (sep != '<') 672c16b380fSderaadt *bp = '>'; 673c16b380fSderaadt 674c16b380fSderaadt return (buf); 675c16b380fSderaadt } 676c16b380fSderaadt 677c16b380fSderaadt static void 678ab83b6d6Sderaadt usage(void) 679c16b380fSderaadt { 680b13cd761Sderaadt int i; 681c16b380fSderaadt 682*c4a732d1Sbeck fprintf(stderr, "usage: %s [-avV] [-f device] command [args ...]\n", 683b13cd761Sderaadt __progname); 684b13cd761Sderaadt fprintf(stderr, "commands:"); 685b13cd761Sderaadt for (i = 0; commands[i].cc_name; i++) 686b13cd761Sderaadt fprintf(stderr, " %s", commands[i].cc_name); 687b13cd761Sderaadt fprintf(stderr, "\n"); 688c16b380fSderaadt exit(1); 689c16b380fSderaadt } 690