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