1 1.33 jnemeth /* $NetBSD: chio.c,v 1.33 2017/10/16 17:08:35 jnemeth Exp $ */ 2 1.1 thorpej 3 1.13 thorpej /*- 4 1.13 thorpej * Copyright (c) 1996, 1998, 1999 The NetBSD Foundation, Inc. 5 1.1 thorpej * All rights reserved. 6 1.1 thorpej * 7 1.13 thorpej * This code is derived from software contributed to The NetBSD Foundation 8 1.13 thorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 9 1.13 thorpej * NASA Ames Research Center. 10 1.13 thorpej * 11 1.1 thorpej * Redistribution and use in source and binary forms, with or without 12 1.1 thorpej * modification, are permitted provided that the following conditions 13 1.1 thorpej * are met: 14 1.1 thorpej * 1. Redistributions of source code must retain the above copyright 15 1.1 thorpej * notice, this list of conditions and the following disclaimer. 16 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 thorpej * notice, this list of conditions and the following disclaimer in the 18 1.1 thorpej * documentation and/or other materials provided with the distribution. 19 1.1 thorpej * 20 1.13 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 1.13 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 1.13 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 1.13 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 1.13 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 1.13 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 1.13 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 1.13 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 1.13 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 1.13 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 1.13 thorpej * POSSIBILITY OF SUCH DAMAGE. 31 1.1 thorpej */ 32 1.13 thorpej 33 1.5 mjacob /* 34 1.5 mjacob * Additional Copyright (c) 1997, by Matthew Jacob, for NASA/Ames Research Ctr. 35 1.5 mjacob */ 36 1.1 thorpej 37 1.2 thorpej #include <sys/cdefs.h> 38 1.2 thorpej #ifndef lint 39 1.7 hpeyerl __COPYRIGHT( 40 1.13 thorpej "@(#) Copyright (c) 1996, 1998, 1999\ 41 1.30 lukem The NetBSD Foundation, Inc. All rights reserved."); 42 1.33 jnemeth __RCSID("$NetBSD: chio.c,v 1.33 2017/10/16 17:08:35 jnemeth Exp $"); 43 1.2 thorpej #endif 44 1.2 thorpej 45 1.1 thorpej #include <sys/param.h> 46 1.1 thorpej #include <sys/ioctl.h> 47 1.18 enami #include <sys/chio.h> 48 1.7 hpeyerl #include <sys/cdio.h> /* for ATAPI CD changer; too bad it uses a lame API */ 49 1.16 wiz 50 1.13 thorpej #include <ctype.h> 51 1.1 thorpej #include <err.h> 52 1.1 thorpej #include <errno.h> 53 1.1 thorpej #include <fcntl.h> 54 1.1 thorpej #include <limits.h> 55 1.1 thorpej #include <stdio.h> 56 1.1 thorpej #include <stdlib.h> 57 1.1 thorpej #include <string.h> 58 1.1 thorpej #include <unistd.h> 59 1.1 thorpej 60 1.1 thorpej #include "defs.h" 61 1.1 thorpej #include "pathnames.h" 62 1.1 thorpej 63 1.31 joerg __dead static void usage(void); 64 1.16 wiz static void cleanup(void); 65 1.16 wiz static int parse_element_type(const char *); 66 1.16 wiz static int parse_element_unit(const char *); 67 1.16 wiz static int parse_special(const char *); 68 1.16 wiz static int is_special(const char *); 69 1.16 wiz static const char *bits_to_string(int, const char *); 70 1.16 wiz 71 1.16 wiz static int do_move(const char *, int, char **); 72 1.16 wiz static int do_exchange(const char *, int, char **); 73 1.16 wiz static int do_position(const char *, int, char **); 74 1.16 wiz static int do_params(const char *, int, char **); 75 1.16 wiz static int do_getpicker(const char *, int, char **); 76 1.16 wiz static int do_setpicker(const char *, int, char **); 77 1.16 wiz static int do_status(const char *, int, char **); 78 1.16 wiz static int do_ielem(const char *, int, char **); 79 1.16 wiz static int do_cdlu(const char *, int, char **); 80 1.1 thorpej 81 1.1 thorpej /* Valid changer element types. */ 82 1.1 thorpej const struct element_type elements[] = { 83 1.1 thorpej { "picker", CHET_MT }, 84 1.1 thorpej { "slot", CHET_ST }, 85 1.1 thorpej { "portal", CHET_IE }, 86 1.1 thorpej { "drive", CHET_DT }, 87 1.1 thorpej { NULL, 0 }, 88 1.1 thorpej }; 89 1.1 thorpej 90 1.1 thorpej /* Valid commands. */ 91 1.1 thorpej const struct changer_command commands[] = { 92 1.12 thorpej { "move", " <from ET> <from EU> <to ET> <to EU> [inv]", 93 1.12 thorpej do_move }, 94 1.12 thorpej 95 1.11 hubertf { "exchange", " <src ET> <src EU> <dst1 ET> <dst1 EU>\n" 96 1.18 enami "\t\t [<dst2 ET> <dst2 EU>] [inv1] [inv2]", 97 1.12 thorpej do_exchange }, 98 1.12 thorpej 99 1.12 thorpej { "position", " <to ET> <to EU> [inv]", do_position }, 100 1.12 thorpej 101 1.12 thorpej { "params", "", 102 1.12 thorpej do_params }, 103 1.12 thorpej 104 1.12 thorpej { "getpicker", "", 105 1.12 thorpej do_getpicker }, 106 1.12 thorpej 107 1.12 thorpej { "setpicker", " <picker>", 108 1.12 thorpej do_setpicker }, 109 1.12 thorpej 110 1.13 thorpej { "status", " [<ET> [unit [count]]] [voltags]", 111 1.12 thorpej do_status }, 112 1.12 thorpej 113 1.12 thorpej { "ielem", "", 114 1.12 thorpej do_ielem }, 115 1.12 thorpej 116 1.11 hubertf { "cdlu", " load|unload <slot>\n" 117 1.18 enami "\t abort", 118 1.12 thorpej do_cdlu }, 119 1.12 thorpej 120 1.12 thorpej { NULL, NULL, 121 1.12 thorpej NULL }, 122 1.1 thorpej }; 123 1.1 thorpej 124 1.1 thorpej /* Valid special words. */ 125 1.1 thorpej const struct special_word specials[] = { 126 1.1 thorpej { "inv", SW_INVERT }, 127 1.1 thorpej { "inv1", SW_INVERT1 }, 128 1.1 thorpej { "inv2", SW_INVERT2 }, 129 1.13 thorpej { "voltags", SW_VOLTAGS }, 130 1.1 thorpej { NULL, 0 }, 131 1.1 thorpej }; 132 1.1 thorpej 133 1.16 wiz static const char *changer_name; 134 1.16 wiz static int changer_fd; 135 1.1 thorpej 136 1.1 thorpej int 137 1.16 wiz main(int argc, char *argv[]) 138 1.1 thorpej { 139 1.1 thorpej int ch, i; 140 1.1 thorpej 141 1.17 wiz setprogname(argv[0]); 142 1.1 thorpej while ((ch = getopt(argc, argv, "f:")) != -1) { 143 1.1 thorpej switch (ch) { 144 1.1 thorpej case 'f': 145 1.1 thorpej changer_name = optarg; 146 1.1 thorpej break; 147 1.1 thorpej default: 148 1.1 thorpej usage(); 149 1.20 jschauma /* NOTREACHED */ 150 1.1 thorpej } 151 1.1 thorpej } 152 1.1 thorpej argc -= optind; 153 1.1 thorpej argv += optind; 154 1.1 thorpej 155 1.1 thorpej if (argc == 0) 156 1.1 thorpej usage(); 157 1.20 jschauma /* NOTREACHED */ 158 1.20 jschauma 159 1.1 thorpej /* Get the default changer if not already specified. */ 160 1.1 thorpej if (changer_name == NULL) 161 1.1 thorpej if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL) 162 1.1 thorpej changer_name = _PATH_CH; 163 1.1 thorpej 164 1.1 thorpej /* Open the changer device. */ 165 1.1 thorpej if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1) 166 1.22 jschauma err(EXIT_FAILURE, "%s: open", changer_name); 167 1.20 jschauma /* NOTREACHED */ 168 1.1 thorpej 169 1.1 thorpej /* Register cleanup function. */ 170 1.1 thorpej if (atexit(cleanup)) 171 1.20 jschauma err(EXIT_FAILURE, "can't register cleanup function"); 172 1.20 jschauma /* NOTREACHED */ 173 1.1 thorpej 174 1.1 thorpej /* Find the specified command. */ 175 1.1 thorpej for (i = 0; commands[i].cc_name != NULL; ++i) 176 1.1 thorpej if (strcmp(*argv, commands[i].cc_name) == 0) 177 1.1 thorpej break; 178 1.1 thorpej if (commands[i].cc_name == NULL) 179 1.20 jschauma errx(EXIT_FAILURE, "unknown command: %s", *argv); 180 1.20 jschauma /* NOTREACHED */ 181 1.1 thorpej 182 1.1 thorpej /* Skip over the command name and call handler. */ 183 1.1 thorpej ++argv; --argc; 184 1.18 enami exit((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); 185 1.6 thorpej /* NOTREACHED */ 186 1.1 thorpej } 187 1.1 thorpej 188 1.1 thorpej static int 189 1.16 wiz do_move(const char *cname, int argc, char **argv) 190 1.1 thorpej { 191 1.13 thorpej struct changer_move_request cmd; 192 1.1 thorpej int val; 193 1.1 thorpej 194 1.1 thorpej /* 195 1.1 thorpej * On a move command, we expect the following: 196 1.1 thorpej * 197 1.1 thorpej * <from ET> <from EU> <to ET> <to EU> [inv] 198 1.1 thorpej * 199 1.1 thorpej * where ET == element type and EU == element unit. 200 1.1 thorpej */ 201 1.1 thorpej if (argc < 4) { 202 1.1 thorpej warnx("%s: too few arguments", cname); 203 1.11 hubertf usage(); 204 1.20 jschauma /*NOTREACHED*/ 205 1.1 thorpej } else if (argc > 5) { 206 1.1 thorpej warnx("%s: too many arguments", cname); 207 1.11 hubertf usage(); 208 1.20 jschauma /*NOTREACHED*/ 209 1.1 thorpej } 210 1.16 wiz (void)memset(&cmd, 0, sizeof(cmd)); 211 1.1 thorpej 212 1.1 thorpej /* <from ET> */ 213 1.1 thorpej cmd.cm_fromtype = parse_element_type(*argv); 214 1.1 thorpej ++argv; --argc; 215 1.1 thorpej 216 1.1 thorpej /* <from EU> */ 217 1.1 thorpej cmd.cm_fromunit = parse_element_unit(*argv); 218 1.1 thorpej ++argv; --argc; 219 1.1 thorpej 220 1.1 thorpej /* <to ET> */ 221 1.1 thorpej cmd.cm_totype = parse_element_type(*argv); 222 1.1 thorpej ++argv; --argc; 223 1.1 thorpej 224 1.1 thorpej /* <to EU> */ 225 1.1 thorpej cmd.cm_tounit = parse_element_unit(*argv); 226 1.1 thorpej ++argv; --argc; 227 1.1 thorpej 228 1.1 thorpej /* Deal with optional command modifier. */ 229 1.1 thorpej if (argc) { 230 1.1 thorpej val = parse_special(*argv); 231 1.1 thorpej switch (val) { 232 1.1 thorpej case SW_INVERT: 233 1.1 thorpej cmd.cm_flags |= CM_INVERT; 234 1.1 thorpej break; 235 1.1 thorpej default: 236 1.20 jschauma errx(EXIT_FAILURE, "%s: inappropriate modifier `%s'", 237 1.1 thorpej cname, *argv); 238 1.1 thorpej /* NOTREACHED */ 239 1.1 thorpej } 240 1.1 thorpej } 241 1.1 thorpej 242 1.1 thorpej /* Send command to changer. */ 243 1.6 thorpej if (ioctl(changer_fd, CHIOMOVE, &cmd)) 244 1.22 jschauma err(EXIT_FAILURE, "%s: CHIOMOVE", changer_name); 245 1.20 jschauma /* NOTREACHED */ 246 1.1 thorpej 247 1.1 thorpej return (0); 248 1.1 thorpej } 249 1.1 thorpej 250 1.1 thorpej static int 251 1.16 wiz do_exchange(const char *cname, int argc, char **argv) 252 1.1 thorpej { 253 1.13 thorpej struct changer_exchange_request cmd; 254 1.1 thorpej int val; 255 1.1 thorpej 256 1.1 thorpej /* 257 1.1 thorpej * On an exchange command, we expect the following: 258 1.1 thorpej * 259 1.1 thorpej * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2] 260 1.1 thorpej * 261 1.1 thorpej * where ET == element type and EU == element unit. 262 1.1 thorpej */ 263 1.1 thorpej if (argc < 4) { 264 1.1 thorpej warnx("%s: too few arguments", cname); 265 1.11 hubertf usage(); 266 1.20 jschauma /*NOTREACHED*/ 267 1.1 thorpej } else if (argc > 8) { 268 1.1 thorpej warnx("%s: too many arguments", cname); 269 1.11 hubertf usage(); 270 1.20 jschauma /*NOTREACHED*/ 271 1.1 thorpej } 272 1.16 wiz (void)memset(&cmd, 0, sizeof(cmd)); 273 1.1 thorpej 274 1.1 thorpej /* <src ET> */ 275 1.1 thorpej cmd.ce_srctype = parse_element_type(*argv); 276 1.1 thorpej ++argv; --argc; 277 1.1 thorpej 278 1.1 thorpej /* <src EU> */ 279 1.1 thorpej cmd.ce_srcunit = parse_element_unit(*argv); 280 1.1 thorpej ++argv; --argc; 281 1.1 thorpej 282 1.1 thorpej /* <dst1 ET> */ 283 1.1 thorpej cmd.ce_fdsttype = parse_element_type(*argv); 284 1.1 thorpej ++argv; --argc; 285 1.1 thorpej 286 1.1 thorpej /* <dst1 EU> */ 287 1.1 thorpej cmd.ce_fdstunit = parse_element_unit(*argv); 288 1.1 thorpej ++argv; --argc; 289 1.1 thorpej 290 1.1 thorpej /* 291 1.1 thorpej * If the next token is a special word or there are no more 292 1.1 thorpej * arguments, then this is a case of simple exchange. 293 1.1 thorpej * dst2 == src. 294 1.1 thorpej */ 295 1.1 thorpej if ((argc == 0) || is_special(*argv)) { 296 1.1 thorpej cmd.ce_sdsttype = cmd.ce_srctype; 297 1.1 thorpej cmd.ce_sdstunit = cmd.ce_srcunit; 298 1.1 thorpej goto do_special; 299 1.1 thorpej } 300 1.1 thorpej 301 1.1 thorpej /* <dst2 ET> */ 302 1.1 thorpej cmd.ce_sdsttype = parse_element_type(*argv); 303 1.1 thorpej ++argv; --argc; 304 1.1 thorpej 305 1.1 thorpej /* <dst2 EU> */ 306 1.1 thorpej cmd.ce_sdstunit = parse_element_unit(*argv); 307 1.1 thorpej ++argv; --argc; 308 1.1 thorpej 309 1.1 thorpej do_special: 310 1.1 thorpej /* Deal with optional command modifiers. */ 311 1.1 thorpej while (argc) { 312 1.1 thorpej val = parse_special(*argv); 313 1.1 thorpej ++argv; --argc; 314 1.1 thorpej switch (val) { 315 1.1 thorpej case SW_INVERT1: 316 1.1 thorpej cmd.ce_flags |= CE_INVERT1; 317 1.1 thorpej break; 318 1.1 thorpej case SW_INVERT2: 319 1.1 thorpej cmd.ce_flags |= CE_INVERT2; 320 1.1 thorpej break; 321 1.1 thorpej default: 322 1.20 jschauma errx(EXIT_FAILURE, "%s: inappropriate modifier `%s'", 323 1.1 thorpej cname, *argv); 324 1.1 thorpej /* NOTREACHED */ 325 1.1 thorpej } 326 1.1 thorpej } 327 1.1 thorpej 328 1.1 thorpej /* Send command to changer. */ 329 1.6 thorpej if (ioctl(changer_fd, CHIOEXCHANGE, &cmd)) 330 1.22 jschauma err(EXIT_FAILURE, "%s: CHIOEXCHANGE", changer_name); 331 1.20 jschauma /* NOTREACHED */ 332 1.1 thorpej 333 1.1 thorpej return (0); 334 1.1 thorpej } 335 1.1 thorpej 336 1.1 thorpej static int 337 1.16 wiz do_position(const char *cname, int argc, char **argv) 338 1.1 thorpej { 339 1.13 thorpej struct changer_position_request cmd; 340 1.1 thorpej int val; 341 1.1 thorpej 342 1.1 thorpej /* 343 1.1 thorpej * On a position command, we expect the following: 344 1.1 thorpej * 345 1.1 thorpej * <to ET> <to EU> [inv] 346 1.1 thorpej * 347 1.1 thorpej * where ET == element type and EU == element unit. 348 1.1 thorpej */ 349 1.1 thorpej if (argc < 2) { 350 1.1 thorpej warnx("%s: too few arguments", cname); 351 1.11 hubertf usage(); 352 1.20 jschauma /*NOTREACHED*/ 353 1.1 thorpej } else if (argc > 3) { 354 1.1 thorpej warnx("%s: too many arguments", cname); 355 1.11 hubertf usage(); 356 1.20 jschauma /*NOTREACHED*/ 357 1.1 thorpej } 358 1.16 wiz (void)memset(&cmd, 0, sizeof(cmd)); 359 1.1 thorpej 360 1.1 thorpej /* <to ET> */ 361 1.1 thorpej cmd.cp_type = parse_element_type(*argv); 362 1.1 thorpej ++argv; --argc; 363 1.1 thorpej 364 1.1 thorpej /* <to EU> */ 365 1.1 thorpej cmd.cp_unit = parse_element_unit(*argv); 366 1.1 thorpej ++argv; --argc; 367 1.1 thorpej 368 1.1 thorpej /* Deal with optional command modifier. */ 369 1.1 thorpej if (argc) { 370 1.1 thorpej val = parse_special(*argv); 371 1.1 thorpej switch (val) { 372 1.1 thorpej case SW_INVERT: 373 1.1 thorpej cmd.cp_flags |= CP_INVERT; 374 1.1 thorpej break; 375 1.1 thorpej default: 376 1.20 jschauma errx(EXIT_FAILURE, "%s: inappropriate modifier `%s'", 377 1.1 thorpej cname, *argv); 378 1.1 thorpej /* NOTREACHED */ 379 1.1 thorpej } 380 1.1 thorpej } 381 1.1 thorpej 382 1.1 thorpej /* Send command to changer. */ 383 1.6 thorpej if (ioctl(changer_fd, CHIOPOSITION, &cmd)) 384 1.22 jschauma err(EXIT_FAILURE, "%s: CHIOPOSITION", changer_name); 385 1.20 jschauma /* NOTREACHED */ 386 1.1 thorpej 387 1.1 thorpej return (0); 388 1.1 thorpej } 389 1.1 thorpej 390 1.6 thorpej /* ARGSUSED */ 391 1.1 thorpej static int 392 1.16 wiz do_params(const char *cname, int argc, char **argv) 393 1.1 thorpej { 394 1.1 thorpej struct changer_params data; 395 1.1 thorpej 396 1.1 thorpej /* No arguments to this command. */ 397 1.1 thorpej if (argc) { 398 1.28 msaitoh warnx("%s: no arguments expected", cname); 399 1.11 hubertf usage(); 400 1.20 jschauma /* NOTREACHED */ 401 1.1 thorpej } 402 1.20 jschauma 403 1.1 thorpej /* Get params from changer and display them. */ 404 1.16 wiz (void)memset(&data, 0, sizeof(data)); 405 1.6 thorpej if (ioctl(changer_fd, CHIOGPARAMS, &data)) 406 1.22 jschauma err(EXIT_FAILURE, "%s: CHIOGPARAMS", changer_name); 407 1.20 jschauma /* NOTREACHED */ 408 1.1 thorpej 409 1.13 thorpej #define PLURAL(n) (n) > 1 ? "s" : "" 410 1.13 thorpej 411 1.16 wiz (void)printf("%s: %d slot%s, %d drive%s, %d picker%s", 412 1.22 jschauma changer_name, 413 1.13 thorpej data.cp_nslots, PLURAL(data.cp_nslots), 414 1.13 thorpej data.cp_ndrives, PLURAL(data.cp_ndrives), 415 1.13 thorpej data.cp_npickers, PLURAL(data.cp_npickers)); 416 1.1 thorpej if (data.cp_nportals) 417 1.16 wiz (void)printf(", %d portal%s", data.cp_nportals, 418 1.13 thorpej PLURAL(data.cp_nportals)); 419 1.13 thorpej 420 1.13 thorpej #undef PLURAL 421 1.13 thorpej 422 1.22 jschauma (void)printf("\n%s: current picker: %d\n", changer_name, data.cp_curpicker); 423 1.1 thorpej 424 1.1 thorpej return (0); 425 1.1 thorpej } 426 1.1 thorpej 427 1.6 thorpej /* ARGSUSED */ 428 1.1 thorpej static int 429 1.16 wiz do_getpicker(const char *cname, int argc, char **argv) 430 1.1 thorpej { 431 1.1 thorpej int picker; 432 1.1 thorpej 433 1.1 thorpej /* No arguments to this command. */ 434 1.1 thorpej if (argc) { 435 1.1 thorpej warnx("%s: no arguments expected", cname); 436 1.11 hubertf usage(); 437 1.20 jschauma /*NOTREACHED*/ 438 1.1 thorpej } 439 1.1 thorpej 440 1.1 thorpej /* Get current picker from changer and display it. */ 441 1.6 thorpej if (ioctl(changer_fd, CHIOGPICKER, &picker)) 442 1.22 jschauma err(EXIT_FAILURE, "%s: CHIOGPICKER", changer_name); 443 1.20 jschauma /* NOTREACHED */ 444 1.1 thorpej 445 1.22 jschauma (void)printf("%s: current picker: %d\n", changer_name, picker); 446 1.1 thorpej 447 1.1 thorpej return (0); 448 1.1 thorpej } 449 1.1 thorpej 450 1.1 thorpej static int 451 1.16 wiz do_setpicker(const char *cname, int argc, char **argv) 452 1.1 thorpej { 453 1.1 thorpej int picker; 454 1.1 thorpej 455 1.1 thorpej if (argc < 1) { 456 1.1 thorpej warnx("%s: too few arguments", cname); 457 1.11 hubertf usage(); 458 1.20 jschauma /*NOTREACHED*/ 459 1.1 thorpej } else if (argc > 1) { 460 1.1 thorpej warnx("%s: too many arguments", cname); 461 1.11 hubertf usage(); 462 1.20 jschauma /*NOTREACHED*/ 463 1.1 thorpej } 464 1.1 thorpej 465 1.1 thorpej picker = parse_element_unit(*argv); 466 1.1 thorpej 467 1.1 thorpej /* Set the changer picker. */ 468 1.6 thorpej if (ioctl(changer_fd, CHIOSPICKER, &picker)) 469 1.22 jschauma err(EXIT_FAILURE, "%s: CHIOSPICKER", changer_name); 470 1.1 thorpej 471 1.1 thorpej return (0); 472 1.1 thorpej } 473 1.1 thorpej 474 1.1 thorpej static int 475 1.16 wiz do_status(const char *cname, int argc, char **argv) 476 1.1 thorpej { 477 1.13 thorpej struct changer_element_status_request cmd; 478 1.1 thorpej struct changer_params data; 479 1.13 thorpej struct changer_element_status *ces; 480 1.16 wiz int i, chet, count, echet, flags, have_ucount, have_unit; 481 1.16 wiz int schet, ucount, unit; 482 1.13 thorpej size_t size; 483 1.18 enami 484 1.16 wiz flags = 0; 485 1.27 lukem ucount = 0; 486 1.27 lukem unit = 0; 487 1.16 wiz have_ucount = 0; 488 1.16 wiz have_unit = 0; 489 1.1 thorpej 490 1.1 thorpej /* 491 1.1 thorpej * On a status command, we expect the following: 492 1.1 thorpej * 493 1.13 thorpej * [<ET> [unit [count]]] [voltags] 494 1.1 thorpej * 495 1.1 thorpej * where ET == element type. 496 1.1 thorpej * 497 1.13 thorpej * If we get no element-related arguments, we get the status of all 498 1.1 thorpej * known element types. 499 1.1 thorpej */ 500 1.13 thorpej if (argc > 4) { 501 1.1 thorpej warnx("%s: too many arguments", cname); 502 1.11 hubertf usage(); 503 1.20 jschauma /*NOTREACHED*/ 504 1.1 thorpej } 505 1.1 thorpej 506 1.1 thorpej /* 507 1.1 thorpej * Get params from changer. Specifically, we need the element 508 1.1 thorpej * counts. 509 1.1 thorpej */ 510 1.16 wiz (void)memset(&data, 0, sizeof(data)); 511 1.6 thorpej if (ioctl(changer_fd, CHIOGPARAMS, &data)) 512 1.22 jschauma err(EXIT_FAILURE, "%s: CHIOGPARAMS", changer_name); 513 1.20 jschauma /* NOTREACHED */ 514 1.1 thorpej 515 1.13 thorpej schet = CHET_MT; 516 1.13 thorpej echet = CHET_DT; 517 1.13 thorpej 518 1.13 thorpej for (; argc != 0; argc--, argv++) { 519 1.13 thorpej /* 520 1.13 thorpej * If we have the voltags modifier, it must be the 521 1.13 thorpej * last argument. 522 1.13 thorpej */ 523 1.13 thorpej if (is_special(argv[0])) { 524 1.13 thorpej if (argc != 1) { 525 1.13 thorpej warnx("%s: malformed command line", cname); 526 1.13 thorpej usage(); 527 1.20 jschauma /*NOTREACHED*/ 528 1.13 thorpej } 529 1.13 thorpej if (parse_special(argv[0]) != SW_VOLTAGS) 530 1.20 jschauma errx(EXIT_FAILURE, 531 1.20 jschauma "%s: inappropriate special word: %s", 532 1.13 thorpej cname, argv[0]); 533 1.20 jschauma /* NOTREACHED */ 534 1.13 thorpej flags |= CESR_VOLTAGS; 535 1.13 thorpej continue; 536 1.13 thorpej } 537 1.13 thorpej 538 1.13 thorpej /* 539 1.13 thorpej * If we get an element type, we can't have specified 540 1.13 thorpej * anything else. 541 1.13 thorpej */ 542 1.26 dsl if (isdigit((unsigned char)*argv[0]) == 0) { 543 1.13 thorpej if (schet == echet || flags != 0 || have_unit || 544 1.13 thorpej have_ucount) { 545 1.13 thorpej warnx("%s: malformed command line", cname); 546 1.13 thorpej usage(); 547 1.20 jschauma /*NOTREACHED*/ 548 1.13 thorpej } 549 1.13 thorpej schet = echet = parse_element_type(argv[0]); 550 1.13 thorpej continue; 551 1.13 thorpej } 552 1.13 thorpej 553 1.13 thorpej /* 554 1.13 thorpej * We know we have a digit here. If we do, we must 555 1.13 thorpej * have specified an element type. 556 1.13 thorpej */ 557 1.13 thorpej if (schet != echet) { 558 1.13 thorpej warnx("%s: malformed command line", cname); 559 1.13 thorpej usage(); 560 1.20 jschauma /*NOTREACHED*/ 561 1.13 thorpej } 562 1.13 thorpej 563 1.13 thorpej i = parse_element_unit(argv[0]); 564 1.13 thorpej 565 1.13 thorpej if (have_unit == 0) { 566 1.13 thorpej unit = i; 567 1.13 thorpej have_unit = 1; 568 1.13 thorpej } else if (have_ucount == 0) { 569 1.13 thorpej ucount = i; 570 1.13 thorpej have_ucount = 1; 571 1.13 thorpej } else { 572 1.13 thorpej warnx("%s: malformed command line", cname); 573 1.13 thorpej usage(); 574 1.20 jschauma /*NOTREACHED*/ 575 1.13 thorpej } 576 1.1 thorpej } 577 1.1 thorpej 578 1.1 thorpej for (chet = schet; chet <= echet; ++chet) { 579 1.1 thorpej switch (chet) { 580 1.1 thorpej case CHET_MT: 581 1.1 thorpej count = data.cp_npickers; 582 1.1 thorpej break; 583 1.1 thorpej case CHET_ST: 584 1.1 thorpej count = data.cp_nslots; 585 1.1 thorpej break; 586 1.1 thorpej case CHET_IE: 587 1.1 thorpej count = data.cp_nportals; 588 1.1 thorpej break; 589 1.1 thorpej case CHET_DT: 590 1.1 thorpej count = data.cp_ndrives; 591 1.1 thorpej break; 592 1.2 thorpej default: 593 1.2 thorpej /* To appease gcc -Wuninitialized. */ 594 1.2 thorpej count = 0; 595 1.1 thorpej } 596 1.1 thorpej 597 1.1 thorpej if (count == 0) { 598 1.13 thorpej if (schet != echet) 599 1.1 thorpej continue; 600 1.1 thorpej else { 601 1.16 wiz (void)printf("%s: no %s elements\n", 602 1.22 jschauma changer_name, 603 1.13 thorpej elements[chet].et_name); 604 1.1 thorpej return (0); 605 1.1 thorpej } 606 1.1 thorpej } 607 1.1 thorpej 608 1.13 thorpej /* 609 1.13 thorpej * If we have a unit, we may or may not have a count. 610 1.13 thorpej * If we don't have a unit, we don't have a count, either. 611 1.13 thorpej * 612 1.13 thorpej * Make sure both are initialized. 613 1.13 thorpej */ 614 1.13 thorpej if (have_unit) { 615 1.13 thorpej if (have_ucount == 0) 616 1.13 thorpej ucount = 1; 617 1.13 thorpej } else { 618 1.13 thorpej unit = 0; 619 1.13 thorpej ucount = count; 620 1.13 thorpej } 621 1.13 thorpej 622 1.13 thorpej if ((unit + ucount) > count) 623 1.33 jnemeth errx(EXIT_FAILURE, "%s: invalid unit/count %d/%d", 624 1.13 thorpej cname, unit, ucount); 625 1.20 jschauma /* NOTREACHED */ 626 1.13 thorpej 627 1.13 thorpej size = ucount * sizeof(struct changer_element_status); 628 1.13 thorpej 629 1.1 thorpej /* Allocate storage for the status bytes. */ 630 1.13 thorpej if ((ces = malloc(size)) == NULL) 631 1.20 jschauma errx(EXIT_FAILURE, "can't allocate status storage"); 632 1.20 jschauma /* NOTREACHED */ 633 1.1 thorpej 634 1.16 wiz (void)memset(ces, 0, size); 635 1.16 wiz (void)memset(&cmd, 0, sizeof(cmd)); 636 1.1 thorpej 637 1.13 thorpej cmd.cesr_type = chet; 638 1.13 thorpej cmd.cesr_unit = unit; 639 1.13 thorpej cmd.cesr_count = ucount; 640 1.13 thorpej cmd.cesr_flags = flags; 641 1.13 thorpej cmd.cesr_data = ces; 642 1.13 thorpej 643 1.13 thorpej /* 644 1.13 thorpej * Should we deal with this eventually? 645 1.13 thorpej */ 646 1.13 thorpej cmd.cesr_vendor_data = NULL; 647 1.1 thorpej 648 1.6 thorpej if (ioctl(changer_fd, CHIOGSTATUS, &cmd)) { 649 1.13 thorpej free(ces); 650 1.22 jschauma err(EXIT_FAILURE, "%s: CHIOGSTATUS", changer_name); 651 1.20 jschauma /* NOTREACHED */ 652 1.1 thorpej } 653 1.1 thorpej 654 1.1 thorpej /* Dump the status for each element of this type. */ 655 1.13 thorpej for (i = 0; i < ucount; i++) { 656 1.16 wiz (void)printf("%s %d: ", elements[chet].et_name, 657 1.13 thorpej unit + i); 658 1.13 thorpej if ((ces[i].ces_flags & CESTATUS_STATUS_VALID) == 0) { 659 1.16 wiz (void)printf("status not available\n"); 660 1.13 thorpej continue; 661 1.13 thorpej } 662 1.16 wiz (void)printf("%s", bits_to_string(ces[i].ces_flags, 663 1.13 thorpej CESTATUS_BITS)); 664 1.13 thorpej if (ces[i].ces_flags & CESTATUS_XNAME_VALID) 665 1.16 wiz (void)printf(" (%s)", ces[i].ces_xname); 666 1.16 wiz (void)printf("\n"); 667 1.13 thorpej if (ces[i].ces_flags & CESTATUS_PVOL_VALID) 668 1.16 wiz (void)printf("\tPrimary volume tag: %s " 669 1.13 thorpej "ver. %d\n", 670 1.13 thorpej ces[i].ces_pvoltag.cv_tag, 671 1.13 thorpej ces[i].ces_pvoltag.cv_serial); 672 1.13 thorpej if (ces[i].ces_flags & CESTATUS_AVOL_VALID) 673 1.16 wiz (void)printf("\tAlternate volume tag: %s " 674 1.13 thorpej "ver. %d\n", 675 1.13 thorpej ces[i].ces_avoltag.cv_tag, 676 1.13 thorpej ces[i].ces_avoltag.cv_serial); 677 1.13 thorpej if (ces[i].ces_flags & CESTATUS_FROM_VALID) 678 1.16 wiz (void)printf("\tFrom: %s %d\n", 679 1.13 thorpej elements[ces[i].ces_from_type].et_name, 680 1.13 thorpej ces[i].ces_from_unit); 681 1.14 thorpej if (ces[i].ces_vendor_len) 682 1.16 wiz (void)printf("\tVendor-specific data size: " 683 1.14 thorpej "%lu\n", (u_long)ces[i].ces_vendor_len); 684 1.1 thorpej } 685 1.13 thorpej free(ces); 686 1.1 thorpej } 687 1.1 thorpej 688 1.1 thorpej return (0); 689 1.1 thorpej } 690 1.1 thorpej 691 1.6 thorpej /* ARGSUSED */ 692 1.1 thorpej static int 693 1.16 wiz do_ielem(const char *cname, int argc, char **argv) 694 1.5 mjacob { 695 1.18 enami 696 1.6 thorpej if (ioctl(changer_fd, CHIOIELEM, NULL)) 697 1.22 jschauma err(EXIT_FAILURE, "%s: CHIOIELEM", changer_name); 698 1.20 jschauma /* NOTREACHED */ 699 1.5 mjacob 700 1.5 mjacob return (0); 701 1.5 mjacob } 702 1.5 mjacob 703 1.13 thorpej /* ARGSUSED */ 704 1.7 hpeyerl static int 705 1.16 wiz do_cdlu(const char *cname, int argc, char **argv) 706 1.7 hpeyerl { 707 1.7 hpeyerl static const struct special_word cdlu_subcmds[] = { 708 1.7 hpeyerl { "load", CD_LU_LOAD }, 709 1.7 hpeyerl { "unload", CD_LU_UNLOAD }, 710 1.7 hpeyerl { "abort", CD_LU_ABORT }, 711 1.7 hpeyerl { NULL, 0 }, 712 1.7 hpeyerl }; 713 1.16 wiz struct ioc_load_unload cmd; 714 1.16 wiz int i; 715 1.7 hpeyerl 716 1.7 hpeyerl /* 717 1.7 hpeyerl * This command is a little different, since we are mostly dealing 718 1.7 hpeyerl * with ATAPI CD changers, which have a lame API (since ATAPI doesn't 719 1.7 hpeyerl * have LUNs). 720 1.7 hpeyerl * 721 1.7 hpeyerl * We have 3 sub-commands: "load", "unload", and "abort". The 722 1.7 hpeyerl * first two take a slot number. The latter does not. 723 1.7 hpeyerl */ 724 1.7 hpeyerl 725 1.7 hpeyerl if (argc < 1 || argc > 2) 726 1.11 hubertf usage(); 727 1.20 jschauma /*NOTREACHED*/ 728 1.7 hpeyerl 729 1.7 hpeyerl for (i = 0; cdlu_subcmds[i].sw_name != NULL; i++) { 730 1.7 hpeyerl if (strcmp(argv[0], cdlu_subcmds[i].sw_name) == 0) { 731 1.7 hpeyerl cmd.options = cdlu_subcmds[i].sw_value; 732 1.7 hpeyerl break; 733 1.7 hpeyerl } 734 1.7 hpeyerl } 735 1.7 hpeyerl if (cdlu_subcmds[i].sw_name == NULL) 736 1.11 hubertf usage(); 737 1.20 jschauma /*NOTREACHED*/ 738 1.7 hpeyerl 739 1.7 hpeyerl if (strcmp(argv[0], "abort") == 0) 740 1.7 hpeyerl cmd.slot = 0; 741 1.7 hpeyerl else 742 1.7 hpeyerl cmd.slot = parse_element_unit(argv[1]); 743 1.7 hpeyerl 744 1.7 hpeyerl /* 745 1.7 hpeyerl * XXX Should maybe do something different with the device 746 1.7 hpeyerl * XXX handling for cdlu; think about this some more. 747 1.7 hpeyerl */ 748 1.7 hpeyerl if (ioctl(changer_fd, CDIOCLOADUNLOAD, &cmd)) 749 1.22 jschauma err(EXIT_FAILURE, "%s: CDIOCLOADUNLOAD", changer_name); 750 1.20 jschauma /* NOTREACHED */ 751 1.7 hpeyerl 752 1.7 hpeyerl return (0); 753 1.7 hpeyerl } 754 1.5 mjacob 755 1.5 mjacob static int 756 1.16 wiz parse_element_type(const char *cp) 757 1.1 thorpej { 758 1.1 thorpej int i; 759 1.1 thorpej 760 1.1 thorpej for (i = 0; elements[i].et_name != NULL; ++i) 761 1.1 thorpej if (strcmp(elements[i].et_name, cp) == 0) 762 1.1 thorpej return (elements[i].et_type); 763 1.1 thorpej 764 1.20 jschauma errx(EXIT_FAILURE, "invalid element type `%s'", cp); 765 1.6 thorpej /* NOTREACHED */ 766 1.1 thorpej } 767 1.1 thorpej 768 1.1 thorpej static int 769 1.16 wiz parse_element_unit(const char *cp) 770 1.1 thorpej { 771 1.16 wiz char *p; 772 1.1 thorpej int i; 773 1.1 thorpej 774 1.1 thorpej i = (int)strtol(cp, &p, 10); 775 1.1 thorpej if ((i < 0) || (*p != '\0')) 776 1.20 jschauma errx(EXIT_FAILURE, "invalid unit number `%s'", cp); 777 1.1 thorpej 778 1.1 thorpej return (i); 779 1.1 thorpej } 780 1.1 thorpej 781 1.1 thorpej static int 782 1.16 wiz parse_special(const char *cp) 783 1.1 thorpej { 784 1.1 thorpej int val; 785 1.1 thorpej 786 1.1 thorpej val = is_special(cp); 787 1.1 thorpej if (val) 788 1.1 thorpej return (val); 789 1.1 thorpej 790 1.20 jschauma errx(EXIT_FAILURE, "invalid modifier `%s'", cp); 791 1.6 thorpej /* NOTREACHED */ 792 1.1 thorpej } 793 1.1 thorpej 794 1.1 thorpej static int 795 1.16 wiz is_special(const char *cp) 796 1.1 thorpej { 797 1.1 thorpej int i; 798 1.1 thorpej 799 1.1 thorpej for (i = 0; specials[i].sw_name != NULL; ++i) 800 1.1 thorpej if (strcmp(specials[i].sw_name, cp) == 0) 801 1.1 thorpej return (specials[i].sw_value); 802 1.1 thorpej 803 1.1 thorpej return (0); 804 1.1 thorpej } 805 1.1 thorpej 806 1.8 mycroft static const char * 807 1.16 wiz bits_to_string(int v, const char *cp) 808 1.1 thorpej { 809 1.16 wiz static char buf[128]; 810 1.1 thorpej const char *np; 811 1.16 wiz char *bp, f; 812 1.8 mycroft int first; 813 1.1 thorpej 814 1.1 thorpej bp = buf; 815 1.8 mycroft *bp++ = '<'; 816 1.8 mycroft for (first = 1; (f = *cp++) != 0; cp = np) { 817 1.1 thorpej for (np = cp; *np >= ' ';) 818 1.1 thorpej np++; 819 1.1 thorpej if ((v & (1 << (f - 1))) == 0) 820 1.1 thorpej continue; 821 1.8 mycroft if (first) 822 1.8 mycroft first = 0; 823 1.8 mycroft else 824 1.8 mycroft *bp++ = ','; 825 1.16 wiz (void)memcpy(bp, cp, np - cp); 826 1.8 mycroft bp += np - cp; 827 1.1 thorpej } 828 1.8 mycroft *bp++ = '>'; 829 1.8 mycroft *bp = '\0'; 830 1.1 thorpej 831 1.1 thorpej return (buf); 832 1.1 thorpej } 833 1.1 thorpej 834 1.1 thorpej static void 835 1.16 wiz cleanup(void) 836 1.1 thorpej { 837 1.18 enami 838 1.1 thorpej /* Simple enough... */ 839 1.1 thorpej (void)close(changer_fd); 840 1.1 thorpej } 841 1.1 thorpej 842 1.1 thorpej static void 843 1.16 wiz usage(void) 844 1.1 thorpej { 845 1.11 hubertf int i; 846 1.1 thorpej 847 1.25 wiz (void)fprintf(stderr, 848 1.25 wiz "usage: %s [-f changer] command arg1 arg2 [arg3 [...]]\n", 849 1.15 cgd getprogname()); 850 1.18 enami 851 1.16 wiz (void)fprintf(stderr, "Where command (and args) are:\n"); 852 1.13 thorpej for (i = 0; commands[i].cc_name != NULL; i++) 853 1.16 wiz (void)fprintf(stderr, "\t%s%s\n", commands[i].cc_name, 854 1.13 thorpej commands[i].cc_args); 855 1.1 thorpej exit(1); 856 1.10 mycroft /* NOTREACHED */ 857 1.1 thorpej } 858