Deleted Added
sdiff udiff text old ( 148719 ) new ( 157740 )
full compact
1/*
2 * Copyright (c) 2003 Poul-Henning Kamp
3 * Copyright (c) 1995 Jason R. Thorpe.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
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
17 * by Jason R. Thorpe.
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.
20 *
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
31 * SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35__FBSDID("$FreeBSD: head/sbin/ccdconfig/ccdconfig.c 148719 2005-08-05 07:39:39Z stefanf $");
36
37#include <sys/param.h>
38#include <sys/linker.h>
39#include <sys/module.h>
40#include <ctype.h>
41#include <err.h>
42#include <errno.h>
43#include <limits.h>
44#include <paths.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include <unistd.h>
49#include <libgeom.h>
50
51#define CCDF_UNIFORM 0x02 /* use LCCD of sizes for uniform interleave */
52#define CCDF_MIRROR 0x04 /* use mirroring */
53
54#include "pathnames.h"
55
56static int lineno = 0;
57static int verbose = 0;
58static const char *ccdconf = _PATH_CCDCONF;
59
60struct flagval {
61 const char *fv_flag;
62 int fv_val;
63} flagvaltab[] = {
64 { "CCDF_UNIFORM", CCDF_UNIFORM },
65 { "uniform", CCDF_UNIFORM },
66 { "CCDF_MIRROR", CCDF_MIRROR },
67 { "mirror", CCDF_MIRROR },
68 { "none", 0 },
69 { NULL, 0 },
70};
71
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 */
77
78static int do_single(int, char **, int);
79static int do_all(int);
80static int dump_ccd(int, char **);
81static int flags_to_val(char *);
82static int resolve_ccdname(char *);
83static void usage(void);
84
85int
86main(int argc, char *argv[])
87{
88 int ch, options = 0, action = CCD_CONFIG;
89
90 while ((ch = getopt(argc, argv, "cCf:guUv")) != -1) {
91 switch (ch) {
92 case 'c':
93 action = CCD_CONFIG;
94 ++options;
95 break;
96
97 case 'C':
98 action = CCD_CONFIGALL;
99 ++options;
100 break;
101
102 case 'f':
103 ccdconf = optarg;
104 break;
105
106 case 'g':
107 action = CCD_DUMP;
108 break;
109
110 case 'u':
111 action = CCD_UNCONFIG;
112 ++options;
113 break;
114
115 case 'U':
116 action = CCD_UNCONFIGALL;
117 ++options;
118 break;
119
120 case 'v':
121 verbose = 1;
122 break;
123
124 default:
125 usage();
126 }
127 }
128 argc -= optind;
129 argv += optind;
130
131 if (options > 1)
132 usage();
133
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!");
138 }
139
140 switch (action) {
141 case CCD_CONFIG:
142 case CCD_UNCONFIG:
143 exit(do_single(argc, argv, action));
144 /* NOTREACHED */
145
146 case CCD_CONFIGALL:
147 case CCD_UNCONFIGALL:
148 exit(do_all(action));
149 /* NOTREACHED */
150
151 case CCD_DUMP:
152 exit(dump_ccd(argc, argv));
153 /* NOTREACHED */
154 }
155 /* NOTREACHED */
156 return (0);
157}
158
159static int
160do_single(int argc, char **argv, int action)
161{
162 char *cp, *cp2;
163 int ccd, noflags = 0, i, ileave, flags = 0;
164 struct gctl_req *grq;
165 char const *errstr;
166 char buf1[BUFSIZ];
167 int ex;
168
169 /*
170 * If unconfiguring, all arguments are treated as ccds.
171 */
172 if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) {
173 ex = 0;
174 for (i = 0; argc != 0; ) {
175 cp = *argv++; --argc;
176 if ((ccd = resolve_ccdname(cp)) < 0) {
177 warnx("invalid ccd name: %s", cp);
178 i = 1;
179 continue;
180 }
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) {
188 if (verbose)
189 printf("%s unconfigured\n", cp);
190 gctl_free(grq);
191 continue;
192 }
193 warnx(
194 "%s\nor possibly kernel and ccdconfig out of sync",
195 errstr);
196 ex = 1;
197 }
198 return (ex);
199 }
200
201 /* Make sure there are enough arguments. */
202 if (argc < 4) {
203 if (argc == 3) {
204 /* Assume that no flags are specified. */
205 noflags = 1;
206 } else {
207 if (action == CCD_CONFIGALL) {
208 warnx("%s: bad line: %d", ccdconf, lineno);
209 return (1);
210 } else
211 usage();
212 }
213 }
214
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);
219 return (1);
220 }
221
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);
228 return (1);
229 }
230
231 if (noflags == 0) {
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);
236 return (1);
237 }
238 }
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);
251 cp = argv[i];
252 if (!strncmp(cp, _PATH_DEV, strlen(_PATH_DEV)))
253 cp += strlen(_PATH_DEV);
254 gctl_ro_param(grq, buf1, -1, cp);
255 }
256 gctl_rw_param(grq, "output", sizeof(buf1), buf1);
257 errstr = gctl_issue(grq);
258 if (errstr == NULL) {
259 if (verbose) {
260 printf("%s", buf1);
261 }
262 gctl_free(grq);
263 return (0);
264 }
265 warnx(
266 "%s\nor possibly kernel and ccdconfig out of sync",
267 errstr);
268 return (1);
269}
270
271static int
272do_all(int action)
273{
274 FILE *f;
275 char line[_POSIX2_LINE_MAX];
276 char *cp, **argv;
277 int argc, rval;
278 gid_t egid;
279
280 rval = 0;
281 egid = getegid();
282 setegid(getgid());
283 if ((f = fopen(ccdconf, "r")) == NULL) {
284 setegid(egid);
285 warn("fopen: %s", ccdconf);
286 return (1);
287 }
288 setegid(egid);
289
290 while (fgets(line, sizeof(line), f) != NULL) {
291 argc = 0;
292 argv = NULL;
293 ++lineno;
294 if ((cp = strrchr(line, '\n')) != NULL)
295 *cp = '\0';
296
297 /* Break up the line and pass it's contents to do_single(). */
298 if (line[0] == '\0')
299 goto end_of_line;
300 for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) {
301 if (*cp == '#')
302 break;
303 if ((argv = realloc(argv,
304 sizeof(char *) * ++argc)) == NULL) {
305 warnx("no memory to configure ccds");
306 return (1);
307 }
308 argv[argc - 1] = cp;
309 /*
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
314 * Thing will happen.
315 */
316 if (action == CCD_UNCONFIGALL) {
317 if (do_single(argc, argv, action))
318 rval = 1;
319 goto end_of_line;
320 }
321 }
322 if (argc != 0)
323 if (do_single(argc, argv, action))
324 rval = 1;
325
326 end_of_line:
327 if (argv != NULL)
328 free(argv);
329 }
330
331 (void)fclose(f);
332 return (rval);
333}
334
335static int
336resolve_ccdname(char *name)
337{
338
339 if (!strncmp(name, _PATH_DEV, strlen(_PATH_DEV)))
340 name += strlen(_PATH_DEV);
341 if (strncmp(name, "ccd", 3))
342 return -1;
343 name += 3;
344 if (!isdigit(*name))
345 return -1;
346 return (strtoul(name, NULL, 10));
347}
348
349static int
350dumpout(int unit)
351{
352 static int v;
353 struct gctl_req *grq;
354 int ncp;
355 char *cp;
356 char const *errstr;
357
358 grq = gctl_get_handle();
359 ncp = 65536;
360 cp = malloc(ncp);
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);
366 if (errstr != NULL)
367 errx(1, "%s\nor possibly kernel and ccdconfig out of sync",
368 errstr);
369 if (strlen(cp) == 0)
370 errx(1, "ccd%d not configured", unit);
371 if (verbose && !v) {
372 printf("# ccd\t\tileave\tflags\tcomponent devices\n");
373 v = 1;
374 }
375 printf("%s", cp);
376 free(cp);
377 return (0);
378}
379
380static int
381dump_ccd(int argc, char **argv)
382{
383 int i, error;
384
385 if (argc == 0) {
386 error = dumpout(-1);
387 } else {
388 error = 0;
389 for (i = 0; error == 0 && i < argc; i++)
390 error = dumpout(resolve_ccdname(argv[i]));
391 }
392 return (error);
393}
394
395static int
396flags_to_val(char *flags)
397{
398 char *cp, *tok;
399 int i, tmp, val;
400
401 errno = 0; /* to check for ERANGE */
402 val = (int)strtol(flags, &cp, 0);
403 if ((errno != ERANGE) && (*cp == '\0')) {
404 if (val & ~(CCDF_UNIFORM|CCDF_MIRROR))
405 return (-1);
406 return (val);
407 }
408
409 /* Check for values represented by strings. */
410 if ((cp = strdup(flags)) == NULL)
411 err(1, "no memory to parse flags");
412 tmp = 0;
413 for (tok = cp; (tok = strtok(tok, ",")) != NULL; tok = NULL) {
414 for (i = 0; flagvaltab[i].fv_flag != NULL; ++i)
415 if (strcmp(tok, flagvaltab[i].fv_flag) == 0)
416 break;
417 if (flagvaltab[i].fv_flag == NULL) {
418 free(cp);
419 return (-1);
420 }
421 tmp |= flagvaltab[i].fv_val;
422 }
423
424 /* If we get here, the string was ok. */
425 free(cp);
426 return (tmp);
427}
428
429static void
430usage(void)
431{
432 fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
433 "usage: ccdconfig [-cv] ccd ileave [flags] dev ...",
434 " ccdconfig -C [-v] [-f config_file]",
435 " ccdconfig -u [-v] ccd ...",
436 " ccdconfig -U [-v] [-f config_file]",
437 " ccdconfig -g [ccd ...]");
438 exit(1);
439}