Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/geom/core/geom.c
39536 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2004-2009 Pawel Jakub Dawidek <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/linker.h>
31
#include <sys/module.h>
32
#include <sys/stat.h>
33
#include <sys/sysctl.h>
34
#include <ctype.h>
35
#include <err.h>
36
#include <errno.h>
37
#include <paths.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <stdarg.h>
41
#include <stdbool.h>
42
#include <stdint.h>
43
#include <string.h>
44
#include <unistd.h>
45
#include <libgen.h>
46
#include <libutil.h>
47
#include <inttypes.h>
48
#include <dlfcn.h>
49
#include <assert.h>
50
#include <libgeom.h>
51
#include <geom.h>
52
53
#include "misc/subr.h"
54
55
#ifdef STATIC_GEOM_CLASSES
56
extern uint32_t gpart_version;
57
extern struct g_command gpart_class_commands[];
58
extern uint32_t glabel_version;
59
extern struct g_command glabel_class_commands[];
60
#endif
61
62
static char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL;
63
static uint32_t *version = NULL;
64
static int verbose = 0;
65
static struct g_command *class_commands = NULL;
66
67
#define GEOM_CLASS_CMDS 0x01
68
#define GEOM_STD_CMDS 0x02
69
70
#define GEOM_CLASS_WIDTH 10
71
72
static struct g_command *find_command(const char *cmdstr, int flags);
73
static void list_one_geom_by_provider(const char *provider_name);
74
static int std_available(const char *name);
75
static int std_list_available(void);
76
static int std_load_available(void);
77
78
static void std_help(struct gctl_req *req, unsigned flags);
79
static void std_list(struct gctl_req *req, unsigned flags);
80
static void std_status(struct gctl_req *req, unsigned flags);
81
static void std_load(struct gctl_req *req, unsigned flags);
82
static void std_unload(struct gctl_req *req, unsigned flags);
83
84
static struct g_command std_commands[] = {
85
{ "help", 0, std_help, G_NULL_OPTS, NULL },
86
{ "list", 0, std_list,
87
{
88
{ 'a', "all", NULL, G_TYPE_BOOL },
89
G_OPT_SENTINEL
90
},
91
"[-a] [name ...]"
92
},
93
{ "status", 0, std_status,
94
{
95
{ 'a', "all", NULL, G_TYPE_BOOL },
96
{ 'g', "geoms", NULL, G_TYPE_BOOL },
97
{ 's', "script", NULL, G_TYPE_BOOL },
98
G_OPT_SENTINEL
99
},
100
"[-ags] [name ...]"
101
},
102
{ "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS,
103
NULL },
104
{ "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS, NULL },
105
G_CMD_SENTINEL
106
};
107
108
static void
109
usage_command(struct g_command *cmd, const char *prefix)
110
{
111
struct g_option *opt;
112
unsigned i;
113
114
if (cmd->gc_usage != NULL) {
115
char *pos, *ptr, *sptr;
116
117
sptr = ptr = strdup(cmd->gc_usage);
118
while ((pos = strsep(&ptr, "\n")) != NULL) {
119
if (*pos == '\0')
120
continue;
121
fprintf(stderr, "%s %s %s %s\n", prefix, comm,
122
cmd->gc_name, pos);
123
}
124
free(sptr);
125
return;
126
}
127
128
fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name);
129
if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
130
fprintf(stderr, " [-v]");
131
for (i = 0; ; i++) {
132
opt = &cmd->gc_options[i];
133
if (opt->go_name == NULL)
134
break;
135
if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
136
fprintf(stderr, " [");
137
else
138
fprintf(stderr, " ");
139
fprintf(stderr, "-%c", opt->go_char);
140
if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
141
fprintf(stderr, " %s", opt->go_name);
142
if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
143
fprintf(stderr, "]");
144
}
145
fprintf(stderr, "\n");
146
}
147
148
static void
149
usage(void)
150
{
151
152
if (class_name == NULL) {
153
fprintf(stderr, "usage: geom <class> <command> [options]\n");
154
fprintf(stderr, " geom -p <provider-name>\n");
155
fprintf(stderr, " geom -t\n");
156
exit(EXIT_FAILURE);
157
} else {
158
struct g_command *cmd;
159
const char *prefix;
160
unsigned i;
161
162
prefix = "usage:";
163
if (class_commands != NULL) {
164
for (i = 0; ; i++) {
165
cmd = &class_commands[i];
166
if (cmd->gc_name == NULL)
167
break;
168
usage_command(cmd, prefix);
169
prefix = " ";
170
}
171
}
172
for (i = 0; ; i++) {
173
cmd = &std_commands[i];
174
if (cmd->gc_name == NULL)
175
break;
176
/*
177
* If class defines command, which has the same name as
178
* standard command, skip it, because it was already
179
* shown on usage().
180
*/
181
if (find_command(cmd->gc_name, GEOM_CLASS_CMDS) != NULL)
182
continue;
183
usage_command(cmd, prefix);
184
prefix = " ";
185
}
186
exit(EXIT_FAILURE);
187
}
188
}
189
190
static void
191
load_module(void)
192
{
193
char name1[64], name2[64];
194
195
snprintf(name1, sizeof(name1), "g_%s", class_name);
196
snprintf(name2, sizeof(name2), "geom_%s", class_name);
197
if (modfind(name1) < 0) {
198
/* Not present in kernel, try loading it. */
199
if (kldload(name2) < 0 || modfind(name1) < 0) {
200
if (errno != EEXIST) {
201
err(EXIT_FAILURE, "cannot load %s", name2);
202
}
203
}
204
}
205
}
206
207
static int
208
strlcatf(char *str, size_t size, const char *format, ...)
209
{
210
size_t len;
211
va_list ap;
212
int ret;
213
214
len = strlen(str);
215
str += len;
216
size -= len;
217
218
va_start(ap, format);
219
ret = vsnprintf(str, size, format, ap);
220
va_end(ap);
221
222
return (ret);
223
}
224
225
/*
226
* Find given option in options available for given command.
227
*/
228
static struct g_option *
229
find_option(struct g_command *cmd, char ch)
230
{
231
struct g_option *opt;
232
unsigned i;
233
234
for (i = 0; ; i++) {
235
opt = &cmd->gc_options[i];
236
if (opt->go_name == NULL)
237
return (NULL);
238
if (opt->go_char == ch)
239
return (opt);
240
}
241
/* NOTREACHED */
242
return (NULL);
243
}
244
245
/*
246
* Add given option to gctl_req.
247
*/
248
static void
249
set_option(struct gctl_req *req, struct g_option *opt, const char *val)
250
{
251
const char *optname;
252
int64_t number;
253
void *ptr;
254
255
if (G_OPT_ISMULTI(opt)) {
256
size_t optnamesize;
257
258
if (G_OPT_NUM(opt) == UCHAR_MAX)
259
errx(EXIT_FAILURE, "Too many -%c options.", opt->go_char);
260
261
/*
262
* Base option name length plus 3 bytes for option number
263
* (max. 255 options) plus 1 byte for terminating '\0'.
264
*/
265
optnamesize = strlen(opt->go_name) + 3 + 1;
266
ptr = malloc(optnamesize);
267
if (ptr == NULL)
268
errx(EXIT_FAILURE, "No memory.");
269
snprintf(ptr, optnamesize, "%s%u", opt->go_name, G_OPT_NUM(opt));
270
G_OPT_NUMINC(opt);
271
optname = ptr;
272
} else {
273
optname = opt->go_name;
274
}
275
276
if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) {
277
if (expand_number(val, &number) == -1) {
278
err(EXIT_FAILURE, "Invalid value for '%c' argument",
279
opt->go_char);
280
}
281
ptr = malloc(sizeof(intmax_t));
282
if (ptr == NULL)
283
errx(EXIT_FAILURE, "No memory.");
284
*(intmax_t *)ptr = number;
285
opt->go_val = ptr;
286
gctl_ro_param(req, optname, sizeof(intmax_t), opt->go_val);
287
} else if (G_OPT_TYPE(opt) == G_TYPE_STRING) {
288
gctl_ro_param(req, optname, -1, val);
289
} else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
290
ptr = malloc(sizeof(int));
291
if (ptr == NULL)
292
errx(EXIT_FAILURE, "No memory.");
293
*(int *)ptr = *val - '0';
294
opt->go_val = ptr;
295
gctl_ro_param(req, optname, sizeof(int), opt->go_val);
296
} else {
297
assert(!"Invalid type");
298
}
299
300
if (G_OPT_ISMULTI(opt))
301
free(__DECONST(char *, optname));
302
}
303
304
/*
305
* 1. Add given argument by caller.
306
* 2. Add default values of not given arguments.
307
* 3. Add the rest of arguments.
308
*/
309
static void
310
parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
311
char ***argv)
312
{
313
struct g_option *opt;
314
char opts[64];
315
unsigned i;
316
int ch, vcount;
317
318
*opts = '\0';
319
if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
320
strlcat(opts, "v", sizeof(opts));
321
for (i = 0; ; i++) {
322
opt = &cmd->gc_options[i];
323
if (opt->go_name == NULL)
324
break;
325
assert(G_OPT_TYPE(opt) != 0);
326
assert((opt->go_type & ~(G_TYPE_MASK | G_TYPE_MULTI)) == 0);
327
/* Multiple bool arguments makes no sense. */
328
assert(G_OPT_TYPE(opt) != G_TYPE_BOOL ||
329
(opt->go_type & G_TYPE_MULTI) == 0);
330
strlcatf(opts, sizeof(opts), "%c", opt->go_char);
331
if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
332
strlcat(opts, ":", sizeof(opts));
333
}
334
335
/*
336
* Add specified arguments.
337
*/
338
vcount = 0;
339
while ((ch = getopt(*argc, *argv, opts)) != -1) {
340
/* Standard (not passed to kernel) options. */
341
if (ch == 'v' && (cmd->gc_flags & G_FLAG_VERBOSE) != 0)
342
verbose = 1;
343
/* Options passed to kernel. */
344
opt = find_option(cmd, ch);
345
if (opt == NULL) {
346
if (ch == 'v' && (cmd->gc_flags & G_FLAG_VERBOSE) != 0){
347
if (++vcount < 2)
348
continue;
349
else
350
warnx("Option 'v' specified twice.");
351
}
352
usage();
353
}
354
if (!G_OPT_ISMULTI(opt) && G_OPT_ISDONE(opt)) {
355
warnx("Option '%c' specified twice.", opt->go_char);
356
usage();
357
}
358
G_OPT_DONE(opt);
359
360
if (G_OPT_TYPE(opt) == G_TYPE_BOOL)
361
set_option(req, opt, "1");
362
else
363
set_option(req, opt, optarg);
364
}
365
*argc -= optind;
366
*argv += optind;
367
368
/*
369
* Add not specified arguments, but with default values.
370
*/
371
for (i = 0; ; i++) {
372
opt = &cmd->gc_options[i];
373
if (opt->go_name == NULL)
374
break;
375
if (G_OPT_ISDONE(opt))
376
continue;
377
378
if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
379
assert(opt->go_val == NULL);
380
set_option(req, opt, "0");
381
} else {
382
if (opt->go_val == NULL) {
383
warnx("Option '%c' not specified.",
384
opt->go_char);
385
usage();
386
} else if (opt->go_val == G_VAL_OPTIONAL) {
387
/* add nothing. */
388
} else {
389
set_option(req, opt, opt->go_val);
390
}
391
}
392
}
393
394
/*
395
* Add rest of given arguments.
396
*/
397
gctl_ro_param(req, "nargs", sizeof(int), argc);
398
for (i = 0; i < (unsigned)*argc; i++) {
399
char argname[16];
400
401
snprintf(argname, sizeof(argname), "arg%u", i);
402
gctl_ro_param(req, argname, -1, (*argv)[i]);
403
}
404
}
405
406
/*
407
* Find given command in commands available for given class.
408
*/
409
static struct g_command *
410
find_command(const char *cmdstr, int flags)
411
{
412
struct g_command *cmd;
413
unsigned i;
414
415
/*
416
* First try to find command defined by loaded library.
417
*/
418
if ((flags & GEOM_CLASS_CMDS) != 0 && class_commands != NULL) {
419
for (i = 0; ; i++) {
420
cmd = &class_commands[i];
421
if (cmd->gc_name == NULL)
422
break;
423
if (strcmp(cmd->gc_name, cmdstr) == 0)
424
return (cmd);
425
}
426
}
427
/*
428
* Now try to find in standard commands.
429
*/
430
if ((flags & GEOM_STD_CMDS) != 0) {
431
for (i = 0; ; i++) {
432
cmd = &std_commands[i];
433
if (cmd->gc_name == NULL)
434
break;
435
if (strcmp(cmd->gc_name, cmdstr) == 0)
436
return (cmd);
437
}
438
}
439
return (NULL);
440
}
441
442
static unsigned
443
set_flags(struct g_command *cmd)
444
{
445
unsigned flags = 0;
446
447
if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
448
flags |= G_FLAG_VERBOSE;
449
450
return (flags);
451
}
452
453
/*
454
* Run command.
455
*/
456
static void
457
run_command(int argc, char *argv[])
458
{
459
struct g_command *cmd;
460
struct gctl_req *req;
461
const char *errstr;
462
char buf[4096];
463
464
/* First try to find a command defined by a class. */
465
cmd = find_command(argv[0], GEOM_CLASS_CMDS);
466
if (cmd == NULL) {
467
/* Now, try to find a standard command. */
468
cmd = find_command(argv[0], GEOM_STD_CMDS);
469
if (cmd == NULL) {
470
warnx("Unknown command: %s.", argv[0]);
471
usage();
472
}
473
if (!std_available(cmd->gc_name)) {
474
warnx("Command '%s' not available; "
475
"try 'load' first.", argv[0]);
476
exit(EXIT_FAILURE);
477
}
478
}
479
if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
480
load_module();
481
482
req = gctl_get_handle();
483
gctl_ro_param(req, "class", -1, gclass_name);
484
gctl_ro_param(req, "verb", -1, argv[0]);
485
if (version != NULL)
486
gctl_ro_param(req, "version", sizeof(*version), version);
487
parse_arguments(cmd, req, &argc, &argv);
488
489
buf[0] = '\0';
490
if (cmd->gc_func != NULL) {
491
unsigned flags;
492
493
flags = set_flags(cmd);
494
cmd->gc_func(req, flags);
495
errstr = req->error;
496
} else {
497
gctl_add_param(req, "output", sizeof(buf), buf,
498
GCTL_PARAM_WR | GCTL_PARAM_ASCII);
499
errstr = gctl_issue(req);
500
}
501
if (errstr != NULL && errstr[0] != '\0') {
502
warnx("%s", errstr);
503
/* Suppress EXIT_FAILURE for warnings */
504
if (strncmp(errstr, "warning: ", strlen("warning: ")) == 0)
505
req->nerror = 0;
506
if (req->nerror != 0) {
507
gctl_free(req);
508
exit(EXIT_FAILURE);
509
}
510
}
511
if (buf[0] != '\0')
512
printf("%s", buf);
513
gctl_free(req);
514
if (verbose)
515
printf("Done.\n");
516
exit(EXIT_SUCCESS);
517
}
518
519
#ifndef STATIC_GEOM_CLASSES
520
static const char *
521
library_path(void)
522
{
523
const char *path;
524
525
path = getenv("GEOM_LIBRARY_PATH");
526
if (path == NULL)
527
path = GEOM_CLASS_DIR;
528
return (path);
529
}
530
531
static void
532
load_library(void)
533
{
534
char *curpath, path[MAXPATHLEN], *tofree, *totalpath;
535
uint32_t *lib_version;
536
void *dlh;
537
int ret;
538
539
ret = 0;
540
tofree = totalpath = strdup(library_path());
541
if (totalpath == NULL)
542
err(EXIT_FAILURE, "Not enough memory for library path");
543
544
if (strchr(totalpath, ':') != NULL)
545
curpath = strsep(&totalpath, ":");
546
else
547
curpath = totalpath;
548
/* Traverse the paths to find one that contains the library we want. */
549
while (curpath != NULL) {
550
snprintf(path, sizeof(path), "%s/geom_%s.so", curpath,
551
class_name);
552
ret = access(path, F_OK);
553
if (ret == -1) {
554
if (errno == ENOENT) {
555
/*
556
* If we cannot find library, try the next
557
* path.
558
*/
559
curpath = strsep(&totalpath, ":");
560
continue;
561
}
562
err(EXIT_FAILURE, "Cannot access library");
563
}
564
break;
565
}
566
free(tofree);
567
/* No library was found, but standard commands can still be used */
568
if (ret == -1)
569
return;
570
dlh = dlopen(path, RTLD_NOW);
571
if (dlh == NULL)
572
errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror());
573
lib_version = dlsym(dlh, "lib_version");
574
if (lib_version == NULL) {
575
warnx("Cannot find symbol %s: %s.", "lib_version", dlerror());
576
dlclose(dlh);
577
exit(EXIT_FAILURE);
578
}
579
if (*lib_version != G_LIB_VERSION) {
580
dlclose(dlh);
581
errx(EXIT_FAILURE, "%s and %s are not synchronized.",
582
getprogname(), path);
583
}
584
version = dlsym(dlh, "version");
585
if (version == NULL) {
586
warnx("Cannot find symbol %s: %s.", "version", dlerror());
587
dlclose(dlh);
588
exit(EXIT_FAILURE);
589
}
590
class_commands = dlsym(dlh, "class_commands");
591
if (class_commands == NULL) {
592
warnx("Cannot find symbol %s: %s.", "class_commands",
593
dlerror());
594
dlclose(dlh);
595
exit(EXIT_FAILURE);
596
}
597
}
598
#endif /* !STATIC_GEOM_CLASSES */
599
600
/*
601
* Class name should be all capital letters.
602
*/
603
static void
604
set_class_name(void)
605
{
606
char *s1, *s2;
607
608
s1 = class_name;
609
for (; *s1 != '\0'; s1++)
610
*s1 = tolower(*s1);
611
gclass_name = malloc(strlen(class_name) + 1);
612
if (gclass_name == NULL)
613
errx(EXIT_FAILURE, "No memory");
614
s1 = gclass_name;
615
s2 = class_name;
616
for (; *s2 != '\0'; s2++)
617
*s1++ = toupper(*s2);
618
*s1 = '\0';
619
}
620
621
static void
622
get_class(int *argc, char ***argv)
623
{
624
625
snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
626
if (strcmp(comm, "geom") == 0) {
627
if (*argc < 2)
628
usage();
629
else if (*argc == 2) {
630
if (strcmp((*argv)[1], "-h") == 0 ||
631
strcmp((*argv)[1], "help") == 0) {
632
usage();
633
}
634
}
635
strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
636
class_name = (*argv)[1];
637
*argc -= 2;
638
*argv += 2;
639
} else if (*comm == 'g') {
640
class_name = comm + 1;
641
*argc -= 1;
642
*argv += 1;
643
} else {
644
errx(EXIT_FAILURE, "Invalid utility name.");
645
}
646
647
#ifndef STATIC_GEOM_CLASSES
648
load_library();
649
#else
650
if (!strcasecmp(class_name, "part")) {
651
version = &gpart_version;
652
class_commands = gpart_class_commands;
653
} else if (!strcasecmp(class_name, "label")) {
654
version = &glabel_version;
655
class_commands = glabel_class_commands;
656
}
657
#endif /* !STATIC_GEOM_CLASSES */
658
659
set_class_name();
660
661
/* If we can't load or list, it's not a class. */
662
if (!std_load_available() && !std_list_available())
663
errx(EXIT_FAILURE, "Invalid class name '%s'.", class_name);
664
665
if (*argc < 1)
666
usage();
667
}
668
669
static struct ggeom *
670
find_geom_by_provider(struct gmesh *mesh, const char *name)
671
{
672
struct gclass *classp;
673
struct ggeom *gp;
674
struct gprovider *pp;
675
676
LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
677
LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
678
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
679
if (strcmp(pp->lg_name, name) == 0)
680
return (gp);
681
}
682
}
683
}
684
685
return (NULL);
686
}
687
688
static int
689
compute_tree_width_geom(struct gmesh *mesh, struct ggeom *gp, int indent)
690
{
691
struct gclass *classp2;
692
struct ggeom *gp2;
693
struct gconsumer *cp2;
694
struct gprovider *pp;
695
int max_width, width;
696
697
max_width = width = indent + strlen(gp->lg_name);
698
699
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
700
LIST_FOREACH(classp2, &mesh->lg_class, lg_class) {
701
LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) {
702
LIST_FOREACH(cp2,
703
&gp2->lg_consumer, lg_consumer) {
704
if (pp != cp2->lg_provider)
705
continue;
706
width = compute_tree_width_geom(mesh,
707
gp2, indent + 2);
708
if (width > max_width)
709
max_width = width;
710
}
711
}
712
}
713
}
714
715
return (max_width);
716
}
717
718
static int
719
compute_tree_width(struct gmesh *mesh)
720
{
721
struct gclass *classp;
722
struct ggeom *gp;
723
int max_width, width;
724
725
max_width = width = 0;
726
727
LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
728
LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
729
if (!LIST_EMPTY(&gp->lg_consumer))
730
continue;
731
width = compute_tree_width_geom(mesh, gp, 0);
732
if (width > max_width)
733
max_width = width;
734
}
735
}
736
737
return (max_width);
738
}
739
740
static void
741
show_tree_geom(struct gmesh *mesh, struct ggeom *gp, int indent, int width)
742
{
743
struct gclass *classp2;
744
struct ggeom *gp2;
745
struct gconsumer *cp2;
746
struct gprovider *pp;
747
748
if (LIST_EMPTY(&gp->lg_provider)) {
749
printf("%*s%-*.*s %-*.*s\n", indent, "",
750
width - indent, width - indent, gp->lg_name,
751
GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name);
752
return;
753
}
754
755
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
756
printf("%*s%-*.*s %-*.*s %s\n", indent, "",
757
width - indent, width - indent, gp->lg_name,
758
GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name,
759
pp->lg_name);
760
761
LIST_FOREACH(classp2, &mesh->lg_class, lg_class) {
762
LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) {
763
LIST_FOREACH(cp2,
764
&gp2->lg_consumer, lg_consumer) {
765
if (pp != cp2->lg_provider)
766
continue;
767
show_tree_geom(mesh, gp2,
768
indent + 2, width);
769
}
770
}
771
}
772
}
773
}
774
775
static void
776
show_tree(void)
777
{
778
struct gmesh mesh;
779
struct gclass *classp;
780
struct ggeom *gp;
781
int error, width;
782
783
error = geom_gettree(&mesh);
784
if (error != 0)
785
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
786
787
width = compute_tree_width(&mesh);
788
789
printf("%-*.*s %-*.*s %s\n",
790
width, width, "Geom",
791
GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, "Class",
792
"Provider");
793
794
LIST_FOREACH(classp, &mesh.lg_class, lg_class) {
795
LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
796
if (!LIST_EMPTY(&gp->lg_consumer))
797
continue;
798
show_tree_geom(&mesh, gp, 0, width);
799
}
800
}
801
}
802
803
int
804
main(int argc, char *argv[])
805
{
806
char *provider_name;
807
bool tflag;
808
int ch;
809
810
provider_name = NULL;
811
tflag = false;
812
813
if (strcmp(getprogname(), "geom") == 0) {
814
while ((ch = getopt(argc, argv, "hp:t")) != -1) {
815
switch (ch) {
816
case 'p':
817
provider_name = strdup(optarg);
818
if (provider_name == NULL)
819
err(1, "strdup");
820
break;
821
case 't':
822
tflag = true;
823
break;
824
case 'h':
825
default:
826
usage();
827
}
828
}
829
830
/*
831
* Don't adjust argc and argv, it would break get_class().
832
*/
833
}
834
835
if (tflag && provider_name != NULL) {
836
errx(EXIT_FAILURE,
837
"At most one of -P and -t may be specified.");
838
}
839
840
if (provider_name != NULL) {
841
list_one_geom_by_provider(provider_name);
842
return (0);
843
}
844
845
if (tflag) {
846
show_tree();
847
return (0);
848
}
849
850
get_class(&argc, &argv);
851
run_command(argc, argv);
852
/* NOTREACHED */
853
854
exit(EXIT_FAILURE);
855
}
856
857
static struct gclass *
858
find_class(struct gmesh *mesh, const char *name)
859
{
860
struct gclass *classp;
861
862
LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
863
if (strcmp(classp->lg_name, name) == 0)
864
return (classp);
865
}
866
return (NULL);
867
}
868
869
static struct ggeom *
870
find_geom(struct gclass *classp, const char *name)
871
{
872
struct ggeom *gp;
873
874
if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
875
name += sizeof(_PATH_DEV) - 1;
876
877
LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
878
if (strcmp(gp->lg_name, name) == 0)
879
return (gp);
880
}
881
return (NULL);
882
}
883
884
static void
885
list_one_provider(struct gprovider *pp, const char *prefix)
886
{
887
struct gconfig *conf;
888
char buf[5];
889
890
printf("Name: %s\n", pp->lg_name);
891
humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
892
HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
893
printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
894
buf);
895
printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
896
if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
897
printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
898
printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
899
}
900
printf("%sMode: %s\n", prefix, pp->lg_mode);
901
LIST_FOREACH(conf, &pp->lg_config, lg_config) {
902
printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
903
}
904
}
905
906
static void
907
list_one_consumer(struct gconsumer *cp, const char *prefix)
908
{
909
struct gprovider *pp;
910
struct gconfig *conf;
911
912
pp = cp->lg_provider;
913
if (pp == NULL)
914
printf("[no provider]\n");
915
else {
916
char buf[5];
917
918
printf("Name: %s\n", pp->lg_name);
919
humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
920
HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
921
printf("%sMediasize: %jd (%s)\n", prefix,
922
(intmax_t)pp->lg_mediasize, buf);
923
printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
924
if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
925
printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
926
printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
927
}
928
printf("%sMode: %s\n", prefix, cp->lg_mode);
929
}
930
LIST_FOREACH(conf, &cp->lg_config, lg_config) {
931
printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
932
}
933
}
934
935
static void
936
list_one_geom(struct ggeom *gp)
937
{
938
struct gprovider *pp;
939
struct gconsumer *cp;
940
struct gconfig *conf;
941
unsigned n;
942
943
printf("Geom name: %s\n", gp->lg_name);
944
LIST_FOREACH(conf, &gp->lg_config, lg_config) {
945
printf("%s: %s\n", conf->lg_name, conf->lg_val);
946
}
947
if (!LIST_EMPTY(&gp->lg_provider)) {
948
printf("Providers:\n");
949
n = 1;
950
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
951
printf("%u. ", n++);
952
list_one_provider(pp, " ");
953
}
954
}
955
if (!LIST_EMPTY(&gp->lg_consumer)) {
956
printf("Consumers:\n");
957
n = 1;
958
LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
959
printf("%u. ", n++);
960
list_one_consumer(cp, " ");
961
}
962
}
963
printf("\n");
964
}
965
966
static void
967
list_one_geom_by_provider(const char *provider_name)
968
{
969
struct gmesh mesh;
970
struct ggeom *gp;
971
int error;
972
973
error = geom_gettree(&mesh);
974
if (error != 0)
975
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
976
977
gp = find_geom_by_provider(&mesh, provider_name);
978
if (gp == NULL)
979
errx(EXIT_FAILURE, "Cannot find provider '%s'.", provider_name);
980
981
printf("Geom class: %s\n", gp->lg_class->lg_name);
982
list_one_geom(gp);
983
}
984
985
static void
986
std_help(struct gctl_req *req __unused, unsigned flags __unused)
987
{
988
989
usage();
990
}
991
992
static int
993
std_list_available(void)
994
{
995
struct gmesh mesh;
996
struct gclass *classp;
997
int error;
998
999
error = geom_gettree_geom(&mesh, gclass_name, "", 0);
1000
if (error != 0)
1001
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1002
classp = find_class(&mesh, gclass_name);
1003
geom_deletetree(&mesh);
1004
if (classp != NULL)
1005
return (1);
1006
return (0);
1007
}
1008
1009
static void
1010
std_list(struct gctl_req *req, unsigned flags __unused)
1011
{
1012
struct gmesh mesh;
1013
struct gclass *classp;
1014
struct ggeom *gp;
1015
const char *name;
1016
int all, error, i, nargs;
1017
1018
nargs = gctl_get_int(req, "nargs");
1019
if (nargs == 1) {
1020
error = geom_gettree_geom(&mesh, gclass_name,
1021
gctl_get_ascii(req, "arg0"), 1);
1022
} else
1023
error = geom_gettree(&mesh);
1024
if (error != 0)
1025
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1026
classp = find_class(&mesh, gclass_name);
1027
if (classp == NULL) {
1028
geom_deletetree(&mesh);
1029
errx(EXIT_FAILURE, "Class '%s' not found.", gclass_name);
1030
}
1031
all = gctl_get_int(req, "all");
1032
if (nargs > 0) {
1033
for (i = 0; i < nargs; i++) {
1034
name = gctl_get_ascii(req, "arg%d", i);
1035
gp = find_geom(classp, name);
1036
if (gp == NULL) {
1037
errx(EXIT_FAILURE, "Class '%s' does not have "
1038
"an instance named '%s'.",
1039
gclass_name, name);
1040
}
1041
list_one_geom(gp);
1042
}
1043
} else {
1044
LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1045
if (LIST_EMPTY(&gp->lg_provider) && !all)
1046
continue;
1047
list_one_geom(gp);
1048
}
1049
}
1050
geom_deletetree(&mesh);
1051
}
1052
1053
static int
1054
std_status_available(void)
1055
{
1056
1057
/* 'status' command is available when 'list' command is. */
1058
return (std_list_available());
1059
}
1060
1061
static void
1062
status_update_len(struct ggeom *gp, int *name_len, int *status_len)
1063
{
1064
struct gconfig *conf;
1065
int len;
1066
1067
assert(gp != NULL);
1068
assert(name_len != NULL);
1069
assert(status_len != NULL);
1070
1071
len = strlen(gp->lg_name);
1072
if (*name_len < len)
1073
*name_len = len;
1074
LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1075
if (strcasecmp(conf->lg_name, "state") == 0) {
1076
len = strlen(conf->lg_val);
1077
if (*status_len < len)
1078
*status_len = len;
1079
}
1080
}
1081
}
1082
1083
static void
1084
status_update_len_prs(struct ggeom *gp, int *name_len, int *status_len)
1085
{
1086
struct gprovider *pp;
1087
struct gconfig *conf;
1088
int len, glen;
1089
1090
assert(gp != NULL);
1091
assert(name_len != NULL);
1092
assert(status_len != NULL);
1093
1094
glen = 0;
1095
LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1096
if (strcasecmp(conf->lg_name, "state") == 0) {
1097
glen = strlen(conf->lg_val);
1098
break;
1099
}
1100
}
1101
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1102
len = strlen(pp->lg_name);
1103
if (*name_len < len)
1104
*name_len = len;
1105
len = glen;
1106
LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1107
if (strcasecmp(conf->lg_name, "state") == 0) {
1108
len = strlen(conf->lg_val);
1109
break;
1110
}
1111
}
1112
if (*status_len < len)
1113
*status_len = len;
1114
}
1115
}
1116
1117
static char *
1118
status_one_consumer(struct gconsumer *cp)
1119
{
1120
static char buf[256];
1121
struct gprovider *pp;
1122
struct gconfig *conf;
1123
const char *state, *syncr;
1124
1125
pp = cp->lg_provider;
1126
if (pp == NULL)
1127
return (NULL);
1128
state = NULL;
1129
syncr = NULL;
1130
LIST_FOREACH(conf, &cp->lg_config, lg_config) {
1131
if (strcasecmp(conf->lg_name, "state") == 0)
1132
state = conf->lg_val;
1133
if (strcasecmp(conf->lg_name, "synchronized") == 0)
1134
syncr = conf->lg_val;
1135
}
1136
if (state == NULL && syncr == NULL)
1137
snprintf(buf, sizeof(buf), "%s", pp->lg_name);
1138
else if (state != NULL && syncr != NULL) {
1139
snprintf(buf, sizeof(buf), "%s (%s, %s)", pp->lg_name,
1140
state, syncr);
1141
} else {
1142
snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name,
1143
state ? state : syncr);
1144
}
1145
return (buf);
1146
}
1147
1148
static void
1149
status_one_geom(struct ggeom *gp, int script, int name_len, int status_len)
1150
{
1151
struct gconsumer *cp;
1152
struct gconfig *conf;
1153
const char *name, *status, *component;
1154
int gotone;
1155
1156
name = gp->lg_name;
1157
status = "N/A";
1158
LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1159
if (strcasecmp(conf->lg_name, "state") == 0) {
1160
status = conf->lg_val;
1161
break;
1162
}
1163
}
1164
gotone = 0;
1165
LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1166
component = status_one_consumer(cp);
1167
if (component == NULL)
1168
continue;
1169
gotone = 1;
1170
printf("%*s %*s %s\n", name_len, name, status_len, status,
1171
component);
1172
if (!script)
1173
name = status = "";
1174
}
1175
if (!gotone) {
1176
printf("%*s %*s %s\n", name_len, name, status_len, status,
1177
"N/A");
1178
}
1179
}
1180
1181
static void
1182
status_one_geom_prs(struct ggeom *gp, int script, int name_len, int status_len)
1183
{
1184
struct gprovider *pp;
1185
struct gconsumer *cp;
1186
struct gconfig *conf;
1187
const char *name, *status, *component;
1188
int gotone;
1189
1190
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1191
name = pp->lg_name;
1192
status = "N/A";
1193
LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1194
if (strcasecmp(conf->lg_name, "state") == 0) {
1195
status = conf->lg_val;
1196
break;
1197
}
1198
}
1199
LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1200
if (strcasecmp(conf->lg_name, "state") == 0) {
1201
status = conf->lg_val;
1202
break;
1203
}
1204
}
1205
gotone = 0;
1206
LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1207
component = status_one_consumer(cp);
1208
if (component == NULL)
1209
continue;
1210
gotone = 1;
1211
printf("%*s %*s %s\n", name_len, name,
1212
status_len, status, component);
1213
if (!script)
1214
name = status = "";
1215
}
1216
if (!gotone) {
1217
printf("%*s %*s %s\n", name_len, name,
1218
status_len, status, "N/A");
1219
}
1220
}
1221
}
1222
1223
static void
1224
std_status(struct gctl_req *req, unsigned flags __unused)
1225
{
1226
struct gmesh mesh;
1227
struct gclass *classp;
1228
struct ggeom *gp;
1229
const char *name;
1230
int name_len, status_len;
1231
int all, error, geoms, i, n, nargs, script;
1232
1233
error = geom_gettree(&mesh);
1234
if (error != 0)
1235
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1236
classp = find_class(&mesh, gclass_name);
1237
if (classp == NULL)
1238
errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
1239
nargs = gctl_get_int(req, "nargs");
1240
all = gctl_get_int(req, "all");
1241
geoms = gctl_get_int(req, "geoms");
1242
script = gctl_get_int(req, "script");
1243
if (script) {
1244
name_len = 0;
1245
status_len = 0;
1246
} else {
1247
name_len = strlen("Name");
1248
status_len = strlen("Status");
1249
}
1250
if (nargs > 0) {
1251
for (i = 0, n = 0; i < nargs; i++) {
1252
name = gctl_get_ascii(req, "arg%d", i);
1253
gp = find_geom(classp, name);
1254
if (gp == NULL)
1255
errx(EXIT_FAILURE, "No such geom: %s.", name);
1256
if (geoms) {
1257
status_update_len(gp,
1258
&name_len, &status_len);
1259
} else {
1260
status_update_len_prs(gp,
1261
&name_len, &status_len);
1262
}
1263
n++;
1264
}
1265
if (n == 0)
1266
goto end;
1267
} else {
1268
n = 0;
1269
LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1270
if (LIST_EMPTY(&gp->lg_provider) && !all)
1271
continue;
1272
if (geoms) {
1273
status_update_len(gp,
1274
&name_len, &status_len);
1275
} else {
1276
status_update_len_prs(gp,
1277
&name_len, &status_len);
1278
}
1279
n++;
1280
}
1281
if (n == 0)
1282
goto end;
1283
}
1284
if (!script) {
1285
printf("%*s %*s %s\n", name_len, "Name", status_len, "Status",
1286
"Components");
1287
}
1288
if (nargs > 0) {
1289
for (i = 0; i < nargs; i++) {
1290
name = gctl_get_ascii(req, "arg%d", i);
1291
gp = find_geom(classp, name);
1292
if (gp == NULL)
1293
continue;
1294
if (geoms) {
1295
status_one_geom(gp, script, name_len,
1296
status_len);
1297
} else {
1298
status_one_geom_prs(gp, script, name_len,
1299
status_len);
1300
}
1301
}
1302
} else {
1303
LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1304
if (LIST_EMPTY(&gp->lg_provider) && !all)
1305
continue;
1306
if (geoms) {
1307
status_one_geom(gp, script, name_len,
1308
status_len);
1309
} else {
1310
status_one_geom_prs(gp, script, name_len,
1311
status_len);
1312
}
1313
}
1314
}
1315
end:
1316
geom_deletetree(&mesh);
1317
}
1318
1319
static int
1320
std_load_available(void)
1321
{
1322
char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
1323
struct stat sb;
1324
size_t len;
1325
1326
snprintf(name, sizeof(name), "g_%s", class_name);
1327
/*
1328
* If already in kernel, "load" command is NOP.
1329
*/
1330
if (modfind(name) >= 0)
1331
return (1);
1332
bzero(paths, sizeof(paths));
1333
len = sizeof(paths);
1334
if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
1335
err(EXIT_FAILURE, "sysctl(kern.module_path)");
1336
for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
1337
snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
1338
/*
1339
* If geom_<name>.ko file exists, "load" command is available.
1340
*/
1341
if (stat(name, &sb) == 0)
1342
return (1);
1343
}
1344
return (0);
1345
}
1346
1347
static void
1348
std_load(struct gctl_req *req __unused, unsigned flags)
1349
{
1350
1351
/*
1352
* Do nothing special here, because of G_FLAG_LOADKLD flag,
1353
* module is already loaded.
1354
*/
1355
if ((flags & G_FLAG_VERBOSE) != 0)
1356
printf("Module available.\n");
1357
}
1358
1359
static int
1360
std_unload_available(void)
1361
{
1362
char name[64];
1363
int id;
1364
1365
snprintf(name, sizeof(name), "geom_%s", class_name);
1366
id = kldfind(name);
1367
if (id >= 0)
1368
return (1);
1369
return (0);
1370
}
1371
1372
static void
1373
std_unload(struct gctl_req *req, unsigned flags __unused)
1374
{
1375
char name[64];
1376
int id;
1377
1378
snprintf(name, sizeof(name), "geom_%s", class_name);
1379
id = kldfind(name);
1380
if (id < 0) {
1381
gctl_error(req, "Could not find module: %s.", strerror(errno));
1382
return;
1383
}
1384
if (kldunload(id) < 0) {
1385
gctl_error(req, "Could not unload module: %s.",
1386
strerror(errno));
1387
return;
1388
}
1389
}
1390
1391
static int
1392
std_available(const char *name)
1393
{
1394
1395
if (strcmp(name, "help") == 0)
1396
return (1);
1397
else if (strcmp(name, "list") == 0)
1398
return (std_list_available());
1399
else if (strcmp(name, "status") == 0)
1400
return (std_status_available());
1401
else if (strcmp(name, "load") == 0)
1402
return (std_load_available());
1403
else if (strcmp(name, "unload") == 0)
1404
return (std_unload_available());
1405
else
1406
assert(!"Unknown standard command.");
1407
return (0);
1408
}
1409
1410