chio.c revision 23449
123449Sjoerg/*	$Id: $	*/
223449Sjoerg
323449Sjoerg/*
423449Sjoerg * Copyright (c) 1996 Jason R. Thorpe <thorpej@and.com>
523449Sjoerg * All rights reserved.
623449Sjoerg *
723449Sjoerg * Redistribution and use in source and binary forms, with or without
823449Sjoerg * modification, are permitted provided that the following conditions
923449Sjoerg * are met:
1023449Sjoerg * 1. Redistributions of source code must retain the above copyright
1123449Sjoerg *    notice, this list of conditions and the following disclaimer.
1223449Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1323449Sjoerg *    notice, this list of conditions and the following disclaimer in the
1423449Sjoerg *    documentation and/or other materials provided with the distribution.
1523449Sjoerg * 3. All advertising materials mentioning features or use of this software
1623449Sjoerg *    must display the following acknowledgements:
1723449Sjoerg *	This product includes software developed by Jason R. Thorpe
1823449Sjoerg *	for And Communications, http://www.and.com/
1923449Sjoerg * 4. The name of the author may not be used to endorse or promote products
2023449Sjoerg *    derived from this software without specific prior written permission.
2123449Sjoerg *
2223449Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2323449Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2423449Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2523449Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2623449Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2723449Sjoerg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2823449Sjoerg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2923449Sjoerg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3023449Sjoerg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3123449Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3223449Sjoerg * SUCH DAMAGE.
3323449Sjoerg */
3423449Sjoerg
3523449Sjoerg#include <sys/param.h>
3623449Sjoerg#include <sys/ioctl.h>
3723449Sjoerg#include <sys/chio.h>
3823449Sjoerg#include <err.h>
3923449Sjoerg#include <errno.h>
4023449Sjoerg#include <fcntl.h>
4123449Sjoerg#include <limits.h>
4223449Sjoerg#include <stdio.h>
4323449Sjoerg#include <stdlib.h>
4423449Sjoerg#include <string.h>
4523449Sjoerg#include <unistd.h>
4623449Sjoerg
4723449Sjoerg#include "defs.h"
4823449Sjoerg#include "pathnames.h"
4923449Sjoerg
5023449Sjoergextern	char *__progname;	/* from crt0.o */
5123449Sjoerg
5223449Sjoergstatic	void usage __P((void));
5323449Sjoergstatic	void cleanup __P((void));
5423449Sjoergstatic	int parse_element_type __P((char *));
5523449Sjoergstatic	int parse_element_unit __P((char *));
5623449Sjoergstatic	int parse_special __P((char *));
5723449Sjoergstatic	int is_special __P((char *));
5823449Sjoergstatic	char *bits_to_string __P((int, const char *));
5923449Sjoerg
6023449Sjoergstatic	int do_move __P((char *, int, char **));
6123449Sjoergstatic	int do_exchange __P((char *, int, char **));
6223449Sjoergstatic	int do_position __P((char *, int, char **));
6323449Sjoergstatic	int do_params __P((char *, int, char **));
6423449Sjoergstatic	int do_getpicker __P((char *, int, char **));
6523449Sjoergstatic	int do_setpicker __P((char *, int, char **));
6623449Sjoergstatic	int do_status __P((char *, int, char **));
6723449Sjoerg
6823449Sjoerg/* Valid changer element types. */
6923449Sjoergconst struct element_type elements[] = {
7023449Sjoerg	{ "picker",		CHET_MT },
7123449Sjoerg	{ "slot",		CHET_ST },
7223449Sjoerg	{ "portal",		CHET_IE },
7323449Sjoerg	{ "drive",		CHET_DT },
7423449Sjoerg	{ NULL,			0 },
7523449Sjoerg};
7623449Sjoerg
7723449Sjoerg/* Valid commands. */
7823449Sjoergconst struct changer_command commands[] = {
7923449Sjoerg	{ "move",		do_move },
8023449Sjoerg	{ "exchange",		do_exchange },
8123449Sjoerg	{ "position",		do_position },
8223449Sjoerg	{ "params",		do_params },
8323449Sjoerg	{ "getpicker",		do_getpicker },
8423449Sjoerg	{ "setpicker",		do_setpicker },
8523449Sjoerg	{ "status",		do_status },
8623449Sjoerg	{ NULL,			0 },
8723449Sjoerg};
8823449Sjoerg
8923449Sjoerg/* Valid special words. */
9023449Sjoergconst struct special_word specials[] = {
9123449Sjoerg	{ "inv",		SW_INVERT },
9223449Sjoerg	{ "inv1",		SW_INVERT1 },
9323449Sjoerg	{ "inv2",		SW_INVERT2 },
9423449Sjoerg	{ NULL,			0 },
9523449Sjoerg};
9623449Sjoerg
9723449Sjoergstatic	int changer_fd;
9823449Sjoergstatic	char *changer_name;
9923449Sjoerg
10023449Sjoergint
10123449Sjoergmain(argc, argv)
10223449Sjoerg	int argc;
10323449Sjoerg	char **argv;
10423449Sjoerg{
10523449Sjoerg	int ch, i;
10623449Sjoerg	char *cp;
10723449Sjoerg
10823449Sjoerg	while ((ch = getopt(argc, argv, "f:")) != -1) {
10923449Sjoerg		switch (ch) {
11023449Sjoerg		case 'f':
11123449Sjoerg			changer_name = optarg;
11223449Sjoerg			break;
11323449Sjoerg
11423449Sjoerg		default:
11523449Sjoerg			usage();
11623449Sjoerg		}
11723449Sjoerg	}
11823449Sjoerg	argc -= optind;
11923449Sjoerg	argv += optind;
12023449Sjoerg
12123449Sjoerg	if (argc == 0)
12223449Sjoerg		usage();
12323449Sjoerg
12423449Sjoerg	/* Get the default changer if not already specified. */
12523449Sjoerg	if (changer_name == NULL)
12623449Sjoerg		if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL)
12723449Sjoerg			changer_name = _PATH_CH;
12823449Sjoerg
12923449Sjoerg	/* Open the changer device. */
13023449Sjoerg	if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1)
13123449Sjoerg		err(1, "%s: open", changer_name);
13223449Sjoerg
13323449Sjoerg	/* Register cleanup function. */
13423449Sjoerg	if (atexit(cleanup))
13523449Sjoerg		err(1, "can't register cleanup function");
13623449Sjoerg
13723449Sjoerg	/* Find the specified command. */
13823449Sjoerg	for (i = 0; commands[i].cc_name != NULL; ++i)
13923449Sjoerg		if (strcmp(*argv, commands[i].cc_name) == 0)
14023449Sjoerg			break;
14123449Sjoerg	if (commands[i].cc_name == NULL)
14223449Sjoerg		errx(1, "unknown command: %s", *argv);
14323449Sjoerg
14423449Sjoerg	/* Skip over the command name and call handler. */
14523449Sjoerg	++argv; --argc;
14623449Sjoerg	exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv));
14723449Sjoerg}
14823449Sjoerg
14923449Sjoergstatic int
15023449Sjoergdo_move(cname, argc, argv)
15123449Sjoerg	char *cname;
15223449Sjoerg	int argc;
15323449Sjoerg	char **argv;
15423449Sjoerg{
15523449Sjoerg	struct changer_move cmd;
15623449Sjoerg	int val;
15723449Sjoerg
15823449Sjoerg	/*
15923449Sjoerg	 * On a move command, we expect the following:
16023449Sjoerg	 *
16123449Sjoerg	 * <from ET> <from EU> <to ET> <to EU> [inv]
16223449Sjoerg	 *
16323449Sjoerg	 * where ET == element type and EU == element unit.
16423449Sjoerg	 */
16523449Sjoerg	if (argc < 4) {
16623449Sjoerg		warnx("%s: too few arguments", cname);
16723449Sjoerg		goto usage;
16823449Sjoerg	} else if (argc > 5) {
16923449Sjoerg		warnx("%s: too many arguments", cname);
17023449Sjoerg		goto usage;
17123449Sjoerg	}
17223449Sjoerg	bzero(&cmd, sizeof(cmd));
17323449Sjoerg
17423449Sjoerg	/* <from ET>  */
17523449Sjoerg	cmd.cm_fromtype = parse_element_type(*argv);
17623449Sjoerg	++argv; --argc;
17723449Sjoerg
17823449Sjoerg	/* <from EU> */
17923449Sjoerg	cmd.cm_fromunit = parse_element_unit(*argv);
18023449Sjoerg	++argv; --argc;
18123449Sjoerg
18223449Sjoerg	/* <to ET> */
18323449Sjoerg	cmd.cm_totype = parse_element_type(*argv);
18423449Sjoerg	++argv; --argc;
18523449Sjoerg
18623449Sjoerg	/* <to EU> */
18723449Sjoerg	cmd.cm_tounit = parse_element_unit(*argv);
18823449Sjoerg	++argv; --argc;
18923449Sjoerg
19023449Sjoerg	/* Deal with optional command modifier. */
19123449Sjoerg	if (argc) {
19223449Sjoerg		val = parse_special(*argv);
19323449Sjoerg		switch (val) {
19423449Sjoerg		case SW_INVERT:
19523449Sjoerg			cmd.cm_flags |= CM_INVERT;
19623449Sjoerg			break;
19723449Sjoerg
19823449Sjoerg		default:
19923449Sjoerg			errx(1, "%s: inappropriate modifier `%s'",
20023449Sjoerg			    cname, *argv);
20123449Sjoerg			/* NOTREACHED */
20223449Sjoerg		}
20323449Sjoerg	}
20423449Sjoerg
20523449Sjoerg	/* Send command to changer. */
20623449Sjoerg	if (ioctl(changer_fd, CHIOMOVE, (char *)&cmd))
20723449Sjoerg		err(1, "%s: CHIOMOVE", changer_name);
20823449Sjoerg
20923449Sjoerg	return (0);
21023449Sjoerg
21123449Sjoerg usage:
21223449Sjoerg	fprintf(stderr, "usage: %s %s "
21323449Sjoerg	    "<from ET> <from EU> <to ET> <to EU> [inv]\n", __progname, cname);
21423449Sjoerg	return (1);
21523449Sjoerg}
21623449Sjoerg
21723449Sjoergstatic int
21823449Sjoergdo_exchange(cname, argc, argv)
21923449Sjoerg	char *cname;
22023449Sjoerg	int argc;
22123449Sjoerg	char **argv;
22223449Sjoerg{
22323449Sjoerg	struct changer_exchange cmd;
22423449Sjoerg	int val;
22523449Sjoerg
22623449Sjoerg	/*
22723449Sjoerg	 * On an exchange command, we expect the following:
22823449Sjoerg	 *
22923449Sjoerg  * <src ET> <src EU> <dst1 ET> <dst1 EU> [<dst2 ET> <dst2 EU>] [inv1] [inv2]
23023449Sjoerg	 *
23123449Sjoerg	 * where ET == element type and EU == element unit.
23223449Sjoerg	 */
23323449Sjoerg	if (argc < 4) {
23423449Sjoerg		warnx("%s: too few arguments", cname);
23523449Sjoerg		goto usage;
23623449Sjoerg	} else if (argc > 8) {
23723449Sjoerg		warnx("%s: too many arguments", cname);
23823449Sjoerg		goto usage;
23923449Sjoerg	}
24023449Sjoerg	bzero(&cmd, sizeof(cmd));
24123449Sjoerg
24223449Sjoerg	/* <src ET>  */
24323449Sjoerg	cmd.ce_srctype = parse_element_type(*argv);
24423449Sjoerg	++argv; --argc;
24523449Sjoerg
24623449Sjoerg	/* <src EU> */
24723449Sjoerg	cmd.ce_srcunit = parse_element_unit(*argv);
24823449Sjoerg	++argv; --argc;
24923449Sjoerg
25023449Sjoerg	/* <dst1 ET> */
25123449Sjoerg	cmd.ce_fdsttype = parse_element_type(*argv);
25223449Sjoerg	++argv; --argc;
25323449Sjoerg
25423449Sjoerg	/* <dst1 EU> */
25523449Sjoerg	cmd.ce_fdstunit = parse_element_unit(*argv);
25623449Sjoerg	++argv; --argc;
25723449Sjoerg
25823449Sjoerg	/*
25923449Sjoerg	 * If the next token is a special word or there are no more
26023449Sjoerg	 * arguments, then this is a case of simple exchange.
26123449Sjoerg	 * dst2 == src.
26223449Sjoerg	 */
26323449Sjoerg	if ((argc == 0) || is_special(*argv)) {
26423449Sjoerg		cmd.ce_sdsttype = cmd.ce_srctype;
26523449Sjoerg		cmd.ce_sdstunit = cmd.ce_srcunit;
26623449Sjoerg		goto do_special;
26723449Sjoerg	}
26823449Sjoerg
26923449Sjoerg	/* <dst2 ET> */
27023449Sjoerg	cmd.ce_sdsttype = parse_element_type(*argv);
27123449Sjoerg	++argv; --argc;
27223449Sjoerg
27323449Sjoerg	/* <dst2 EU> */
27423449Sjoerg	cmd.ce_sdstunit = parse_element_unit(*argv);
27523449Sjoerg	++argv; --argc;
27623449Sjoerg
27723449Sjoerg do_special:
27823449Sjoerg	/* Deal with optional command modifiers. */
27923449Sjoerg	while (argc) {
28023449Sjoerg		val = parse_special(*argv);
28123449Sjoerg		++argv; --argc;
28223449Sjoerg		switch (val) {
28323449Sjoerg		case SW_INVERT1:
28423449Sjoerg			cmd.ce_flags |= CE_INVERT1;
28523449Sjoerg			break;
28623449Sjoerg
28723449Sjoerg		case SW_INVERT2:
28823449Sjoerg			cmd.ce_flags |= CE_INVERT2;
28923449Sjoerg			break;
29023449Sjoerg
29123449Sjoerg		default:
29223449Sjoerg			errx(1, "%s: inappropriate modifier `%s'",
29323449Sjoerg			    cname, *argv);
29423449Sjoerg			/* NOTREACHED */
29523449Sjoerg		}
29623449Sjoerg	}
29723449Sjoerg
29823449Sjoerg	/* Send command to changer. */
29923449Sjoerg	if (ioctl(changer_fd, CHIOEXCHANGE, (char *)&cmd))
30023449Sjoerg		err(1, "%s: CHIOEXCHANGE", changer_name);
30123449Sjoerg
30223449Sjoerg	return (0);
30323449Sjoerg
30423449Sjoerg usage:
30523449Sjoerg	fprintf(stderr, "usage: %s %s <src ET> <src EU> <dst1 ET> <dst1 EU>\n"
30623449Sjoerg	    "       [<dst2 ET> <dst2 EU>] [inv1] [inv2]\n",
30723449Sjoerg	    __progname, cname);
30823449Sjoerg	return (1);
30923449Sjoerg}
31023449Sjoerg
31123449Sjoergstatic int
31223449Sjoergdo_position(cname, argc, argv)
31323449Sjoerg	char *cname;
31423449Sjoerg	int argc;
31523449Sjoerg	char **argv;
31623449Sjoerg{
31723449Sjoerg	struct changer_position cmd;
31823449Sjoerg	int val;
31923449Sjoerg
32023449Sjoerg	/*
32123449Sjoerg	 * On a position command, we expect the following:
32223449Sjoerg	 *
32323449Sjoerg	 * <to ET> <to EU> [inv]
32423449Sjoerg	 *
32523449Sjoerg	 * where ET == element type and EU == element unit.
32623449Sjoerg	 */
32723449Sjoerg	if (argc < 2) {
32823449Sjoerg		warnx("%s: too few arguments", cname);
32923449Sjoerg		goto usage;
33023449Sjoerg	} else if (argc > 3) {
33123449Sjoerg		warnx("%s: too many arguments", cname);
33223449Sjoerg		goto usage;
33323449Sjoerg	}
33423449Sjoerg	bzero(&cmd, sizeof(cmd));
33523449Sjoerg
33623449Sjoerg	/* <to ET>  */
33723449Sjoerg	cmd.cp_type = parse_element_type(*argv);
33823449Sjoerg	++argv; --argc;
33923449Sjoerg
34023449Sjoerg	/* <to EU> */
34123449Sjoerg	cmd.cp_unit = parse_element_unit(*argv);
34223449Sjoerg	++argv; --argc;
34323449Sjoerg
34423449Sjoerg	/* Deal with optional command modifier. */
34523449Sjoerg	if (argc) {
34623449Sjoerg		val = parse_special(*argv);
34723449Sjoerg		switch (val) {
34823449Sjoerg		case SW_INVERT:
34923449Sjoerg			cmd.cp_flags |= CP_INVERT;
35023449Sjoerg			break;
35123449Sjoerg
35223449Sjoerg		default:
35323449Sjoerg			errx(1, "%s: inappropriate modifier `%s'",
35423449Sjoerg			    cname, *argv);
35523449Sjoerg			/* NOTREACHED */
35623449Sjoerg		}
35723449Sjoerg	}
35823449Sjoerg
35923449Sjoerg	/* Send command to changer. */
36023449Sjoerg	if (ioctl(changer_fd, CHIOPOSITION, (char *)&cmd))
36123449Sjoerg		err(1, "%s: CHIOPOSITION", changer_name);
36223449Sjoerg
36323449Sjoerg	return (0);
36423449Sjoerg
36523449Sjoerg usage:
36623449Sjoerg	fprintf(stderr, "usage: %s %s <to ET> <to EU> [inv]\n",
36723449Sjoerg	    __progname, cname);
36823449Sjoerg	return (1);
36923449Sjoerg}
37023449Sjoerg
37123449Sjoergstatic int
37223449Sjoergdo_params(cname, argc, argv)
37323449Sjoerg	char *cname;
37423449Sjoerg	int argc;
37523449Sjoerg	char **argv;
37623449Sjoerg{
37723449Sjoerg	struct changer_params data;
37823449Sjoerg
37923449Sjoerg	/* No arguments to this command. */
38023449Sjoerg	if (argc) {
38123449Sjoerg		warnx("%s: no arguements expected", cname);
38223449Sjoerg		goto usage;
38323449Sjoerg	}
38423449Sjoerg
38523449Sjoerg	/* Get params from changer and display them. */
38623449Sjoerg	bzero(&data, sizeof(data));
38723449Sjoerg	if (ioctl(changer_fd, CHIOGPARAMS, (char *)&data))
38823449Sjoerg		err(1, "%s: CHIOGPARAMS", changer_name);
38923449Sjoerg
39023449Sjoerg	printf("%s: %d slot%s, %d drive%s, %d picker%s",
39123449Sjoerg	    changer_name,
39223449Sjoerg	    data.cp_nslots, (data.cp_nslots > 1) ? "s" : "",
39323449Sjoerg	    data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "",
39423449Sjoerg	    data.cp_npickers, (data.cp_npickers > 1) ? "s" : "");
39523449Sjoerg	if (data.cp_nportals)
39623449Sjoerg		printf(", %d portal%s", data.cp_nportals,
39723449Sjoerg		    (data.cp_nportals > 1) ? "s" : "");
39823449Sjoerg	printf("\n%s: current picker: %d\n", changer_name, data.cp_curpicker);
39923449Sjoerg
40023449Sjoerg	return (0);
40123449Sjoerg
40223449Sjoerg usage:
40323449Sjoerg	fprintf(stderr, "usage: %s %s\n", __progname, cname);
40423449Sjoerg	return (1);
40523449Sjoerg}
40623449Sjoerg
40723449Sjoergstatic int
40823449Sjoergdo_getpicker(cname, argc, argv)
40923449Sjoerg	char *cname;
41023449Sjoerg	int argc;
41123449Sjoerg	char **argv;
41223449Sjoerg{
41323449Sjoerg	int picker;
41423449Sjoerg
41523449Sjoerg	/* No arguments to this command. */
41623449Sjoerg	if (argc) {
41723449Sjoerg		warnx("%s: no arguments expected", cname);
41823449Sjoerg		goto usage;
41923449Sjoerg	}
42023449Sjoerg
42123449Sjoerg	/* Get current picker from changer and display it. */
42223449Sjoerg	if (ioctl(changer_fd, CHIOGPICKER, (char *)&picker))
42323449Sjoerg		err(1, "%s: CHIOGPICKER", changer_name);
42423449Sjoerg
42523449Sjoerg	printf("%s: current picker: %d\n", changer_name, picker);
42623449Sjoerg
42723449Sjoerg	return (0);
42823449Sjoerg
42923449Sjoerg usage:
43023449Sjoerg	fprintf(stderr, "usage: %s %s\n", __progname, cname);
43123449Sjoerg	return (1);
43223449Sjoerg}
43323449Sjoerg
43423449Sjoergstatic int
43523449Sjoergdo_setpicker(cname, argc, argv)
43623449Sjoerg	char *cname;
43723449Sjoerg	int argc;
43823449Sjoerg	char **argv;
43923449Sjoerg{
44023449Sjoerg	int picker;
44123449Sjoerg
44223449Sjoerg	if (argc < 1) {
44323449Sjoerg		warnx("%s: too few arguments", cname);
44423449Sjoerg		goto usage;
44523449Sjoerg	} else if (argc > 1) {
44623449Sjoerg		warnx("%s: too many arguments", cname);
44723449Sjoerg		goto usage;
44823449Sjoerg	}
44923449Sjoerg
45023449Sjoerg	picker = parse_element_unit(*argv);
45123449Sjoerg
45223449Sjoerg	/* Set the changer picker. */
45323449Sjoerg	if (ioctl(changer_fd, CHIOSPICKER, (char *)&picker))
45423449Sjoerg		err(1, "%s: CHIOSPICKER", changer_name);
45523449Sjoerg
45623449Sjoerg	return (0);
45723449Sjoerg
45823449Sjoerg usage:
45923449Sjoerg	fprintf(stderr, "usage: %s %s <picker>\n", __progname, cname);
46023449Sjoerg	return (1);
46123449Sjoerg}
46223449Sjoerg
46323449Sjoergstatic int
46423449Sjoergdo_status(cname, argc, argv)
46523449Sjoerg	char *cname;
46623449Sjoerg	int argc;
46723449Sjoerg	char **argv;
46823449Sjoerg{
46923449Sjoerg	struct changer_element_status cmd;
47023449Sjoerg	struct changer_params data;
47123449Sjoerg	u_int8_t *statusp;
47223449Sjoerg	int i, count, chet, schet, echet;
47323449Sjoerg	char *cmdname, *description;
47423449Sjoerg
47523449Sjoerg	/*
47623449Sjoerg	 * On a status command, we expect the following:
47723449Sjoerg	 *
47823449Sjoerg	 * [<ET>]
47923449Sjoerg	 *
48023449Sjoerg	 * where ET == element type.
48123449Sjoerg	 *
48223449Sjoerg	 * If we get no arguments, we get the status of all
48323449Sjoerg	 * known element types.
48423449Sjoerg	 */
48523449Sjoerg	if (argc > 1) {
48623449Sjoerg		warnx("%s: too many arguments", cname);
48723449Sjoerg		goto usage;
48823449Sjoerg	}
48923449Sjoerg
49023449Sjoerg	/*
49123449Sjoerg	 * Get params from changer.  Specifically, we need the element
49223449Sjoerg	 * counts.
49323449Sjoerg	 */
49423449Sjoerg	bzero(&data, sizeof(data));
49523449Sjoerg	if (ioctl(changer_fd, CHIOGPARAMS, (char *)&data))
49623449Sjoerg		err(1, "%s: CHIOGPARAMS", changer_name);
49723449Sjoerg
49823449Sjoerg	if (argc)
49923449Sjoerg		schet = echet = parse_element_type(*argv);
50023449Sjoerg	else {
50123449Sjoerg		schet = CHET_MT;
50223449Sjoerg		echet = CHET_DT;
50323449Sjoerg	}
50423449Sjoerg
50523449Sjoerg	for (chet = schet; chet <= echet; ++chet) {
50623449Sjoerg		switch (chet) {
50723449Sjoerg		case CHET_MT:
50823449Sjoerg			count = data.cp_npickers;
50923449Sjoerg			description = "picker";
51023449Sjoerg			break;
51123449Sjoerg
51223449Sjoerg		case CHET_ST:
51323449Sjoerg			count = data.cp_nslots;
51423449Sjoerg			description = "slot";
51523449Sjoerg			break;
51623449Sjoerg
51723449Sjoerg		case CHET_IE:
51823449Sjoerg			count = data.cp_nportals;
51923449Sjoerg			description = "portal";
52023449Sjoerg			break;
52123449Sjoerg
52223449Sjoerg		case CHET_DT:
52323449Sjoerg			count = data.cp_ndrives;
52423449Sjoerg			description = "drive";
52523449Sjoerg			break;
52623449Sjoerg		}
52723449Sjoerg
52823449Sjoerg		if (count == 0) {
52923449Sjoerg			if (argc == 0)
53023449Sjoerg				continue;
53123449Sjoerg			else {
53223449Sjoerg				printf("%s: no %s elements\n",
53323449Sjoerg				    changer_name, description);
53423449Sjoerg				return (0);
53523449Sjoerg			}
53623449Sjoerg		}
53723449Sjoerg
53823449Sjoerg		/* Allocate storage for the status bytes. */
53923449Sjoerg		if ((statusp = (u_int8_t *)malloc(count)) == NULL)
54023449Sjoerg			errx(1, "can't allocate status storage");
54123449Sjoerg
54223449Sjoerg		bzero(statusp, count);
54323449Sjoerg		bzero(&cmd, sizeof(cmd));
54423449Sjoerg
54523449Sjoerg		cmd.ces_type = chet;
54623449Sjoerg		cmd.ces_data = statusp;
54723449Sjoerg
54823449Sjoerg		if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cmd)) {
54923449Sjoerg			free(statusp);
55023449Sjoerg			err(1, "%s: CHIOGSTATUS", changer_name);
55123449Sjoerg		}
55223449Sjoerg
55323449Sjoerg		/* Dump the status for each element of this type. */
55423449Sjoerg		for (i = 0; i < count; ++i) {
55523449Sjoerg			printf("%s %d: %s\n", description, i,
55623449Sjoerg			    bits_to_string(statusp[i], CESTATUS_BITS));
55723449Sjoerg		}
55823449Sjoerg
55923449Sjoerg		free(statusp);
56023449Sjoerg	}
56123449Sjoerg
56223449Sjoerg	return (0);
56323449Sjoerg
56423449Sjoerg usage:
56523449Sjoerg	fprintf(stderr, "usage: %s %s [<element type>]\n", __progname,
56623449Sjoerg	    cname);
56723449Sjoerg	return (1);
56823449Sjoerg}
56923449Sjoerg
57023449Sjoergstatic int
57123449Sjoergparse_element_type(cp)
57223449Sjoerg	char *cp;
57323449Sjoerg{
57423449Sjoerg	int i;
57523449Sjoerg
57623449Sjoerg	for (i = 0; elements[i].et_name != NULL; ++i)
57723449Sjoerg		if (strcmp(elements[i].et_name, cp) == 0)
57823449Sjoerg			return (elements[i].et_type);
57923449Sjoerg
58023449Sjoerg	errx(1, "invalid element type `%s'", cp);
58123449Sjoerg}
58223449Sjoerg
58323449Sjoergstatic int
58423449Sjoergparse_element_unit(cp)
58523449Sjoerg	char *cp;
58623449Sjoerg{
58723449Sjoerg	int i;
58823449Sjoerg	char *p;
58923449Sjoerg
59023449Sjoerg	i = (int)strtol(cp, &p, 10);
59123449Sjoerg	if ((i < 0) || (*p != '\0'))
59223449Sjoerg		errx(1, "invalid unit number `%s'", cp);
59323449Sjoerg
59423449Sjoerg	return (i);
59523449Sjoerg}
59623449Sjoerg
59723449Sjoergstatic int
59823449Sjoergparse_special(cp)
59923449Sjoerg	char *cp;
60023449Sjoerg{
60123449Sjoerg	int val;
60223449Sjoerg
60323449Sjoerg	val = is_special(cp);
60423449Sjoerg	if (val)
60523449Sjoerg		return (val);
60623449Sjoerg
60723449Sjoerg	errx(1, "invalid modifier `%s'", cp);
60823449Sjoerg}
60923449Sjoerg
61023449Sjoergstatic int
61123449Sjoergis_special(cp)
61223449Sjoerg	char *cp;
61323449Sjoerg{
61423449Sjoerg	int i;
61523449Sjoerg
61623449Sjoerg	for (i = 0; specials[i].sw_name != NULL; ++i)
61723449Sjoerg		if (strcmp(specials[i].sw_name, cp) == 0)
61823449Sjoerg			return (specials[i].sw_value);
61923449Sjoerg
62023449Sjoerg	return (0);
62123449Sjoerg}
62223449Sjoerg
62323449Sjoergstatic char *
62423449Sjoergbits_to_string(v, cp)
62523449Sjoerg	int v;
62623449Sjoerg	const char *cp;
62723449Sjoerg{
62823449Sjoerg	const char *np;
62923449Sjoerg	char f, sep, *bp;
63023449Sjoerg	static char buf[128];
63123449Sjoerg
63223449Sjoerg	bp = buf;
63323449Sjoerg	bzero(buf, sizeof(buf));
63423449Sjoerg
63523449Sjoerg	for (sep = '<'; (f = *cp++) != 0; cp = np) {
63623449Sjoerg		for (np = cp; *np >= ' ';)
63723449Sjoerg			np++;
63823449Sjoerg		if ((v & (1 << (f - 1))) == 0)
63923449Sjoerg			continue;
64023449Sjoerg		bp += sprintf(bp, "%c%.*s", sep, np - cp, cp);
64123449Sjoerg		sep = ',';
64223449Sjoerg	}
64323449Sjoerg	if (sep != '<')
64423449Sjoerg		*bp = '>';
64523449Sjoerg
64623449Sjoerg	return (buf);
64723449Sjoerg}
64823449Sjoerg
64923449Sjoergstatic void
65023449Sjoergcleanup()
65123449Sjoerg{
65223449Sjoerg
65323449Sjoerg	/* Simple enough... */
65423449Sjoerg	(void)close(changer_fd);
65523449Sjoerg}
65623449Sjoerg
65723449Sjoergstatic void
65823449Sjoergusage()
65923449Sjoerg{
66023449Sjoerg
66123449Sjoerg	fprintf(stderr, "usage: %s command arg1 arg2 ...\n", __progname);
66223449Sjoerg	exit(1);
66323449Sjoerg}
664