1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd@FreeBSD.org>
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
usage_command(struct g_command * cmd,const char * prefix)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
usage(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
load_module(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 err(EXIT_FAILURE, "cannot load %s", name2);
205 }
206 }
207 }
208 }
209
210 static int
strlcatf(char * str,size_t size,const char * format,...)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 *
find_option(struct g_command * cmd,char ch)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
set_option(struct gctl_req * req,struct g_option * opt,const char * val)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 errx(EXIT_FAILURE, "Too many -%c options.", opt->go_char);
263
264 /*
265 * Base option name length plus 3 bytes for option number
266 * (max. 255 options) plus 1 byte for terminating '\0'.
267 */
268 optnamesize = strlen(opt->go_name) + 3 + 1;
269 ptr = malloc(optnamesize);
270 if (ptr == NULL)
271 errx(EXIT_FAILURE, "No memory.");
272 snprintf(ptr, optnamesize, "%s%u", opt->go_name, G_OPT_NUM(opt));
273 G_OPT_NUMINC(opt);
274 optname = ptr;
275 } else {
276 optname = opt->go_name;
277 }
278
279 if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) {
280 if (expand_number(val, &number) == -1) {
281 err(EXIT_FAILURE, "Invalid value for '%c' argument",
282 opt->go_char);
283 }
284 ptr = malloc(sizeof(intmax_t));
285 if (ptr == NULL)
286 errx(EXIT_FAILURE, "No memory.");
287 *(intmax_t *)ptr = number;
288 opt->go_val = ptr;
289 gctl_ro_param(req, optname, sizeof(intmax_t), opt->go_val);
290 } else if (G_OPT_TYPE(opt) == G_TYPE_STRING) {
291 gctl_ro_param(req, optname, -1, val);
292 } else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
293 ptr = malloc(sizeof(int));
294 if (ptr == NULL)
295 errx(EXIT_FAILURE, "No memory.");
296 *(int *)ptr = *val - '0';
297 opt->go_val = ptr;
298 gctl_ro_param(req, optname, sizeof(int), opt->go_val);
299 } else {
300 assert(!"Invalid type");
301 }
302
303 if (G_OPT_ISMULTI(opt))
304 free(__DECONST(char *, optname));
305 }
306
307 /*
308 * 1. Add given argument by caller.
309 * 2. Add default values of not given arguments.
310 * 3. Add the rest of arguments.
311 */
312 static void
parse_arguments(struct g_command * cmd,struct gctl_req * req,int * argc,char *** argv)313 parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
314 char ***argv)
315 {
316 struct g_option *opt;
317 char opts[64];
318 unsigned i;
319 int ch, vcount;
320
321 *opts = '\0';
322 if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
323 strlcat(opts, "v", sizeof(opts));
324 for (i = 0; ; i++) {
325 opt = &cmd->gc_options[i];
326 if (opt->go_name == NULL)
327 break;
328 assert(G_OPT_TYPE(opt) != 0);
329 assert((opt->go_type & ~(G_TYPE_MASK | G_TYPE_MULTI)) == 0);
330 /* Multiple bool arguments makes no sense. */
331 assert(G_OPT_TYPE(opt) != G_TYPE_BOOL ||
332 (opt->go_type & G_TYPE_MULTI) == 0);
333 strlcatf(opts, sizeof(opts), "%c", opt->go_char);
334 if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
335 strlcat(opts, ":", sizeof(opts));
336 }
337
338 /*
339 * Add specified arguments.
340 */
341 vcount = 0;
342 while ((ch = getopt(*argc, *argv, opts)) != -1) {
343 /* Standard (not passed to kernel) options. */
344 if (ch == 'v' && (cmd->gc_flags & G_FLAG_VERBOSE) != 0)
345 verbose = 1;
346 /* Options passed to kernel. */
347 opt = find_option(cmd, ch);
348 if (opt == NULL) {
349 if (ch == 'v' && (cmd->gc_flags & G_FLAG_VERBOSE) != 0){
350 if (++vcount < 2)
351 continue;
352 else
353 warnx("Option 'v' specified twice.");
354 }
355 usage();
356 }
357 if (!G_OPT_ISMULTI(opt) && G_OPT_ISDONE(opt)) {
358 warnx("Option '%c' specified twice.", opt->go_char);
359 usage();
360 }
361 G_OPT_DONE(opt);
362
363 if (G_OPT_TYPE(opt) == G_TYPE_BOOL)
364 set_option(req, opt, "1");
365 else
366 set_option(req, opt, optarg);
367 }
368 *argc -= optind;
369 *argv += optind;
370
371 /*
372 * Add not specified arguments, but with default values.
373 */
374 for (i = 0; ; i++) {
375 opt = &cmd->gc_options[i];
376 if (opt->go_name == NULL)
377 break;
378 if (G_OPT_ISDONE(opt))
379 continue;
380
381 if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
382 assert(opt->go_val == NULL);
383 set_option(req, opt, "0");
384 } else {
385 if (opt->go_val == NULL) {
386 warnx("Option '%c' not specified.",
387 opt->go_char);
388 usage();
389 } else if (opt->go_val == G_VAL_OPTIONAL) {
390 /* add nothing. */
391 } else {
392 set_option(req, opt, opt->go_val);
393 }
394 }
395 }
396
397 /*
398 * Add rest of given arguments.
399 */
400 gctl_ro_param(req, "nargs", sizeof(int), argc);
401 for (i = 0; i < (unsigned)*argc; i++) {
402 char argname[16];
403
404 snprintf(argname, sizeof(argname), "arg%u", i);
405 gctl_ro_param(req, argname, -1, (*argv)[i]);
406 }
407 }
408
409 /*
410 * Find given command in commands available for given class.
411 */
412 static struct g_command *
find_command(const char * cmdstr,int flags)413 find_command(const char *cmdstr, int flags)
414 {
415 struct g_command *cmd;
416 unsigned i;
417
418 /*
419 * First try to find command defined by loaded library.
420 */
421 if ((flags & GEOM_CLASS_CMDS) != 0 && class_commands != NULL) {
422 for (i = 0; ; i++) {
423 cmd = &class_commands[i];
424 if (cmd->gc_name == NULL)
425 break;
426 if (strcmp(cmd->gc_name, cmdstr) == 0)
427 return (cmd);
428 }
429 }
430 /*
431 * Now try to find in standard commands.
432 */
433 if ((flags & GEOM_STD_CMDS) != 0) {
434 for (i = 0; ; i++) {
435 cmd = &std_commands[i];
436 if (cmd->gc_name == NULL)
437 break;
438 if (strcmp(cmd->gc_name, cmdstr) == 0)
439 return (cmd);
440 }
441 }
442 return (NULL);
443 }
444
445 static unsigned
set_flags(struct g_command * cmd)446 set_flags(struct g_command *cmd)
447 {
448 unsigned flags = 0;
449
450 if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
451 flags |= G_FLAG_VERBOSE;
452
453 return (flags);
454 }
455
456 /*
457 * Run command.
458 */
459 static void
run_command(int argc,char * argv[])460 run_command(int argc, char *argv[])
461 {
462 struct g_command *cmd;
463 struct gctl_req *req;
464 const char *errstr;
465 char buf[4096];
466
467 /* First try to find a command defined by a class. */
468 cmd = find_command(argv[0], GEOM_CLASS_CMDS);
469 if (cmd == NULL) {
470 /* Now, try to find a standard command. */
471 cmd = find_command(argv[0], GEOM_STD_CMDS);
472 if (cmd == NULL) {
473 warnx("Unknown command: %s.", argv[0]);
474 usage();
475 }
476 if (!std_available(cmd->gc_name)) {
477 warnx("Command '%s' not available; "
478 "try 'load' first.", argv[0]);
479 exit(EXIT_FAILURE);
480 }
481 }
482 if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
483 load_module();
484
485 req = gctl_get_handle();
486 gctl_ro_param(req, "class", -1, gclass_name);
487 gctl_ro_param(req, "verb", -1, argv[0]);
488 if (version != NULL)
489 gctl_ro_param(req, "version", sizeof(*version), version);
490 parse_arguments(cmd, req, &argc, &argv);
491
492 buf[0] = '\0';
493 if (cmd->gc_func != NULL) {
494 unsigned flags;
495
496 flags = set_flags(cmd);
497 cmd->gc_func(req, flags);
498 errstr = req->error;
499 } else {
500 gctl_add_param(req, "output", sizeof(buf), buf,
501 GCTL_PARAM_WR | GCTL_PARAM_ASCII);
502 errstr = gctl_issue(req);
503 }
504 if (errstr != NULL && errstr[0] != '\0') {
505 warnx("%s", errstr);
506 /* Suppress EXIT_FAILURE for warnings */
507 if (strncmp(errstr, "warning: ", strlen("warning: ")) == 0)
508 req->nerror = 0;
509 if (req->nerror != 0) {
510 gctl_free(req);
511 exit(EXIT_FAILURE);
512 }
513 }
514 if (buf[0] != '\0')
515 printf("%s", buf);
516 gctl_free(req);
517 if (verbose)
518 printf("Done.\n");
519 xo_finish();
520 exit(EXIT_SUCCESS);
521 }
522
523 #ifndef STATIC_GEOM_CLASSES
524 static const char *
library_path(void)525 library_path(void)
526 {
527 const char *path;
528
529 path = getenv("GEOM_LIBRARY_PATH");
530 if (path == NULL)
531 path = GEOM_CLASS_DIR;
532 return (path);
533 }
534
535 static void
load_library(void)536 load_library(void)
537 {
538 char *curpath, path[MAXPATHLEN], *tofree, *totalpath;
539 uint32_t *lib_version;
540 void *dlh;
541 int ret;
542
543 ret = 0;
544 tofree = totalpath = strdup(library_path());
545 if (totalpath == NULL)
546 err(EXIT_FAILURE, "Not enough memory for library path");
547
548 if (strchr(totalpath, ':') != NULL)
549 curpath = strsep(&totalpath, ":");
550 else
551 curpath = totalpath;
552 /* Traverse the paths to find one that contains the library we want. */
553 while (curpath != NULL) {
554 snprintf(path, sizeof(path), "%s/geom_%s.so", curpath,
555 class_name);
556 ret = access(path, F_OK);
557 if (ret == -1) {
558 if (errno == ENOENT) {
559 /*
560 * If we cannot find library, try the next
561 * path.
562 */
563 curpath = strsep(&totalpath, ":");
564 continue;
565 }
566 err(EXIT_FAILURE, "Cannot access library");
567 }
568 break;
569 }
570 free(tofree);
571 /* No library was found, but standard commands can still be used */
572 if (ret == -1)
573 return;
574 dlh = dlopen(path, RTLD_NOW);
575 if (dlh == NULL)
576 errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror());
577 lib_version = dlsym(dlh, "lib_version");
578 if (lib_version == NULL) {
579 warnx("Cannot find symbol %s: %s.", "lib_version", dlerror());
580 dlclose(dlh);
581 exit(EXIT_FAILURE);
582 }
583 if (*lib_version != G_LIB_VERSION) {
584 dlclose(dlh);
585 errx(EXIT_FAILURE, "%s and %s are not synchronized.",
586 getprogname(), path);
587 }
588 version = dlsym(dlh, "version");
589 if (version == NULL) {
590 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 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
set_class_name(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 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
get_class(int * argc,char *** argv)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 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 errx(EXIT_FAILURE, "Invalid class name '%s'.", class_name);
668
669 if (*argc < 1)
670 usage();
671 }
672
673 static struct ggeom *
find_geom_by_provider(struct gmesh * mesh,const char * name)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
compute_tree_width_geom(struct gmesh * mesh,struct ggeom * gp,int indent)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
compute_tree_width(struct gmesh * mesh)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
show_tree_geom(struct gmesh * mesh,struct ggeom * gp,int indent,int width)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
show_tree(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 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
main(int argc,char * argv[])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 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 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 *
find_class(struct gmesh * mesh,const char * name)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 *
find_geom(struct gclass * classp,const char * name)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
list_one_provider(struct gprovider * pp,const char * padding)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 xo_emit("{P:/%s}{Lcwa:}{a:}\n", padding, conf->lg_name,
916 conf->lg_name, conf->lg_val ? conf->lg_val : "");
917 }
918 }
919
920 static void
list_one_consumer(struct gconsumer * cp,const char * padding)921 list_one_consumer(struct gconsumer *cp, const char *padding)
922 {
923 struct gprovider *pp;
924 struct gconfig *conf;
925
926 pp = cp->lg_provider;
927 if (pp == NULL)
928 printf("[no provider]\n");
929 else {
930 char buf[5];
931
932 xo_emit("{Lcw:Name}{:name}\n", pp->lg_name);
933 humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
934 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
935 xo_emit("{P:/%s}{Lcw:Mediasize}{:mediasize/%jd} ({N:/%s})\n",
936 padding, (intmax_t)pp->lg_mediasize, buf);
937 xo_emit("{P:/%s}{Lcw:Sectorsize}{:sectorsize/%u}\n",
938 padding, pp->lg_sectorsize);
939 if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
940 xo_emit("{P:/%s}{Lcw:Stripesize}{:stripesize/%ju}\n",
941 padding, pp->lg_stripesize);
942 xo_emit("{P:/%s}{Lcw:Stripeoffset}{:stripeoffset/%ju}\n",
943 padding, pp->lg_stripeoffset);
944 }
945 xo_emit("{P:/%s}{Lcw:Mode}{:mode}\n", padding, pp->lg_mode);
946 }
947 LIST_FOREACH(conf, &cp->lg_config, lg_config) {
948 xo_emit("{P:/%s}{Lcwa:}{a:}\n", padding, conf->lg_name,
949 conf->lg_name, conf->lg_val ? conf->lg_val : "");
950 }
951 }
952
953 static void
list_one_geom(struct ggeom * gp)954 list_one_geom(struct ggeom *gp)
955 {
956 struct gprovider *pp;
957 struct gconsumer *cp;
958 struct gconfig *conf;
959 unsigned n;
960
961 xo_emit("{Lcw:Geom name}{:name}\n", gp->lg_name);
962 LIST_FOREACH(conf, &gp->lg_config, lg_config) {
963 xo_emit("{Lcwa:}{a:}\n", conf->lg_name, conf->lg_name,
964 conf->lg_val ? conf->lg_val : "");
965 }
966 if (!LIST_EMPTY(&gp->lg_provider)) {
967 xo_open_list("providers");
968 xo_emit("{Tc:Providers}\n");
969 n = 1;
970 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
971 xo_emit("{T:/%u}. ", n++);
972 xo_open_instance("provider");
973 list_one_provider(pp, " ");
974 xo_close_instance("provider");
975 }
976 xo_close_list("providers");
977 }
978 if (!LIST_EMPTY(&gp->lg_consumer)) {
979 xo_open_list("consumers");
980 xo_emit("{Tc:Consumers}\n");
981 n = 1;
982 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
983 xo_emit("{T:/%u}. ", n++);
984 xo_open_instance("consumer");
985 list_one_consumer(cp, " ");
986 xo_close_instance("consumer");
987 }
988 xo_close_list("consumers");
989 }
990 xo_emit("\n");
991 }
992
993 static void
list_one_geom_by_provider(const char * provider_name)994 list_one_geom_by_provider(const char *provider_name)
995 {
996 struct gmesh mesh;
997 struct ggeom *gp;
998 int error;
999
1000 error = geom_gettree(&mesh);
1001 if (error != 0)
1002 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1003
1004 gp = find_geom_by_provider(&mesh, provider_name);
1005 if (gp == NULL)
1006 errx(EXIT_FAILURE, "Cannot find provider '%s'.", provider_name);
1007
1008 xo_open_container(provider_name);
1009 xo_emit("{Lwc:Geom class}{:class}\n", gp->lg_class->lg_name);
1010 list_one_geom(gp);
1011 xo_close_container(provider_name);
1012 }
1013
1014 static void
std_help(struct gctl_req * req __unused,unsigned flags __unused)1015 std_help(struct gctl_req *req __unused, unsigned flags __unused)
1016 {
1017
1018 usage();
1019 }
1020
1021 static int
std_list_available(void)1022 std_list_available(void)
1023 {
1024 struct gmesh mesh;
1025 struct gclass *classp;
1026 int error;
1027
1028 error = geom_gettree_geom(&mesh, gclass_name, "", 0);
1029 if (error != 0)
1030 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1031 classp = find_class(&mesh, gclass_name);
1032 geom_deletetree(&mesh);
1033 if (classp != NULL)
1034 return (1);
1035 return (0);
1036 }
1037
1038 static void
std_list(struct gctl_req * req,unsigned flags __unused)1039 std_list(struct gctl_req *req, unsigned flags __unused)
1040 {
1041 struct gmesh mesh;
1042 struct gclass *classp;
1043 struct ggeom *gp;
1044 const char *name;
1045 int all, error, i, nargs;
1046
1047 nargs = gctl_get_int(req, "nargs");
1048 if (nargs == 1) {
1049 error = geom_gettree_geom(&mesh, gclass_name,
1050 gctl_get_ascii(req, "arg0"), 1);
1051 } else
1052 error = geom_gettree(&mesh);
1053 if (error != 0)
1054 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1055 classp = find_class(&mesh, gclass_name);
1056 if (classp == NULL) {
1057 geom_deletetree(&mesh);
1058 errx(EXIT_FAILURE, "Class '%s' not found.", gclass_name);
1059 }
1060 all = gctl_get_int(req, "all");
1061 if (nargs > 0) {
1062 for (i = 0; i < nargs; i++) {
1063 name = gctl_get_ascii(req, "arg%d", i);
1064 gp = find_geom(classp, name);
1065 if (gp == NULL) {
1066 errx(EXIT_FAILURE, "Class '%s' does not have "
1067 "an instance named '%s'.",
1068 gclass_name, name);
1069 }
1070 xo_open_container(gclass_name);
1071 list_one_geom(gp);
1072 xo_close_container(gclass_name);
1073 }
1074 } else {
1075 xo_open_list(gclass_name);
1076 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1077 if (LIST_EMPTY(&gp->lg_provider) && !all)
1078 continue;
1079 xo_open_instance("geom");
1080 list_one_geom(gp);
1081 xo_close_instance("geom");
1082 }
1083 xo_close_list(gclass_name);
1084 }
1085 geom_deletetree(&mesh);
1086 }
1087
1088 static int
std_status_available(void)1089 std_status_available(void)
1090 {
1091
1092 /* 'status' command is available when 'list' command is. */
1093 return (std_list_available());
1094 }
1095
1096 static void
status_update_len(struct ggeom * gp,int * name_len,int * status_len)1097 status_update_len(struct ggeom *gp, int *name_len, int *status_len)
1098 {
1099 struct gconfig *conf;
1100 int len;
1101
1102 assert(gp != NULL);
1103 assert(name_len != NULL);
1104 assert(status_len != NULL);
1105
1106 len = strlen(gp->lg_name);
1107 if (*name_len < len)
1108 *name_len = len;
1109 LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1110 if (strcasecmp(conf->lg_name, "state") == 0) {
1111 len = strlen(conf->lg_val);
1112 if (*status_len < len)
1113 *status_len = len;
1114 }
1115 }
1116 }
1117
1118 static void
status_update_len_prs(struct ggeom * gp,int * name_len,int * status_len)1119 status_update_len_prs(struct ggeom *gp, int *name_len, int *status_len)
1120 {
1121 struct gprovider *pp;
1122 struct gconfig *conf;
1123 int len, glen;
1124
1125 assert(gp != NULL);
1126 assert(name_len != NULL);
1127 assert(status_len != NULL);
1128
1129 glen = 0;
1130 LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1131 if (strcasecmp(conf->lg_name, "state") == 0) {
1132 glen = strlen(conf->lg_val);
1133 break;
1134 }
1135 }
1136 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1137 len = strlen(pp->lg_name);
1138 if (*name_len < len)
1139 *name_len = len;
1140 len = glen;
1141 LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1142 if (strcasecmp(conf->lg_name, "state") == 0) {
1143 len = strlen(conf->lg_val);
1144 break;
1145 }
1146 }
1147 if (*status_len < len)
1148 *status_len = len;
1149 }
1150 }
1151
1152 static char *
status_one_consumer(struct gconsumer * cp,const char * value)1153 status_one_consumer(struct gconsumer *cp, const char *value)
1154 {
1155 struct gprovider *pp;
1156 struct gconfig *conf;
1157 char *ret;
1158
1159 pp = cp->lg_provider;
1160 if (pp == NULL)
1161 return (NULL);
1162 ret = NULL;
1163 LIST_FOREACH(conf, &cp->lg_config, lg_config) {
1164 if (strcasecmp(conf->lg_name, value) == 0)
1165 ret = conf->lg_val;
1166 }
1167
1168 if (ret == NULL)
1169 return (NULL);
1170 return (ret);
1171 }
1172
1173 static void
status_one_geom(struct ggeom * gp,int script,int name_len,int status_len)1174 status_one_geom(struct ggeom *gp, int script, int name_len, int status_len)
1175 {
1176 struct gconsumer *cp;
1177 struct gconfig *conf;
1178 char fmt[64];
1179 const char *name, *status, *cstate, *csyncr;
1180 int gotone, len;
1181
1182 name = gp->lg_name;
1183 status = "N/A";
1184 LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1185 if (strcasecmp(conf->lg_name, "state") == 0) {
1186 status = conf->lg_val;
1187 break;
1188 }
1189 }
1190 gotone = len = 0;
1191 xo_open_instance("status");
1192 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1193 if (cp->lg_provider == NULL)
1194 continue;
1195
1196 cstate = status_one_consumer(cp, "state");
1197 csyncr = status_one_consumer(cp, "synchronized");
1198 if (!gotone || script) {
1199 if (!gotone) {
1200 xo_emit("{t:name/%*s} {t:status/%*s} ",
1201 name_len, name, status_len, status);
1202 xo_open_list("components");
1203 } else {
1204 /*
1205 * XXX: running the same xo_emit() as above or
1206 * variations of it will cause the XML/JSON to
1207 * produce extra "components" lists in script
1208 * mode
1209 */
1210
1211 snprintf(fmt, sizeof(fmt), "%*s %*s ",
1212 name_len, name, status_len, status);
1213 xo_emit(fmt);
1214 }
1215 }
1216
1217 xo_open_instance("components");
1218 if (cstate != NULL && csyncr != NULL) {
1219 xo_emit("{P:/%*s}{:component} ({:state}, {:synchronized})\n",
1220 len, "", cp->lg_provider->lg_name, cstate, csyncr);
1221 } else if (cstate != NULL) {
1222 xo_emit("{P:/%*s}{:component} ({:state})\n",
1223 len, "", cp->lg_provider->lg_name, cstate);
1224 } else if (csyncr != NULL) {
1225 xo_emit("{P:/%*s}{:component} ({:synchronized})\n",
1226 len, "", cp->lg_provider->lg_name, csyncr);
1227 } else {
1228 xo_emit("{P:/%*s}{:component}\n",
1229 len, "", cp->lg_provider->lg_name);
1230 }
1231 xo_close_instance("components");
1232 gotone = 1;
1233 if (!len && !script)
1234 len = name_len + status_len + 4;
1235 }
1236 if (!gotone) {
1237 xo_emit("{t:name/%*s} {t:status/%*s} N/A\n",
1238 name_len, name, status_len, status);
1239 } else {
1240 xo_close_list("components");
1241 }
1242 xo_close_instance("status");
1243 }
1244
1245 static void
status_one_geom_prs(struct ggeom * gp,int script,int name_len,int status_len)1246 status_one_geom_prs(struct ggeom *gp, int script, int name_len, int status_len)
1247 {
1248 struct gprovider *pp;
1249 struct gconsumer *cp;
1250 struct gconfig *conf;
1251 const char *name, *status, *cstate, *csyncr;
1252 char fmt[64];
1253 int gotone, len;
1254
1255 xo_open_instance("status");
1256 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1257 name = pp->lg_name;
1258 status = "N/A";
1259 LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1260 if (strcasecmp(conf->lg_name, "state") == 0) {
1261 status = conf->lg_val;
1262 break;
1263 }
1264 }
1265 LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1266 if (strcasecmp(conf->lg_name, "state") == 0) {
1267 status = conf->lg_val;
1268 break;
1269 }
1270 }
1271 gotone = len = 0;
1272 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1273 if (cp->lg_provider == NULL)
1274 continue;
1275
1276 cstate = status_one_consumer(cp, "state");
1277 csyncr = status_one_consumer(cp, "synchronized");
1278 if (!gotone || script) {
1279 if (!gotone) {
1280 xo_emit("{t:name/%*s} {t:status/%*s} ",
1281 name_len, name, status_len, status);
1282 xo_open_list("components");
1283 } else {
1284 /*
1285 * XXX: running the same xo_emit() as
1286 * above or variations of it will
1287 * cause the XML/JSON to produce
1288 * extra "components" lists in
1289 * script mode
1290 */
1291
1292 snprintf(fmt, sizeof(fmt), "%*s %*s ",
1293 name_len, name, status_len, status);
1294 xo_emit(fmt);
1295 }
1296 }
1297
1298 xo_open_instance("component");
1299 if (cstate != NULL && csyncr != NULL) {
1300 xo_emit("{P:/%*s}{:component} ({:state}, {:synchronized})\n",
1301 len, "", cp->lg_provider->lg_name, cstate, csyncr);
1302 } else if (cstate != NULL) {
1303 xo_emit("{P:/%*s}{:component} ({:state})\n",
1304 len, "", cp->lg_provider->lg_name, cstate);
1305 } else if (csyncr != NULL) {
1306 xo_emit("{P:/%*s}{:component} ({:synchronized})\n",
1307 len, "", cp->lg_provider->lg_name, csyncr);
1308 } else {
1309 xo_emit("{P:/%*s}{:component}\n",
1310 len, "", cp->lg_provider->lg_name);
1311 }
1312 xo_close_instance("component");
1313 gotone = 1;
1314 if (!len && !script)
1315 len = name_len + status_len + 4;
1316 }
1317 if (!gotone) {
1318 xo_emit("{t:name/%*s} {t:status/%*s} N/A\n",
1319 name_len, name, status_len, status);
1320 } else {
1321 xo_close_list("components");
1322 }
1323 }
1324 xo_close_instance("status");
1325 }
1326
1327 static void
std_status(struct gctl_req * req,unsigned flags __unused)1328 std_status(struct gctl_req *req, unsigned flags __unused)
1329 {
1330 struct gmesh mesh;
1331 struct gclass *classp;
1332 struct ggeom *gp;
1333 const char *name;
1334 int name_len, status_len;
1335 int all, error, geoms, i, n, nargs, script;
1336
1337 error = geom_gettree(&mesh);
1338 if (error != 0)
1339 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1340 classp = find_class(&mesh, gclass_name);
1341 if (classp == NULL)
1342 errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
1343 nargs = gctl_get_int(req, "nargs");
1344 all = gctl_get_int(req, "all");
1345 geoms = gctl_get_int(req, "geoms");
1346 script = gctl_get_int(req, "script");
1347 name_len = strlen("Name");
1348 status_len = strlen("Status");
1349
1350 if (nargs > 0) {
1351 for (i = 0, n = 0; i < nargs; i++) {
1352 name = gctl_get_ascii(req, "arg%d", i);
1353 gp = find_geom(classp, name);
1354 if (gp == NULL)
1355 errx(EXIT_FAILURE, "No such geom: %s.", name);
1356 if (geoms) {
1357 status_update_len(gp,
1358 &name_len, &status_len);
1359 } else {
1360 status_update_len_prs(gp,
1361 &name_len, &status_len);
1362 }
1363 n++;
1364 }
1365 if (n == 0)
1366 goto end;
1367 } else {
1368 n = 0;
1369 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1370 if (LIST_EMPTY(&gp->lg_provider) && !all)
1371 continue;
1372 if (geoms) {
1373 status_update_len(gp,
1374 &name_len, &status_len);
1375 } else {
1376 status_update_len_prs(gp,
1377 &name_len, &status_len);
1378 }
1379 n++;
1380 }
1381 if (n == 0)
1382 goto end;
1383 }
1384 if (!script) {
1385 xo_emit("{T:/%*s} {T:/%*s} {T:Components}\n",
1386 name_len, "Name", status_len, "Status");
1387 }
1388 xo_open_list(gclass_name);
1389 if (nargs > 0) {
1390 for (i = 0; i < nargs; i++) {
1391 name = gctl_get_ascii(req, "arg%d", i);
1392 gp = find_geom(classp, name);
1393 if (gp == NULL)
1394 continue;
1395 if (geoms) {
1396 status_one_geom(gp, script, name_len,
1397 status_len);
1398 } else {
1399 status_one_geom_prs(gp, script, name_len,
1400 status_len);
1401 }
1402 }
1403 } else {
1404 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1405 if (LIST_EMPTY(&gp->lg_provider) && !all)
1406 continue;
1407 if (geoms) {
1408 status_one_geom(gp, script, name_len,
1409 status_len);
1410 } else {
1411 status_one_geom_prs(gp, script, name_len,
1412 status_len);
1413 }
1414 }
1415 }
1416 xo_close_list(gclass_name);
1417 end:
1418 geom_deletetree(&mesh);
1419 }
1420
1421 static int
std_load_available(void)1422 std_load_available(void)
1423 {
1424 char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
1425 struct stat sb;
1426 size_t len;
1427
1428 snprintf(name, sizeof(name), "g_%s", class_name);
1429 /*
1430 * If already in kernel, "load" command is NOP.
1431 */
1432 if (modfind(name) >= 0)
1433 return (1);
1434 bzero(paths, sizeof(paths));
1435 len = sizeof(paths);
1436 if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
1437 err(EXIT_FAILURE, "sysctl(kern.module_path)");
1438 for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
1439 snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
1440 /*
1441 * If geom_<name>.ko file exists, "load" command is available.
1442 */
1443 if (stat(name, &sb) == 0)
1444 return (1);
1445 }
1446 return (0);
1447 }
1448
1449 static void
std_load(struct gctl_req * req __unused,unsigned flags)1450 std_load(struct gctl_req *req __unused, unsigned flags)
1451 {
1452
1453 /*
1454 * Do nothing special here, because of G_FLAG_LOADKLD flag,
1455 * module is already loaded.
1456 */
1457 if ((flags & G_FLAG_VERBOSE) != 0)
1458 printf("Module available.\n");
1459 }
1460
1461 static int
std_unload_available(void)1462 std_unload_available(void)
1463 {
1464 char name[64];
1465 int id;
1466
1467 snprintf(name, sizeof(name), "geom_%s", class_name);
1468 id = kldfind(name);
1469 if (id >= 0)
1470 return (1);
1471 return (0);
1472 }
1473
1474 static void
std_unload(struct gctl_req * req,unsigned flags __unused)1475 std_unload(struct gctl_req *req, unsigned flags __unused)
1476 {
1477 char name[64];
1478 int id;
1479
1480 snprintf(name, sizeof(name), "geom_%s", class_name);
1481 id = kldfind(name);
1482 if (id < 0) {
1483 gctl_error(req, "Could not find module: %s.", strerror(errno));
1484 return;
1485 }
1486 if (kldunload(id) < 0) {
1487 gctl_error(req, "Could not unload module: %s.",
1488 strerror(errno));
1489 return;
1490 }
1491 }
1492
1493 static int
std_available(const char * name)1494 std_available(const char *name)
1495 {
1496
1497 if (strcmp(name, "help") == 0)
1498 return (1);
1499 else if (strcmp(name, "list") == 0)
1500 return (std_list_available());
1501 else if (strcmp(name, "status") == 0)
1502 return (std_status_available());
1503 else if (strcmp(name, "load") == 0)
1504 return (std_load_available());
1505 else if (strcmp(name, "unload") == 0)
1506 return (std_unload_available());
1507 else
1508 assert(!"Unknown standard command.");
1509 return (0);
1510 }
1511