ccdconfig.c revision 115730
113044Sasami/*	$NetBSD: ccdconfig.c,v 1.2.2.1 1995/11/11 02:43:35 thorpej Exp $	*/
213044Sasami
313044Sasami/*
413044Sasami * Copyright (c) 1995 Jason R. Thorpe.
513044Sasami * All rights reserved.
613044Sasami *
713044Sasami * Redistribution and use in source and binary forms, with or without
813044Sasami * modification, are permitted provided that the following conditions
913044Sasami * are met:
1013044Sasami * 1. Redistributions of source code must retain the above copyright
1113044Sasami *    notice, this list of conditions and the following disclaimer.
1213044Sasami * 2. Redistributions in binary form must reproduce the above copyright
1313044Sasami *    notice, this list of conditions and the following disclaimer in the
1413044Sasami *    documentation and/or other materials provided with the distribution.
1513044Sasami * 3. All advertising materials mentioning features or use of this software
1613044Sasami *    must display the following acknowledgement:
1713044Sasami *	This product includes software developed for the NetBSD Project
1813044Sasami *	by Jason R. Thorpe.
1913044Sasami * 4. The name of the author may not be used to endorse or promote products
2013044Sasami *    derived from this software without specific prior written permission.
2113044Sasami *
2213044Sasami * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2313044Sasami * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2413044Sasami * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2513044Sasami * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2613044Sasami * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2713044Sasami * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2813044Sasami * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2913044Sasami * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3013044Sasami * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3113044Sasami * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3213044Sasami * SUCH DAMAGE.
3313044Sasami */
3413044Sasami
35114589Sobrien#include <sys/cdefs.h>
36114589Sobrien__FBSDID("$FreeBSD: head/sbin/ccdconfig/ccdconfig.c 115730 2003-06-02 20:50:59Z phk $");
3736628Scharnier
3813044Sasami#include <sys/param.h>
3948568Sbillf#include <sys/linker.h>
4013044Sasami#include <sys/disklabel.h>
4113044Sasami#include <sys/stat.h>
4245329Speter#include <sys/module.h>
4313044Sasami#include <ctype.h>
4413044Sasami#include <err.h>
4513044Sasami#include <errno.h>
4613044Sasami#include <fcntl.h>
4713044Sasami#include <limits.h>
4869793Sobrien#include <paths.h>
4913044Sasami#include <stdio.h>
5013044Sasami#include <stdlib.h>
5113044Sasami#include <string.h>
5213044Sasami#include <unistd.h>
53115730Sphk#include <libgeom.h>
5413044Sasami
5539228Sgibbs#include <sys/devicestat.h>
5613052Sasami#include <sys/ccdvar.h>
5713044Sasami
5813044Sasami#include "pathnames.h"
5913044Sasami
6013044Sasamistatic	int lineno = 0;
6113044Sasamistatic	int verbose = 0;
62109417Sphkstatic	const char *ccdconf = _PATH_CCDCONF;
6313044Sasami
6413044Sasamistruct	flagval {
65109417Sphk	const char	*fv_flag;
6613044Sasami	int	fv_val;
6713044Sasami} flagvaltab[] = {
6813044Sasami	{ "CCDF_UNIFORM",	CCDF_UNIFORM },
6913762Sasami	{ "CCDF_MIRROR",	CCDF_MIRROR },
7013044Sasami	{ NULL,			0 },
7113044Sasami};
7213044Sasami
7313044Sasami#define CCD_CONFIG		0	/* configure a device */
7413044Sasami#define CCD_CONFIGALL		1	/* configure all devices */
7513044Sasami#define CCD_UNCONFIG		2	/* unconfigure a device */
7613044Sasami#define CCD_UNCONFIGALL		3	/* unconfigure all devices */
7713044Sasami#define CCD_DUMP		4	/* dump a ccd's configuration */
7813044Sasami
7992539Simpstatic	int checkdev(char *);
80109417Sphkstatic	int do_io(int, u_long, struct ccd_ioctl *);
8192539Simpstatic	int do_single(int, char **, int);
8292539Simpstatic	int do_all(int);
8392539Simpstatic	int dump_ccd(int, char **);
8492539Simpstatic	int flags_to_val(char *);
8592539Simpstatic	void print_ccd_info(struct ccd_s *);
86109417Sphkstatic	int resolve_ccdname(char *);
8792539Simpstatic	void usage(void);
8813044Sasami
8913044Sasamiint
9092539Simpmain(int argc, char *argv[])
9113044Sasami{
9213044Sasami	int ch, options = 0, action = CCD_CONFIG;
9313044Sasami
9483329Sru	while ((ch = getopt(argc, argv, "cCf:guUv")) != -1) {
9513044Sasami		switch (ch) {
9613044Sasami		case 'c':
9713044Sasami			action = CCD_CONFIG;
9813044Sasami			++options;
9913044Sasami			break;
10013044Sasami
10113044Sasami		case 'C':
10213044Sasami			action = CCD_CONFIGALL;
10313044Sasami			++options;
10413044Sasami			break;
10513044Sasami
10613044Sasami		case 'f':
10713044Sasami			ccdconf = optarg;
10813044Sasami			break;
10913044Sasami
11013044Sasami		case 'g':
11113044Sasami			action = CCD_DUMP;
11213044Sasami			break;
11313044Sasami
11413044Sasami		case 'u':
11513044Sasami			action = CCD_UNCONFIG;
11613044Sasami			++options;
11713044Sasami			break;
11813044Sasami
11913044Sasami		case 'U':
12013044Sasami			action = CCD_UNCONFIGALL;
12113044Sasami			++options;
12213044Sasami			break;
12313044Sasami
12413044Sasami		case 'v':
12513044Sasami			verbose = 1;
12613044Sasami			break;
12713044Sasami
12813044Sasami		default:
12913044Sasami			usage();
13013044Sasami		}
13113044Sasami	}
13213044Sasami	argc -= optind;
13313044Sasami	argv += optind;
13413044Sasami
13513044Sasami	if (options > 1)
13613044Sasami		usage();
13713044Sasami
13845329Speter	if (modfind("ccd") < 0) {
13945329Speter		/* Not present in kernel, try loading it */
14045329Speter		if (kldload("ccd") < 0 || modfind("ccd") < 0)
14145329Speter			warn("ccd module not available!");
14245329Speter	}
14345329Speter
14413044Sasami	switch (action) {
14513044Sasami		case CCD_CONFIG:
14613044Sasami		case CCD_UNCONFIG:
14713044Sasami			exit(do_single(argc, argv, action));
14813044Sasami			/* NOTREACHED */
14913044Sasami
15013044Sasami		case CCD_CONFIGALL:
15113044Sasami		case CCD_UNCONFIGALL:
15213044Sasami			exit(do_all(action));
15313044Sasami			/* NOTREACHED */
15413044Sasami
15513044Sasami		case CCD_DUMP:
15613044Sasami			exit(dump_ccd(argc, argv));
15713044Sasami			/* NOTREACHED */
15813044Sasami	}
15913044Sasami	/* NOTREACHED */
16036628Scharnier	return (0);
16113044Sasami}
16213044Sasami
16313044Sasamistatic int
16492539Simpdo_single(int argc, char **argv, int action)
16513044Sasami{
16613044Sasami	struct ccd_ioctl ccio;
167109417Sphk	char *cp, *cp2, **disks;
168109417Sphk	int ccd, noflags = 0, i, ileave, flags = 0, j;
169109417Sphk	u_int u;
17013044Sasami
17113044Sasami	bzero(&ccio, sizeof(ccio));
17213044Sasami
17313044Sasami	/*
17413044Sasami	 * If unconfiguring, all arguments are treated as ccds.
17513044Sasami	 */
17613044Sasami	if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) {
17713044Sasami		for (i = 0; argc != 0; ) {
17813044Sasami			cp = *argv++; --argc;
179109472Sphk			if ((ccd = resolve_ccdname(cp)) < 0) {
18013044Sasami				warnx("invalid ccd name: %s", cp);
18113044Sasami				i = 1;
18213044Sasami				continue;
18313044Sasami			}
184109421Sphk			ccio.ccio_size = ccd;
18513044Sasami			if (do_io(ccd, CCDIOCCLR, &ccio))
18613044Sasami				i = 1;
18713044Sasami			else
18813044Sasami				if (verbose)
18913044Sasami					printf("%s unconfigured\n", cp);
19013044Sasami		}
19113044Sasami		return (i);
19213044Sasami	}
19313044Sasami
19413044Sasami	/* Make sure there are enough arguments. */
19548568Sbillf	if (argc < 4) {
19613044Sasami		if (argc == 3) {
19713044Sasami			/* Assume that no flags are specified. */
19813044Sasami			noflags = 1;
19913044Sasami		} else {
20013044Sasami			if (action == CCD_CONFIGALL) {
20113044Sasami				warnx("%s: bad line: %d", ccdconf, lineno);
20213044Sasami				return (1);
20313044Sasami			} else
20413044Sasami				usage();
20513044Sasami		}
20648568Sbillf	}
20713044Sasami
20813044Sasami	/* First argument is the ccd to configure. */
20913044Sasami	cp = *argv++; --argc;
210109472Sphk	if ((ccd = resolve_ccdname(cp)) < 0) {
21113044Sasami		warnx("invalid ccd name: %s", cp);
21213044Sasami		return (1);
21313044Sasami	}
21413044Sasami
21513044Sasami	/* Next argument is the interleave factor. */
21613044Sasami	cp = *argv++; --argc;
21713044Sasami	errno = 0;	/* to check for ERANGE */
21813044Sasami	ileave = (int)strtol(cp, &cp2, 10);
21913044Sasami	if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) {
22013044Sasami		warnx("invalid interleave factor: %s", cp);
22113044Sasami		return (1);
22213044Sasami	}
22313044Sasami
22413044Sasami	if (noflags == 0) {
22513044Sasami		/* Next argument is the ccd configuration flags. */
22613044Sasami		cp = *argv++; --argc;
22713044Sasami		if ((flags = flags_to_val(cp)) < 0) {
22813044Sasami			warnx("invalid flags argument: %s", cp);
22913044Sasami			return (1);
23013044Sasami		}
23113044Sasami	}
23213044Sasami
23313044Sasami	/* Next is the list of disks to make the ccd from. */
23413044Sasami	disks = malloc(argc * sizeof(char *));
23513044Sasami	if (disks == NULL) {
23613044Sasami		warnx("no memory to configure ccd");
23713044Sasami		return (1);
23813044Sasami	}
23913044Sasami	for (i = 0; argc != 0; ) {
24013044Sasami		cp = *argv++; --argc;
24113044Sasami		if ((j = checkdev(cp)) == 0)
24213044Sasami			disks[i++] = cp;
24313044Sasami		else {
24413044Sasami			warnx("%s: %s", cp, strerror(j));
24513044Sasami			return (1);
24613044Sasami		}
24713044Sasami	}
24813044Sasami
24913044Sasami	/* Fill in the ccio. */
25013044Sasami	ccio.ccio_disks = disks;
25113044Sasami	ccio.ccio_ndisks = i;
25213044Sasami	ccio.ccio_ileave = ileave;
25313044Sasami	ccio.ccio_flags = flags;
254109421Sphk	ccio.ccio_size = ccd;
25513044Sasami
25613044Sasami	if (do_io(ccd, CCDIOCSET, &ccio)) {
25713044Sasami		free(disks);
25813044Sasami		return (1);
25913044Sasami	}
26013044Sasami
26113044Sasami	if (verbose) {
26213044Sasami		printf("ccd%d: %d components ", ccio.ccio_unit,
26313044Sasami		    ccio.ccio_ndisks);
264109417Sphk		for (u = 0; u < ccio.ccio_ndisks; ++u) {
265109417Sphk			if ((cp2 = strrchr(disks[u], '/')) != NULL)
26613044Sasami				++cp2;
26713044Sasami			else
268109417Sphk				cp2 = disks[u];
26913044Sasami			printf("%c%s%c",
270109417Sphk			    u == 0 ? '(' : ' ', cp2,
271109417Sphk			    u == ccio.ccio_ndisks - 1 ? ')' : ',');
27213044Sasami		}
27348568Sbillf		printf(", %lu blocks ", (u_long)ccio.ccio_size);
27413044Sasami		if (ccio.ccio_ileave != 0)
27513044Sasami			printf("interleaved at %d blocks\n", ccio.ccio_ileave);
27613044Sasami		else
27713044Sasami			printf("concatenated\n");
27813044Sasami	}
27913044Sasami
28013044Sasami	free(disks);
28113044Sasami	return (0);
28213044Sasami}
28313044Sasami
28413044Sasamistatic int
28592539Simpdo_all(int action)
28613044Sasami{
28713044Sasami	FILE *f;
28813044Sasami	char line[_POSIX2_LINE_MAX];
28913044Sasami	char *cp, **argv;
29013044Sasami	int argc, rval;
29132116Simp	gid_t egid;
29213044Sasami
29351690Sbillf	rval = 0;
29432116Simp	egid = getegid();
29532116Simp	setegid(getgid());
29613044Sasami	if ((f = fopen(ccdconf, "r")) == NULL) {
29732116Simp		setegid(egid);
29813044Sasami		warn("fopen: %s", ccdconf);
29913044Sasami		return (1);
30013044Sasami	}
30132116Simp	setegid(egid);
30213044Sasami
30313044Sasami	while (fgets(line, sizeof(line), f) != NULL) {
30413044Sasami		argc = 0;
30513044Sasami		argv = NULL;
30613044Sasami		++lineno;
30713044Sasami		if ((cp = strrchr(line, '\n')) != NULL)
30813044Sasami			*cp = '\0';
30913044Sasami
31013044Sasami		/* Break up the line and pass it's contents to do_single(). */
31113044Sasami		if (line[0] == '\0')
31213044Sasami			goto end_of_line;
31313044Sasami		for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) {
31413044Sasami			if (*cp == '#')
31513044Sasami				break;
31613044Sasami			if ((argv = realloc(argv,
31713044Sasami			    sizeof(char *) * ++argc)) == NULL) {
31813044Sasami				warnx("no memory to configure ccds");
31913044Sasami				return (1);
32013044Sasami			}
32113044Sasami			argv[argc - 1] = cp;
32213044Sasami			/*
32313044Sasami			 * If our action is to unconfigure all, then pass
32413044Sasami			 * just the first token to do_single() and ignore
32513044Sasami			 * the rest.  Since this will be encountered on
32613044Sasami			 * our first pass through the line, the Right
32713044Sasami			 * Thing will happen.
32813044Sasami			 */
32913044Sasami			if (action == CCD_UNCONFIGALL) {
33013044Sasami				if (do_single(argc, argv, action))
33113044Sasami					rval = 1;
33213044Sasami				goto end_of_line;
33313044Sasami			}
33413044Sasami		}
33513044Sasami		if (argc != 0)
33613044Sasami			if (do_single(argc, argv, action))
33713044Sasami				rval = 1;
33813044Sasami
33913044Sasami end_of_line:
34013044Sasami		if (argv != NULL)
34113044Sasami			free(argv);
34213044Sasami	}
34313044Sasami
34413044Sasami	(void)fclose(f);
34513044Sasami	return (rval);
34613044Sasami}
34713044Sasami
34813044Sasamistatic int
34992539Simpcheckdev(char *path)
35013044Sasami{
35113044Sasami	struct stat st;
35213044Sasami
35313044Sasami	if (stat(path, &st) != 0)
35413044Sasami		return (errno);
35513044Sasami
35613044Sasami	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
35713044Sasami		return (EINVAL);
35813044Sasami
35913044Sasami	return (0);
36013044Sasami}
36113044Sasami
36213044Sasamistatic int
36392539Simpresolve_ccdname(char *name)
36413044Sasami{
36513044Sasami
366109417Sphk	if (!strncmp(name, _PATH_DEV, strlen(_PATH_DEV)))
367109417Sphk		name += strlen(_PATH_DEV);
368109417Sphk	if (strncmp(name, "ccd", 3))
369109417Sphk		return -1;
370109417Sphk	name += 3;
371109417Sphk	if (!isdigit(*name))
372109417Sphk		return -1;
373109417Sphk	return (strtoul(name, NULL, 10));
37413044Sasami}
37513044Sasami
37613044Sasamistatic int
377109417Sphkdo_io(int unit, u_long cmd, struct ccd_ioctl *cciop)
37813044Sasami{
37913044Sasami	int fd;
38013044Sasami	char *cp;
381109417Sphk	char *path;
38213044Sasami
383109421Sphk	asprintf(&path, "%s%s", _PATH_DEV, _PATH_CCDCTL);
384109417Sphk
38513044Sasami	if ((fd = open(path, O_RDWR, 0640)) < 0) {
386109421Sphk		asprintf(&path, "%sccd%dc", _PATH_DEV, unit);
387109421Sphk		if ((fd = open(path, O_RDWR, 0640)) < 0) {
388109421Sphk			warn("open: %s", path);
389109421Sphk			return (1);
390109421Sphk		}
391109421Sphk		fprintf(stderr,
392109421Sphk		    "***WARNING***: Kernel older than ccdconfig(8), please upgrade it.\n");
393109421Sphk		fprintf(stderr,
394109421Sphk		    "***WARNING***: Continuing in 30 seconds\n");
395109421Sphk		sleep(30);
39613044Sasami	}
39713044Sasami
39813044Sasami	if (ioctl(fd, cmd, cciop) < 0) {
39913044Sasami		switch (cmd) {
40013044Sasami		case CCDIOCSET:
40113044Sasami			cp = "CCDIOCSET";
40213044Sasami			break;
40313044Sasami
40413044Sasami		case CCDIOCCLR:
40513044Sasami			cp = "CCDIOCCLR";
40613044Sasami			break;
40713044Sasami
40882943Sphk		case CCDCONFINFO:
40982943Sphk			cp = "CCDCONFINFO";
41082943Sphk			break;
41182943Sphk
41282943Sphk		case CCDCPPINFO:
41382943Sphk			cp = "CCDCPPINFO";
41482943Sphk			break;
41582943Sphk
41613044Sasami		default:
41713044Sasami			cp = "unknown";
41813044Sasami		}
41913044Sasami		warn("ioctl (%s): %s", cp, path);
42013044Sasami		return (1);
42113044Sasami	}
42213044Sasami
42313044Sasami	return (0);
42413044Sasami}
42513044Sasami
42613044Sasamistatic int
42792539Simpdump_ccd(int argc, char **argv)
42813044Sasami{
429109417Sphk	char *cp;
430115730Sphk	char const *errstr;
43113044Sasami	int i, error, numccd, numconfiged = 0;
43282943Sphk	struct ccdconf conf;
433109417Sphk	int ccd;
434115730Sphk	struct gctl_req *grq;
43513044Sasami
436115730Sphk	grq = gctl_get_handle();
437115730Sphk	gctl_ro_param(grq, "verb", -1, "list");
438115730Sphk	gctl_ro_param(grq, "class", -1, "CCD");
439115730Sphk	cp = malloc(65536);
440115730Sphk	gctl_rw_param(grq, "output", 65536, cp);
441115730Sphk	if (verbose)
442115730Sphk		gctl_ro_param(grq, "verbose", -1, "yes");
443115730Sphk	errstr = gctl_issue(grq);
444115730Sphk	if (errstr == NULL) {
445115730Sphk		printf("%s", cp);
446115730Sphk		return (0);
447115730Sphk	} else {
448115730Sphk		warnx("%s\nor possibly kernel and ccdconfig out of sync",
449115730Sphk		    errstr);
450115730Sphk	}
451115730Sphk
45282943Sphk	/*
45382943Sphk	 * Read the ccd configuration data from the kernel and dump
45482943Sphk	 * it to stdout.
45582943Sphk	 */
456109417Sphk	if ((ccd = resolve_ccdname("ccd0")) < 0) {		/* XXX */
45782943Sphk		warnx("invalid ccd name: %s", cp);
45813044Sasami		return (1);
45913044Sasami	}
46082943Sphk	conf.size = 0;
46182943Sphk	if (do_io(ccd, CCDCONFINFO, (struct ccd_ioctl *) &conf))
46282943Sphk		return (1);
46382943Sphk	if (conf.size == 0) {
46482943Sphk		printf("no concatenated disks configured\n");
46582943Sphk		return (0);
46613044Sasami	}
46713044Sasami	/* Allocate space for the configuration data. */
46882943Sphk	conf.buffer = alloca(conf.size);
46982943Sphk	if (conf.buffer == NULL) {
47013044Sasami		warnx("no memory for configuration data");
47182943Sphk		return (1);
47213044Sasami	}
47382943Sphk	if (do_io(ccd, CCDCONFINFO, (struct ccd_ioctl *) &conf))
47482943Sphk		return (1);
47513044Sasami
47682943Sphk	numconfiged = conf.size / sizeof(struct ccd_s);
47713044Sasami
47813044Sasami	if (argc == 0) {
47982943Sphk		for (i = 0; i < numconfiged; i++)
48082943Sphk			print_ccd_info(&(conf.buffer[i]));
48113044Sasami	} else {
48213044Sasami		while (argc) {
48313044Sasami			cp = *argv++; --argc;
484109417Sphk			if ((ccd = resolve_ccdname(cp)) < 0) {
48513044Sasami				warnx("invalid ccd name: %s", cp);
48613044Sasami				continue;
48713044Sasami			}
48882943Sphk			error = 1;
48982943Sphk			for (i = 0; i < numconfiged; i++) {
490109417Sphk				if (conf.buffer[i].sc_unit == ccd) {
49182943Sphk					print_ccd_info(&(conf.buffer[i]));
49282943Sphk					error = 0;
49382943Sphk					break;
49482943Sphk				}
49582943Sphk			}
49682943Sphk			if (error) {
49782943Sphk				warnx("ccd%d not configured", numccd);
49813044Sasami				continue;
49913044Sasami			}
50013044Sasami		}
50182943Sphk	}
50213044Sasami
50313044Sasami	return (0);
50413044Sasami}
50513044Sasami
50613044Sasamistatic void
50792539Simpprint_ccd_info(struct ccd_s *cs)
50813044Sasami{
509109417Sphk	char *cp;
51013044Sasami	static int header_printed = 0;
51182943Sphk	struct ccdcpps cpps;
512109417Sphk	int ccd;
51313044Sasami
51482943Sphk	/* Print out header if necessary*/
51513044Sasami	if (header_printed == 0 && verbose) {
51613044Sasami		printf("# ccd\t\tileave\tflags\tcompnent devices\n");
51713044Sasami		header_printed = 1;
51813044Sasami	}
51913044Sasami
52013044Sasami	/* Dump out softc information. */
52113044Sasami	printf("ccd%d\t\t%d\t%d\t", cs->sc_unit, cs->sc_ileave,
52213044Sasami	    cs->sc_cflags & CCDF_USERMASK);
52313044Sasami	fflush(stdout);
52413044Sasami
52513044Sasami	/* Read in the component info. */
526111943Sphk	asprintf(&cp, "ccd%d", cs->sc_unit);
52782943Sphk	if (cp == NULL) {
52813044Sasami		printf("\n");
52982943Sphk		warn("ccd%d: can't allocate memory",
53082943Sphk		    cs->sc_unit);
53182943Sphk		return;
53282943Sphk	}
53382943Sphk
534109417Sphk	if ((ccd = resolve_ccdname(cp)) < 0) {
53582943Sphk		printf("\n");
53682943Sphk		warnx("can't read component info: invalid ccd name: %s", cp);
53782943Sphk		return;
53882943Sphk	}
539109421Sphk	cpps.size = 1024;
54082943Sphk	cpps.buffer = alloca(cpps.size);
541109421Sphk	memcpy(cpps.buffer, &ccd, sizeof ccd);
54282943Sphk	if (do_io(ccd, CCDCPPINFO, (struct ccd_ioctl *) &cpps)) {
54382943Sphk		printf("\n");
54482943Sphk		warnx("can't read component info");
54582943Sphk		return;
54682943Sphk	}
54713044Sasami
54882943Sphk	/* Display component info. */
549109421Sphk	for (cp = cpps.buffer; *cp && cp - cpps.buffer < cpps.size; cp += strlen(cp) + 1) {
55082943Sphk		printf((cp + strlen(cp) + 1) < (cpps.buffer + cpps.size) ?
551109421Sphk		    "%s " : "%s", cp);
55213044Sasami	}
553109421Sphk	printf("\n");
55482943Sphk	return;
55513044Sasami}
55613044Sasami
55713044Sasamistatic int
55892539Simpflags_to_val(char *flags)
55913044Sasami{
56013044Sasami	char *cp, *tok;
56113044Sasami	int i, tmp, val = ~CCDF_USERMASK;
56213044Sasami	size_t flagslen;
56313044Sasami
56413044Sasami	/*
56513044Sasami	 * The most common case is that of NIL flags, so check for
56613044Sasami	 * those first.
56713044Sasami	 */
56813044Sasami	if (strcmp("none", flags) == 0 || strcmp("0x0", flags) == 0 ||
56913044Sasami	    strcmp("0", flags) == 0)
57013044Sasami		return (0);
57113044Sasami
57213044Sasami	flagslen = strlen(flags);
57313044Sasami
57413044Sasami	/* Check for values represented by strings. */
57513044Sasami	if ((cp = strdup(flags)) == NULL)
57613044Sasami		err(1, "no memory to parse flags");
57713044Sasami	tmp = 0;
57813044Sasami	for (tok = cp; (tok = strtok(tok, ",")) != NULL; tok = NULL) {
57913044Sasami		for (i = 0; flagvaltab[i].fv_flag != NULL; ++i)
58013044Sasami			if (strcmp(tok, flagvaltab[i].fv_flag) == 0)
58113044Sasami				break;
58213044Sasami		if (flagvaltab[i].fv_flag == NULL) {
58313044Sasami			free(cp);
58413044Sasami			goto bad_string;
58513044Sasami		}
58613044Sasami		tmp |= flagvaltab[i].fv_val;
58713044Sasami	}
58813044Sasami
58913044Sasami	/* If we get here, the string was ok. */
59013044Sasami	free(cp);
59113044Sasami	val = tmp;
59213044Sasami	goto out;
59313044Sasami
59413044Sasami bad_string:
59513044Sasami
59613044Sasami	/* Check for values represented in hex. */
59713044Sasami	if (flagslen > 2 && flags[0] == '0' && flags[1] == 'x') {
59813044Sasami		errno = 0;	/* to check for ERANGE */
59913044Sasami		val = (int)strtol(&flags[2], &cp, 16);
60013044Sasami		if ((errno == ERANGE) || (*cp != '\0'))
60113044Sasami			return (-1);
60213044Sasami		goto out;
60313044Sasami	}
60413044Sasami
60513044Sasami	/* Check for values represented in decimal. */
60613044Sasami	errno = 0;	/* to check for ERANGE */
60713044Sasami	val = (int)strtol(flags, &cp, 10);
60813044Sasami	if ((errno == ERANGE) || (*cp != '\0'))
60913044Sasami		return (-1);
61013044Sasami
61113044Sasami out:
61213044Sasami	return (((val & ~CCDF_USERMASK) == 0) ? val : -1);
61313044Sasami}
61413044Sasami
61513044Sasamistatic void
61692539Simpusage(void)
61713044Sasami{
61826541Scharnier	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
61926541Scharnier		"usage: ccdconfig [-cv] ccd ileave [flags] dev [...]",
62026541Scharnier		"       ccdconfig -C [-v] [-f config_file]",
62126541Scharnier		"       ccdconfig -u [-v] ccd [...]",
62226541Scharnier		"       ccdconfig -U [-v] [-f config_file]",
62382943Sphk		"       ccdconfig -g [ccd [...]]");
62413044Sasami	exit(1);
62513044Sasami}
62626541Scharnier
62713052Sasami/* Local Variables: */
62813052Sasami/* c-argdecl-indent: 8 */
62913052Sasami/* c-indent-level: 8 */
63013052Sasami/* End: */
631