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 xo_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 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
parse_arguments(struct g_command * cmd,struct gctl_req * req,int * argc,char *** argv)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 *
find_command(const char * cmdstr,int flags)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
set_flags(struct g_command * cmd)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
run_command(int argc,char * argv[])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 *
library_path(void)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
load_library(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
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 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
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 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 *
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 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
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 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 *
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 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
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 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
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 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
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 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
std_load_available(void)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
std_load(struct gctl_req * req __unused,unsigned flags)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
std_unload_available(void)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
std_unload(struct gctl_req * req,unsigned flags __unused)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
std_available(const char * name)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