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