ccdconfig.c revision 69793
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 69793 2000-12-09 09:35:55Z obrien $";
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 <kvm.h>
5013044Sasami#include <limits.h>
5169793Sobrien#include <paths.h>
5213044Sasami#include <stdio.h>
5313044Sasami#include <stdlib.h>
5413044Sasami#include <string.h>
5513044Sasami#include <unistd.h>
5613044Sasami
5739228Sgibbs#include <sys/devicestat.h>
5813052Sasami#include <sys/ccdvar.h>
5913044Sasami
6013044Sasami#include "pathnames.h"
6113044Sasami
6213044Sasamistatic	int lineno = 0;
6313044Sasamistatic	int verbose = 0;
6413044Sasamistatic	char *ccdconf = _PATH_CCDCONF;
6513044Sasami
6613044Sasamistatic	char *core = NULL;
6713044Sasamistatic	char *kernel = NULL;
6813044Sasami
6913044Sasamistruct	flagval {
7013044Sasami	char	*fv_flag;
7113044Sasami	int	fv_val;
7213044Sasami} flagvaltab[] = {
7313044Sasami	{ "CCDF_SWAP",		CCDF_SWAP },
7413044Sasami	{ "CCDF_UNIFORM",	CCDF_UNIFORM },
7513762Sasami	{ "CCDF_MIRROR",	CCDF_MIRROR },
7613762Sasami	{ "CCDF_PARITY",	CCDF_PARITY },
7713044Sasami	{ NULL,			0 },
7813044Sasami};
7913044Sasami
8013044Sasamistatic	struct nlist nl[] = {
8113044Sasami	{ "_ccd_softc" },
8213044Sasami#define SYM_CCDSOFTC		0
8313044Sasami	{ "_numccd" },
8413044Sasami#define SYM_NUMCCD		1
8513044Sasami	{ NULL },
8613044Sasami};
8713044Sasami
8813044Sasami#define CCD_CONFIG		0	/* configure a device */
8913044Sasami#define CCD_CONFIGALL		1	/* configure all devices */
9013044Sasami#define CCD_UNCONFIG		2	/* unconfigure a device */
9113044Sasami#define CCD_UNCONFIGALL		3	/* unconfigure all devices */
9213044Sasami#define CCD_DUMP		4	/* dump a ccd's configuration */
9313044Sasami
9413044Sasamistatic	int checkdev __P((char *));
9513044Sasamistatic	int do_io __P((char *, u_long, struct ccd_ioctl *));
9613044Sasamistatic	int do_single __P((int, char **, int));
9713044Sasamistatic	int do_all __P((int));
9813044Sasamistatic	int dump_ccd __P((int, char **));
9913044Sasamistatic	int getmaxpartitions __P((void));
10013044Sasamistatic	int getrawpartition __P((void));
10113044Sasamistatic	int flags_to_val __P((char *));
10213044Sasamistatic	void print_ccd_info __P((struct ccd_softc *, kvm_t *));
10313044Sasamistatic	char *resolve_ccdname __P((char *));
10413044Sasamistatic	void usage __P((void));
10513044Sasami
10613044Sasamiint
10713044Sasamimain(argc, argv)
10813044Sasami	int argc;
10913044Sasami	char **argv;
11013044Sasami{
11113044Sasami	int ch, options = 0, action = CCD_CONFIG;
11213044Sasami
11313044Sasami	while ((ch = getopt(argc, argv, "cCf:gM:N:uUv")) != -1) {
11413044Sasami		switch (ch) {
11513044Sasami		case 'c':
11613044Sasami			action = CCD_CONFIG;
11713044Sasami			++options;
11813044Sasami			break;
11913044Sasami
12013044Sasami		case 'C':
12113044Sasami			action = CCD_CONFIGALL;
12213044Sasami			++options;
12313044Sasami			break;
12413044Sasami
12513044Sasami		case 'f':
12613044Sasami			ccdconf = optarg;
12713044Sasami			break;
12813044Sasami
12913044Sasami		case 'g':
13013044Sasami			action = CCD_DUMP;
13113044Sasami			break;
13213044Sasami
13313044Sasami		case 'M':
13413044Sasami			core = optarg;
13513044Sasami			break;
13613044Sasami
13713044Sasami		case 'N':
13813044Sasami			kernel = optarg;
13913044Sasami			break;
14013044Sasami
14113044Sasami		case 'u':
14213044Sasami			action = CCD_UNCONFIG;
14313044Sasami			++options;
14413044Sasami			break;
14513044Sasami
14613044Sasami		case 'U':
14713044Sasami			action = CCD_UNCONFIGALL;
14813044Sasami			++options;
14913044Sasami			break;
15013044Sasami
15113044Sasami		case 'v':
15213044Sasami			verbose = 1;
15313044Sasami			break;
15413044Sasami
15513044Sasami		default:
15613044Sasami			usage();
15713044Sasami		}
15813044Sasami	}
15913044Sasami	argc -= optind;
16013044Sasami	argv += optind;
16113044Sasami
16213044Sasami	if (options > 1)
16313044Sasami		usage();
16413044Sasami
16532116Simp	/*
16632116Simp	 * Discard setgid privileges if not the running kernel so that bad
16732116Simp	 * guys can't print interesting stuff from kernel memory.
16832116Simp	 */
16932116Simp	if (core != NULL || kernel != NULL || action != CCD_DUMP) {
17032116Simp		setegid(getgid());
17132116Simp		setgid(getgid());
17232116Simp	}
17332116Simp
17445329Speter	if (modfind("ccd") < 0) {
17545329Speter		/* Not present in kernel, try loading it */
17645329Speter		if (kldload("ccd") < 0 || modfind("ccd") < 0)
17745329Speter			warn("ccd module not available!");
17845329Speter	}
17945329Speter
18013044Sasami	switch (action) {
18113044Sasami		case CCD_CONFIG:
18213044Sasami		case CCD_UNCONFIG:
18313044Sasami			exit(do_single(argc, argv, action));
18413044Sasami			/* NOTREACHED */
18513044Sasami
18613044Sasami		case CCD_CONFIGALL:
18713044Sasami		case CCD_UNCONFIGALL:
18813044Sasami			exit(do_all(action));
18913044Sasami			/* NOTREACHED */
19013044Sasami
19113044Sasami		case CCD_DUMP:
19213044Sasami			exit(dump_ccd(argc, argv));
19313044Sasami			/* NOTREACHED */
19413044Sasami	}
19513044Sasami	/* NOTREACHED */
19636628Scharnier	return (0);
19713044Sasami}
19813044Sasami
19913044Sasamistatic int
20013044Sasamido_single(argc, argv, action)
20113044Sasami	int argc;
20213044Sasami	char **argv;
20313044Sasami	int action;
20413044Sasami{
20513044Sasami	struct ccd_ioctl ccio;
20613044Sasami	char *ccd, *cp, *cp2, **disks;
20751690Sbillf	int noflags = 0, i, ileave, flags = 0, j;
20813044Sasami
20913044Sasami	bzero(&ccio, sizeof(ccio));
21013044Sasami
21113044Sasami	/*
21213044Sasami	 * If unconfiguring, all arguments are treated as ccds.
21313044Sasami	 */
21413044Sasami	if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) {
21513044Sasami		for (i = 0; argc != 0; ) {
21613044Sasami			cp = *argv++; --argc;
21713044Sasami			if ((ccd = resolve_ccdname(cp)) == NULL) {
21813044Sasami				warnx("invalid ccd name: %s", cp);
21913044Sasami				i = 1;
22013044Sasami				continue;
22113044Sasami			}
22213044Sasami			if (do_io(ccd, CCDIOCCLR, &ccio))
22313044Sasami				i = 1;
22413044Sasami			else
22513044Sasami				if (verbose)
22613044Sasami					printf("%s unconfigured\n", cp);
22713044Sasami		}
22813044Sasami		return (i);
22913044Sasami	}
23013044Sasami
23113044Sasami	/* Make sure there are enough arguments. */
23248568Sbillf	if (argc < 4) {
23313044Sasami		if (argc == 3) {
23413044Sasami			/* Assume that no flags are specified. */
23513044Sasami			noflags = 1;
23613044Sasami		} else {
23713044Sasami			if (action == CCD_CONFIGALL) {
23813044Sasami				warnx("%s: bad line: %d", ccdconf, lineno);
23913044Sasami				return (1);
24013044Sasami			} else
24113044Sasami				usage();
24213044Sasami		}
24348568Sbillf	}
24413044Sasami
24513044Sasami	/* First argument is the ccd to configure. */
24613044Sasami	cp = *argv++; --argc;
24713044Sasami	if ((ccd = resolve_ccdname(cp)) == NULL) {
24813044Sasami		warnx("invalid ccd name: %s", cp);
24913044Sasami		return (1);
25013044Sasami	}
25113044Sasami
25213044Sasami	/* Next argument is the interleave factor. */
25313044Sasami	cp = *argv++; --argc;
25413044Sasami	errno = 0;	/* to check for ERANGE */
25513044Sasami	ileave = (int)strtol(cp, &cp2, 10);
25613044Sasami	if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) {
25713044Sasami		warnx("invalid interleave factor: %s", cp);
25813044Sasami		return (1);
25913044Sasami	}
26013044Sasami
26113044Sasami	if (noflags == 0) {
26213044Sasami		/* Next argument is the ccd configuration flags. */
26313044Sasami		cp = *argv++; --argc;
26413044Sasami		if ((flags = flags_to_val(cp)) < 0) {
26513044Sasami			warnx("invalid flags argument: %s", cp);
26613044Sasami			return (1);
26713044Sasami		}
26813044Sasami	}
26913044Sasami
27013044Sasami	/* Next is the list of disks to make the ccd from. */
27113044Sasami	disks = malloc(argc * sizeof(char *));
27213044Sasami	if (disks == NULL) {
27313044Sasami		warnx("no memory to configure ccd");
27413044Sasami		return (1);
27513044Sasami	}
27613044Sasami	for (i = 0; argc != 0; ) {
27713044Sasami		cp = *argv++; --argc;
27813044Sasami		if ((j = checkdev(cp)) == 0)
27913044Sasami			disks[i++] = cp;
28013044Sasami		else {
28113044Sasami			warnx("%s: %s", cp, strerror(j));
28213044Sasami			return (1);
28313044Sasami		}
28413044Sasami	}
28513044Sasami
28613044Sasami	/* Fill in the ccio. */
28713044Sasami	ccio.ccio_disks = disks;
28813044Sasami	ccio.ccio_ndisks = i;
28913044Sasami	ccio.ccio_ileave = ileave;
29013044Sasami	ccio.ccio_flags = flags;
29113044Sasami
29213044Sasami	if (do_io(ccd, CCDIOCSET, &ccio)) {
29313044Sasami		free(disks);
29413044Sasami		return (1);
29513044Sasami	}
29613044Sasami
29713044Sasami	if (verbose) {
29813044Sasami		printf("ccd%d: %d components ", ccio.ccio_unit,
29913044Sasami		    ccio.ccio_ndisks);
30013044Sasami		for (i = 0; i < ccio.ccio_ndisks; ++i) {
30113044Sasami			if ((cp2 = strrchr(disks[i], '/')) != NULL)
30213044Sasami				++cp2;
30313044Sasami			else
30413044Sasami				cp2 = disks[i];
30513044Sasami			printf("%c%s%c",
30613044Sasami			    i == 0 ? '(' : ' ', cp2,
30713044Sasami			    i == ccio.ccio_ndisks - 1 ? ')' : ',');
30813044Sasami		}
30948568Sbillf		printf(", %lu blocks ", (u_long)ccio.ccio_size);
31013044Sasami		if (ccio.ccio_ileave != 0)
31113044Sasami			printf("interleaved at %d blocks\n", ccio.ccio_ileave);
31213044Sasami		else
31313044Sasami			printf("concatenated\n");
31413044Sasami	}
31513044Sasami
31613044Sasami	free(disks);
31713044Sasami	return (0);
31813044Sasami}
31913044Sasami
32013044Sasamistatic int
32113044Sasamido_all(action)
32213044Sasami	int action;
32313044Sasami{
32413044Sasami	FILE *f;
32513044Sasami	char line[_POSIX2_LINE_MAX];
32613044Sasami	char *cp, **argv;
32713044Sasami	int argc, rval;
32832116Simp	gid_t egid;
32913044Sasami
33051690Sbillf	rval = 0;
33132116Simp	egid = getegid();
33232116Simp	setegid(getgid());
33313044Sasami	if ((f = fopen(ccdconf, "r")) == NULL) {
33432116Simp		setegid(egid);
33513044Sasami		warn("fopen: %s", ccdconf);
33613044Sasami		return (1);
33713044Sasami	}
33832116Simp	setegid(egid);
33913044Sasami
34013044Sasami	while (fgets(line, sizeof(line), f) != NULL) {
34113044Sasami		argc = 0;
34213044Sasami		argv = NULL;
34313044Sasami		++lineno;
34413044Sasami		if ((cp = strrchr(line, '\n')) != NULL)
34513044Sasami			*cp = '\0';
34613044Sasami
34713044Sasami		/* Break up the line and pass it's contents to do_single(). */
34813044Sasami		if (line[0] == '\0')
34913044Sasami			goto end_of_line;
35013044Sasami		for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) {
35113044Sasami			if (*cp == '#')
35213044Sasami				break;
35313044Sasami			if ((argv = realloc(argv,
35413044Sasami			    sizeof(char *) * ++argc)) == NULL) {
35513044Sasami				warnx("no memory to configure ccds");
35613044Sasami				return (1);
35713044Sasami			}
35813044Sasami			argv[argc - 1] = cp;
35913044Sasami			/*
36013044Sasami			 * If our action is to unconfigure all, then pass
36113044Sasami			 * just the first token to do_single() and ignore
36213044Sasami			 * the rest.  Since this will be encountered on
36313044Sasami			 * our first pass through the line, the Right
36413044Sasami			 * Thing will happen.
36513044Sasami			 */
36613044Sasami			if (action == CCD_UNCONFIGALL) {
36713044Sasami				if (do_single(argc, argv, action))
36813044Sasami					rval = 1;
36913044Sasami				goto end_of_line;
37013044Sasami			}
37113044Sasami		}
37213044Sasami		if (argc != 0)
37313044Sasami			if (do_single(argc, argv, action))
37413044Sasami				rval = 1;
37513044Sasami
37613044Sasami end_of_line:
37713044Sasami		if (argv != NULL)
37813044Sasami			free(argv);
37913044Sasami	}
38013044Sasami
38113044Sasami	(void)fclose(f);
38213044Sasami	return (rval);
38313044Sasami}
38413044Sasami
38513044Sasamistatic int
38613044Sasamicheckdev(path)
38713044Sasami	char *path;
38813044Sasami{
38913044Sasami	struct stat st;
39013044Sasami
39113044Sasami	if (stat(path, &st) != 0)
39213044Sasami		return (errno);
39313044Sasami
39413044Sasami	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
39513044Sasami		return (EINVAL);
39613044Sasami
39713044Sasami	return (0);
39813044Sasami}
39913044Sasami
40013044Sasamistatic int
40113044Sasamipathtounit(path, unitp)
40213044Sasami	char *path;
40313044Sasami	int *unitp;
40413044Sasami{
40513044Sasami	struct stat st;
40613044Sasami	int maxpartitions;
40713044Sasami
40813044Sasami	if (stat(path, &st) != 0)
40913044Sasami		return (errno);
41013044Sasami
41113044Sasami	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
41213044Sasami		return (EINVAL);
41313044Sasami
41413044Sasami	if ((maxpartitions = getmaxpartitions()) < 0)
41513044Sasami		return (errno);
41613044Sasami
41713044Sasami	*unitp = minor(st.st_rdev) / maxpartitions;
41813044Sasami
41913044Sasami	return (0);
42013044Sasami}
42113044Sasami
42213044Sasamistatic char *
42313044Sasamiresolve_ccdname(name)
42413044Sasami	char *name;
42513044Sasami{
42636628Scharnier	char c, *path;
42713044Sasami	size_t len, newlen;
42813044Sasami	int rawpart;
42913044Sasami
43013044Sasami	if (name[0] == '/' || name[0] == '.') {
43113044Sasami		/* Assume they gave the correct pathname. */
43213044Sasami		return (strdup(name));
43313044Sasami	}
43413044Sasami
43513044Sasami	len = strlen(name);
43613044Sasami	c = name[len - 1];
43713044Sasami
43813044Sasami	newlen = len + 8;
43913044Sasami	if ((path = malloc(newlen)) == NULL)
44013044Sasami		return (NULL);
44113044Sasami	bzero(path, newlen);
44213044Sasami
44313044Sasami	if (isdigit(c)) {
44413044Sasami		if ((rawpart = getrawpartition()) < 0) {
44513044Sasami			free(path);
44613044Sasami			return (NULL);
44713044Sasami		}
44869793Sobrien		(void)sprintf(path, "%s%s%c", _PATH_DEV, name, 'a' + rawpart);
44913044Sasami	} else
45069793Sobrien		(void)sprintf(path, "%s%s", _PATH_DEV, name);
45113044Sasami
45213044Sasami	return (path);
45313044Sasami}
45413044Sasami
45513044Sasamistatic int
45613044Sasamido_io(path, cmd, cciop)
45713044Sasami	char *path;
45813044Sasami	u_long cmd;
45913044Sasami	struct ccd_ioctl *cciop;
46013044Sasami{
46113044Sasami	int fd;
46213044Sasami	char *cp;
46313044Sasami
46413044Sasami	if ((fd = open(path, O_RDWR, 0640)) < 0) {
46513044Sasami		warn("open: %s", path);
46613044Sasami		return (1);
46713044Sasami	}
46813044Sasami
46913044Sasami	if (ioctl(fd, cmd, cciop) < 0) {
47013044Sasami		switch (cmd) {
47113044Sasami		case CCDIOCSET:
47213044Sasami			cp = "CCDIOCSET";
47313044Sasami			break;
47413044Sasami
47513044Sasami		case CCDIOCCLR:
47613044Sasami			cp = "CCDIOCCLR";
47713044Sasami			break;
47813044Sasami
47913044Sasami		default:
48013044Sasami			cp = "unknown";
48113044Sasami		}
48213044Sasami		warn("ioctl (%s): %s", cp, path);
48313044Sasami		return (1);
48413044Sasami	}
48513044Sasami
48613044Sasami	return (0);
48713044Sasami}
48813044Sasami
48913044Sasami#define KVM_ABORT(kd, str) {						\
49013044Sasami	(void)kvm_close((kd));						\
49164275Skris	warnx("%s", (str));							\
49264275Skris	warnx("%s", kvm_geterr((kd)));					\
49313044Sasami	return (1);							\
49413044Sasami}
49513044Sasami
49613044Sasamistatic int
49713044Sasamidump_ccd(argc, argv)
49813044Sasami	int argc;
49913044Sasami	char **argv;
50013044Sasami{
50113044Sasami	char errbuf[_POSIX2_LINE_MAX], *ccd, *cp;
50213044Sasami	struct ccd_softc *cs, *kcs;
50313044Sasami	size_t readsize;
50413044Sasami	int i, error, numccd, numconfiged = 0;
50513044Sasami	kvm_t *kd;
50613044Sasami
50713044Sasami	bzero(errbuf, sizeof(errbuf));
50813044Sasami
50913044Sasami	if ((kd = kvm_openfiles(kernel, core, NULL, O_RDONLY,
51013044Sasami	    errbuf)) == NULL) {
51113044Sasami		warnx("can't open kvm: %s", errbuf);
51213044Sasami		return (1);
51313044Sasami	}
51413044Sasami
51513044Sasami	if (kvm_nlist(kd, nl))
51613044Sasami		KVM_ABORT(kd, "ccd-related symbols not available");
51713044Sasami
51813044Sasami	/* Check to see how many ccds are currently configured. */
51913044Sasami	if (kvm_read(kd, nl[SYM_NUMCCD].n_value, (char *)&numccd,
52013044Sasami	    sizeof(numccd)) != sizeof(numccd))
52113044Sasami		KVM_ABORT(kd, "can't determine number of configured ccds");
52213044Sasami
52313044Sasami	if (numccd == 0) {
52413044Sasami		printf("ccd driver in kernel, but is uninitialized\n");
52513044Sasami		goto done;
52613044Sasami	}
52713044Sasami
52813044Sasami	/* Allocate space for the configuration data. */
52913044Sasami	readsize = numccd * sizeof(struct ccd_softc);
53013044Sasami	if ((cs = malloc(readsize)) == NULL) {
53113044Sasami		warnx("no memory for configuration data");
53213044Sasami		goto bad;
53313044Sasami	}
53413044Sasami	bzero(cs, readsize);
53513044Sasami
53613044Sasami	/*
53713044Sasami	 * Read the ccd configuration data from the kernel and dump
53813044Sasami	 * it to stdout.
53913044Sasami	 */
54013044Sasami	if (kvm_read(kd, nl[SYM_CCDSOFTC].n_value, (char *)&kcs,
54113044Sasami	    sizeof(kcs)) != sizeof(kcs)) {
54213044Sasami		free(cs);
54313044Sasami		KVM_ABORT(kd, "can't find pointer to configuration data");
54413044Sasami	}
54513044Sasami	if (kvm_read(kd, (u_long)kcs, (char *)cs, readsize) != readsize) {
54613044Sasami		free(cs);
54713044Sasami		KVM_ABORT(kd, "can't read configuration data");
54813044Sasami	}
54913044Sasami
55013044Sasami	if (argc == 0) {
55113044Sasami		for (i = 0; i < numccd; ++i)
55213044Sasami			if (cs[i].sc_flags & CCDF_INITED) {
55313044Sasami				++numconfiged;
55413044Sasami				print_ccd_info(&cs[i], kd);
55513044Sasami			}
55613044Sasami
55713044Sasami		if (numconfiged == 0)
55813044Sasami			printf("no concatenated disks configured\n");
55913044Sasami	} else {
56013044Sasami		while (argc) {
56113044Sasami			cp = *argv++; --argc;
56213044Sasami			if ((ccd = resolve_ccdname(cp)) == NULL) {
56313044Sasami				warnx("invalid ccd name: %s", cp);
56413044Sasami				continue;
56513044Sasami			}
56613044Sasami			if ((error = pathtounit(ccd, &i)) != 0) {
56713044Sasami				warnx("%s: %s", ccd, strerror(error));
56813044Sasami				continue;
56913044Sasami			}
57013044Sasami			if (i >= numccd) {
57113044Sasami				warnx("ccd%d not configured", i);
57213044Sasami				continue;
57313044Sasami			}
57413044Sasami			if (cs[i].sc_flags & CCDF_INITED)
57513044Sasami				print_ccd_info(&cs[i], kd);
57613044Sasami			else
57713044Sasami				printf("ccd%d not configured\n", i);
57813044Sasami		}
57913044Sasami	}
58013044Sasami
58113044Sasami	free(cs);
58213044Sasami
58313044Sasami done:
58413044Sasami	(void)kvm_close(kd);
58513044Sasami	return (0);
58613044Sasami
58713044Sasami bad:
58813044Sasami	(void)kvm_close(kd);
58913044Sasami	return (1);
59013044Sasami}
59113044Sasami
59213044Sasamistatic void
59313044Sasamiprint_ccd_info(cs, kd)
59413044Sasami	struct ccd_softc *cs;
59513044Sasami	kvm_t *kd;
59613044Sasami{
59713044Sasami	static int header_printed = 0;
59813044Sasami	struct ccdcinfo *cip;
59913044Sasami	size_t readsize;
60013044Sasami	char path[MAXPATHLEN];
60113044Sasami	int i;
60213044Sasami
60313044Sasami	if (header_printed == 0 && verbose) {
60413044Sasami		printf("# ccd\t\tileave\tflags\tcompnent devices\n");
60513044Sasami		header_printed = 1;
60613044Sasami	}
60713044Sasami
60813044Sasami	readsize = cs->sc_nccdisks * sizeof(struct ccdcinfo);
60913044Sasami	if ((cip = malloc(readsize)) == NULL) {
61013044Sasami		warn("ccd%d: can't allocate memory for component info",
61113044Sasami		    cs->sc_unit);
61213044Sasami		return;
61313044Sasami	}
61413044Sasami	bzero(cip, readsize);
61513044Sasami
61613044Sasami	/* Dump out softc information. */
61713044Sasami	printf("ccd%d\t\t%d\t%d\t", cs->sc_unit, cs->sc_ileave,
61813044Sasami	    cs->sc_cflags & CCDF_USERMASK);
61913044Sasami	fflush(stdout);
62013044Sasami
62113044Sasami	/* Read in the component info. */
62213044Sasami	if (kvm_read(kd, (u_long)cs->sc_cinfo, (char *)cip,
62313044Sasami	    readsize) != readsize) {
62413044Sasami		printf("\n");
62513044Sasami		warnx("can't read component info");
62664275Skris		warnx("%s", kvm_geterr(kd));
62713044Sasami		goto done;
62813044Sasami	}
62913044Sasami
63013044Sasami	/* Read component pathname and display component info. */
63113044Sasami	for (i = 0; i < cs->sc_nccdisks; ++i) {
63213044Sasami		if (kvm_read(kd, (u_long)cip[i].ci_path, (char *)path,
63313044Sasami		    cip[i].ci_pathlen) != cip[i].ci_pathlen) {
63413044Sasami			printf("\n");
63513044Sasami			warnx("can't read component pathname");
63664282Salex			warnx("%s", kvm_geterr(kd));
63713044Sasami			goto done;
63813044Sasami		}
63913044Sasami		printf((i + 1 < cs->sc_nccdisks) ? "%s " : "%s\n", path);
64013044Sasami		fflush(stdout);
64113044Sasami	}
64213044Sasami
64313044Sasami done:
64413044Sasami	free(cip);
64513044Sasami}
64613044Sasami
64713044Sasamistatic int
64813044Sasamigetmaxpartitions()
64913044Sasami{
65013052Sasami    return (MAXPARTITIONS);
65113044Sasami}
65213044Sasami
65313044Sasamistatic int
65413044Sasamigetrawpartition()
65513044Sasami{
65613052Sasami	return (RAW_PART);
65713044Sasami}
65813044Sasami
65913044Sasamistatic int
66013044Sasamiflags_to_val(flags)
66113044Sasami	char *flags;
66213044Sasami{
66313044Sasami	char *cp, *tok;
66413044Sasami	int i, tmp, val = ~CCDF_USERMASK;
66513044Sasami	size_t flagslen;
66613044Sasami
66713044Sasami	/*
66813044Sasami	 * The most common case is that of NIL flags, so check for
66913044Sasami	 * those first.
67013044Sasami	 */
67113044Sasami	if (strcmp("none", flags) == 0 || strcmp("0x0", flags) == 0 ||
67213044Sasami	    strcmp("0", flags) == 0)
67313044Sasami		return (0);
67413044Sasami
67513044Sasami	flagslen = strlen(flags);
67613044Sasami
67713044Sasami	/* Check for values represented by strings. */
67813044Sasami	if ((cp = strdup(flags)) == NULL)
67913044Sasami		err(1, "no memory to parse flags");
68013044Sasami	tmp = 0;
68113044Sasami	for (tok = cp; (tok = strtok(tok, ",")) != NULL; tok = NULL) {
68213044Sasami		for (i = 0; flagvaltab[i].fv_flag != NULL; ++i)
68313044Sasami			if (strcmp(tok, flagvaltab[i].fv_flag) == 0)
68413044Sasami				break;
68513044Sasami		if (flagvaltab[i].fv_flag == NULL) {
68613044Sasami			free(cp);
68713044Sasami			goto bad_string;
68813044Sasami		}
68913044Sasami		tmp |= flagvaltab[i].fv_val;
69013044Sasami	}
69113044Sasami
69213044Sasami	/* If we get here, the string was ok. */
69313044Sasami	free(cp);
69413044Sasami	val = tmp;
69513044Sasami	goto out;
69613044Sasami
69713044Sasami bad_string:
69813044Sasami
69913044Sasami	/* Check for values represented in hex. */
70013044Sasami	if (flagslen > 2 && flags[0] == '0' && flags[1] == 'x') {
70113044Sasami		errno = 0;	/* to check for ERANGE */
70213044Sasami		val = (int)strtol(&flags[2], &cp, 16);
70313044Sasami		if ((errno == ERANGE) || (*cp != '\0'))
70413044Sasami			return (-1);
70513044Sasami		goto out;
70613044Sasami	}
70713044Sasami
70813044Sasami	/* Check for values represented in decimal. */
70913044Sasami	errno = 0;	/* to check for ERANGE */
71013044Sasami	val = (int)strtol(flags, &cp, 10);
71113044Sasami	if ((errno == ERANGE) || (*cp != '\0'))
71213044Sasami		return (-1);
71313044Sasami
71413044Sasami out:
71513044Sasami	return (((val & ~CCDF_USERMASK) == 0) ? val : -1);
71613044Sasami}
71713044Sasami
71813044Sasamistatic void
71913044Sasamiusage()
72013044Sasami{
72126541Scharnier	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
72226541Scharnier		"usage: ccdconfig [-cv] ccd ileave [flags] dev [...]",
72326541Scharnier		"       ccdconfig -C [-v] [-f config_file]",
72426541Scharnier		"       ccdconfig -u [-v] ccd [...]",
72526541Scharnier		"       ccdconfig -U [-v] [-f config_file]",
72626541Scharnier		"       ccdconfig -g [-M core] [-N system] [ccd [...]]");
72713044Sasami	exit(1);
72813044Sasami}
72926541Scharnier
73013052Sasami/* Local Variables: */
73113052Sasami/* c-argdecl-indent: 8 */
73213052Sasami/* c-indent-level: 8 */
73313052Sasami/* End: */
734