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 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
list_one_consumer(struct gconsumer * cp,const char * padding)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
list_one_geom(struct ggeom * gp)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
list_one_geom_by_provider(const char * provider_name)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 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1007
1008 gp = find_geom_by_provider(&mesh, provider_name);
1009 if (gp == NULL)
1010 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
std_help(struct gctl_req * req __unused,unsigned flags __unused)1019 std_help(struct gctl_req *req __unused, unsigned flags __unused)
1020 {
1021
1022 usage();
1023 }
1024
1025 static int
std_list_available(void)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 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
std_list(struct gctl_req * req,unsigned flags __unused)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 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1059 classp = find_class(&mesh, gclass_name);
1060 if (classp == NULL) {
1061 geom_deletetree(&mesh);
1062 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 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
std_status_available(void)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
status_update_len(struct ggeom * gp,int * name_len,int * status_len)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
status_update_len_prs(struct ggeom * gp,int * name_len,int * status_len)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 *
status_one_consumer(struct gconsumer * cp,const char * value)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
status_one_geom(struct ggeom * gp,int script,int name_len,int status_len)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
status_one_geom_prs(struct ggeom * gp,int script,int name_len,int status_len)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
std_status(struct gctl_req * req,unsigned flags __unused)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 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1344 classp = find_class(&mesh, gclass_name);
1345 if (classp == NULL)
1346 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 errx(EXIT_FAILURE, "No such geom: %s.", name);
1360 if (geoms) {
1361 status_update_len(gp,
1362 &name_len, &status_len);
1363 } else {
1364 status_update_len_prs(gp,
1365 &name_len, &status_len);
1366 }
1367 n++;
1368 }
1369 if (n == 0)
1370 goto end;
1371 } else {
1372 n = 0;
1373 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1374 if (LIST_EMPTY(&gp->lg_provider) && !all)
1375 continue;
1376 if (geoms) {
1377 status_update_len(gp,
1378 &name_len, &status_len);
1379 } else {
1380 status_update_len_prs(gp,
1381 &name_len, &status_len);
1382 }
1383 n++;
1384 }
1385 if (n == 0)
1386 goto end;
1387 }
1388 if (!script) {
1389 xo_emit("{T:/%*s} {T:/%*s} {T:Components}\n",
1390 name_len, "Name", status_len, "Status");
1391 }
1392 xo_open_list(gclass_name);
1393 if (nargs > 0) {
1394 for (i = 0; i < nargs; i++) {
1395 name = gctl_get_ascii(req, "arg%d", i);
1396 gp = find_geom(classp, name);
1397 if (gp == NULL)
1398 continue;
1399 if (geoms) {
1400 status_one_geom(gp, script, name_len,
1401 status_len);
1402 } else {
1403 status_one_geom_prs(gp, script, name_len,
1404 status_len);
1405 }
1406 }
1407 } else {
1408 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1409 if (LIST_EMPTY(&gp->lg_provider) && !all)
1410 continue;
1411 if (geoms) {
1412 status_one_geom(gp, script, name_len,
1413 status_len);
1414 } else {
1415 status_one_geom_prs(gp, script, name_len,
1416 status_len);
1417 }
1418 }
1419 }
1420 xo_close_list(gclass_name);
1421 end:
1422 geom_deletetree(&mesh);
1423 }
1424
1425 static int
std_load_available(void)1426 std_load_available(void)
1427 {
1428 char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
1429 struct stat sb;
1430 size_t len;
1431
1432 snprintf(name, sizeof(name), "g_%s", class_name);
1433 /*
1434 * If already in kernel, "load" command is NOP.
1435 */
1436 if (modfind(name) >= 0)
1437 return (1);
1438 bzero(paths, sizeof(paths));
1439 len = sizeof(paths);
1440 if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
1441 err(EXIT_FAILURE, "sysctl(kern.module_path)");
1442 for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
1443 snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
1444 /*
1445 * If geom_<name>.ko file exists, "load" command is available.
1446 */
1447 if (stat(name, &sb) == 0)
1448 return (1);
1449 }
1450 return (0);
1451 }
1452
1453 static void
std_load(struct gctl_req * req __unused,unsigned flags)1454 std_load(struct gctl_req *req __unused, unsigned flags)
1455 {
1456
1457 /*
1458 * Do nothing special here, because of G_FLAG_LOADKLD flag,
1459 * module is already loaded.
1460 */
1461 if ((flags & G_FLAG_VERBOSE) != 0)
1462 printf("Module available.\n");
1463 }
1464
1465 static int
std_unload_available(void)1466 std_unload_available(void)
1467 {
1468 char name[64];
1469 int id;
1470
1471 snprintf(name, sizeof(name), "geom_%s", class_name);
1472 id = kldfind(name);
1473 if (id >= 0)
1474 return (1);
1475 return (0);
1476 }
1477
1478 static void
std_unload(struct gctl_req * req,unsigned flags __unused)1479 std_unload(struct gctl_req *req, unsigned flags __unused)
1480 {
1481 char name[64];
1482 int id;
1483
1484 snprintf(name, sizeof(name), "geom_%s", class_name);
1485 id = kldfind(name);
1486 if (id < 0) {
1487 gctl_error(req, "Could not find module: %s.", strerror(errno));
1488 return;
1489 }
1490 if (kldunload(id) < 0) {
1491 gctl_error(req, "Could not unload module: %s.",
1492 strerror(errno));
1493 return;
1494 }
1495 }
1496
1497 static int
std_available(const char * name)1498 std_available(const char *name)
1499 {
1500
1501 if (strcmp(name, "help") == 0)
1502 return (1);
1503 else if (strcmp(name, "list") == 0)
1504 return (std_list_available());
1505 else if (strcmp(name, "status") == 0)
1506 return (std_status_available());
1507 else if (strcmp(name, "load") == 0)
1508 return (std_load_available());
1509 else if (strcmp(name, "unload") == 0)
1510 return (std_unload_available());
1511 else
1512 assert(!"Unknown standard command.");
1513 return (0);
1514 }
1515