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