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$"); 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; 180209052Suqs for (; argc != 0;) { 18113044Sasami cp = *argv++; --argc; 182109472Sphk if ((ccd = resolve_ccdname(cp)) < 0) { 18313044Sasami warnx("invalid ccd name: %s", cp); 18413044Sasami continue; 18513044Sasami } 186116111Sphk grq = gctl_get_handle(); 187116111Sphk gctl_ro_param(grq, "verb", -1, "destroy geom"); 188116111Sphk gctl_ro_param(grq, "class", -1, "CCD"); 189116111Sphk sprintf(buf1, "ccd%d", ccd); 190116111Sphk gctl_ro_param(grq, "geom", -1, buf1); 191116111Sphk errstr = gctl_issue(grq); 192116111Sphk if (errstr == NULL) { 19313044Sasami if (verbose) 19413044Sasami printf("%s unconfigured\n", cp); 195116111Sphk gctl_free(grq); 196116111Sphk continue; 197116111Sphk } 198116111Sphk warnx( 199116111Sphk "%s\nor possibly kernel and ccdconfig out of sync", 200116111Sphk errstr); 201116111Sphk ex = 1; 20213044Sasami } 203116111Sphk return (ex); 20413044Sasami } 20513044Sasami 20613044Sasami /* Make sure there are enough arguments. */ 20748568Sbillf if (argc < 4) { 20813044Sasami if (argc == 3) { 20913044Sasami /* Assume that no flags are specified. */ 21013044Sasami noflags = 1; 21113044Sasami } else { 21213044Sasami if (action == CCD_CONFIGALL) { 21313044Sasami warnx("%s: bad line: %d", ccdconf, lineno); 21413044Sasami return (1); 21513044Sasami } else 21613044Sasami usage(); 21713044Sasami } 21848568Sbillf } 21913044Sasami 22013044Sasami /* First argument is the ccd to configure. */ 22113044Sasami cp = *argv++; --argc; 222109472Sphk if ((ccd = resolve_ccdname(cp)) < 0) { 22313044Sasami warnx("invalid ccd name: %s", cp); 22413044Sasami return (1); 22513044Sasami } 22613044Sasami 22713044Sasami /* Next argument is the interleave factor. */ 22813044Sasami cp = *argv++; --argc; 22913044Sasami errno = 0; /* to check for ERANGE */ 23013044Sasami ileave = (int)strtol(cp, &cp2, 10); 23113044Sasami if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) { 23213044Sasami warnx("invalid interleave factor: %s", cp); 23313044Sasami return (1); 23413044Sasami } 23513044Sasami 23613044Sasami if (noflags == 0) { 23713044Sasami /* Next argument is the ccd configuration flags. */ 23813044Sasami cp = *argv++; --argc; 23913044Sasami if ((flags = flags_to_val(cp)) < 0) { 24013044Sasami warnx("invalid flags argument: %s", cp); 24113044Sasami return (1); 24213044Sasami } 24313044Sasami } 244116111Sphk grq = gctl_get_handle(); 245116111Sphk gctl_ro_param(grq, "verb", -1, "create geom"); 246116111Sphk gctl_ro_param(grq, "class", -1, "CCD"); 247116111Sphk gctl_ro_param(grq, "unit", sizeof(ccd), &ccd); 248116111Sphk gctl_ro_param(grq, "ileave", sizeof(ileave), &ileave); 249116111Sphk if (flags & CCDF_UNIFORM) 250116111Sphk gctl_ro_param(grq, "uniform", -1, ""); 251116111Sphk if (flags & CCDF_MIRROR) 252116111Sphk gctl_ro_param(grq, "mirror", -1, ""); 253157740Scracauer if (flags & CCDF_NO_OFFSET) 254157740Scracauer gctl_ro_param(grq, "no_offset", -1, ""); 255157740Scracauer if (flags & CCDF_LINUX) 256157740Scracauer gctl_ro_param(grq, "linux", -1, ""); 257116111Sphk gctl_ro_param(grq, "nprovider", sizeof(argc), &argc); 258116111Sphk for (i = 0; i < argc; i++) { 259116111Sphk sprintf(buf1, "provider%d", i); 260116111Sphk cp = argv[i]; 261116111Sphk if (!strncmp(cp, _PATH_DEV, strlen(_PATH_DEV))) 262116111Sphk cp += strlen(_PATH_DEV); 263116111Sphk gctl_ro_param(grq, buf1, -1, cp); 26413044Sasami } 265116111Sphk gctl_rw_param(grq, "output", sizeof(buf1), buf1); 266116111Sphk errstr = gctl_issue(grq); 267116111Sphk if (errstr == NULL) { 268116111Sphk if (verbose) { 269116111Sphk printf("%s", buf1); 27013044Sasami } 271116111Sphk gctl_free(grq); 272116111Sphk return (0); 27313044Sasami } 274116111Sphk warnx( 275116111Sphk "%s\nor possibly kernel and ccdconfig out of sync", 276116111Sphk errstr); 277116111Sphk return (1); 27813044Sasami} 27913044Sasami 28013044Sasamistatic int 28192539Simpdo_all(int action) 28213044Sasami{ 28313044Sasami FILE *f; 28413044Sasami char line[_POSIX2_LINE_MAX]; 28513044Sasami char *cp, **argv; 28613044Sasami int argc, rval; 28732116Simp gid_t egid; 28813044Sasami 28951690Sbillf rval = 0; 29032116Simp egid = getegid(); 291242166Seadler if (setegid(getgid()) != 0) 292242166Seadler err(1, "setegid failed"); 29313044Sasami if ((f = fopen(ccdconf, "r")) == NULL) { 294242166Seadler if (setegid(egid) != 0) 295242166Seadler err(1, "setegid failed"); 29613044Sasami warn("fopen: %s", ccdconf); 29713044Sasami return (1); 29813044Sasami } 299242166Seadler if (setegid(egid) != 0) 300242166Seadler err(1, "setegid failed"); 30113044Sasami 30213044Sasami while (fgets(line, sizeof(line), f) != NULL) { 30313044Sasami argc = 0; 30413044Sasami argv = NULL; 30513044Sasami ++lineno; 30613044Sasami if ((cp = strrchr(line, '\n')) != NULL) 30713044Sasami *cp = '\0'; 30813044Sasami 30913044Sasami /* Break up the line and pass it's contents to do_single(). */ 31013044Sasami if (line[0] == '\0') 31113044Sasami goto end_of_line; 31213044Sasami for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) { 31313044Sasami if (*cp == '#') 31413044Sasami break; 31513044Sasami if ((argv = realloc(argv, 31613044Sasami sizeof(char *) * ++argc)) == NULL) { 31713044Sasami warnx("no memory to configure ccds"); 31813044Sasami return (1); 31913044Sasami } 32013044Sasami argv[argc - 1] = cp; 32113044Sasami /* 32213044Sasami * If our action is to unconfigure all, then pass 32313044Sasami * just the first token to do_single() and ignore 32413044Sasami * the rest. Since this will be encountered on 32513044Sasami * our first pass through the line, the Right 32613044Sasami * Thing will happen. 32713044Sasami */ 32813044Sasami if (action == CCD_UNCONFIGALL) { 32913044Sasami if (do_single(argc, argv, action)) 33013044Sasami rval = 1; 33113044Sasami goto end_of_line; 33213044Sasami } 33313044Sasami } 33413044Sasami if (argc != 0) 33513044Sasami if (do_single(argc, argv, action)) 33613044Sasami rval = 1; 33713044Sasami 33813044Sasami end_of_line: 33913044Sasami if (argv != NULL) 34013044Sasami free(argv); 34113044Sasami } 34213044Sasami 34313044Sasami (void)fclose(f); 34413044Sasami return (rval); 34513044Sasami} 34613044Sasami 34713044Sasamistatic int 34892539Simpresolve_ccdname(char *name) 34913044Sasami{ 35013044Sasami 351109417Sphk if (!strncmp(name, _PATH_DEV, strlen(_PATH_DEV))) 352109417Sphk name += strlen(_PATH_DEV); 353109417Sphk if (strncmp(name, "ccd", 3)) 354109417Sphk return -1; 355109417Sphk name += 3; 356109417Sphk if (!isdigit(*name)) 357109417Sphk return -1; 358109417Sphk return (strtoul(name, NULL, 10)); 35913044Sasami} 36013044Sasami 36113044Sasamistatic int 362115731Sphkdumpout(int unit) 36313044Sasami{ 364115731Sphk static int v; 365115731Sphk struct gctl_req *grq; 366115731Sphk int ncp; 367109417Sphk char *cp; 368115730Sphk char const *errstr; 36913044Sasami 370115730Sphk grq = gctl_get_handle(); 371115731Sphk ncp = 65536; 372115731Sphk cp = malloc(ncp); 373115730Sphk gctl_ro_param(grq, "verb", -1, "list"); 374115730Sphk gctl_ro_param(grq, "class", -1, "CCD"); 375115731Sphk gctl_ro_param(grq, "unit", sizeof(unit), &unit); 376115731Sphk gctl_rw_param(grq, "output", ncp, cp); 377115730Sphk errstr = gctl_issue(grq); 378115731Sphk if (errstr != NULL) 379115731Sphk errx(1, "%s\nor possibly kernel and ccdconfig out of sync", 380115731Sphk errstr); 381115731Sphk if (strlen(cp) == 0) 382115731Sphk errx(1, "ccd%d not configured", unit); 383115731Sphk if (verbose && !v) { 384115731Sphk printf("# ccd\t\tileave\tflags\tcomponent devices\n"); 385115731Sphk v = 1; 386115730Sphk } 387115731Sphk printf("%s", cp); 388115731Sphk free(cp); 38913044Sasami return (0); 39013044Sasami} 39113044Sasami 392115731Sphkstatic int 393115731Sphkdump_ccd(int argc, char **argv) 39413044Sasami{ 395118632Sjohan int i, error; 39613044Sasami 397115731Sphk if (argc == 0) { 398118632Sjohan error = dumpout(-1); 399115731Sphk } else { 400118632Sjohan error = 0; 401118632Sjohan for (i = 0; error == 0 && i < argc; i++) 402118632Sjohan error = dumpout(resolve_ccdname(argv[i])); 40313044Sasami } 404118632Sjohan return (error); 40513044Sasami} 40613044Sasami 40713044Sasamistatic int 40892539Simpflags_to_val(char *flags) 40913044Sasami{ 41013044Sasami char *cp, *tok; 411116111Sphk int i, tmp, val; 41213044Sasami 413116111Sphk errno = 0; /* to check for ERANGE */ 414116111Sphk val = (int)strtol(flags, &cp, 0); 415116111Sphk if ((errno != ERANGE) && (*cp == '\0')) { 416116111Sphk if (val & ~(CCDF_UNIFORM|CCDF_MIRROR)) 417116111Sphk return (-1); 418116111Sphk return (val); 419116111Sphk } 42013044Sasami 42113044Sasami /* Check for values represented by strings. */ 42213044Sasami if ((cp = strdup(flags)) == NULL) 42313044Sasami err(1, "no memory to parse flags"); 42413044Sasami tmp = 0; 42513044Sasami for (tok = cp; (tok = strtok(tok, ",")) != NULL; tok = NULL) { 42613044Sasami for (i = 0; flagvaltab[i].fv_flag != NULL; ++i) 42713044Sasami if (strcmp(tok, flagvaltab[i].fv_flag) == 0) 42813044Sasami break; 42913044Sasami if (flagvaltab[i].fv_flag == NULL) { 43013044Sasami free(cp); 431116111Sphk return (-1); 43213044Sasami } 43313044Sasami tmp |= flagvaltab[i].fv_val; 43413044Sasami } 43513044Sasami 43613044Sasami /* If we get here, the string was ok. */ 43713044Sasami free(cp); 438116111Sphk return (tmp); 43913044Sasami} 44013044Sasami 44113044Sasamistatic void 44292539Simpusage(void) 44313044Sasami{ 44426541Scharnier fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", 445141611Sru "usage: ccdconfig [-cv] ccd ileave [flags] dev ...", 44626541Scharnier " ccdconfig -C [-v] [-f config_file]", 447141611Sru " ccdconfig -u [-v] ccd ...", 44826541Scharnier " ccdconfig -U [-v] [-f config_file]", 449141611Sru " ccdconfig -g [ccd ...]"); 45013044Sasami exit(1); 45113044Sasami} 452