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