ccdconfig.c revision 157740
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 157740 2006-04-13 20:35:31Z cracauer $"); 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 */ 53157740Scracauer#define CCDF_NO_OFFSET 0x08 /* do not leave space in front */ 54157740Scracauer#define CCDF_LINUX 0x10 /* use Linux compatibility mode */ 5513044Sasami 5613044Sasami#include "pathnames.h" 5713044Sasami 5813044Sasamistatic int lineno = 0; 5913044Sasamistatic int verbose = 0; 60109417Sphkstatic const char *ccdconf = _PATH_CCDCONF; 6113044Sasami 6213044Sasamistruct flagval { 63109417Sphk const char *fv_flag; 64116111Sphk int fv_val; 6513044Sasami} flagvaltab[] = { 6613044Sasami { "CCDF_UNIFORM", CCDF_UNIFORM }, 67116111Sphk { "uniform", CCDF_UNIFORM }, 6813762Sasami { "CCDF_MIRROR", CCDF_MIRROR }, 69116111Sphk { "mirror", CCDF_MIRROR }, 70157740Scracauer { "CCDF_NO_OFFSET", CCDF_NO_OFFSET }, 71157740Scracauer { "no_offset", CCDF_NO_OFFSET }, 72157740Scracauer { "CCDF_LINUX", CCDF_LINUX }, 73157740Scracauer { "linux", CCDF_LINUX }, 74116111Sphk { "none", 0 }, 7513044Sasami { NULL, 0 }, 7613044Sasami}; 7713044Sasami 7813044Sasami#define CCD_CONFIG 0 /* configure a device */ 7913044Sasami#define CCD_CONFIGALL 1 /* configure all devices */ 8013044Sasami#define CCD_UNCONFIG 2 /* unconfigure a device */ 8113044Sasami#define CCD_UNCONFIGALL 3 /* unconfigure all devices */ 8213044Sasami#define CCD_DUMP 4 /* dump a ccd's configuration */ 8313044Sasami 8492539Simpstatic int do_single(int, char **, int); 8592539Simpstatic int do_all(int); 8692539Simpstatic int dump_ccd(int, char **); 8792539Simpstatic int flags_to_val(char *); 88109417Sphkstatic int resolve_ccdname(char *); 8992539Simpstatic void usage(void); 9013044Sasami 9113044Sasamiint 9292539Simpmain(int argc, char *argv[]) 9313044Sasami{ 9413044Sasami int ch, options = 0, action = CCD_CONFIG; 9513044Sasami 9683329Sru while ((ch = getopt(argc, argv, "cCf:guUv")) != -1) { 9713044Sasami switch (ch) { 9813044Sasami case 'c': 9913044Sasami action = CCD_CONFIG; 10013044Sasami ++options; 10113044Sasami break; 10213044Sasami 10313044Sasami case 'C': 10413044Sasami action = CCD_CONFIGALL; 10513044Sasami ++options; 10613044Sasami break; 10713044Sasami 10813044Sasami case 'f': 10913044Sasami ccdconf = optarg; 11013044Sasami break; 11113044Sasami 11213044Sasami case 'g': 11313044Sasami action = CCD_DUMP; 11413044Sasami break; 11513044Sasami 11613044Sasami case 'u': 11713044Sasami action = CCD_UNCONFIG; 11813044Sasami ++options; 11913044Sasami break; 12013044Sasami 12113044Sasami case 'U': 12213044Sasami action = CCD_UNCONFIGALL; 12313044Sasami ++options; 12413044Sasami break; 12513044Sasami 12613044Sasami case 'v': 12713044Sasami verbose = 1; 12813044Sasami break; 12913044Sasami 13013044Sasami default: 13113044Sasami usage(); 13213044Sasami } 13313044Sasami } 13413044Sasami argc -= optind; 13513044Sasami argv += optind; 13613044Sasami 13713044Sasami if (options > 1) 13813044Sasami usage(); 13913044Sasami 140116111Sphk if (modfind("g_ccd") < 0) { 14145329Speter /* Not present in kernel, try loading it */ 142116126Sphk if (kldload("geom_ccd") < 0 || modfind("g_ccd") < 0) 143116126Sphk warn("geom_ccd module not available!"); 14445329Speter } 14545329Speter 14613044Sasami switch (action) { 14713044Sasami case CCD_CONFIG: 14813044Sasami case CCD_UNCONFIG: 14913044Sasami exit(do_single(argc, argv, action)); 15013044Sasami /* NOTREACHED */ 15113044Sasami 15213044Sasami case CCD_CONFIGALL: 15313044Sasami case CCD_UNCONFIGALL: 15413044Sasami exit(do_all(action)); 15513044Sasami /* NOTREACHED */ 15613044Sasami 15713044Sasami case CCD_DUMP: 15813044Sasami exit(dump_ccd(argc, argv)); 15913044Sasami /* NOTREACHED */ 16013044Sasami } 16113044Sasami /* NOTREACHED */ 16236628Scharnier return (0); 16313044Sasami} 16413044Sasami 16513044Sasamistatic int 16692539Simpdo_single(int argc, char **argv, int action) 16713044Sasami{ 168116111Sphk char *cp, *cp2; 169116111Sphk int ccd, noflags = 0, i, ileave, flags = 0; 170116111Sphk struct gctl_req *grq; 171116111Sphk char const *errstr; 172116111Sphk char buf1[BUFSIZ]; 173116111Sphk int ex; 17413044Sasami 17513044Sasami /* 17613044Sasami * If unconfiguring, all arguments are treated as ccds. 17713044Sasami */ 17813044Sasami if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) { 179116111Sphk ex = 0; 18013044Sasami for (i = 0; argc != 0; ) { 18113044Sasami cp = *argv++; --argc; 182109472Sphk if ((ccd = resolve_ccdname(cp)) < 0) { 18313044Sasami warnx("invalid ccd name: %s", cp); 18413044Sasami i = 1; 18513044Sasami continue; 18613044Sasami } 187116111Sphk grq = gctl_get_handle(); 188116111Sphk gctl_ro_param(grq, "verb", -1, "destroy geom"); 189116111Sphk gctl_ro_param(grq, "class", -1, "CCD"); 190116111Sphk sprintf(buf1, "ccd%d", ccd); 191116111Sphk gctl_ro_param(grq, "geom", -1, buf1); 192116111Sphk errstr = gctl_issue(grq); 193116111Sphk if (errstr == NULL) { 19413044Sasami if (verbose) 19513044Sasami printf("%s unconfigured\n", cp); 196116111Sphk gctl_free(grq); 197116111Sphk continue; 198116111Sphk } 199116111Sphk warnx( 200116111Sphk "%s\nor possibly kernel and ccdconfig out of sync", 201116111Sphk errstr); 202116111Sphk ex = 1; 20313044Sasami } 204116111Sphk return (ex); 20513044Sasami } 20613044Sasami 20713044Sasami /* Make sure there are enough arguments. */ 20848568Sbillf if (argc < 4) { 20913044Sasami if (argc == 3) { 21013044Sasami /* Assume that no flags are specified. */ 21113044Sasami noflags = 1; 21213044Sasami } else { 21313044Sasami if (action == CCD_CONFIGALL) { 21413044Sasami warnx("%s: bad line: %d", ccdconf, lineno); 21513044Sasami return (1); 21613044Sasami } else 21713044Sasami usage(); 21813044Sasami } 21948568Sbillf } 22013044Sasami 22113044Sasami /* First argument is the ccd to configure. */ 22213044Sasami cp = *argv++; --argc; 223109472Sphk if ((ccd = resolve_ccdname(cp)) < 0) { 22413044Sasami warnx("invalid ccd name: %s", cp); 22513044Sasami return (1); 22613044Sasami } 22713044Sasami 22813044Sasami /* Next argument is the interleave factor. */ 22913044Sasami cp = *argv++; --argc; 23013044Sasami errno = 0; /* to check for ERANGE */ 23113044Sasami ileave = (int)strtol(cp, &cp2, 10); 23213044Sasami if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) { 23313044Sasami warnx("invalid interleave factor: %s", cp); 23413044Sasami return (1); 23513044Sasami } 23613044Sasami 23713044Sasami if (noflags == 0) { 23813044Sasami /* Next argument is the ccd configuration flags. */ 23913044Sasami cp = *argv++; --argc; 24013044Sasami if ((flags = flags_to_val(cp)) < 0) { 24113044Sasami warnx("invalid flags argument: %s", cp); 24213044Sasami return (1); 24313044Sasami } 24413044Sasami } 245116111Sphk grq = gctl_get_handle(); 246116111Sphk gctl_ro_param(grq, "verb", -1, "create geom"); 247116111Sphk gctl_ro_param(grq, "class", -1, "CCD"); 248116111Sphk gctl_ro_param(grq, "unit", sizeof(ccd), &ccd); 249116111Sphk gctl_ro_param(grq, "ileave", sizeof(ileave), &ileave); 250116111Sphk if (flags & CCDF_UNIFORM) 251116111Sphk gctl_ro_param(grq, "uniform", -1, ""); 252116111Sphk if (flags & CCDF_MIRROR) 253116111Sphk gctl_ro_param(grq, "mirror", -1, ""); 254157740Scracauer if (flags & CCDF_NO_OFFSET) 255157740Scracauer gctl_ro_param(grq, "no_offset", -1, ""); 256157740Scracauer if (flags & CCDF_LINUX) 257157740Scracauer gctl_ro_param(grq, "linux", -1, ""); 258116111Sphk gctl_ro_param(grq, "nprovider", sizeof(argc), &argc); 259116111Sphk for (i = 0; i < argc; i++) { 260116111Sphk sprintf(buf1, "provider%d", i); 261116111Sphk cp = argv[i]; 262116111Sphk if (!strncmp(cp, _PATH_DEV, strlen(_PATH_DEV))) 263116111Sphk cp += strlen(_PATH_DEV); 264116111Sphk gctl_ro_param(grq, buf1, -1, cp); 26513044Sasami } 266116111Sphk gctl_rw_param(grq, "output", sizeof(buf1), buf1); 267116111Sphk errstr = gctl_issue(grq); 268116111Sphk if (errstr == NULL) { 269116111Sphk if (verbose) { 270116111Sphk printf("%s", buf1); 27113044Sasami } 272116111Sphk gctl_free(grq); 273116111Sphk return (0); 27413044Sasami } 275116111Sphk warnx( 276116111Sphk "%s\nor possibly kernel and ccdconfig out of sync", 277116111Sphk errstr); 278116111Sphk return (1); 27913044Sasami} 28013044Sasami 28113044Sasamistatic int 28292539Simpdo_all(int action) 28313044Sasami{ 28413044Sasami FILE *f; 28513044Sasami char line[_POSIX2_LINE_MAX]; 28613044Sasami char *cp, **argv; 28713044Sasami int argc, rval; 28832116Simp gid_t egid; 28913044Sasami 29051690Sbillf rval = 0; 29132116Simp egid = getegid(); 29232116Simp setegid(getgid()); 29313044Sasami if ((f = fopen(ccdconf, "r")) == NULL) { 29432116Simp setegid(egid); 29513044Sasami warn("fopen: %s", ccdconf); 29613044Sasami return (1); 29713044Sasami } 29832116Simp setegid(egid); 29913044Sasami 30013044Sasami while (fgets(line, sizeof(line), f) != NULL) { 30113044Sasami argc = 0; 30213044Sasami argv = NULL; 30313044Sasami ++lineno; 30413044Sasami if ((cp = strrchr(line, '\n')) != NULL) 30513044Sasami *cp = '\0'; 30613044Sasami 30713044Sasami /* Break up the line and pass it's contents to do_single(). */ 30813044Sasami if (line[0] == '\0') 30913044Sasami goto end_of_line; 31013044Sasami for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) { 31113044Sasami if (*cp == '#') 31213044Sasami break; 31313044Sasami if ((argv = realloc(argv, 31413044Sasami sizeof(char *) * ++argc)) == NULL) { 31513044Sasami warnx("no memory to configure ccds"); 31613044Sasami return (1); 31713044Sasami } 31813044Sasami argv[argc - 1] = cp; 31913044Sasami /* 32013044Sasami * If our action is to unconfigure all, then pass 32113044Sasami * just the first token to do_single() and ignore 32213044Sasami * the rest. Since this will be encountered on 32313044Sasami * our first pass through the line, the Right 32413044Sasami * Thing will happen. 32513044Sasami */ 32613044Sasami if (action == CCD_UNCONFIGALL) { 32713044Sasami if (do_single(argc, argv, action)) 32813044Sasami rval = 1; 32913044Sasami goto end_of_line; 33013044Sasami } 33113044Sasami } 33213044Sasami if (argc != 0) 33313044Sasami if (do_single(argc, argv, action)) 33413044Sasami rval = 1; 33513044Sasami 33613044Sasami end_of_line: 33713044Sasami if (argv != NULL) 33813044Sasami free(argv); 33913044Sasami } 34013044Sasami 34113044Sasami (void)fclose(f); 34213044Sasami return (rval); 34313044Sasami} 34413044Sasami 34513044Sasamistatic int 34692539Simpresolve_ccdname(char *name) 34713044Sasami{ 34813044Sasami 349109417Sphk if (!strncmp(name, _PATH_DEV, strlen(_PATH_DEV))) 350109417Sphk name += strlen(_PATH_DEV); 351109417Sphk if (strncmp(name, "ccd", 3)) 352109417Sphk return -1; 353109417Sphk name += 3; 354109417Sphk if (!isdigit(*name)) 355109417Sphk return -1; 356109417Sphk return (strtoul(name, NULL, 10)); 35713044Sasami} 35813044Sasami 35913044Sasamistatic int 360115731Sphkdumpout(int unit) 36113044Sasami{ 362115731Sphk static int v; 363115731Sphk struct gctl_req *grq; 364115731Sphk int ncp; 365109417Sphk char *cp; 366115730Sphk char const *errstr; 36713044Sasami 368115730Sphk grq = gctl_get_handle(); 369115731Sphk ncp = 65536; 370115731Sphk cp = malloc(ncp); 371115730Sphk gctl_ro_param(grq, "verb", -1, "list"); 372115730Sphk gctl_ro_param(grq, "class", -1, "CCD"); 373115731Sphk gctl_ro_param(grq, "unit", sizeof(unit), &unit); 374115731Sphk gctl_rw_param(grq, "output", ncp, cp); 375115730Sphk errstr = gctl_issue(grq); 376115731Sphk if (errstr != NULL) 377115731Sphk errx(1, "%s\nor possibly kernel and ccdconfig out of sync", 378115731Sphk errstr); 379115731Sphk if (strlen(cp) == 0) 380115731Sphk errx(1, "ccd%d not configured", unit); 381115731Sphk if (verbose && !v) { 382115731Sphk printf("# ccd\t\tileave\tflags\tcomponent devices\n"); 383115731Sphk v = 1; 384115730Sphk } 385115731Sphk printf("%s", cp); 386115731Sphk free(cp); 38713044Sasami return (0); 38813044Sasami} 38913044Sasami 390115731Sphkstatic int 391115731Sphkdump_ccd(int argc, char **argv) 39213044Sasami{ 393118632Sjohan int i, error; 39413044Sasami 395115731Sphk if (argc == 0) { 396118632Sjohan error = dumpout(-1); 397115731Sphk } else { 398118632Sjohan error = 0; 399118632Sjohan for (i = 0; error == 0 && i < argc; i++) 400118632Sjohan error = dumpout(resolve_ccdname(argv[i])); 40113044Sasami } 402118632Sjohan return (error); 40313044Sasami} 40413044Sasami 40513044Sasamistatic int 40692539Simpflags_to_val(char *flags) 40713044Sasami{ 40813044Sasami char *cp, *tok; 409116111Sphk int i, tmp, val; 41013044Sasami 411116111Sphk errno = 0; /* to check for ERANGE */ 412116111Sphk val = (int)strtol(flags, &cp, 0); 413116111Sphk if ((errno != ERANGE) && (*cp == '\0')) { 414116111Sphk if (val & ~(CCDF_UNIFORM|CCDF_MIRROR)) 415116111Sphk return (-1); 416116111Sphk return (val); 417116111Sphk } 41813044Sasami 41913044Sasami /* Check for values represented by strings. */ 42013044Sasami if ((cp = strdup(flags)) == NULL) 42113044Sasami err(1, "no memory to parse flags"); 42213044Sasami tmp = 0; 42313044Sasami for (tok = cp; (tok = strtok(tok, ",")) != NULL; tok = NULL) { 42413044Sasami for (i = 0; flagvaltab[i].fv_flag != NULL; ++i) 42513044Sasami if (strcmp(tok, flagvaltab[i].fv_flag) == 0) 42613044Sasami break; 42713044Sasami if (flagvaltab[i].fv_flag == NULL) { 42813044Sasami free(cp); 429116111Sphk return (-1); 43013044Sasami } 43113044Sasami tmp |= flagvaltab[i].fv_val; 43213044Sasami } 43313044Sasami 43413044Sasami /* If we get here, the string was ok. */ 43513044Sasami free(cp); 436116111Sphk return (tmp); 43713044Sasami} 43813044Sasami 43913044Sasamistatic void 44092539Simpusage(void) 44113044Sasami{ 44226541Scharnier fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", 443141611Sru "usage: ccdconfig [-cv] ccd ileave [flags] dev ...", 44426541Scharnier " ccdconfig -C [-v] [-f config_file]", 445141611Sru " ccdconfig -u [-v] ccd ...", 44626541Scharnier " ccdconfig -U [-v] [-f config_file]", 447141611Sru " ccdconfig -g [ccd ...]"); 44813044Sasami exit(1); 44913044Sasami} 450