ccdconfig.c revision 118632
113044Sasami/* 2116111Sphk * Copyright (c) 2003 Poul-Henning Kamp 313044Sasami * Copyright (c) 1995 Jason R. Thorpe. 413044Sasami * All rights reserved. 513044Sasami * 613044Sasami * Redistribution and use in source and binary forms, with or without 713044Sasami * modification, are permitted provided that the following conditions 813044Sasami * are met: 913044Sasami * 1. Redistributions of source code must retain the above copyright 1013044Sasami * notice, this list of conditions and the following disclaimer. 1113044Sasami * 2. Redistributions in binary form must reproduce the above copyright 1213044Sasami * notice, this list of conditions and the following disclaimer in the 1313044Sasami * documentation and/or other materials provided with the distribution. 1413044Sasami * 3. All advertising materials mentioning features or use of this software 1513044Sasami * must display the following acknowledgement: 1613044Sasami * This product includes software developed for the NetBSD Project 1713044Sasami * by Jason R. Thorpe. 1813044Sasami * 4. The name of the author may not be used to endorse or promote products 1913044Sasami * derived from this software without specific prior written permission. 2013044Sasami * 2113044Sasami * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2213044Sasami * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2313044Sasami * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2413044Sasami * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2513044Sasami * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2613044Sasami * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2713044Sasami * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2813044Sasami * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2913044Sasami * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3013044Sasami * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3113044Sasami * SUCH DAMAGE. 3213044Sasami */ 3313044Sasami 34114589Sobrien#include <sys/cdefs.h> 35114589Sobrien__FBSDID("$FreeBSD: head/sbin/ccdconfig/ccdconfig.c 118632 2003-08-07 19:10:35Z johan $"); 3636628Scharnier 3713044Sasami#include <sys/param.h> 3848568Sbillf#include <sys/linker.h> 3945329Speter#include <sys/module.h> 4013044Sasami#include <ctype.h> 4113044Sasami#include <err.h> 4213044Sasami#include <errno.h> 4313044Sasami#include <limits.h> 4469793Sobrien#include <paths.h> 4513044Sasami#include <stdio.h> 4613044Sasami#include <stdlib.h> 4713044Sasami#include <string.h> 4813044Sasami#include <unistd.h> 49115730Sphk#include <libgeom.h> 5013044Sasami 51116111Sphk#define CCDF_UNIFORM 0x02 /* use LCCD of sizes for uniform interleave */ 52116111Sphk#define CCDF_MIRROR 0x04 /* use mirroring */ 5313044Sasami 5413044Sasami#include "pathnames.h" 5513044Sasami 5613044Sasamistatic int lineno = 0; 5713044Sasamistatic int verbose = 0; 58109417Sphkstatic const char *ccdconf = _PATH_CCDCONF; 5913044Sasami 6013044Sasamistruct flagval { 61109417Sphk const char *fv_flag; 62116111Sphk int fv_val; 6313044Sasami} flagvaltab[] = { 6413044Sasami { "CCDF_UNIFORM", CCDF_UNIFORM }, 65116111Sphk { "uniform", CCDF_UNIFORM }, 6613762Sasami { "CCDF_MIRROR", CCDF_MIRROR }, 67116111Sphk { "mirror", CCDF_MIRROR }, 68116111Sphk { "none", 0 }, 6913044Sasami { NULL, 0 }, 7013044Sasami}; 7113044Sasami 7213044Sasami#define CCD_CONFIG 0 /* configure a device */ 7313044Sasami#define CCD_CONFIGALL 1 /* configure all devices */ 7413044Sasami#define CCD_UNCONFIG 2 /* unconfigure a device */ 7513044Sasami#define CCD_UNCONFIGALL 3 /* unconfigure all devices */ 7613044Sasami#define CCD_DUMP 4 /* dump a ccd's configuration */ 7713044Sasami 7892539Simpstatic int do_single(int, char **, int); 7992539Simpstatic int do_all(int); 8092539Simpstatic int dump_ccd(int, char **); 8192539Simpstatic int flags_to_val(char *); 82109417Sphkstatic int resolve_ccdname(char *); 8392539Simpstatic void usage(void); 8413044Sasami 8513044Sasamiint 8692539Simpmain(int argc, char *argv[]) 8713044Sasami{ 8813044Sasami int ch, options = 0, action = CCD_CONFIG; 8913044Sasami 9083329Sru while ((ch = getopt(argc, argv, "cCf:guUv")) != -1) { 9113044Sasami switch (ch) { 9213044Sasami case 'c': 9313044Sasami action = CCD_CONFIG; 9413044Sasami ++options; 9513044Sasami break; 9613044Sasami 9713044Sasami case 'C': 9813044Sasami action = CCD_CONFIGALL; 9913044Sasami ++options; 10013044Sasami break; 10113044Sasami 10213044Sasami case 'f': 10313044Sasami ccdconf = optarg; 10413044Sasami break; 10513044Sasami 10613044Sasami case 'g': 10713044Sasami action = CCD_DUMP; 10813044Sasami break; 10913044Sasami 11013044Sasami case 'u': 11113044Sasami action = CCD_UNCONFIG; 11213044Sasami ++options; 11313044Sasami break; 11413044Sasami 11513044Sasami case 'U': 11613044Sasami action = CCD_UNCONFIGALL; 11713044Sasami ++options; 11813044Sasami break; 11913044Sasami 12013044Sasami case 'v': 12113044Sasami verbose = 1; 12213044Sasami break; 12313044Sasami 12413044Sasami default: 12513044Sasami usage(); 12613044Sasami } 12713044Sasami } 12813044Sasami argc -= optind; 12913044Sasami argv += optind; 13013044Sasami 13113044Sasami if (options > 1) 13213044Sasami usage(); 13313044Sasami 134116111Sphk if (modfind("g_ccd") < 0) { 13545329Speter /* Not present in kernel, try loading it */ 136116126Sphk if (kldload("geom_ccd") < 0 || modfind("g_ccd") < 0) 137116126Sphk warn("geom_ccd module not available!"); 13845329Speter } 13945329Speter 14013044Sasami switch (action) { 14113044Sasami case CCD_CONFIG: 14213044Sasami case CCD_UNCONFIG: 14313044Sasami exit(do_single(argc, argv, action)); 14413044Sasami /* NOTREACHED */ 14513044Sasami 14613044Sasami case CCD_CONFIGALL: 14713044Sasami case CCD_UNCONFIGALL: 14813044Sasami exit(do_all(action)); 14913044Sasami /* NOTREACHED */ 15013044Sasami 15113044Sasami case CCD_DUMP: 15213044Sasami exit(dump_ccd(argc, argv)); 15313044Sasami /* NOTREACHED */ 15413044Sasami } 15513044Sasami /* NOTREACHED */ 15636628Scharnier return (0); 15713044Sasami} 15813044Sasami 15913044Sasamistatic int 16092539Simpdo_single(int argc, char **argv, int action) 16113044Sasami{ 162116111Sphk char *cp, *cp2; 163116111Sphk int ccd, noflags = 0, i, ileave, flags = 0; 164116111Sphk struct gctl_req *grq; 165116111Sphk char const *errstr; 166116111Sphk char buf1[BUFSIZ]; 167116111Sphk int ex; 16813044Sasami 16913044Sasami /* 17013044Sasami * If unconfiguring, all arguments are treated as ccds. 17113044Sasami */ 17213044Sasami if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) { 173116111Sphk ex = 0; 17413044Sasami for (i = 0; argc != 0; ) { 17513044Sasami cp = *argv++; --argc; 176109472Sphk if ((ccd = resolve_ccdname(cp)) < 0) { 17713044Sasami warnx("invalid ccd name: %s", cp); 17813044Sasami i = 1; 17913044Sasami continue; 18013044Sasami } 181116111Sphk grq = gctl_get_handle(); 182116111Sphk gctl_ro_param(grq, "verb", -1, "destroy geom"); 183116111Sphk gctl_ro_param(grq, "class", -1, "CCD"); 184116111Sphk sprintf(buf1, "ccd%d", ccd); 185116111Sphk gctl_ro_param(grq, "geom", -1, buf1); 186116111Sphk errstr = gctl_issue(grq); 187116111Sphk if (errstr == NULL) { 18813044Sasami if (verbose) 18913044Sasami printf("%s unconfigured\n", cp); 190116111Sphk gctl_free(grq); 191116111Sphk continue; 192116111Sphk } 193116111Sphk warnx( 194116111Sphk "%s\nor possibly kernel and ccdconfig out of sync", 195116111Sphk errstr); 196116111Sphk ex = 1; 19713044Sasami } 198116111Sphk return (ex); 19913044Sasami } 20013044Sasami 20113044Sasami /* Make sure there are enough arguments. */ 20248568Sbillf if (argc < 4) { 20313044Sasami if (argc == 3) { 20413044Sasami /* Assume that no flags are specified. */ 20513044Sasami noflags = 1; 20613044Sasami } else { 20713044Sasami if (action == CCD_CONFIGALL) { 20813044Sasami warnx("%s: bad line: %d", ccdconf, lineno); 20913044Sasami return (1); 21013044Sasami } else 21113044Sasami usage(); 21213044Sasami } 21348568Sbillf } 21413044Sasami 21513044Sasami /* First argument is the ccd to configure. */ 21613044Sasami cp = *argv++; --argc; 217109472Sphk if ((ccd = resolve_ccdname(cp)) < 0) { 21813044Sasami warnx("invalid ccd name: %s", cp); 21913044Sasami return (1); 22013044Sasami } 22113044Sasami 22213044Sasami /* Next argument is the interleave factor. */ 22313044Sasami cp = *argv++; --argc; 22413044Sasami errno = 0; /* to check for ERANGE */ 22513044Sasami ileave = (int)strtol(cp, &cp2, 10); 22613044Sasami if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) { 22713044Sasami warnx("invalid interleave factor: %s", cp); 22813044Sasami return (1); 22913044Sasami } 23013044Sasami 23113044Sasami if (noflags == 0) { 23213044Sasami /* Next argument is the ccd configuration flags. */ 23313044Sasami cp = *argv++; --argc; 23413044Sasami if ((flags = flags_to_val(cp)) < 0) { 23513044Sasami warnx("invalid flags argument: %s", cp); 23613044Sasami return (1); 23713044Sasami } 23813044Sasami } 239116111Sphk grq = gctl_get_handle(); 240116111Sphk gctl_ro_param(grq, "verb", -1, "create geom"); 241116111Sphk gctl_ro_param(grq, "class", -1, "CCD"); 242116111Sphk gctl_ro_param(grq, "unit", sizeof(ccd), &ccd); 243116111Sphk gctl_ro_param(grq, "ileave", sizeof(ileave), &ileave); 244116111Sphk if (flags & CCDF_UNIFORM) 245116111Sphk gctl_ro_param(grq, "uniform", -1, ""); 246116111Sphk if (flags & CCDF_MIRROR) 247116111Sphk gctl_ro_param(grq, "mirror", -1, ""); 248116111Sphk gctl_ro_param(grq, "nprovider", sizeof(argc), &argc); 249116111Sphk for (i = 0; i < argc; i++) { 250116111Sphk sprintf(buf1, "provider%d", i); 251116111Sphk cp = argv[i]; 252116111Sphk if (!strncmp(cp, _PATH_DEV, strlen(_PATH_DEV))) 253116111Sphk cp += strlen(_PATH_DEV); 254116111Sphk gctl_ro_param(grq, buf1, -1, cp); 25513044Sasami } 256116111Sphk gctl_rw_param(grq, "output", sizeof(buf1), buf1); 257116111Sphk errstr = gctl_issue(grq); 258116111Sphk if (errstr == NULL) { 259116111Sphk if (verbose) { 260116111Sphk printf("%s", buf1); 26113044Sasami } 262116111Sphk gctl_free(grq); 263116111Sphk return (0); 26413044Sasami } 265116111Sphk warnx( 266116111Sphk "%s\nor possibly kernel and ccdconfig out of sync", 267116111Sphk errstr); 268116111Sphk return (1); 26913044Sasami} 27013044Sasami 27113044Sasamistatic int 27292539Simpdo_all(int action) 27313044Sasami{ 27413044Sasami FILE *f; 27513044Sasami char line[_POSIX2_LINE_MAX]; 27613044Sasami char *cp, **argv; 27713044Sasami int argc, rval; 27832116Simp gid_t egid; 27913044Sasami 28051690Sbillf rval = 0; 28132116Simp egid = getegid(); 28232116Simp setegid(getgid()); 28313044Sasami if ((f = fopen(ccdconf, "r")) == NULL) { 28432116Simp setegid(egid); 28513044Sasami warn("fopen: %s", ccdconf); 28613044Sasami return (1); 28713044Sasami } 28832116Simp setegid(egid); 28913044Sasami 29013044Sasami while (fgets(line, sizeof(line), f) != NULL) { 29113044Sasami argc = 0; 29213044Sasami argv = NULL; 29313044Sasami ++lineno; 29413044Sasami if ((cp = strrchr(line, '\n')) != NULL) 29513044Sasami *cp = '\0'; 29613044Sasami 29713044Sasami /* Break up the line and pass it's contents to do_single(). */ 29813044Sasami if (line[0] == '\0') 29913044Sasami goto end_of_line; 30013044Sasami for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) { 30113044Sasami if (*cp == '#') 30213044Sasami break; 30313044Sasami if ((argv = realloc(argv, 30413044Sasami sizeof(char *) * ++argc)) == NULL) { 30513044Sasami warnx("no memory to configure ccds"); 30613044Sasami return (1); 30713044Sasami } 30813044Sasami argv[argc - 1] = cp; 30913044Sasami /* 31013044Sasami * If our action is to unconfigure all, then pass 31113044Sasami * just the first token to do_single() and ignore 31213044Sasami * the rest. Since this will be encountered on 31313044Sasami * our first pass through the line, the Right 31413044Sasami * Thing will happen. 31513044Sasami */ 31613044Sasami if (action == CCD_UNCONFIGALL) { 31713044Sasami if (do_single(argc, argv, action)) 31813044Sasami rval = 1; 31913044Sasami goto end_of_line; 32013044Sasami } 32113044Sasami } 32213044Sasami if (argc != 0) 32313044Sasami if (do_single(argc, argv, action)) 32413044Sasami rval = 1; 32513044Sasami 32613044Sasami end_of_line: 32713044Sasami if (argv != NULL) 32813044Sasami free(argv); 32913044Sasami } 33013044Sasami 33113044Sasami (void)fclose(f); 33213044Sasami return (rval); 33313044Sasami} 33413044Sasami 33513044Sasamistatic int 33692539Simpresolve_ccdname(char *name) 33713044Sasami{ 33813044Sasami 339109417Sphk if (!strncmp(name, _PATH_DEV, strlen(_PATH_DEV))) 340109417Sphk name += strlen(_PATH_DEV); 341109417Sphk if (strncmp(name, "ccd", 3)) 342109417Sphk return -1; 343109417Sphk name += 3; 344109417Sphk if (!isdigit(*name)) 345109417Sphk return -1; 346109417Sphk return (strtoul(name, NULL, 10)); 34713044Sasami} 34813044Sasami 34913044Sasamistatic int 350115731Sphkdumpout(int unit) 35113044Sasami{ 352115731Sphk static int v; 353115731Sphk struct gctl_req *grq; 354115731Sphk int ncp; 355109417Sphk char *cp; 356115730Sphk char const *errstr; 35713044Sasami 358115730Sphk grq = gctl_get_handle(); 359115731Sphk ncp = 65536; 360115731Sphk cp = malloc(ncp); 361115730Sphk gctl_ro_param(grq, "verb", -1, "list"); 362115730Sphk gctl_ro_param(grq, "class", -1, "CCD"); 363115731Sphk gctl_ro_param(grq, "unit", sizeof(unit), &unit); 364115731Sphk gctl_rw_param(grq, "output", ncp, cp); 365115730Sphk errstr = gctl_issue(grq); 366115731Sphk if (errstr != NULL) 367115731Sphk errx(1, "%s\nor possibly kernel and ccdconfig out of sync", 368115731Sphk errstr); 369115731Sphk if (strlen(cp) == 0) 370115731Sphk errx(1, "ccd%d not configured", unit); 371115731Sphk if (verbose && !v) { 372115731Sphk printf("# ccd\t\tileave\tflags\tcomponent devices\n"); 373115731Sphk v = 1; 374115730Sphk } 375115731Sphk printf("%s", cp); 376115731Sphk free(cp); 37713044Sasami return (0); 37813044Sasami} 37913044Sasami 380115731Sphkstatic int 381115731Sphkdump_ccd(int argc, char **argv) 38213044Sasami{ 383118632Sjohan int i, error; 38413044Sasami 385115731Sphk if (argc == 0) { 386118632Sjohan error = dumpout(-1); 387115731Sphk } else { 388118632Sjohan error = 0; 389118632Sjohan for (i = 0; error == 0 && i < argc; i++) 390118632Sjohan error = dumpout(resolve_ccdname(argv[i])); 39113044Sasami } 392118632Sjohan return (error); 39313044Sasami} 39413044Sasami 39513044Sasamistatic int 39692539Simpflags_to_val(char *flags) 39713044Sasami{ 39813044Sasami char *cp, *tok; 399116111Sphk int i, tmp, val; 40013044Sasami size_t flagslen; 40113044Sasami 402116111Sphk errno = 0; /* to check for ERANGE */ 403116111Sphk val = (int)strtol(flags, &cp, 0); 404116111Sphk if ((errno != ERANGE) && (*cp == '\0')) { 405116111Sphk if (val & ~(CCDF_UNIFORM|CCDF_MIRROR)) 406116111Sphk return (-1); 407116111Sphk return (val); 408116111Sphk } 40913044Sasami 41013044Sasami flagslen = strlen(flags); 41113044Sasami /* Check for values represented by strings. */ 41213044Sasami if ((cp = strdup(flags)) == NULL) 41313044Sasami err(1, "no memory to parse flags"); 41413044Sasami tmp = 0; 41513044Sasami for (tok = cp; (tok = strtok(tok, ",")) != NULL; tok = NULL) { 41613044Sasami for (i = 0; flagvaltab[i].fv_flag != NULL; ++i) 41713044Sasami if (strcmp(tok, flagvaltab[i].fv_flag) == 0) 41813044Sasami break; 41913044Sasami if (flagvaltab[i].fv_flag == NULL) { 42013044Sasami free(cp); 421116111Sphk return (-1); 42213044Sasami } 42313044Sasami tmp |= flagvaltab[i].fv_val; 42413044Sasami } 42513044Sasami 42613044Sasami /* If we get here, the string was ok. */ 42713044Sasami free(cp); 428116111Sphk return (tmp); 42913044Sasami} 43013044Sasami 43113044Sasamistatic void 43292539Simpusage(void) 43313044Sasami{ 43426541Scharnier fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", 43526541Scharnier "usage: ccdconfig [-cv] ccd ileave [flags] dev [...]", 43626541Scharnier " ccdconfig -C [-v] [-f config_file]", 43726541Scharnier " ccdconfig -u [-v] ccd [...]", 43826541Scharnier " ccdconfig -U [-v] [-f config_file]", 43982943Sphk " ccdconfig -g [ccd [...]]"); 44013044Sasami exit(1); 44113044Sasami} 442