ccdconfig.c revision 83329
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
3536628Scharnier#ifndef lint
3636628Scharnierstatic const char rcsid[] =
3750476Speter  "$FreeBSD: head/sbin/ccdconfig/ccdconfig.c 83329 2001-09-11 09:49:36Z ru $";
3836628Scharnier#endif /* not lint */
3936628Scharnier
4013044Sasami#include <sys/param.h>
4148568Sbillf#include <sys/linker.h>
4213044Sasami#include <sys/disklabel.h>
4313044Sasami#include <sys/stat.h>
4445329Speter#include <sys/module.h>
4513044Sasami#include <ctype.h>
4613044Sasami#include <err.h>
4713044Sasami#include <errno.h>
4813044Sasami#include <fcntl.h>
4913044Sasami#include <limits.h>
5069793Sobrien#include <paths.h>
5113044Sasami#include <stdio.h>
5213044Sasami#include <stdlib.h>
5313044Sasami#include <string.h>
5413044Sasami#include <unistd.h>
5513044Sasami
5639228Sgibbs#include <sys/devicestat.h>
5713052Sasami#include <sys/ccdvar.h>
5813044Sasami
5913044Sasami#include "pathnames.h"
6013044Sasami
6113044Sasamistatic	int lineno = 0;
6213044Sasamistatic	int verbose = 0;
6313044Sasamistatic	char *ccdconf = _PATH_CCDCONF;
6413044Sasami
6513044Sasamistruct	flagval {
6613044Sasami	char	*fv_flag;
6713044Sasami	int	fv_val;
6813044Sasami} flagvaltab[] = {
6913044Sasami	{ "CCDF_SWAP",		CCDF_SWAP },
7013044Sasami	{ "CCDF_UNIFORM",	CCDF_UNIFORM },
7113762Sasami	{ "CCDF_MIRROR",	CCDF_MIRROR },
7213762Sasami	{ "CCDF_PARITY",	CCDF_PARITY },
7313044Sasami	{ NULL,			0 },
7413044Sasami};
7513044Sasami
7613044Sasami#define CCD_CONFIG		0	/* configure a device */
7713044Sasami#define CCD_CONFIGALL		1	/* configure all devices */
7813044Sasami#define CCD_UNCONFIG		2	/* unconfigure a device */
7913044Sasami#define CCD_UNCONFIGALL		3	/* unconfigure all devices */
8013044Sasami#define CCD_DUMP		4	/* dump a ccd's configuration */
8113044Sasami
8213044Sasamistatic	int checkdev __P((char *));
8313044Sasamistatic	int do_io __P((char *, u_long, struct ccd_ioctl *));
8413044Sasamistatic	int do_single __P((int, char **, int));
8513044Sasamistatic	int do_all __P((int));
8613044Sasamistatic	int dump_ccd __P((int, char **));
8713044Sasamistatic	int getmaxpartitions __P((void));
8813044Sasamistatic	int getrawpartition __P((void));
8913044Sasamistatic	int flags_to_val __P((char *));
9082943Sphkstatic	void print_ccd_info __P((struct ccd_s *));
9113044Sasamistatic	char *resolve_ccdname __P((char *));
9213044Sasamistatic	void usage __P((void));
9313044Sasami
9413044Sasamiint
9513044Sasamimain(argc, argv)
9613044Sasami	int argc;
9713044Sasami	char **argv;
9813044Sasami{
9913044Sasami	int ch, options = 0, action = CCD_CONFIG;
10013044Sasami
10183329Sru	while ((ch = getopt(argc, argv, "cCf:guUv")) != -1) {
10213044Sasami		switch (ch) {
10313044Sasami		case 'c':
10413044Sasami			action = CCD_CONFIG;
10513044Sasami			++options;
10613044Sasami			break;
10713044Sasami
10813044Sasami		case 'C':
10913044Sasami			action = CCD_CONFIGALL;
11013044Sasami			++options;
11113044Sasami			break;
11213044Sasami
11313044Sasami		case 'f':
11413044Sasami			ccdconf = optarg;
11513044Sasami			break;
11613044Sasami
11713044Sasami		case 'g':
11813044Sasami			action = CCD_DUMP;
11913044Sasami			break;
12013044Sasami
12113044Sasami		case 'u':
12213044Sasami			action = CCD_UNCONFIG;
12313044Sasami			++options;
12413044Sasami			break;
12513044Sasami
12613044Sasami		case 'U':
12713044Sasami			action = CCD_UNCONFIGALL;
12813044Sasami			++options;
12913044Sasami			break;
13013044Sasami
13113044Sasami		case 'v':
13213044Sasami			verbose = 1;
13313044Sasami			break;
13413044Sasami
13513044Sasami		default:
13613044Sasami			usage();
13713044Sasami		}
13813044Sasami	}
13913044Sasami	argc -= optind;
14013044Sasami	argv += optind;
14113044Sasami
14213044Sasami	if (options > 1)
14313044Sasami		usage();
14413044Sasami
14545329Speter	if (modfind("ccd") < 0) {
14645329Speter		/* Not present in kernel, try loading it */
14745329Speter		if (kldload("ccd") < 0 || modfind("ccd") < 0)
14845329Speter			warn("ccd module not available!");
14945329Speter	}
15045329Speter
15113044Sasami	switch (action) {
15213044Sasami		case CCD_CONFIG:
15313044Sasami		case CCD_UNCONFIG:
15413044Sasami			exit(do_single(argc, argv, action));
15513044Sasami			/* NOTREACHED */
15613044Sasami
15713044Sasami		case CCD_CONFIGALL:
15813044Sasami		case CCD_UNCONFIGALL:
15913044Sasami			exit(do_all(action));
16013044Sasami			/* NOTREACHED */
16113044Sasami
16213044Sasami		case CCD_DUMP:
16313044Sasami			exit(dump_ccd(argc, argv));
16413044Sasami			/* NOTREACHED */
16513044Sasami	}
16613044Sasami	/* NOTREACHED */
16736628Scharnier	return (0);
16813044Sasami}
16913044Sasami
17013044Sasamistatic int
17113044Sasamido_single(argc, argv, action)
17213044Sasami	int argc;
17313044Sasami	char **argv;
17413044Sasami	int action;
17513044Sasami{
17613044Sasami	struct ccd_ioctl ccio;
17713044Sasami	char *ccd, *cp, *cp2, **disks;
17851690Sbillf	int noflags = 0, i, ileave, flags = 0, j;
17913044Sasami
18013044Sasami	bzero(&ccio, sizeof(ccio));
18113044Sasami
18213044Sasami	/*
18313044Sasami	 * If unconfiguring, all arguments are treated as ccds.
18413044Sasami	 */
18513044Sasami	if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) {
18613044Sasami		for (i = 0; argc != 0; ) {
18713044Sasami			cp = *argv++; --argc;
18813044Sasami			if ((ccd = resolve_ccdname(cp)) == NULL) {
18913044Sasami				warnx("invalid ccd name: %s", cp);
19013044Sasami				i = 1;
19113044Sasami				continue;
19213044Sasami			}
19313044Sasami			if (do_io(ccd, CCDIOCCLR, &ccio))
19413044Sasami				i = 1;
19513044Sasami			else
19613044Sasami				if (verbose)
19713044Sasami					printf("%s unconfigured\n", cp);
19813044Sasami		}
19913044Sasami		return (i);
20013044Sasami	}
20113044Sasami
20213044Sasami	/* Make sure there are enough arguments. */
20348568Sbillf	if (argc < 4) {
20413044Sasami		if (argc == 3) {
20513044Sasami			/* Assume that no flags are specified. */
20613044Sasami			noflags = 1;
20713044Sasami		} else {
20813044Sasami			if (action == CCD_CONFIGALL) {
20913044Sasami				warnx("%s: bad line: %d", ccdconf, lineno);
21013044Sasami				return (1);
21113044Sasami			} else
21213044Sasami				usage();
21313044Sasami		}
21448568Sbillf	}
21513044Sasami
21613044Sasami	/* First argument is the ccd to configure. */
21713044Sasami	cp = *argv++; --argc;
21813044Sasami	if ((ccd = resolve_ccdname(cp)) == NULL) {
21913044Sasami		warnx("invalid ccd name: %s", cp);
22013044Sasami		return (1);
22113044Sasami	}
22213044Sasami
22313044Sasami	/* Next argument is the interleave factor. */
22413044Sasami	cp = *argv++; --argc;
22513044Sasami	errno = 0;	/* to check for ERANGE */
22613044Sasami	ileave = (int)strtol(cp, &cp2, 10);
22713044Sasami	if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) {
22813044Sasami		warnx("invalid interleave factor: %s", cp);
22913044Sasami		return (1);
23013044Sasami	}
23113044Sasami
23213044Sasami	if (noflags == 0) {
23313044Sasami		/* Next argument is the ccd configuration flags. */
23413044Sasami		cp = *argv++; --argc;
23513044Sasami		if ((flags = flags_to_val(cp)) < 0) {
23613044Sasami			warnx("invalid flags argument: %s", cp);
23713044Sasami			return (1);
23813044Sasami		}
23913044Sasami	}
24013044Sasami
24113044Sasami	/* Next is the list of disks to make the ccd from. */
24213044Sasami	disks = malloc(argc * sizeof(char *));
24313044Sasami	if (disks == NULL) {
24413044Sasami		warnx("no memory to configure ccd");
24513044Sasami		return (1);
24613044Sasami	}
24713044Sasami	for (i = 0; argc != 0; ) {
24813044Sasami		cp = *argv++; --argc;
24913044Sasami		if ((j = checkdev(cp)) == 0)
25013044Sasami			disks[i++] = cp;
25113044Sasami		else {
25213044Sasami			warnx("%s: %s", cp, strerror(j));
25313044Sasami			return (1);
25413044Sasami		}
25513044Sasami	}
25613044Sasami
25713044Sasami	/* Fill in the ccio. */
25813044Sasami	ccio.ccio_disks = disks;
25913044Sasami	ccio.ccio_ndisks = i;
26013044Sasami	ccio.ccio_ileave = ileave;
26113044Sasami	ccio.ccio_flags = flags;
26213044Sasami
26313044Sasami	if (do_io(ccd, CCDIOCSET, &ccio)) {
26413044Sasami		free(disks);
26513044Sasami		return (1);
26613044Sasami	}
26713044Sasami
26813044Sasami	if (verbose) {
26913044Sasami		printf("ccd%d: %d components ", ccio.ccio_unit,
27013044Sasami		    ccio.ccio_ndisks);
27113044Sasami		for (i = 0; i < ccio.ccio_ndisks; ++i) {
27213044Sasami			if ((cp2 = strrchr(disks[i], '/')) != NULL)
27313044Sasami				++cp2;
27413044Sasami			else
27513044Sasami				cp2 = disks[i];
27613044Sasami			printf("%c%s%c",
27713044Sasami			    i == 0 ? '(' : ' ', cp2,
27813044Sasami			    i == ccio.ccio_ndisks - 1 ? ')' : ',');
27913044Sasami		}
28048568Sbillf		printf(", %lu blocks ", (u_long)ccio.ccio_size);
28113044Sasami		if (ccio.ccio_ileave != 0)
28213044Sasami			printf("interleaved at %d blocks\n", ccio.ccio_ileave);
28313044Sasami		else
28413044Sasami			printf("concatenated\n");
28513044Sasami	}
28613044Sasami
28713044Sasami	free(disks);
28813044Sasami	return (0);
28913044Sasami}
29013044Sasami
29113044Sasamistatic int
29213044Sasamido_all(action)
29313044Sasami	int action;
29413044Sasami{
29513044Sasami	FILE *f;
29613044Sasami	char line[_POSIX2_LINE_MAX];
29713044Sasami	char *cp, **argv;
29813044Sasami	int argc, rval;
29932116Simp	gid_t egid;
30013044Sasami
30151690Sbillf	rval = 0;
30232116Simp	egid = getegid();
30332116Simp	setegid(getgid());
30413044Sasami	if ((f = fopen(ccdconf, "r")) == NULL) {
30532116Simp		setegid(egid);
30613044Sasami		warn("fopen: %s", ccdconf);
30713044Sasami		return (1);
30813044Sasami	}
30932116Simp	setegid(egid);
31013044Sasami
31113044Sasami	while (fgets(line, sizeof(line), f) != NULL) {
31213044Sasami		argc = 0;
31313044Sasami		argv = NULL;
31413044Sasami		++lineno;
31513044Sasami		if ((cp = strrchr(line, '\n')) != NULL)
31613044Sasami			*cp = '\0';
31713044Sasami
31813044Sasami		/* Break up the line and pass it's contents to do_single(). */
31913044Sasami		if (line[0] == '\0')
32013044Sasami			goto end_of_line;
32113044Sasami		for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) {
32213044Sasami			if (*cp == '#')
32313044Sasami				break;
32413044Sasami			if ((argv = realloc(argv,
32513044Sasami			    sizeof(char *) * ++argc)) == NULL) {
32613044Sasami				warnx("no memory to configure ccds");
32713044Sasami				return (1);
32813044Sasami			}
32913044Sasami			argv[argc - 1] = cp;
33013044Sasami			/*
33113044Sasami			 * If our action is to unconfigure all, then pass
33213044Sasami			 * just the first token to do_single() and ignore
33313044Sasami			 * the rest.  Since this will be encountered on
33413044Sasami			 * our first pass through the line, the Right
33513044Sasami			 * Thing will happen.
33613044Sasami			 */
33713044Sasami			if (action == CCD_UNCONFIGALL) {
33813044Sasami				if (do_single(argc, argv, action))
33913044Sasami					rval = 1;
34013044Sasami				goto end_of_line;
34113044Sasami			}
34213044Sasami		}
34313044Sasami		if (argc != 0)
34413044Sasami			if (do_single(argc, argv, action))
34513044Sasami				rval = 1;
34613044Sasami
34713044Sasami end_of_line:
34813044Sasami		if (argv != NULL)
34913044Sasami			free(argv);
35013044Sasami	}
35113044Sasami
35213044Sasami	(void)fclose(f);
35313044Sasami	return (rval);
35413044Sasami}
35513044Sasami
35613044Sasamistatic int
35713044Sasamicheckdev(path)
35813044Sasami	char *path;
35913044Sasami{
36013044Sasami	struct stat st;
36113044Sasami
36213044Sasami	if (stat(path, &st) != 0)
36313044Sasami		return (errno);
36413044Sasami
36513044Sasami	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
36613044Sasami		return (EINVAL);
36713044Sasami
36813044Sasami	return (0);
36913044Sasami}
37013044Sasami
37113044Sasamistatic int
37213044Sasamipathtounit(path, unitp)
37313044Sasami	char *path;
37413044Sasami	int *unitp;
37513044Sasami{
37613044Sasami	struct stat st;
37713044Sasami	int maxpartitions;
37813044Sasami
37913044Sasami	if (stat(path, &st) != 0)
38013044Sasami		return (errno);
38113044Sasami
38213044Sasami	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
38313044Sasami		return (EINVAL);
38413044Sasami
38513044Sasami	if ((maxpartitions = getmaxpartitions()) < 0)
38613044Sasami		return (errno);
38713044Sasami
38813044Sasami	*unitp = minor(st.st_rdev) / maxpartitions;
38913044Sasami
39013044Sasami	return (0);
39113044Sasami}
39213044Sasami
39313044Sasamistatic char *
39413044Sasamiresolve_ccdname(name)
39513044Sasami	char *name;
39613044Sasami{
39736628Scharnier	char c, *path;
39813044Sasami	size_t len, newlen;
39913044Sasami	int rawpart;
40013044Sasami
40113044Sasami	if (name[0] == '/' || name[0] == '.') {
40213044Sasami		/* Assume they gave the correct pathname. */
40313044Sasami		return (strdup(name));
40413044Sasami	}
40513044Sasami
40613044Sasami	len = strlen(name);
40713044Sasami	c = name[len - 1];
40813044Sasami
40913044Sasami	newlen = len + 8;
41013044Sasami	if ((path = malloc(newlen)) == NULL)
41113044Sasami		return (NULL);
41213044Sasami	bzero(path, newlen);
41313044Sasami
41413044Sasami	if (isdigit(c)) {
41513044Sasami		if ((rawpart = getrawpartition()) < 0) {
41613044Sasami			free(path);
41713044Sasami			return (NULL);
41813044Sasami		}
41969793Sobrien		(void)sprintf(path, "%s%s%c", _PATH_DEV, name, 'a' + rawpart);
42013044Sasami	} else
42169793Sobrien		(void)sprintf(path, "%s%s", _PATH_DEV, name);
42213044Sasami
42313044Sasami	return (path);
42413044Sasami}
42513044Sasami
42613044Sasamistatic int
42713044Sasamido_io(path, cmd, cciop)
42813044Sasami	char *path;
42913044Sasami	u_long cmd;
43013044Sasami	struct ccd_ioctl *cciop;
43113044Sasami{
43213044Sasami	int fd;
43313044Sasami	char *cp;
43413044Sasami
43513044Sasami	if ((fd = open(path, O_RDWR, 0640)) < 0) {
43613044Sasami		warn("open: %s", path);
43713044Sasami		return (1);
43813044Sasami	}
43913044Sasami
44013044Sasami	if (ioctl(fd, cmd, cciop) < 0) {
44113044Sasami		switch (cmd) {
44213044Sasami		case CCDIOCSET:
44313044Sasami			cp = "CCDIOCSET";
44413044Sasami			break;
44513044Sasami
44613044Sasami		case CCDIOCCLR:
44713044Sasami			cp = "CCDIOCCLR";
44813044Sasami			break;
44913044Sasami
45082943Sphk		case CCDCONFINFO:
45182943Sphk			cp = "CCDCONFINFO";
45282943Sphk			break;
45382943Sphk
45482943Sphk		case CCDCPPINFO:
45582943Sphk			cp = "CCDCPPINFO";
45682943Sphk			break;
45782943Sphk
45813044Sasami		default:
45913044Sasami			cp = "unknown";
46013044Sasami		}
46113044Sasami		warn("ioctl (%s): %s", cp, path);
46213044Sasami		return (1);
46313044Sasami	}
46413044Sasami
46513044Sasami	return (0);
46613044Sasami}
46713044Sasami
46813044Sasamistatic int
46913044Sasamidump_ccd(argc, argv)
47013044Sasami	int argc;
47113044Sasami	char **argv;
47213044Sasami{
47382943Sphk	char *ccd, *cp;
47413044Sasami	int i, error, numccd, numconfiged = 0;
47582943Sphk	struct ccdconf conf;
47613044Sasami
47782943Sphk	/*
47882943Sphk	 * Read the ccd configuration data from the kernel and dump
47982943Sphk	 * it to stdout.
48082943Sphk	 */
48182943Sphk	if ((ccd = resolve_ccdname("ccd0")) == NULL) {		/* XXX */
48282943Sphk		warnx("invalid ccd name: %s", cp);
48313044Sasami		return (1);
48413044Sasami	}
48582943Sphk	conf.size = 0;
48682943Sphk	if (do_io(ccd, CCDCONFINFO, (struct ccd_ioctl *) &conf))
48782943Sphk		return (1);
48882943Sphk	if (conf.size == 0) {
48982943Sphk		printf("no concatenated disks configured\n");
49082943Sphk		return (0);
49113044Sasami	}
49213044Sasami	/* Allocate space for the configuration data. */
49382943Sphk	conf.buffer = alloca(conf.size);
49482943Sphk	if (conf.buffer == NULL) {
49513044Sasami		warnx("no memory for configuration data");
49682943Sphk		return (1);
49713044Sasami	}
49882943Sphk	if (do_io(ccd, CCDCONFINFO, (struct ccd_ioctl *) &conf))
49982943Sphk		return (1);
50013044Sasami
50182943Sphk	numconfiged = conf.size / sizeof(struct ccd_s);
50213044Sasami
50313044Sasami	if (argc == 0) {
50482943Sphk		for (i = 0; i < numconfiged; i++)
50582943Sphk			print_ccd_info(&(conf.buffer[i]));
50613044Sasami	} else {
50713044Sasami		while (argc) {
50813044Sasami			cp = *argv++; --argc;
50913044Sasami			if ((ccd = resolve_ccdname(cp)) == NULL) {
51013044Sasami				warnx("invalid ccd name: %s", cp);
51113044Sasami				continue;
51213044Sasami			}
51382943Sphk			if ((error = pathtounit(ccd, &numccd)) != 0) {
51413044Sasami				warnx("%s: %s", ccd, strerror(error));
51513044Sasami				continue;
51613044Sasami			}
51782943Sphk			error = 1;
51882943Sphk			for (i = 0; i < numconfiged; i++) {
51982943Sphk				if (conf.buffer[i].sc_unit == numccd) {
52082943Sphk					print_ccd_info(&(conf.buffer[i]));
52182943Sphk					error = 0;
52282943Sphk					break;
52382943Sphk				}
52482943Sphk			}
52582943Sphk			if (error) {
52682943Sphk				warnx("ccd%d not configured", numccd);
52713044Sasami				continue;
52813044Sasami			}
52913044Sasami		}
53082943Sphk	}
53113044Sasami
53213044Sasami	return (0);
53313044Sasami}
53413044Sasami
53513044Sasamistatic void
53682943Sphkprint_ccd_info(cs)
53782943Sphk	struct ccd_s *cs;
53813044Sasami{
53982943Sphk	char *cp, *ccd;
54013044Sasami	static int header_printed = 0;
54182943Sphk	struct ccdcpps cpps;
54213044Sasami
54382943Sphk	/* Print out header if necessary*/
54413044Sasami	if (header_printed == 0 && verbose) {
54513044Sasami		printf("# ccd\t\tileave\tflags\tcompnent devices\n");
54613044Sasami		header_printed = 1;
54713044Sasami	}
54813044Sasami
54913044Sasami	/* Dump out softc information. */
55013044Sasami	printf("ccd%d\t\t%d\t%d\t", cs->sc_unit, cs->sc_ileave,
55113044Sasami	    cs->sc_cflags & CCDF_USERMASK);
55213044Sasami	fflush(stdout);
55313044Sasami
55413044Sasami	/* Read in the component info. */
55582943Sphk	asprintf(&cp, "%s%d", cs->device_stats.device_name,
55682943Sphk	    cs->device_stats.unit_number);
55782943Sphk	if (cp == NULL) {
55813044Sasami		printf("\n");
55982943Sphk		warn("ccd%d: can't allocate memory",
56082943Sphk		    cs->sc_unit);
56182943Sphk		return;
56282943Sphk	}
56382943Sphk
56482943Sphk	if ((ccd = resolve_ccdname(cp)) == NULL) {
56582943Sphk		printf("\n");
56682943Sphk		warnx("can't read component info: invalid ccd name: %s", cp);
56782943Sphk		return;
56882943Sphk	}
56982943Sphk	cpps.size = 0;
57082943Sphk	if (do_io(ccd, CCDCPPINFO, (struct ccd_ioctl *) &cpps)) {
57182943Sphk		printf("\n");
57213044Sasami		warnx("can't read component info");
57382943Sphk		return;
57413044Sasami	}
57582943Sphk	cpps.buffer = alloca(cpps.size);
57682943Sphk	if (cpps.buffer == NULL) {
57782943Sphk		printf("\n");
57882943Sphk		warn("ccd%d: can't allocate memory for component info",
57982943Sphk		    cs->sc_unit);
58082943Sphk		return;
58182943Sphk	}
58282943Sphk	if (do_io(ccd, CCDCPPINFO, (struct ccd_ioctl *) &cpps)) {
58382943Sphk		printf("\n");
58482943Sphk		warnx("can't read component info");
58582943Sphk		return;
58682943Sphk	}
58713044Sasami
58882943Sphk	/* Display component info. */
58982943Sphk	for (cp = cpps.buffer; cp - cpps.buffer < cpps.size; cp += strlen(cp) + 1) {
59082943Sphk		printf((cp + strlen(cp) + 1) < (cpps.buffer + cpps.size) ?
59182943Sphk		    "%s " : "%s\n", cp);
59213044Sasami		fflush(stdout);
59313044Sasami	}
59482943Sphk	return;
59513044Sasami}
59613044Sasami
59713044Sasamistatic int
59813044Sasamigetmaxpartitions()
59913044Sasami{
60013052Sasami    return (MAXPARTITIONS);
60113044Sasami}
60213044Sasami
60313044Sasamistatic int
60413044Sasamigetrawpartition()
60513044Sasami{
60613052Sasami	return (RAW_PART);
60713044Sasami}
60813044Sasami
60913044Sasamistatic int
61013044Sasamiflags_to_val(flags)
61113044Sasami	char *flags;
61213044Sasami{
61313044Sasami	char *cp, *tok;
61413044Sasami	int i, tmp, val = ~CCDF_USERMASK;
61513044Sasami	size_t flagslen;
61613044Sasami
61713044Sasami	/*
61813044Sasami	 * The most common case is that of NIL flags, so check for
61913044Sasami	 * those first.
62013044Sasami	 */
62113044Sasami	if (strcmp("none", flags) == 0 || strcmp("0x0", flags) == 0 ||
62213044Sasami	    strcmp("0", flags) == 0)
62313044Sasami		return (0);
62413044Sasami
62513044Sasami	flagslen = strlen(flags);
62613044Sasami
62713044Sasami	/* Check for values represented by strings. */
62813044Sasami	if ((cp = strdup(flags)) == NULL)
62913044Sasami		err(1, "no memory to parse flags");
63013044Sasami	tmp = 0;
63113044Sasami	for (tok = cp; (tok = strtok(tok, ",")) != NULL; tok = NULL) {
63213044Sasami		for (i = 0; flagvaltab[i].fv_flag != NULL; ++i)
63313044Sasami			if (strcmp(tok, flagvaltab[i].fv_flag) == 0)
63413044Sasami				break;
63513044Sasami		if (flagvaltab[i].fv_flag == NULL) {
63613044Sasami			free(cp);
63713044Sasami			goto bad_string;
63813044Sasami		}
63913044Sasami		tmp |= flagvaltab[i].fv_val;
64013044Sasami	}
64113044Sasami
64213044Sasami	/* If we get here, the string was ok. */
64313044Sasami	free(cp);
64413044Sasami	val = tmp;
64513044Sasami	goto out;
64613044Sasami
64713044Sasami bad_string:
64813044Sasami
64913044Sasami	/* Check for values represented in hex. */
65013044Sasami	if (flagslen > 2 && flags[0] == '0' && flags[1] == 'x') {
65113044Sasami		errno = 0;	/* to check for ERANGE */
65213044Sasami		val = (int)strtol(&flags[2], &cp, 16);
65313044Sasami		if ((errno == ERANGE) || (*cp != '\0'))
65413044Sasami			return (-1);
65513044Sasami		goto out;
65613044Sasami	}
65713044Sasami
65813044Sasami	/* Check for values represented in decimal. */
65913044Sasami	errno = 0;	/* to check for ERANGE */
66013044Sasami	val = (int)strtol(flags, &cp, 10);
66113044Sasami	if ((errno == ERANGE) || (*cp != '\0'))
66213044Sasami		return (-1);
66313044Sasami
66413044Sasami out:
66513044Sasami	return (((val & ~CCDF_USERMASK) == 0) ? val : -1);
66613044Sasami}
66713044Sasami
66813044Sasamistatic void
66913044Sasamiusage()
67013044Sasami{
67126541Scharnier	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
67226541Scharnier		"usage: ccdconfig [-cv] ccd ileave [flags] dev [...]",
67326541Scharnier		"       ccdconfig -C [-v] [-f config_file]",
67426541Scharnier		"       ccdconfig -u [-v] ccd [...]",
67526541Scharnier		"       ccdconfig -U [-v] [-f config_file]",
67682943Sphk		"       ccdconfig -g [ccd [...]]");
67713044Sasami	exit(1);
67813044Sasami}
67926541Scharnier
68013052Sasami/* Local Variables: */
68113052Sasami/* c-argdecl-indent: 8 */
68213052Sasami/* c-indent-level: 8 */
68313052Sasami/* End: */
684