]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ccdconfig/ccdconfig.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / sbin / ccdconfig / ccdconfig.c
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$");
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
56 static  int lineno = 0;
57 static  int verbose = 0;
58 static  const char *ccdconf = _PATH_CCDCONF;
59
60 struct  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
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);
84
85 int
86 main(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
159 static int
160 do_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
271 static int
272 do_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
335 static int
336 resolve_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
349 static int
350 dumpout(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
380 static int
381 dump_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
395 static int
396 flags_to_val(char *flags)
397 {
398         char *cp, *tok;
399         int i, tmp, val;
400         size_t flagslen;
401
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))
406                         return (-1);
407                 return (val);
408         }
409
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");
414         tmp = 0;
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)
418                                 break;
419                 if (flagvaltab[i].fv_flag == NULL) {
420                         free(cp);
421                         return (-1);
422                 }
423                 tmp |= flagvaltab[i].fv_val;
424         }
425
426         /* If we get here, the string was ok. */
427         free(cp);
428         return (tmp);
429 }
430
431 static void
432 usage(void)
433 {
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 ...]");
440         exit(1);
441 }