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