1*b7041c07Sderaadt /* $OpenBSD: chio.c,v 1.29 2021/10/24 21:24:21 deraadt 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 36f4faee91Sderaadt #include <sys/types.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 *); 62a3f7ec94Srobert static const char * element_type_name(int et); 63c72b5b24Smillert static char *bits_to_string(int, const char *); 642db6d628Sbeck static void find_voltag(char *, int *, int *); 652db6d628Sbeck static void check_source_drive(int); 66c16b380fSderaadt 67c72b5b24Smillert static int do_move(char *, int, char **); 68c72b5b24Smillert static int do_exchange(char *, int, char **); 69c72b5b24Smillert static int do_position(char *, int, char **); 70c72b5b24Smillert static int do_params(char *, int, char **); 71c72b5b24Smillert static int do_getpicker(char *, int, char **); 72c72b5b24Smillert static int do_setpicker(char *, int, char **); 73c72b5b24Smillert static int do_status(char *, int, char **); 74c16b380fSderaadt 75c16b380fSderaadt /* Valid changer element types. */ 76c16b380fSderaadt const struct element_type elements[] = { 77c16b380fSderaadt { "drive", CHET_DT }, 78b13cd761Sderaadt { "picker", CHET_MT }, 79b13cd761Sderaadt { "portal", CHET_IE }, 80b13cd761Sderaadt { "slot", CHET_ST }, 81c16b380fSderaadt { NULL, 0 }, 82c16b380fSderaadt }; 83c16b380fSderaadt 84c16b380fSderaadt /* Valid commands. */ 85c16b380fSderaadt const struct changer_command commands[] = { 86c16b380fSderaadt { "exchange", do_exchange }, 87c16b380fSderaadt { "getpicker", do_getpicker }, 88b13cd761Sderaadt { "move", do_move }, 89b13cd761Sderaadt { "params", do_params }, 90b13cd761Sderaadt { "position", do_position }, 91c16b380fSderaadt { "setpicker", do_setpicker }, 92c16b380fSderaadt { "status", do_status }, 93c16b380fSderaadt { NULL, 0 }, 94c16b380fSderaadt }; 95c16b380fSderaadt 96c16b380fSderaadt /* Valid special words. */ 97c16b380fSderaadt const struct special_word specials[] = { 98c16b380fSderaadt { "inv", SW_INVERT }, 99c16b380fSderaadt { "inv1", SW_INVERT1 }, 100c16b380fSderaadt { "inv2", SW_INVERT2 }, 101c16b380fSderaadt { NULL, 0 }, 102c16b380fSderaadt }; 103c16b380fSderaadt 104c16b380fSderaadt static int changer_fd; 105c16b380fSderaadt static char *changer_name; 106c4a732d1Sbeck static int avoltag; 107c4a732d1Sbeck static int pvoltag; 108a3f7ec94Srobert static int sense; 109a3f7ec94Srobert static int source; 110c16b380fSderaadt 111c16b380fSderaadt int 112ab83b6d6Sderaadt main(int argc, char *argv[]) 113c16b380fSderaadt { 114c16b380fSderaadt int ch, i; 115c16b380fSderaadt 116f2f647aaSderaadt while ((ch = getopt(argc, argv, "f:")) != -1) { 117c16b380fSderaadt switch (ch) { 118c16b380fSderaadt case 'f': 119c16b380fSderaadt changer_name = optarg; 120c16b380fSderaadt break; 121c16b380fSderaadt default: 122c16b380fSderaadt usage(); 123c16b380fSderaadt } 124c16b380fSderaadt } 125c16b380fSderaadt argc -= optind; 126c16b380fSderaadt argv += optind; 127c16b380fSderaadt 128c16b380fSderaadt if (argc == 0) 129c16b380fSderaadt usage(); 130c16b380fSderaadt 131c16b380fSderaadt /* Get the default changer if not already specified. */ 132c16b380fSderaadt if (changer_name == NULL) 133c16b380fSderaadt if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL) 134c16b380fSderaadt changer_name = _PATH_CH; 135c16b380fSderaadt 136c16b380fSderaadt /* Open the changer device. */ 137*b7041c07Sderaadt if ((changer_fd = open(changer_name, O_RDWR)) == -1) 138c16b380fSderaadt err(1, "%s: open", changer_name); 139c16b380fSderaadt 140c16b380fSderaadt /* Find the specified command. */ 141c16b380fSderaadt for (i = 0; commands[i].cc_name != NULL; ++i) 142c16b380fSderaadt if (strcmp(*argv, commands[i].cc_name) == 0) 143c16b380fSderaadt break; 144b13cd761Sderaadt if (commands[i].cc_name == NULL) { 145b13cd761Sderaadt /* look for abbreviation */ 146b13cd761Sderaadt for (i = 0; commands[i].cc_name != NULL; ++i) 147b13cd761Sderaadt if (strncmp(*argv, commands[i].cc_name, 148b13cd761Sderaadt strlen(*argv)) == 0) 149b13cd761Sderaadt break; 150b13cd761Sderaadt } 151c16b380fSderaadt if (commands[i].cc_name == NULL) 152c16b380fSderaadt errx(1, "unknown command: %s", *argv); 153c16b380fSderaadt 154c16b380fSderaadt exit((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); 155c16b380fSderaadt } 156c16b380fSderaadt 157c16b380fSderaadt static int 158ab83b6d6Sderaadt do_move(char *cname, int argc, char *argv[]) 159c16b380fSderaadt { 160c16b380fSderaadt struct changer_move cmd; 161c16b380fSderaadt int val; 162c16b380fSderaadt 163c16b380fSderaadt /* 164c16b380fSderaadt * On a move command, we expect the following: 165c16b380fSderaadt * 166c16b380fSderaadt * <from ET> <from EU> <to ET> <to EU> [inv] 167c16b380fSderaadt * 168c16b380fSderaadt * where ET == element type and EU == element unit. 169c16b380fSderaadt */ 170f2f647aaSderaadt 171f2f647aaSderaadt ++argv; --argc; 172f2f647aaSderaadt 173c16b380fSderaadt if (argc < 4) { 174c16b380fSderaadt warnx("%s: too few arguments", cname); 175c16b380fSderaadt goto usage; 176c16b380fSderaadt } else if (argc > 5) { 177c16b380fSderaadt warnx("%s: too many arguments", cname); 178c16b380fSderaadt goto usage; 179c16b380fSderaadt } 180c16b380fSderaadt bzero(&cmd, sizeof(cmd)); 181c16b380fSderaadt 1822db6d628Sbeck /* 1832db6d628Sbeck * Get the from ET and EU - we search for it if the ET is 1842db6d628Sbeck * "voltag", otherwise, we just use the ET and EU given to us. 1852db6d628Sbeck */ 1862db6d628Sbeck if (strcmp(*argv, "voltag") == 0) { 1872db6d628Sbeck ++argv; --argc; 1882db6d628Sbeck find_voltag(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit); 1892db6d628Sbeck ++argv; --argc; 1902db6d628Sbeck } else { 191c16b380fSderaadt cmd.cm_fromtype = parse_element_type(*argv); 192c16b380fSderaadt ++argv; --argc; 193c16b380fSderaadt cmd.cm_fromunit = parse_element_unit(*argv); 194c16b380fSderaadt ++argv; --argc; 195b2b21931Sbeck } 196b2b21931Sbeck 1972db6d628Sbeck if (cmd.cm_fromtype == CHET_DT) 1982db6d628Sbeck check_source_drive(cmd.cm_fromunit); 1992db6d628Sbeck 2002db6d628Sbeck /* 2012db6d628Sbeck * Don't allow voltag on the to ET, using a volume 2022db6d628Sbeck * as a destination makes no sense on a move 2032db6d628Sbeck */ 204c16b380fSderaadt cmd.cm_totype = parse_element_type(*argv); 205c16b380fSderaadt ++argv; --argc; 206c16b380fSderaadt cmd.cm_tounit = parse_element_unit(*argv); 207c16b380fSderaadt ++argv; --argc; 208c16b380fSderaadt 209c16b380fSderaadt /* Deal with optional command modifier. */ 210c16b380fSderaadt if (argc) { 211c16b380fSderaadt val = parse_special(*argv); 212c16b380fSderaadt switch (val) { 213c16b380fSderaadt case SW_INVERT: 214c16b380fSderaadt cmd.cm_flags |= CM_INVERT; 215c16b380fSderaadt break; 216c16b380fSderaadt 217c16b380fSderaadt default: 218c16b380fSderaadt errx(1, "%s: inappropriate modifier `%s'", 219c16b380fSderaadt cname, *argv); 220c16b380fSderaadt /* NOTREACHED */ 221c16b380fSderaadt } 222c16b380fSderaadt } 223c16b380fSderaadt 224c16b380fSderaadt /* Send command to changer. */ 2253aaa63ebSderaadt if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1) 226c16b380fSderaadt err(1, "%s: CHIOMOVE", changer_name); 227c16b380fSderaadt 228c16b380fSderaadt return (0); 229c16b380fSderaadt 230c16b380fSderaadt usage: 231c16b380fSderaadt fprintf(stderr, "usage: %s %s " 232c16b380fSderaadt "<from ET> <from EU> <to ET> <to EU> [inv]\n", __progname, cname); 233c16b380fSderaadt return (1); 234c16b380fSderaadt } 235c16b380fSderaadt 236c16b380fSderaadt static int 237ab83b6d6Sderaadt do_exchange(char *cname, int argc, char *argv[]) 238c16b380fSderaadt { 239c16b380fSderaadt struct changer_exchange cmd; 240c16b380fSderaadt int val; 241c16b380fSderaadt 242c16b380fSderaadt /* 243c16b380fSderaadt * On an exchange command, we expect the following: 244c16b380fSderaadt * 245c16b380fSderaadt * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2] 246c16b380fSderaadt * 247c16b380fSderaadt * where ET == element type and EU == element unit. 248c16b380fSderaadt */ 249f2f647aaSderaadt 250f2f647aaSderaadt ++argv; --argc; 251f2f647aaSderaadt 252c16b380fSderaadt if (argc < 4) { 253c16b380fSderaadt warnx("%s: too few arguments", cname); 254c16b380fSderaadt goto usage; 255c16b380fSderaadt } else if (argc > 8) { 256c16b380fSderaadt warnx("%s: too many arguments", cname); 257c16b380fSderaadt goto usage; 258c16b380fSderaadt } 259c16b380fSderaadt bzero(&cmd, sizeof(cmd)); 260c16b380fSderaadt 261c16b380fSderaadt /* <src ET> */ 262c16b380fSderaadt cmd.ce_srctype = parse_element_type(*argv); 263c16b380fSderaadt ++argv; --argc; 264c16b380fSderaadt 265c16b380fSderaadt /* <src EU> */ 266c16b380fSderaadt cmd.ce_srcunit = parse_element_unit(*argv); 267c16b380fSderaadt ++argv; --argc; 268c16b380fSderaadt 269c16b380fSderaadt /* <dst1 ET> */ 270c16b380fSderaadt cmd.ce_fdsttype = parse_element_type(*argv); 271c16b380fSderaadt ++argv; --argc; 272c16b380fSderaadt 273c16b380fSderaadt /* <dst1 EU> */ 274c16b380fSderaadt cmd.ce_fdstunit = parse_element_unit(*argv); 275c16b380fSderaadt ++argv; --argc; 276c16b380fSderaadt 277c16b380fSderaadt /* 278c16b380fSderaadt * If the next token is a special word or there are no more 279c16b380fSderaadt * arguments, then this is a case of simple exchange. 280c16b380fSderaadt * dst2 == src. 281c16b380fSderaadt */ 282c16b380fSderaadt if ((argc == 0) || is_special(*argv)) { 283c16b380fSderaadt cmd.ce_sdsttype = cmd.ce_srctype; 284c16b380fSderaadt cmd.ce_sdstunit = cmd.ce_srcunit; 285c16b380fSderaadt goto do_special; 286c16b380fSderaadt } 287c16b380fSderaadt 288c16b380fSderaadt /* <dst2 ET> */ 289c16b380fSderaadt cmd.ce_sdsttype = parse_element_type(*argv); 290c16b380fSderaadt ++argv; --argc; 291c16b380fSderaadt 292c16b380fSderaadt /* <dst2 EU> */ 293c16b380fSderaadt cmd.ce_sdstunit = parse_element_unit(*argv); 294c16b380fSderaadt ++argv; --argc; 295c16b380fSderaadt 296c16b380fSderaadt do_special: 297c16b380fSderaadt /* Deal with optional command modifiers. */ 298c16b380fSderaadt while (argc) { 299c16b380fSderaadt val = parse_special(*argv); 300c16b380fSderaadt ++argv; --argc; 301c16b380fSderaadt switch (val) { 302c16b380fSderaadt case SW_INVERT1: 303c16b380fSderaadt cmd.ce_flags |= CE_INVERT1; 304c16b380fSderaadt break; 305c16b380fSderaadt 306c16b380fSderaadt case SW_INVERT2: 307c16b380fSderaadt cmd.ce_flags |= CE_INVERT2; 308c16b380fSderaadt break; 309c16b380fSderaadt 310c16b380fSderaadt default: 311c16b380fSderaadt errx(1, "%s: inappropriate modifier `%s'", 312c16b380fSderaadt cname, *argv); 313c16b380fSderaadt /* NOTREACHED */ 314c16b380fSderaadt } 315c16b380fSderaadt } 316c16b380fSderaadt 317c16b380fSderaadt /* Send command to changer. */ 3183aaa63ebSderaadt if (ioctl(changer_fd, CHIOEXCHANGE, &cmd) == -1) 319c16b380fSderaadt err(1, "%s: CHIOEXCHANGE", changer_name); 320c16b380fSderaadt 321c16b380fSderaadt return (0); 322c16b380fSderaadt 323c16b380fSderaadt usage: 324c16b380fSderaadt fprintf(stderr, "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n" 325c16b380fSderaadt " [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n", 326c16b380fSderaadt __progname, cname); 327c16b380fSderaadt return (1); 328c16b380fSderaadt } 329c16b380fSderaadt 330c16b380fSderaadt static int 331ab83b6d6Sderaadt do_position(char *cname, int argc, char *argv[]) 332c16b380fSderaadt { 333c16b380fSderaadt struct changer_position cmd; 334c16b380fSderaadt int val; 335c16b380fSderaadt 336c16b380fSderaadt /* 337c16b380fSderaadt * On a position command, we expect the following: 338c16b380fSderaadt * 339c16b380fSderaadt * <to ET> <to EU> [inv] 340c16b380fSderaadt * 341c16b380fSderaadt * where ET == element type and EU == element unit. 342c16b380fSderaadt */ 343f2f647aaSderaadt 344f2f647aaSderaadt ++argv; --argc; 345f2f647aaSderaadt 346c16b380fSderaadt if (argc < 2) { 347c16b380fSderaadt warnx("%s: too few arguments", cname); 348c16b380fSderaadt goto usage; 349c16b380fSderaadt } else if (argc > 3) { 350c16b380fSderaadt warnx("%s: too many arguments", cname); 351c16b380fSderaadt goto usage; 352c16b380fSderaadt } 353c16b380fSderaadt bzero(&cmd, sizeof(cmd)); 354c16b380fSderaadt 355c16b380fSderaadt /* <to ET> */ 356c16b380fSderaadt cmd.cp_type = parse_element_type(*argv); 357c16b380fSderaadt ++argv; --argc; 358c16b380fSderaadt 359c16b380fSderaadt /* <to EU> */ 360c16b380fSderaadt cmd.cp_unit = parse_element_unit(*argv); 361c16b380fSderaadt ++argv; --argc; 362c16b380fSderaadt 363c16b380fSderaadt /* Deal with optional command modifier. */ 364c16b380fSderaadt if (argc) { 365c16b380fSderaadt val = parse_special(*argv); 366c16b380fSderaadt switch (val) { 367c16b380fSderaadt case SW_INVERT: 368c16b380fSderaadt cmd.cp_flags |= CP_INVERT; 369c16b380fSderaadt break; 370c16b380fSderaadt 371c16b380fSderaadt default: 372c16b380fSderaadt errx(1, "%s: inappropriate modifier `%s'", 373c16b380fSderaadt cname, *argv); 374c16b380fSderaadt /* NOTREACHED */ 375c16b380fSderaadt } 376c16b380fSderaadt } 377c16b380fSderaadt 378c16b380fSderaadt /* Send command to changer. */ 3793aaa63ebSderaadt if (ioctl(changer_fd, CHIOPOSITION, &cmd) == -1) 380c16b380fSderaadt err(1, "%s: CHIOPOSITION", changer_name); 381c16b380fSderaadt 382c16b380fSderaadt return (0); 383c16b380fSderaadt 384c16b380fSderaadt usage: 385c16b380fSderaadt fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n", 386c16b380fSderaadt __progname, cname); 387c16b380fSderaadt return (1); 388c16b380fSderaadt } 389c16b380fSderaadt 390c16b380fSderaadt static int 391ab83b6d6Sderaadt do_params(char *cname, int argc, char *argv[]) 392c16b380fSderaadt { 393c16b380fSderaadt struct changer_params data; 394c16b380fSderaadt 395c16b380fSderaadt /* No arguments to this command. */ 396f2f647aaSderaadt 397f2f647aaSderaadt ++argv; --argc; 398f2f647aaSderaadt 399c16b380fSderaadt if (argc) { 400d9248734Stodd warnx("%s: no arguments expected", cname); 401c16b380fSderaadt goto usage; 402c16b380fSderaadt } 403c16b380fSderaadt 404c16b380fSderaadt /* Get params from changer and display them. */ 405c16b380fSderaadt bzero(&data, sizeof(data)); 4063aaa63ebSderaadt if (ioctl(changer_fd, CHIOGPARAMS, &data) == -1) 407c16b380fSderaadt err(1, "%s: CHIOGPARAMS", changer_name); 408c16b380fSderaadt 409c16b380fSderaadt printf("%s: %d slot%s, %d drive%s, %d picker%s", 410c16b380fSderaadt changer_name, 411c16b380fSderaadt data.cp_nslots, (data.cp_nslots > 1) ? "s" : "", 412c16b380fSderaadt data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "", 413c16b380fSderaadt data.cp_npickers, (data.cp_npickers > 1) ? "s" : ""); 414c16b380fSderaadt if (data.cp_nportals) 415c16b380fSderaadt printf(", %d portal%s", data.cp_nportals, 416c16b380fSderaadt (data.cp_nportals > 1) ? "s" : ""); 417c16b380fSderaadt printf("\n%s: current picker: %d\n", changer_name, data.cp_curpicker); 418c16b380fSderaadt 419c16b380fSderaadt return (0); 420c16b380fSderaadt 421c16b380fSderaadt usage: 422c16b380fSderaadt fprintf(stderr, "usage: %s %s\n", __progname, cname); 423c16b380fSderaadt return (1); 424c16b380fSderaadt } 425c16b380fSderaadt 426c16b380fSderaadt static int 427ab83b6d6Sderaadt do_getpicker(char *cname, int argc, char *argv[]) 428c16b380fSderaadt { 429c16b380fSderaadt int picker; 430c16b380fSderaadt 431c16b380fSderaadt /* No arguments to this command. */ 432f2f647aaSderaadt 433f2f647aaSderaadt ++argv; --argc; 434f2f647aaSderaadt 435c16b380fSderaadt if (argc) { 436c16b380fSderaadt warnx("%s: no arguments expected", cname); 437c16b380fSderaadt goto usage; 438c16b380fSderaadt } 439c16b380fSderaadt 440c16b380fSderaadt /* Get current picker from changer and display it. */ 4413aaa63ebSderaadt if (ioctl(changer_fd, CHIOGPICKER, &picker) == -1) 442c16b380fSderaadt err(1, "%s: CHIOGPICKER", changer_name); 443c16b380fSderaadt 444c16b380fSderaadt printf("%s: current picker: %d\n", changer_name, picker); 445c16b380fSderaadt 446c16b380fSderaadt return (0); 447c16b380fSderaadt 448c16b380fSderaadt usage: 449c16b380fSderaadt fprintf(stderr, "usage: %s %s\n", __progname, cname); 450c16b380fSderaadt return (1); 451c16b380fSderaadt } 452c16b380fSderaadt 453c16b380fSderaadt static int 454ab83b6d6Sderaadt do_setpicker(char *cname, int argc, char *argv[]) 455c16b380fSderaadt { 456c16b380fSderaadt int picker; 457c16b380fSderaadt 458f2f647aaSderaadt ++argv; --argc; 459f2f647aaSderaadt 460c16b380fSderaadt if (argc < 1) { 461c16b380fSderaadt warnx("%s: too few arguments", cname); 462c16b380fSderaadt goto usage; 463c16b380fSderaadt } else if (argc > 1) { 464c16b380fSderaadt warnx("%s: too many arguments", cname); 465c16b380fSderaadt goto usage; 466c16b380fSderaadt } 467c16b380fSderaadt 468c16b380fSderaadt picker = parse_element_unit(*argv); 469c16b380fSderaadt 470c16b380fSderaadt /* Set the changer picker. */ 4713aaa63ebSderaadt if (ioctl(changer_fd, CHIOSPICKER, &picker) == -1) 472c16b380fSderaadt err(1, "%s: CHIOSPICKER", changer_name); 473c16b380fSderaadt 474c16b380fSderaadt return (0); 475c16b380fSderaadt 476c16b380fSderaadt usage: 477c16b380fSderaadt fprintf(stderr, "usage: %s %s <picker>\n", __progname, cname); 478c16b380fSderaadt return (1); 479c16b380fSderaadt } 480c16b380fSderaadt 481c16b380fSderaadt static int 482ab83b6d6Sderaadt do_status(char *cname, int argc, char *argv[]) 483c16b380fSderaadt { 484c4a732d1Sbeck struct changer_element_status_request cmd; 485c16b380fSderaadt struct changer_params data; 486f2f647aaSderaadt int i, chet, schet, echet, c; 487764064c4Smickey char *description; 488496bd962Sderaadt size_t count; 489764064c4Smickey 490f2f647aaSderaadt optreset = 1; 491f2f647aaSderaadt optind = 1; 492a3f7ec94Srobert while ((c = getopt(argc, argv, "SsvVa")) != -1) { 493f2f647aaSderaadt switch (c) { 494a3f7ec94Srobert case 's': 495a3f7ec94Srobert sense = 1; 496a3f7ec94Srobert break; 497a3f7ec94Srobert case 'S': 498a3f7ec94Srobert source = 1; 499a3f7ec94Srobert break; 500f2f647aaSderaadt case 'v': 501f2f647aaSderaadt pvoltag = 1; 502f2f647aaSderaadt break; 503f2f647aaSderaadt case 'V': 504f2f647aaSderaadt avoltag = 1; 505f2f647aaSderaadt break; 506f2f647aaSderaadt case 'a': 507a3f7ec94Srobert pvoltag = avoltag = source = sense = 1; 508f2f647aaSderaadt break; 509f2f647aaSderaadt default: 510f2f647aaSderaadt goto usage; 511f2f647aaSderaadt } 512f2f647aaSderaadt } 513f2f647aaSderaadt 514f2f647aaSderaadt argc -= optind; 515f2f647aaSderaadt argv += optind; 516f2f647aaSderaadt 517c16b380fSderaadt /* 518c16b380fSderaadt * On a status command, we expect the following: 519c16b380fSderaadt * 520c16b380fSderaadt * [<ET>] 521c16b380fSderaadt * 522c16b380fSderaadt * where ET == element type. 523c16b380fSderaadt * 524c16b380fSderaadt * If we get no arguments, we get the status of all 525c16b380fSderaadt * known element types. 526c16b380fSderaadt */ 527c16b380fSderaadt if (argc > 1) { 528c16b380fSderaadt warnx("%s: too many arguments", cname); 529c16b380fSderaadt goto usage; 530c16b380fSderaadt } 531c16b380fSderaadt 532c16b380fSderaadt /* 533c16b380fSderaadt * Get params from changer. Specifically, we need the element 534c16b380fSderaadt * counts. 535c16b380fSderaadt */ 536c16b380fSderaadt bzero(&data, sizeof(data)); 5373aaa63ebSderaadt if (ioctl(changer_fd, CHIOGPARAMS, &data) == -1) 538c16b380fSderaadt err(1, "%s: CHIOGPARAMS", changer_name); 539c16b380fSderaadt 540c16b380fSderaadt if (argc) 541c16b380fSderaadt schet = echet = parse_element_type(*argv); 542c16b380fSderaadt else { 543c16b380fSderaadt schet = CHET_MT; 544c16b380fSderaadt echet = CHET_DT; 545c16b380fSderaadt } 546c16b380fSderaadt 547c16b380fSderaadt for (chet = schet; chet <= echet; ++chet) { 548c16b380fSderaadt switch (chet) { 549c16b380fSderaadt case CHET_MT: 550c16b380fSderaadt count = data.cp_npickers; 551c16b380fSderaadt description = "picker"; 552c16b380fSderaadt break; 553c16b380fSderaadt 554c16b380fSderaadt case CHET_ST: 555c16b380fSderaadt count = data.cp_nslots; 556c16b380fSderaadt description = "slot"; 557c16b380fSderaadt break; 558c16b380fSderaadt 559c16b380fSderaadt case CHET_IE: 560c16b380fSderaadt count = data.cp_nportals; 561c16b380fSderaadt description = "portal"; 562c16b380fSderaadt break; 563c16b380fSderaadt 564c16b380fSderaadt case CHET_DT: 565c16b380fSderaadt count = data.cp_ndrives; 566c16b380fSderaadt description = "drive"; 567c16b380fSderaadt break; 568c16b380fSderaadt } 569c16b380fSderaadt 570c16b380fSderaadt if (count == 0) { 571c16b380fSderaadt if (argc == 0) 572c16b380fSderaadt continue; 573c16b380fSderaadt else { 574c16b380fSderaadt printf("%s: no %s elements\n", 575c16b380fSderaadt changer_name, description); 576c16b380fSderaadt return (0); 577c16b380fSderaadt } 578c16b380fSderaadt } 579c16b380fSderaadt 580c16b380fSderaadt bzero(&cmd, sizeof(cmd)); 581c16b380fSderaadt 582c4a732d1Sbeck cmd.cesr_type = chet; 583c4a732d1Sbeck /* Allocate storage for the status info. */ 584c4a732d1Sbeck cmd.cesr_data = calloc(count, sizeof(*cmd.cesr_data)); 585c4a732d1Sbeck if ((cmd.cesr_data) == NULL) 586c4a732d1Sbeck errx(1, "can't allocate status storage"); 587c4a732d1Sbeck if (avoltag || pvoltag) 588c4a732d1Sbeck cmd.cesr_flags |= CESR_VOLTAGS; 589c16b380fSderaadt 5903aaa63ebSderaadt if (ioctl(changer_fd, CHIOGSTATUS, &cmd) == -1) { 591c4a732d1Sbeck free(cmd.cesr_data); 592c16b380fSderaadt err(1, "%s: CHIOGSTATUS", changer_name); 593c16b380fSderaadt } 594c16b380fSderaadt 595c16b380fSderaadt /* Dump the status for each element of this type. */ 596c16b380fSderaadt for (i = 0; i < count; ++i) { 597c4a732d1Sbeck struct changer_element_status *ces = 598c4a732d1Sbeck &(cmd.cesr_data[i]); 599c4a732d1Sbeck printf("%s %d: %s", description, i, 600c4a732d1Sbeck bits_to_string(ces->ces_flags, CESTATUS_BITS)); 601a3f7ec94Srobert if (sense) 602a3f7ec94Srobert printf(" sense: <0x%02x/0x%02x>", 603a3f7ec94Srobert ces->ces_sensecode, 604a3f7ec94Srobert ces->ces_sensequal); 605c4a732d1Sbeck if (pvoltag) 606c4a732d1Sbeck printf(" voltag: <%s:%d>", 607c4a732d1Sbeck ces->ces_pvoltag.cv_volid, 608c4a732d1Sbeck ces->ces_pvoltag.cv_serial); 609c4a732d1Sbeck if (avoltag) 610c4a732d1Sbeck printf(" avoltag: <%s:%d>", 611c4a732d1Sbeck ces->ces_avoltag.cv_volid, 612c4a732d1Sbeck ces->ces_avoltag.cv_serial); 613a3f7ec94Srobert if (source) { 614a3f7ec94Srobert if (ces->ces_flags & CESTATUS_ACCESS) 615a3f7ec94Srobert printf(" source: <%s %d>", 616a3f7ec94Srobert element_type_name( 617a3f7ec94Srobert ces->ces_source_type), 618a3f7ec94Srobert ces->ces_source_addr); 619a3f7ec94Srobert else 620a3f7ec94Srobert printf(" source: <>"); 621a3f7ec94Srobert } 622c4a732d1Sbeck printf("\n"); 623c16b380fSderaadt } 624c16b380fSderaadt 625c4a732d1Sbeck free(cmd.cesr_data); 626c16b380fSderaadt } 627c16b380fSderaadt 628c16b380fSderaadt return (0); 629c16b380fSderaadt 630c16b380fSderaadt usage: 631c16b380fSderaadt fprintf(stderr, "usage: %s %s [<element type>]\n", __progname, 632c16b380fSderaadt cname); 633c16b380fSderaadt return (1); 634c16b380fSderaadt } 635c16b380fSderaadt 6362db6d628Sbeck /* 6372db6d628Sbeck * Check a drive unit as the source for a move or exchange 6382db6d628Sbeck * operation. If the drive is not accessible, we attempt 6392db6d628Sbeck * to unmount the tape in it before moving to avoid 6402db6d628Sbeck * errors in "disconnected" type pickers where the drive 64180adcad8Smartynas * is on a separate target from the changer. 6422db6d628Sbeck */ 6432db6d628Sbeck static void 644f2f647aaSderaadt check_source_drive(int unit) 645f2f647aaSderaadt { 6462db6d628Sbeck struct mtop mtoffl = { MTOFFL, 1 }; 6472db6d628Sbeck struct changer_element_status_request cmd; 6482db6d628Sbeck struct changer_element_status *ces; 6492db6d628Sbeck struct changer_params data; 6502db6d628Sbeck size_t count = 0; 6512db6d628Sbeck int mtfd; 6522db6d628Sbeck char *tapedev; 6532db6d628Sbeck 6542db6d628Sbeck /* 6552db6d628Sbeck * Get params from changer. Specifically, we need the element 6562db6d628Sbeck * counts. 6572db6d628Sbeck */ 6582db6d628Sbeck bzero(&data, sizeof(data)); 6593aaa63ebSderaadt if (ioctl(changer_fd, CHIOGPARAMS, &data) == -1) 6602db6d628Sbeck err(1, "%s: CHIOGPARAMS", changer_name); 6612db6d628Sbeck 6622db6d628Sbeck count = data.cp_ndrives; 6632db6d628Sbeck if (unit < 0 || unit >= count) 6642db6d628Sbeck err(1, "%s: invalid drive: drive %d", changer_name, unit); 6652db6d628Sbeck 6662db6d628Sbeck bzero(&cmd, sizeof(cmd)); 6672db6d628Sbeck cmd.cesr_type = CHET_DT; 6682db6d628Sbeck /* Allocate storage for the status info. */ 6692db6d628Sbeck cmd.cesr_data = calloc(count, sizeof(*cmd.cesr_data)); 6702db6d628Sbeck if ((cmd.cesr_data) == NULL) 6712db6d628Sbeck errx(1, "can't allocate status storage"); 6722db6d628Sbeck 6733aaa63ebSderaadt if (ioctl(changer_fd, CHIOGSTATUS, &cmd) == -1) { 6742db6d628Sbeck free(cmd.cesr_data); 6752db6d628Sbeck err(1, "%s: CHIOGSTATUS", changer_name); 6762db6d628Sbeck } 6772db6d628Sbeck ces = &(cmd.cesr_data[unit]); 6782db6d628Sbeck 6792db6d628Sbeck if ((ces->ces_flags & CESTATUS_FULL) != CESTATUS_FULL) 6802db6d628Sbeck err(1, "%s: drive %d is empty!", changer_name, unit); 6812db6d628Sbeck 6822db6d628Sbeck if ((ces->ces_flags & CESTATUS_ACCESS) == CESTATUS_ACCESS) 6832db6d628Sbeck return; /* changer thinks all is well - trust it */ 6842db6d628Sbeck 6852db6d628Sbeck /* 6862db6d628Sbeck * Otherwise, drive is FULL, but not accessible. 6872db6d628Sbeck * Try to make it accessible by doing an mt offline. 6882db6d628Sbeck */ 6892db6d628Sbeck tapedev = parse_tapedev(_PATH_CH_CONF, changer_name, unit); 690f2875fa7Skrw mtfd = opendev(tapedev, O_RDONLY, 0, NULL); 6912db6d628Sbeck if (mtfd == -1) 6922db6d628Sbeck err(1, "%s drive %d (%s): open", changer_name, unit, tapedev); 6932db6d628Sbeck if (ioctl(mtfd, MTIOCTOP, &mtoffl) == -1) 6942db6d628Sbeck err(1, "%s drive %d (%s): rewoffl", changer_name, unit, 6952db6d628Sbeck tapedev); 6962db6d628Sbeck close(mtfd); 6972db6d628Sbeck } 6982db6d628Sbeck 6992db6d628Sbeck void 7002db6d628Sbeck find_voltag(char *voltag, int *type, int *unit) 7012db6d628Sbeck { 7022db6d628Sbeck struct changer_element_status_request cmd; 7032db6d628Sbeck struct changer_params data; 7042db6d628Sbeck int i, chet, schet, echet, found; 7052db6d628Sbeck size_t count = 0; 7062db6d628Sbeck 7072db6d628Sbeck /* 7082db6d628Sbeck * Get params from changer. Specifically, we need the element 7092db6d628Sbeck * counts. 7102db6d628Sbeck */ 7112db6d628Sbeck bzero(&data, sizeof(data)); 7123aaa63ebSderaadt if (ioctl(changer_fd, CHIOGPARAMS, &data) == -1) 7132db6d628Sbeck err(1, "%s: CHIOGPARAMS", changer_name); 7142db6d628Sbeck 7152db6d628Sbeck found = 0; 7162db6d628Sbeck schet = CHET_MT; 7172db6d628Sbeck echet = CHET_DT; 7182db6d628Sbeck 7192db6d628Sbeck /* 7202db6d628Sbeck * For each type of element, iterate through each one until 7212db6d628Sbeck * we find the correct volume id. 7222db6d628Sbeck */ 7232db6d628Sbeck for (chet = schet; chet <= echet; ++chet) { 7242db6d628Sbeck switch (chet) { 7252db6d628Sbeck case CHET_MT: 7262db6d628Sbeck count = data.cp_npickers; 7272db6d628Sbeck break; 7282db6d628Sbeck case CHET_ST: 7292db6d628Sbeck count = data.cp_nslots; 7302db6d628Sbeck break; 7312db6d628Sbeck case CHET_IE: 7322db6d628Sbeck count = data.cp_nportals; 7332db6d628Sbeck break; 7342db6d628Sbeck case CHET_DT: 7352db6d628Sbeck count = data.cp_ndrives; 7362db6d628Sbeck break; 7372db6d628Sbeck } 7382db6d628Sbeck if (count == 0 || found) 7392db6d628Sbeck continue; 7402db6d628Sbeck 7412db6d628Sbeck bzero(&cmd, sizeof(cmd)); 7422db6d628Sbeck cmd.cesr_type = chet; 7432db6d628Sbeck /* Allocate storage for the status info. */ 7442db6d628Sbeck cmd.cesr_data = calloc(count, sizeof(*cmd.cesr_data)); 7452db6d628Sbeck if ((cmd.cesr_data) == NULL) 7462db6d628Sbeck errx(1, "can't allocate status storage"); 7472db6d628Sbeck cmd.cesr_flags |= CESR_VOLTAGS; 7482db6d628Sbeck 7493aaa63ebSderaadt if (ioctl(changer_fd, CHIOGSTATUS, &cmd) == -1) { 7502db6d628Sbeck free(cmd.cesr_data); 7512db6d628Sbeck err(1, "%s: CHIOGSTATUS", changer_name); 7522db6d628Sbeck } 7532db6d628Sbeck 7542db6d628Sbeck /* 7552db6d628Sbeck * look through each element to see if it has our desired 7562db6d628Sbeck * volume tag. 7572db6d628Sbeck */ 7582db6d628Sbeck for (i = 0; i < count; ++i) { 7592db6d628Sbeck struct changer_element_status *ces = 7602db6d628Sbeck &(cmd.cesr_data[i]); 7612db6d628Sbeck if ((ces->ces_flags & CESTATUS_FULL) != CESTATUS_FULL) 7622db6d628Sbeck continue; /* no tape in drive */ 7632db6d628Sbeck if (strcasecmp(voltag, ces->ces_pvoltag.cv_volid) 7642db6d628Sbeck == 0) { 7652db6d628Sbeck *type = chet; 7662db6d628Sbeck *unit = i; 7672db6d628Sbeck found = 1; 7682db6d628Sbeck free(cmd.cesr_data); 7692db6d628Sbeck return; 7702db6d628Sbeck } 7712db6d628Sbeck } 7722db6d628Sbeck free(cmd.cesr_data); 7732db6d628Sbeck } 7742db6d628Sbeck errx(1, "%s: unable to locate voltag: %s", changer_name, voltag); 7752db6d628Sbeck } 7762db6d628Sbeck 7772db6d628Sbeck 778c16b380fSderaadt static int 779ab83b6d6Sderaadt parse_element_type(char *cp) 780c16b380fSderaadt { 781c16b380fSderaadt int i; 782c16b380fSderaadt 783c16b380fSderaadt for (i = 0; elements[i].et_name != NULL; ++i) 784c16b380fSderaadt if (strcmp(elements[i].et_name, cp) == 0) 785c16b380fSderaadt return (elements[i].et_type); 786c16b380fSderaadt 787c16b380fSderaadt errx(1, "invalid element type `%s'", cp); 788c16b380fSderaadt } 789c16b380fSderaadt 790a3f7ec94Srobert static const char * 791a3f7ec94Srobert element_type_name(int et) 792a3f7ec94Srobert { 793a3f7ec94Srobert int i; 794a3f7ec94Srobert 795a3f7ec94Srobert for (i = 0; elements[i].et_name != NULL; i++) 796a3f7ec94Srobert if (elements[i].et_type == et) 797a3f7ec94Srobert return elements[i].et_name; 798a3f7ec94Srobert 799a3f7ec94Srobert return "unknown"; 800a3f7ec94Srobert } 801a3f7ec94Srobert 802c16b380fSderaadt static int 803ab83b6d6Sderaadt parse_element_unit(char *cp) 804c16b380fSderaadt { 805c16b380fSderaadt int i; 806c16b380fSderaadt char *p; 807c16b380fSderaadt 808c16b380fSderaadt i = (int)strtol(cp, &p, 10); 809c16b380fSderaadt if ((i < 0) || (*p != '\0')) 810c16b380fSderaadt errx(1, "invalid unit number `%s'", cp); 811c16b380fSderaadt 812c16b380fSderaadt return (i); 813c16b380fSderaadt } 814c16b380fSderaadt 815c16b380fSderaadt static int 816ab83b6d6Sderaadt parse_special(char *cp) 817c16b380fSderaadt { 818c16b380fSderaadt int val; 819c16b380fSderaadt 820c16b380fSderaadt val = is_special(cp); 821c16b380fSderaadt if (val) 822c16b380fSderaadt return (val); 823c16b380fSderaadt 824c16b380fSderaadt errx(1, "invalid modifier `%s'", cp); 825c16b380fSderaadt } 826c16b380fSderaadt 827c16b380fSderaadt static int 828ab83b6d6Sderaadt is_special(char *cp) 829c16b380fSderaadt { 830c16b380fSderaadt int i; 831c16b380fSderaadt 832c16b380fSderaadt for (i = 0; specials[i].sw_name != NULL; ++i) 833c16b380fSderaadt if (strcmp(specials[i].sw_name, cp) == 0) 834c16b380fSderaadt return (specials[i].sw_value); 835c16b380fSderaadt 836c16b380fSderaadt return (0); 837c16b380fSderaadt } 838c16b380fSderaadt 839c16b380fSderaadt static char * 840ab83b6d6Sderaadt bits_to_string(int v, const char *cp) 841c16b380fSderaadt { 842c16b380fSderaadt const char *np; 843c16b380fSderaadt char f, sep, *bp; 844c16b380fSderaadt static char buf[128]; 845c16b380fSderaadt 846c16b380fSderaadt bp = buf; 847c16b380fSderaadt bzero(buf, sizeof(buf)); 848c16b380fSderaadt 849c16b380fSderaadt for (sep = '<'; (f = *cp++) != 0; cp = np) { 850c16b380fSderaadt for (np = cp; *np >= ' ';) 851c16b380fSderaadt np++; 852c16b380fSderaadt if ((v & (1 << (f - 1))) == 0) 853c16b380fSderaadt continue; 8542f61c7c6Smillert (void)snprintf(bp, sizeof(buf) - (bp - &buf[0]), 855707c1213Sart "%c%.*s", sep, (int)(np - cp), cp); 8562f61c7c6Smillert bp += strlen(bp); 857c16b380fSderaadt sep = ','; 858c16b380fSderaadt } 859c16b380fSderaadt if (sep != '<') 860c16b380fSderaadt *bp = '>'; 861c16b380fSderaadt 862c16b380fSderaadt return (buf); 863c16b380fSderaadt } 864c16b380fSderaadt 865c16b380fSderaadt static void 866ab83b6d6Sderaadt usage(void) 867c16b380fSderaadt { 868b13cd761Sderaadt int i; 869c16b380fSderaadt 870cc600725Ssobrado fprintf(stderr, "usage: %s [-f changer] command [arg ...]\n", 871b13cd761Sderaadt __progname); 872c16b380fSderaadt exit(1); 873c16b380fSderaadt } 874