2 * Copyright (c) 2003 Poul-Henning Kamp
3 * Copyright (c) 1995 Jason R. Thorpe.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed for the NetBSD Project
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
38 #include <sys/linker.h>
39 #include <sys/module.h>
51 #define CCDF_UNIFORM 0x02 /* use LCCD of sizes for uniform interleave */
52 #define CCDF_MIRROR 0x04 /* use mirroring */
54 #include "pathnames.h"
56 static int lineno = 0;
57 static int verbose = 0;
58 static const char *ccdconf = _PATH_CCDCONF;
64 { "CCDF_UNIFORM", CCDF_UNIFORM },
65 { "uniform", CCDF_UNIFORM },
66 { "CCDF_MIRROR", CCDF_MIRROR },
67 { "mirror", CCDF_MIRROR },
72 #define CCD_CONFIG 0 /* configure a device */
73 #define CCD_CONFIGALL 1 /* configure all devices */
74 #define CCD_UNCONFIG 2 /* unconfigure a device */
75 #define CCD_UNCONFIGALL 3 /* unconfigure all devices */
76 #define CCD_DUMP 4 /* dump a ccd's configuration */
78 static int do_single(int, char **, int);
79 static int do_all(int);
80 static int dump_ccd(int, char **);
81 static int flags_to_val(char *);
82 static int resolve_ccdname(char *);
83 static void usage(void);
86 main(int argc, char *argv[])
88 int ch, options = 0, action = CCD_CONFIG;
90 while ((ch = getopt(argc, argv, "cCf:guUv")) != -1) {
98 action = CCD_CONFIGALL;
111 action = CCD_UNCONFIG;
116 action = CCD_UNCONFIGALL;
134 if (modfind("g_ccd") < 0) {
135 /* Not present in kernel, try loading it */
136 if (kldload("geom_ccd") < 0 || modfind("g_ccd") < 0)
137 warn("geom_ccd module not available!");
143 exit(do_single(argc, argv, action));
147 case CCD_UNCONFIGALL:
148 exit(do_all(action));
152 exit(dump_ccd(argc, argv));
160 do_single(int argc, char **argv, int action)
163 int ccd, noflags = 0, i, ileave, flags = 0;
164 struct gctl_req *grq;
170 * If unconfiguring, all arguments are treated as ccds.
172 if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) {
174 for (i = 0; argc != 0; ) {
175 cp = *argv++; --argc;
176 if ((ccd = resolve_ccdname(cp)) < 0) {
177 warnx("invalid ccd name: %s", cp);
181 grq = gctl_get_handle();
182 gctl_ro_param(grq, "verb", -1, "destroy geom");
183 gctl_ro_param(grq, "class", -1, "CCD");
184 sprintf(buf1, "ccd%d", ccd);
185 gctl_ro_param(grq, "geom", -1, buf1);
186 errstr = gctl_issue(grq);
187 if (errstr == NULL) {
189 printf("%s unconfigured\n", cp);
194 "%s\nor possibly kernel and ccdconfig out of sync",
201 /* Make sure there are enough arguments. */
204 /* Assume that no flags are specified. */
207 if (action == CCD_CONFIGALL) {
208 warnx("%s: bad line: %d", ccdconf, lineno);
215 /* First argument is the ccd to configure. */
216 cp = *argv++; --argc;
217 if ((ccd = resolve_ccdname(cp)) < 0) {
218 warnx("invalid ccd name: %s", cp);
222 /* Next argument is the interleave factor. */
223 cp = *argv++; --argc;
224 errno = 0; /* to check for ERANGE */
225 ileave = (int)strtol(cp, &cp2, 10);
226 if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) {
227 warnx("invalid interleave factor: %s", cp);
232 /* Next argument is the ccd configuration flags. */
233 cp = *argv++; --argc;
234 if ((flags = flags_to_val(cp)) < 0) {
235 warnx("invalid flags argument: %s", cp);
239 grq = gctl_get_handle();
240 gctl_ro_param(grq, "verb", -1, "create geom");
241 gctl_ro_param(grq, "class", -1, "CCD");
242 gctl_ro_param(grq, "unit", sizeof(ccd), &ccd);
243 gctl_ro_param(grq, "ileave", sizeof(ileave), &ileave);
244 if (flags & CCDF_UNIFORM)
245 gctl_ro_param(grq, "uniform", -1, "");
246 if (flags & CCDF_MIRROR)
247 gctl_ro_param(grq, "mirror", -1, "");
248 gctl_ro_param(grq, "nprovider", sizeof(argc), &argc);
249 for (i = 0; i < argc; i++) {
250 sprintf(buf1, "provider%d", i);
252 if (!strncmp(cp, _PATH_DEV, strlen(_PATH_DEV)))
253 cp += strlen(_PATH_DEV);
254 gctl_ro_param(grq, buf1, -1, cp);
256 gctl_rw_param(grq, "output", sizeof(buf1), buf1);
257 errstr = gctl_issue(grq);
258 if (errstr == NULL) {
266 "%s\nor possibly kernel and ccdconfig out of sync",
275 char line[_POSIX2_LINE_MAX];
283 if ((f = fopen(ccdconf, "r")) == NULL) {
285 warn("fopen: %s", ccdconf);
290 while (fgets(line, sizeof(line), f) != NULL) {
294 if ((cp = strrchr(line, '\n')) != NULL)
297 /* Break up the line and pass it's contents to do_single(). */
300 for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) {
303 if ((argv = realloc(argv,
304 sizeof(char *) * ++argc)) == NULL) {
305 warnx("no memory to configure ccds");
310 * If our action is to unconfigure all, then pass
311 * just the first token to do_single() and ignore
312 * the rest. Since this will be encountered on
313 * our first pass through the line, the Right
316 if (action == CCD_UNCONFIGALL) {
317 if (do_single(argc, argv, action))
323 if (do_single(argc, argv, action))
336 resolve_ccdname(char *name)
339 if (!strncmp(name, _PATH_DEV, strlen(_PATH_DEV)))
340 name += strlen(_PATH_DEV);
341 if (strncmp(name, "ccd", 3))
346 return (strtoul(name, NULL, 10));
353 struct gctl_req *grq;
358 grq = gctl_get_handle();
361 gctl_ro_param(grq, "verb", -1, "list");
362 gctl_ro_param(grq, "class", -1, "CCD");
363 gctl_ro_param(grq, "unit", sizeof(unit), &unit);
364 gctl_rw_param(grq, "output", ncp, cp);
365 errstr = gctl_issue(grq);
367 errx(1, "%s\nor possibly kernel and ccdconfig out of sync",
370 errx(1, "ccd%d not configured", unit);
372 printf("# ccd\t\tileave\tflags\tcomponent devices\n");
381 dump_ccd(int argc, char **argv)
389 for (i = 0; error == 0 && i < argc; i++)
390 error = dumpout(resolve_ccdname(argv[i]));
396 flags_to_val(char *flags)
402 errno = 0; /* to check for ERANGE */
403 val = (int)strtol(flags, &cp, 0);
404 if ((errno != ERANGE) && (*cp == '\0')) {
405 if (val & ~(CCDF_UNIFORM|CCDF_MIRROR))
410 flagslen = strlen(flags);
411 /* Check for values represented by strings. */
412 if ((cp = strdup(flags)) == NULL)
413 err(1, "no memory to parse flags");
415 for (tok = cp; (tok = strtok(tok, ",")) != NULL; tok = NULL) {
416 for (i = 0; flagvaltab[i].fv_flag != NULL; ++i)
417 if (strcmp(tok, flagvaltab[i].fv_flag) == 0)
419 if (flagvaltab[i].fv_flag == NULL) {
423 tmp |= flagvaltab[i].fv_val;
426 /* If we get here, the string was ok. */
434 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
435 "usage: ccdconfig [-cv] ccd ileave [flags] dev ...",
436 " ccdconfig -C [-v] [-f config_file]",
437 " ccdconfig -u [-v] ccd ...",
438 " ccdconfig -U [-v] [-f config_file]",
439 " ccdconfig -g [ccd ...]");