]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ccdconfig/ccdconfig.c
Merge ^/head r327169 through r327340.
[FreeBSD/FreeBSD.git] / sbin / ccdconfig / ccdconfig.c
1 /*      $NetBSD: ccdconfig.c,v 1.6 1996/05/16 07:11:18 thorpej Exp $    */
2
3 /*-
4  * SPDX-License-Identifier: BSD-4-Clause
5  *
6  * Copyright (c) 2003 Poul-Henning Kamp
7  * Copyright (c) 1996 The NetBSD Foundation, Inc.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to The NetBSD Foundation
11  * by Jason R. Thorpe.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. All advertising materials mentioning features or use of this software
22  *    must display the following acknowledgement:
23  *        This product includes software developed by the NetBSD
24  *        Foundation, Inc. and its contributors.
25  * 4. Neither the name of The NetBSD Foundation nor the names of its
26  *    contributors may be used to endorse or promote products derived
27  *    from this software without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
33  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39  * POSSIBILITY OF SUCH DAMAGE.
40  */
41
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44
45 #include <sys/param.h>
46 #include <sys/linker.h>
47 #include <sys/module.h>
48 #include <ctype.h>
49 #include <err.h>
50 #include <errno.h>
51 #include <limits.h>
52 #include <paths.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <libgeom.h>
58
59 #define CCDF_UNIFORM    0x02    /* use LCCD of sizes for uniform interleave */
60 #define CCDF_MIRROR     0x04    /* use mirroring */
61 #define CCDF_NO_OFFSET  0x08    /* do not leave space in front */
62 #define CCDF_LINUX      0x10    /* use Linux compatibility mode */
63
64 #include "pathnames.h"
65
66 static  int lineno = 0;
67 static  int verbose = 0;
68 static  const char *ccdconf = _PATH_CCDCONF;
69
70 static struct flagval {
71         const char      *fv_flag;
72         int             fv_val;
73 } flagvaltab[] = {
74         { "CCDF_UNIFORM",       CCDF_UNIFORM },
75         { "uniform",            CCDF_UNIFORM },
76         { "CCDF_MIRROR",        CCDF_MIRROR },
77         { "mirror",             CCDF_MIRROR },
78         { "CCDF_NO_OFFSET",     CCDF_NO_OFFSET },
79         { "no_offset",          CCDF_NO_OFFSET },
80         { "CCDF_LINUX",         CCDF_LINUX },
81         { "linux",              CCDF_LINUX },
82         { "none",               0 },
83         { NULL,                 0 },
84 };
85
86 #define CCD_CONFIG              0       /* configure a device */
87 #define CCD_CONFIGALL           1       /* configure all devices */
88 #define CCD_UNCONFIG            2       /* unconfigure a device */
89 #define CCD_UNCONFIGALL         3       /* unconfigure all devices */
90 #define CCD_DUMP                4       /* dump a ccd's configuration */
91
92 static  int do_single(int, char **, int);
93 static  int do_all(int);
94 static  int dump_ccd(int, char **);
95 static  int flags_to_val(char *);
96 static  int resolve_ccdname(char *);
97 static  void usage(void);
98
99 int
100 main(int argc, char *argv[])
101 {
102         int ch, options = 0, action = CCD_CONFIG;
103
104         while ((ch = getopt(argc, argv, "cCf:guUv")) != -1) {
105                 switch (ch) {
106                 case 'c':
107                         action = CCD_CONFIG;
108                         ++options;
109                         break;
110
111                 case 'C':
112                         action = CCD_CONFIGALL;
113                         ++options;
114                         break;
115
116                 case 'f':
117                         ccdconf = optarg;
118                         break;
119
120                 case 'g':
121                         action = CCD_DUMP;
122                         break;
123
124                 case 'u':
125                         action = CCD_UNCONFIG;
126                         ++options;
127                         break;
128
129                 case 'U':
130                         action = CCD_UNCONFIGALL;
131                         ++options;
132                         break;
133
134                 case 'v':
135                         verbose = 1;
136                         break;
137
138                 default:
139                         usage();
140                 }
141         }
142         argc -= optind;
143         argv += optind;
144
145         if (options > 1)
146                 usage();
147
148         if (modfind("g_ccd") < 0) {
149                 /* Not present in kernel, try loading it */
150                 if (kldload("geom_ccd") < 0 || modfind("g_ccd") < 0)
151                         warn("geom_ccd module not available!");
152         }
153
154         switch (action) {
155                 case CCD_CONFIG:
156                 case CCD_UNCONFIG:
157                         exit(do_single(argc, argv, action));
158                         /* NOTREACHED */
159
160                 case CCD_CONFIGALL:
161                 case CCD_UNCONFIGALL:
162                         exit(do_all(action));
163                         /* NOTREACHED */
164
165                 case CCD_DUMP:
166                         exit(dump_ccd(argc, argv));
167                         /* NOTREACHED */
168         }
169         /* NOTREACHED */
170         return (0);
171 }
172
173 static int
174 do_single(int argc, char **argv, int action)
175 {
176         char *cp, *cp2;
177         int ccd, noflags = 0, i, ileave, flags = 0;
178         struct gctl_req *grq;
179         char const *errstr;
180         char buf1[BUFSIZ];
181         int ex;
182
183         /*
184          * If unconfiguring, all arguments are treated as ccds.
185          */
186         if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) {
187                 ex = 0;
188                 for (; argc != 0;) {
189                         cp = *argv++; --argc;
190                         if ((ccd = resolve_ccdname(cp)) < 0) {
191                                 warnx("invalid ccd name: %s", cp);
192                                 continue;
193                         }
194                         grq = gctl_get_handle();
195                         gctl_ro_param(grq, "verb", -1, "destroy geom");
196                         gctl_ro_param(grq, "class", -1, "CCD");
197                         sprintf(buf1, "ccd%d", ccd);
198                         gctl_ro_param(grq, "geom", -1, buf1);
199                         errstr = gctl_issue(grq);
200                         if (errstr == NULL) {           
201                                 if (verbose)
202                                         printf("%s unconfigured\n", cp);
203                                 gctl_free(grq);
204                                 continue;
205                         }
206                         warnx(
207                             "%s\nor possibly kernel and ccdconfig out of sync",
208                             errstr);
209                         ex = 1;
210                 }
211                 return (ex);
212         }
213
214         /* Make sure there are enough arguments. */
215         if (argc < 4) {
216                 if (argc == 3) {
217                         /* Assume that no flags are specified. */
218                         noflags = 1;
219                 } else {
220                         if (action == CCD_CONFIGALL) {
221                                 warnx("%s: bad line: %d", ccdconf, lineno);
222                                 return (1);
223                         } else
224                                 usage();
225                 }
226         }
227
228         /* First argument is the ccd to configure. */
229         cp = *argv++; --argc;
230         if ((ccd = resolve_ccdname(cp)) < 0) {
231                 warnx("invalid ccd name: %s", cp);
232                 return (1);
233         }
234
235         /* Next argument is the interleave factor. */
236         cp = *argv++; --argc;
237         errno = 0;      /* to check for ERANGE */
238         ileave = (int)strtol(cp, &cp2, 10);
239         if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) {
240                 warnx("invalid interleave factor: %s", cp);
241                 return (1);
242         }
243
244         if (noflags == 0) {
245                 /* Next argument is the ccd configuration flags. */
246                 cp = *argv++; --argc;
247                 if ((flags = flags_to_val(cp)) < 0) {
248                         warnx("invalid flags argument: %s", cp);
249                         return (1);
250                 }
251         }
252         grq = gctl_get_handle();
253         gctl_ro_param(grq, "verb", -1, "create geom");
254         gctl_ro_param(grq, "class", -1, "CCD");
255         gctl_ro_param(grq, "unit", sizeof(ccd), &ccd);
256         gctl_ro_param(grq, "ileave", sizeof(ileave), &ileave);
257         if (flags & CCDF_UNIFORM)
258                 gctl_ro_param(grq, "uniform", -1, "");
259         if (flags & CCDF_MIRROR)
260                 gctl_ro_param(grq, "mirror", -1, "");
261         if (flags & CCDF_NO_OFFSET)
262                 gctl_ro_param(grq, "no_offset", -1, "");
263         if (flags & CCDF_LINUX)
264                 gctl_ro_param(grq, "linux", -1, "");
265         gctl_ro_param(grq, "nprovider", sizeof(argc), &argc);
266         for (i = 0; i < argc; i++) {
267                 sprintf(buf1, "provider%d", i);
268                 cp = argv[i];
269                 if (!strncmp(cp, _PATH_DEV, strlen(_PATH_DEV)))
270                         cp += strlen(_PATH_DEV);
271                 gctl_ro_param(grq, buf1, -1, cp);
272         }
273         gctl_rw_param(grq, "output", sizeof(buf1), buf1);
274         errstr = gctl_issue(grq);
275         if (errstr == NULL) {           
276                 if (verbose) {
277                         printf("%s", buf1);
278                 }
279                 gctl_free(grq);
280                 return (0);
281         }
282         warnx(
283             "%s\nor possibly kernel and ccdconfig out of sync",
284             errstr);
285         return (1);
286 }
287
288 static int
289 do_all(int action)
290 {
291         FILE *f;
292         char line[_POSIX2_LINE_MAX];
293         char *cp, **argv;
294         int argc, rval;
295         gid_t egid;
296
297         rval = 0;
298         egid = getegid();
299         if (setegid(getgid()) != 0)
300                 err(1, "setegid failed");
301         if ((f = fopen(ccdconf, "r")) == NULL) {
302                 if (setegid(egid) != 0)
303                         err(1, "setegid failed");
304                 warn("fopen: %s", ccdconf);
305                 return (1);
306         }
307         if (setegid(egid) != 0)
308                 err(1, "setegid failed");
309
310         while (fgets(line, sizeof(line), f) != NULL) {
311                 argc = 0;
312                 argv = NULL;
313                 ++lineno;
314                 if ((cp = strrchr(line, '\n')) != NULL)
315                         *cp = '\0';
316
317                 /* Break up the line and pass it's contents to do_single(). */
318                 if (line[0] == '\0')
319                         goto end_of_line;
320                 for (cp = line; (cp = strtok(cp, " \t")) != NULL; cp = NULL) {
321                         if (*cp == '#')
322                                 break;
323                         if ((argv = realloc(argv,
324                             sizeof(char *) * ++argc)) == NULL) {
325                                 warnx("no memory to configure ccds");
326                                 return (1);
327                         }
328                         argv[argc - 1] = cp;
329                         /*
330                          * If our action is to unconfigure all, then pass
331                          * just the first token to do_single() and ignore
332                          * the rest.  Since this will be encountered on
333                          * our first pass through the line, the Right
334                          * Thing will happen.
335                          */
336                         if (action == CCD_UNCONFIGALL) {
337                                 if (do_single(argc, argv, action))
338                                         rval = 1;
339                                 goto end_of_line;
340                         }
341                 }
342                 if (argc != 0)
343                         if (do_single(argc, argv, action))
344                                 rval = 1;
345
346  end_of_line:
347                 if (argv != NULL)
348                         free(argv);
349         }
350
351         (void)fclose(f);
352         return (rval);
353 }
354
355 static int
356 resolve_ccdname(char *name)
357 {
358
359         if (!strncmp(name, _PATH_DEV, strlen(_PATH_DEV)))
360                 name += strlen(_PATH_DEV);
361         if (strncmp(name, "ccd", 3))
362                 return -1;
363         name += 3;
364         if (!isdigit(*name))
365                 return -1;
366         return (strtoul(name, NULL, 10));
367 }
368
369 static int
370 dumpout(int unit)
371 {
372         static int v;
373         struct gctl_req *grq;
374         int ncp;
375         char *cp;
376         char const *errstr;
377
378         grq = gctl_get_handle();
379         ncp = 65536;
380         cp = malloc(ncp);
381         gctl_ro_param(grq, "verb", -1, "list");
382         gctl_ro_param(grq, "class", -1, "CCD");
383         gctl_ro_param(grq, "unit", sizeof(unit), &unit);
384         gctl_rw_param(grq, "output", ncp, cp);
385         errstr = gctl_issue(grq);
386         if (errstr != NULL)
387                 errx(1, "%s\nor possibly kernel and ccdconfig out of sync",
388                         errstr);
389         if (strlen(cp) == 0)
390                 errx(1, "ccd%d not configured", unit);
391         if (verbose && !v) {
392                 printf("# ccd\t\tileave\tflags\tcomponent devices\n");
393                 v = 1;
394         }
395         printf("%s", cp);
396         free(cp);
397         return (0);
398 }
399
400 static int
401 dump_ccd(int argc, char **argv)
402 {
403         int i, error;
404
405         if (argc == 0) {
406                 error = dumpout(-1);
407         } else {
408                 error = 0;
409                 for (i = 0; error == 0 && i < argc; i++)
410                         error = dumpout(resolve_ccdname(argv[i]));
411         }
412         return (error);
413 }
414
415 static int
416 flags_to_val(char *flags)
417 {
418         char *cp, *tok;
419         int i, tmp, val;
420
421         errno = 0;      /* to check for ERANGE */
422         val = (int)strtol(flags, &cp, 0);
423         if ((errno != ERANGE) && (*cp == '\0')) {
424                 if (val & ~(CCDF_UNIFORM|CCDF_MIRROR))
425                         return (-1);
426                 return (val);
427         }
428
429         /* Check for values represented by strings. */
430         if ((cp = strdup(flags)) == NULL)
431                 err(1, "no memory to parse flags");
432         tmp = 0;
433         for (tok = cp; (tok = strtok(tok, ",")) != NULL; tok = NULL) {
434                 for (i = 0; flagvaltab[i].fv_flag != NULL; ++i)
435                         if (strcmp(tok, flagvaltab[i].fv_flag) == 0)
436                                 break;
437                 if (flagvaltab[i].fv_flag == NULL) {
438                         free(cp);
439                         return (-1);
440                 }
441                 tmp |= flagvaltab[i].fv_val;
442         }
443
444         /* If we get here, the string was ok. */
445         free(cp);
446         return (tmp);
447 }
448
449 static void
450 usage(void)
451 {
452         fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
453                 "usage: ccdconfig [-cv] ccd ileave [flags] dev ...",
454                 "       ccdconfig -C [-v] [-f config_file]",
455                 "       ccdconfig -u [-v] ccd ...",
456                 "       ccdconfig -U [-v] [-f config_file]",
457                 "       ccdconfig -g [ccd ...]");
458         exit(1);
459 }