argv = nargv;
static	char *resolve_ccdname __P((char *));static	void usage __P((void));intmain(argc, argv)	int argc;	char **argv;{	int ch, options = 0, action = CCD_CONFIG;	while ((ch = getopt(argc, argv, "cCf:gM:N:uUv")) != -1) {		switch (ch) {		case 'c':			action = CCD_CONFIG;			++options;			break;		case 'C':			action = CCD_CONFIGALL;			++options;			break;		case 'f':			ccdconf = optarg;			break;		case 'g':			action = CCD_DUMP;			break;		case 'M':			core = optarg;			break;		case 'N':			kernel = optarg;			break;		case 'u':			action = CCD_UNCONFIG;			++options;			break;		case 'U':			action = CCD_UNCONFIGALL;			++options;			break;		case 'v':			verbose = 1;			break;		default:			usage();		}	}	argc -= optind;	argv += optind;	if (options > 1)		usage();	/*	 * Discard setgid privileges if not the running kernel so that bad	 * guys can't print interesting stuff from kernel memory.	 */	if (core != NULL || kernel != NULL || action != CCD_DUMP) {		setegid(getgid());		setgid(getgid());	}	switch (action) {	case CCD_CONFIG:	case CCD_UNCONFIG:		setegid(getgid());		setgid(getgid());		exit(do_single(argc, argv, action));		/* NOTREACHED */	case CCD_CONFIGALL:	case CCD_UNCONFIGALL:		setegid(getgid());		setgid(getgid());		exit(do_all(action));		/* NOTREACHED */	case CCD_DUMP:		exit(dump_ccd(argc, argv));		/* NOTREACHED */	}	/* NOTREACHED */	exit(0);}static intdo_single(argc, argv, action)	int argc;	char **argv;	int action;{	struct ccd_ioctl ccio;	char *ccd, *cp, *cp2, **disks;	int noflags = 0, i, ileave, flags = 0, j;	memset(&ccio, 0, sizeof(ccio));	/*	 * If unconfiguring, all arguments are treated as ccds.	 */	if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) {		for (i = 0; argc != 0; ) {			cp = *argv++; --argc;			if ((ccd = resolve_ccdname(cp)) == NULL) {				warnx("invalid ccd name: %s", cp);				i = 1;				continue;			}			if (do_io(ccd, CCDIOCCLR, &ccio))				i = 1;			else				if (verbose)					printf("%s unconfigured\n", cp);		}		return (i);	}	/* Make sure there are enough arguments. */	if (argc < 4)		if (argc == 3) {			/* Assume that no flags are specified. */			noflags = 1;		} else {			if (action == CCD_CONFIGALL) {				warnx("%s: bad line: %d", ccdconf, lineno);				return (1);			} else				usage();		}	/* First argument is the ccd to configure. */	cp = *argv++; --argc;	if ((ccd = resolve_ccdname(cp)) == NULL) {		warnx("invalid ccd name: %s", cp);		return (1);	}	/* Next argument is the interleave factor. */	cp = *argv++; --argc;	errno = 0;	/* to check for ERANGE */	ileave = (int)strtol(cp, &cp2, 10);	if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) {		warnx("invalid interleave factor: %s", cp);		return (1);	}	if (noflags == 0) {		/* Next argument is the ccd configuration flags. */		cp = *argv++; --argc;		if ((flags = flags_to_val(cp)) < 0) {			warnx("invalid flags argument: %s", cp);			return (1);		}	}	/* Next is the list of disks to make the ccd from. */	disks = malloc(argc * sizeof(char *));	if (disks == NULL) {		warnx("no memory to configure ccd");		return (1);	}	for (i = 0; argc != 0; ) {		cp = *argv++; --argc;		if ((j = checkdev(cp)) == 0)			disks[i++] = cp;		else {			warnx("%s: %s", cp, strerror(j));			return (1);		}	}	/* Fill in the ccio. */	ccio.ccio_disks = disks;	ccio.ccio_ndisks = i;	ccio.ccio_ileave = ileave;	ccio.ccio_flags = flags;	if (do_io(ccd, CCDIOCSET, &ccio)) {		free(disks);		return (1);	}	if (verbose) {		printf("ccd%d: %d components ", ccio.ccio_unit,		    ccio.ccio_ndisks);		for (i = 0; i < ccio.ccio_ndisks; ++i) {			if ((cp2 = strrchr(disks[i], '/')) != NULL)				++cp2;			else				cp2 = disks[i];			printf("%c%s%c",			    i == 0 ? '(' : ' ', cp2,			    i == ccio.ccio_ndisks - 1 ? ')' : ',');		}		printf(", %d blocks ", ccio.ccio_size);		if (ccio.ccio_ileave != 0)			printf("interleaved at %d blocks\n", ccio.ccio_ileave);		else			printf("concatenated\n");	}	free(disks);	return (0);}static intdo_all(action)	int action;{	FILE *f;	char line[_POSIX2_LINE_MAX];	char *cp, **argv;	int argc, rval = 0;	gid_t egid;	egid = getegid();	setegid(getgid());	if ((f = fopen(ccdconf, "r")) == NULL) {		setegid(egid);		warn("fopen: %s", ccdconf);		return (1);	}	setegid(egid);	while (fgets(line, sizeof(line), f) != NULL) {		argc = 0;		argv = NULL;		++lineno;		if ((cp = strrchr(line, '\n')) != NULL)			*cp = '\0';		/* Break up the line and pass it's contents to do_single(). */		if (line[0] == '\0')			goto end_of_line;		for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) {			if (*cp == '#')				break;			if ((argv = realloc(argv,			    sizeof(char *) * ++argc)) == NULL) {				warnx("no memory to configure ccds");				return (1);			}			argv[argc - 1] = cp;			/*			 * If our action is to unconfigure all, then pass			 * just the first token to do_single() and ignore			 * the rest.  Since this will be encountered on			 * our first pass through the line, the Right			 * Thing will happen.			 */			if (action == CCD_UNCONFIGALL) {				if (do_single(argc, argv, action))					rval = 1;				goto end_of_line;			}		}		if (argc != 0)			if (do_single(argc, argv, action))				rval = 1; end_of_line:		if (argv != NULL)			free(argv);	}	(void)fclose(f);	return (rval);}static intcheckdev(path)	char *path;{	struct stat st;	if (stat(path, &st) != 0)		return (errno);	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))		return (EINVAL);	return (0);}static intpathtounit(path, unitp)	char *path;	int *unitp;{	struct stat st;	int maxpartitions;	if (stat(path, &st) != 0)		return (errno);	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))		return (EINVAL);	if ((maxpartitions = getmaxpartitions()) < 0)		return (errno);	*unitp = minor(st.st_rdev) / maxpartitions;	return (0);}static char *resolve_ccdname(name)	char *name;{	char c, *path;	size_t len, newlen;	int rawpart;	if (name[0] == '/' || name[0] == '.') {		/* Assume they gave the correct pathname. */		return (strdup(name));	}	len = strlen(name);	c = name[len - 1];	newlen = len + 8;	if ((path = malloc(newlen)) == NULL)		return (NULL);	memset(path, 0, newlen);	if (isdigit(c)) {		if ((rawpart = getrawpartition()) < 0) {			free(path);			return (NULL);		}		(void)sprintf(path, "/dev/%s%c", name, 'a' + rawpart);	} else		(void)sprintf(path, "/dev/%s", name);	return (path);}