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