xref: /freebsd/sbin/geom/core/geom.c (revision 1ddff51060ad759e35dcc4716b0bdcdb40255862)
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
112 usage_command(struct g_command *cmd, const char *prefix)
113 {
114 	struct g_option *opt;
115 	unsigned i;
116 
117 	if (cmd->gc_usage != NULL) {
118 		char *pos, *ptr, *sptr;
119 
120 		sptr = ptr = strdup(cmd->gc_usage);
121 		while ((pos = strsep(&ptr, "\n")) != NULL) {
122 			if (*pos == '\0')
123 				continue;
124 			fprintf(stderr, "%s %s %s %s\n", prefix, comm,
125 			    cmd->gc_name, pos);
126 		}
127 		free(sptr);
128 		return;
129 	}
130 
131 	fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name);
132 	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
133 		fprintf(stderr, " [-v]");
134 	for (i = 0; ; i++) {
135 		opt = &cmd->gc_options[i];
136 		if (opt->go_name == NULL)
137 			break;
138 		if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
139 			fprintf(stderr, " [");
140 		else
141 			fprintf(stderr, " ");
142 		fprintf(stderr, "-%c", opt->go_char);
143 		if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
144 			fprintf(stderr, " %s", opt->go_name);
145 		if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
146 			fprintf(stderr, "]");
147 	}
148 	fprintf(stderr, "\n");
149 }
150 
151 static void
152 usage(void)
153 {
154 
155 	if (class_name == NULL) {
156 		fprintf(stderr, "usage: geom <class> <command> [options]\n");
157 		fprintf(stderr, "       geom -p <provider-name>\n");
158 		fprintf(stderr, "       geom -t\n");
159 		exit(EXIT_FAILURE);
160 	} else {
161 		struct g_command *cmd;
162 		const char *prefix;
163 		unsigned i;
164 
165 		prefix = "usage:";
166 		if (class_commands != NULL) {
167 			for (i = 0; ; i++) {
168 				cmd = &class_commands[i];
169 				if (cmd->gc_name == NULL)
170 					break;
171 				usage_command(cmd, prefix);
172 				prefix = "      ";
173 			}
174 		}
175 		for (i = 0; ; i++) {
176 			cmd = &std_commands[i];
177 			if (cmd->gc_name == NULL)
178 				break;
179 			/*
180 			 * If class defines command, which has the same name as
181 			 * standard command, skip it, because it was already
182 			 * shown on usage().
183 			 */
184 			if (find_command(cmd->gc_name, GEOM_CLASS_CMDS) != NULL)
185 				continue;
186 			usage_command(cmd, prefix);
187 			prefix = "      ";
188 		}
189 		exit(EXIT_FAILURE);
190 	}
191 }
192 
193 static void
194 load_module(void)
195 {
196 	char name1[64], name2[64];
197 
198 	snprintf(name1, sizeof(name1), "g_%s", class_name);
199 	snprintf(name2, sizeof(name2), "geom_%s", class_name);
200 	if (modfind(name1) < 0) {
201 		/* Not present in kernel, try loading it. */
202 		if (kldload(name2) < 0 || modfind(name1) < 0) {
203 			if (errno != EEXIST) {
204 				err(EXIT_FAILURE, "cannot load %s", name2);
205 			}
206 		}
207 	}
208 }
209 
210 static int
211 strlcatf(char *str, size_t size, const char *format, ...)
212 {
213 	size_t len;
214 	va_list ap;
215 	int ret;
216 
217 	len = strlen(str);
218 	str += len;
219 	size -= len;
220 
221 	va_start(ap, format);
222 	ret = vsnprintf(str, size, format, ap);
223 	va_end(ap);
224 
225 	return (ret);
226 }
227 
228 /*
229  * Find given option in options available for given command.
230  */
231 static struct g_option *
232 find_option(struct g_command *cmd, char ch)
233 {
234 	struct g_option *opt;
235 	unsigned i;
236 
237 	for (i = 0; ; i++) {
238 		opt = &cmd->gc_options[i];
239 		if (opt->go_name == NULL)
240 			return (NULL);
241 		if (opt->go_char == ch)
242 			return (opt);
243 	}
244 	/* NOTREACHED */
245 	return (NULL);
246 }
247 
248 /*
249  * Add given option to gctl_req.
250  */
251 static void
252 set_option(struct gctl_req *req, struct g_option *opt, const char *val)
253 {
254 	const char *optname;
255 	int64_t number;
256 	void *ptr;
257 
258 	if (G_OPT_ISMULTI(opt)) {
259 		size_t optnamesize;
260 
261 		if (G_OPT_NUM(opt) == UCHAR_MAX)
262 			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
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 *
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
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
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 *
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
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
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
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 *
674 find_geom_by_provider(struct gmesh *mesh, const char *name)
675 {
676 	struct gclass *classp;
677 	struct ggeom *gp;
678 	struct gprovider *pp;
679 
680 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
681 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
682 			LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
683 				if (strcmp(pp->lg_name, name) == 0)
684 					return (gp);
685 			}
686 		}
687 	}
688 
689 	return (NULL);
690 }
691 
692 static int
693 compute_tree_width_geom(struct gmesh *mesh, struct ggeom *gp, int indent)
694 {
695 	struct gclass *classp2;
696 	struct ggeom *gp2;
697 	struct gconsumer *cp2;
698 	struct gprovider *pp;
699 	int max_width, width;
700 
701 	max_width = width = indent + strlen(gp->lg_name);
702 
703 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
704 		LIST_FOREACH(classp2, &mesh->lg_class, lg_class) {
705 			LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) {
706 				LIST_FOREACH(cp2,
707 				    &gp2->lg_consumer, lg_consumer) {
708 					if (pp != cp2->lg_provider)
709 						continue;
710 					width = compute_tree_width_geom(mesh,
711 					    gp2, indent + 2);
712 					if (width > max_width)
713 						max_width = width;
714 				}
715 			}
716 		}
717 	}
718 
719 	return (max_width);
720 }
721 
722 static int
723 compute_tree_width(struct gmesh *mesh)
724 {
725 	struct gclass *classp;
726 	struct ggeom *gp;
727 	int max_width, width;
728 
729 	max_width = width = 0;
730 
731 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
732 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
733 			if (!LIST_EMPTY(&gp->lg_consumer))
734 				continue;
735 			width = compute_tree_width_geom(mesh, gp, 0);
736 			if (width > max_width)
737 				max_width = width;
738 		}
739 	}
740 
741 	return (max_width);
742 }
743 
744 static void
745 show_tree_geom(struct gmesh *mesh, struct ggeom *gp, int indent, int width)
746 {
747 	struct gclass *classp2;
748 	struct ggeom *gp2;
749 	struct gconsumer *cp2;
750 	struct gprovider *pp;
751 
752 	if (LIST_EMPTY(&gp->lg_provider)) {
753 		printf("%*s%-*.*s %-*.*s\n", indent, "",
754 		    width - indent, width - indent, gp->lg_name,
755 		    GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name);
756 		return;
757 	}
758 
759 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
760 		printf("%*s%-*.*s %-*.*s %s\n", indent, "",
761 		    width - indent, width - indent, gp->lg_name,
762 		    GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name,
763 		    pp->lg_name);
764 
765 		LIST_FOREACH(classp2, &mesh->lg_class, lg_class) {
766 			LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) {
767 				LIST_FOREACH(cp2,
768 				    &gp2->lg_consumer, lg_consumer) {
769 					if (pp != cp2->lg_provider)
770 						continue;
771 					show_tree_geom(mesh, gp2,
772 					    indent + 2, width);
773 				}
774 			}
775 		}
776 	}
777 }
778 
779 static void
780 show_tree(void)
781 {
782 	struct gmesh mesh;
783 	struct gclass *classp;
784 	struct ggeom *gp;
785 	int error, width;
786 
787 	error = geom_gettree(&mesh);
788 	if (error != 0)
789 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
790 
791 	width = compute_tree_width(&mesh);
792 
793 	printf("%-*.*s %-*.*s %s\n",
794 	    width, width, "Geom",
795 	    GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, "Class",
796 	    "Provider");
797 
798 	LIST_FOREACH(classp, &mesh.lg_class, lg_class) {
799 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
800 			if (!LIST_EMPTY(&gp->lg_consumer))
801 				continue;
802 			show_tree_geom(&mesh, gp, 0, width);
803 		}
804 	}
805 }
806 
807 int
808 main(int argc, char *argv[])
809 {
810 	char *provider_name;
811 	bool tflag;
812 	int ch;
813 
814 	provider_name = NULL;
815 	tflag = false;
816 
817 	argc = xo_parse_args(argc, argv);
818 	if (argc < 0)
819 		return (argc);
820 
821 	if (strcmp(getprogname(), "geom") == 0) {
822 		while ((ch = getopt(argc, argv, "hp:t")) != -1) {
823 			switch (ch) {
824 			case 'p':
825 				provider_name = strdup(optarg);
826 				if (provider_name == NULL)
827 					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 *
868 find_class(struct gmesh *mesh, const char *name)
869 {
870 	struct gclass *classp;
871 
872 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
873 		if (strcmp(classp->lg_name, name) == 0)
874 			return (classp);
875 	}
876 	return (NULL);
877 }
878 
879 static struct ggeom *
880 find_geom(struct gclass *classp, const char *name)
881 {
882 	struct ggeom *gp;
883 
884 	if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
885 		name += sizeof(_PATH_DEV) - 1;
886 
887 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
888 		if (strcmp(gp->lg_name, name) == 0)
889 			return (gp);
890 	}
891 	return (NULL);
892 }
893 
894 static void
895 list_one_provider(struct gprovider *pp, const char *padding)
896 {
897 	struct gconfig *conf;
898 	char buf[5];
899 
900 	xo_emit("{Lcw:Name}{:Name}\n", pp->lg_name);
901 	humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
902 	    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
903 	xo_emit("{P:/%s}{Lcw:Mediasize}{:Mediasize/%jd} ({N:/%s})\n",
904 	    padding, (intmax_t)pp->lg_mediasize, buf);
905 	xo_emit("{P:/%s}{Lcw:Sectorsize}{:Sectorsize/%u} \n",
906 	    padding, pp->lg_sectorsize);
907 	if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
908 		xo_emit("{P:/%s}{Lcw:Stripesize}{Stripesize/%ju}\n",
909 		    padding, pp->lg_stripesize);
910 		xo_emit("{P:/%s}{Lcw:Stripeoffset}{Stripeoffset/%ju}\n",
911 		    padding, pp->lg_stripeoffset);
912 	}
913 	xo_emit("{P:/%s}{Lcw:Mode}{Mode}\n", padding, pp->lg_mode);
914 	LIST_FOREACH(conf, &pp->lg_config, lg_config) {
915 		xo_emit("{P:/%s}{Lcwa:}{a:}\n", padding, conf->lg_name,
916 		    conf->lg_name, conf->lg_val);
917 	}
918 }
919 
920 static void
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}{:Stripesize/%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);
950 	}
951 }
952 
953 static void
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);
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
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("Geom");
1009 	xo_emit("{Lwc:Geom class}{:Class}\n", gp->lg_class->lg_name);
1010 	list_one_geom(gp);
1011 	xo_close_container("Geom");
1012 }
1013 
1014 static void
1015 std_help(struct gctl_req *req __unused, unsigned flags __unused)
1016 {
1017 
1018 	usage();
1019 }
1020 
1021 static int
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
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("Geom");
1071 			list_one_geom(gp);
1072 			xo_close_container("Geom");
1073 		}
1074 	} else {
1075 		xo_open_list("Geoms");
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("Geoms");
1084 	}
1085 	geom_deletetree(&mesh);
1086 }
1087 
1088 static int
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
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
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 *
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
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 	const char *name, *status, *cstate, *csyncr;
1179 	int gotone, len;
1180 
1181 	name = gp->lg_name;
1182 	status = "N/A";
1183 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1184 		if (strcasecmp(conf->lg_name, "state") == 0) {
1185 			status = conf->lg_val;
1186 			break;
1187 		}
1188 	}
1189 	gotone = len = 0;
1190 	xo_open_instance("status");
1191 	LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1192 		cstate = status_one_consumer(cp, "state");
1193 		csyncr = status_one_consumer(cp, "synchronized");
1194 		if (cstate == NULL && csyncr == NULL)
1195 			continue;
1196 		if (!gotone || script) {
1197 			if (!gotone) {
1198 				xo_emit("{:name/%*s}  {:status/%*s}  ",
1199 				    name_len, name, status_len, status);
1200 			} else {
1201 				xo_emit("{d:name/%*s}  {d:status/%*s}  ",
1202 				    name_len, name, status_len, status);
1203 			}
1204 			xo_open_list("components");
1205 		}
1206 
1207 		xo_open_instance("components");
1208 		if (cstate != NULL && csyncr != NULL) {
1209 			xo_emit("{P:/%*s}{:compontent} ({:state}, {:synchronized})\n",
1210 			len, "", cp->lg_provider->lg_name, cstate, csyncr);
1211 		} else if (cstate != NULL) {
1212 			xo_emit("{P:/%*s}{:compontent} ({:state})\n",
1213 			len, "", cp->lg_provider->lg_name, cstate);
1214 		} else {
1215 			xo_emit("{P:/%*s}{:compontent} ({:synchronized})\n",
1216 			len, "", cp->lg_provider->lg_name, csyncr);
1217 		}
1218 		xo_close_instance("components");
1219 		gotone = 1;
1220 		if (!len && !script)
1221 			len = name_len + status_len + 4;
1222 	}
1223 	if (!gotone) {
1224 		xo_emit("{:name/%*s}  {:status/%*s}  ", name_len, name, status_len, status);
1225 		xo_open_list("components");
1226 		xo_open_instance("components");
1227 		xo_emit("{P:/%*s}{d:compontent}\n", len, "", "N/A");
1228 		xo_close_instance("components");
1229 	}
1230 	xo_close_list("components");
1231 	xo_close_instance("status");
1232 }
1233 
1234 static void
1235 status_one_geom_prs(struct ggeom *gp, int script, int name_len, int status_len)
1236 {
1237 	struct gprovider *pp;
1238 	struct gconsumer *cp;
1239 	struct gconfig *conf;
1240 	const char *name, *status, *cstate, *csyncr;
1241 	int gotone, len;
1242 
1243 	xo_open_instance("status");
1244 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1245 		name = pp->lg_name;
1246 		status = "N/A";
1247 		LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1248 			if (strcasecmp(conf->lg_name, "state") == 0) {
1249 				status = conf->lg_val;
1250 				break;
1251 			}
1252 		}
1253 		LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1254 			if (strcasecmp(conf->lg_name, "state") == 0) {
1255 				status = conf->lg_val;
1256 				break;
1257 			}
1258 		}
1259 		gotone = len = 0;
1260 		LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1261 			cstate = status_one_consumer(cp, "state");
1262 			csyncr = status_one_consumer(cp, "synchronized");
1263 			if (cstate == NULL && csyncr == NULL)
1264 				continue;
1265 
1266 			if (!gotone || script) {
1267 				if (!gotone) {
1268 					xo_emit("{:name/%*s}  {:status/%*s}  ",
1269 					    name_len, name, status_len, status);
1270 				} else {
1271 					xo_emit("{d:name/%*s}  {d:status/%*s}  ",
1272 					    name_len, name, status_len, status);
1273 				}
1274 				xo_open_list("components");
1275 			}
1276 
1277 			xo_open_instance("component");
1278 			if (cstate != NULL && csyncr != NULL) {
1279 				xo_emit("{P:/%*s}{:compontent} ({:state}, {:synchronized})\n",
1280 				len, "", cp->lg_provider->lg_name, cstate, csyncr);
1281 			} else if (cstate != NULL) {
1282 				xo_emit("{P:/%*s}{:compontent} ({:state})\n",
1283 				len, "", cp->lg_provider->lg_name, cstate);
1284 			} else {
1285 				xo_emit("{P:/%*s}{:compontent} ({:synchronized})\n",
1286 				len, "", cp->lg_provider->lg_name, csyncr);
1287 			}
1288 			xo_close_instance("component");
1289 			gotone = 1;
1290 			if (!len && !script)
1291 				len = name_len + status_len + 4;
1292 		}
1293 		if (!gotone) {
1294 			xo_emit("{:name/%*s}  {:status/%*s}  ", name_len, name, status_len, status);
1295 			xo_open_list("components");
1296 			xo_open_instance("components");
1297 			xo_emit("{P:/%*s}{d:compontent}\n", len, "", "N/A");
1298 			xo_close_instance("components");
1299 		}
1300 		xo_close_list("components");
1301 	}
1302 	xo_close_instance("status");
1303 }
1304 
1305 static void
1306 std_status(struct gctl_req *req, unsigned flags __unused)
1307 {
1308 	struct gmesh mesh;
1309 	struct gclass *classp;
1310 	struct ggeom *gp;
1311 	const char *name;
1312 	int name_len, status_len;
1313 	int all, error, geoms, i, n, nargs, script;
1314 
1315 	error = geom_gettree(&mesh);
1316 	if (error != 0)
1317 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1318 	classp = find_class(&mesh, gclass_name);
1319 	if (classp == NULL)
1320 		errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
1321 	nargs = gctl_get_int(req, "nargs");
1322 	all = gctl_get_int(req, "all");
1323 	geoms = gctl_get_int(req, "geoms");
1324 	script = gctl_get_int(req, "script");
1325 	name_len = strlen("Name");
1326 	status_len = strlen("Status");
1327 
1328 	if (nargs > 0) {
1329 		for (i = 0, n = 0; i < nargs; i++) {
1330 			name = gctl_get_ascii(req, "arg%d", i);
1331 			gp = find_geom(classp, name);
1332 			if (gp == NULL)
1333 				errx(EXIT_FAILURE, "No such geom: %s.", name);
1334 			if (geoms) {
1335 				status_update_len(gp,
1336 				    &name_len, &status_len);
1337 			} else {
1338 				status_update_len_prs(gp,
1339 				    &name_len, &status_len);
1340 			}
1341 			n++;
1342 		}
1343 		if (n == 0)
1344 			goto end;
1345 	} else {
1346 		n = 0;
1347 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1348 			if (LIST_EMPTY(&gp->lg_provider) && !all)
1349 				continue;
1350 			if (geoms) {
1351 				status_update_len(gp,
1352 				    &name_len, &status_len);
1353 			} else {
1354 				status_update_len_prs(gp,
1355 				    &name_len, &status_len);
1356 			}
1357 			n++;
1358 		}
1359 		if (n == 0)
1360 			goto end;
1361 	}
1362 	if (!script) {
1363 		xo_emit("{T:/%*s}  {T:/%*s}  {T:Components}\n",
1364 		    name_len, "Name", status_len, "Status");
1365 	}
1366 	xo_open_list("status");
1367 	if (nargs > 0) {
1368 		for (i = 0; i < nargs; i++) {
1369 			name = gctl_get_ascii(req, "arg%d", i);
1370 			gp = find_geom(classp, name);
1371 			if (gp == NULL)
1372 				continue;
1373 			if (geoms) {
1374 				status_one_geom(gp, script, name_len,
1375 				    status_len);
1376 			} else {
1377 				status_one_geom_prs(gp, script, name_len,
1378 				    status_len);
1379 			}
1380 		}
1381 	} else {
1382 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1383 			if (LIST_EMPTY(&gp->lg_provider) && !all)
1384 				continue;
1385 			if (geoms) {
1386 				status_one_geom(gp, script, name_len,
1387 				    status_len);
1388 			} else {
1389 				status_one_geom_prs(gp, script, name_len,
1390 				    status_len);
1391 			}
1392 		}
1393 	}
1394 	xo_close_list("status");
1395 end:
1396 	geom_deletetree(&mesh);
1397 }
1398 
1399 static int
1400 std_load_available(void)
1401 {
1402 	char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
1403 	struct stat sb;
1404 	size_t len;
1405 
1406 	snprintf(name, sizeof(name), "g_%s", class_name);
1407 	/*
1408 	 * If already in kernel, "load" command is NOP.
1409 	 */
1410 	if (modfind(name) >= 0)
1411 		return (1);
1412 	bzero(paths, sizeof(paths));
1413 	len = sizeof(paths);
1414 	if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
1415 		err(EXIT_FAILURE, "sysctl(kern.module_path)");
1416 	for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
1417 		snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
1418 		/*
1419 		 * If geom_<name>.ko file exists, "load" command is available.
1420 		 */
1421 		if (stat(name, &sb) == 0)
1422 			return (1);
1423 	}
1424 	return (0);
1425 }
1426 
1427 static void
1428 std_load(struct gctl_req *req __unused, unsigned flags)
1429 {
1430 
1431 	/*
1432 	 * Do nothing special here, because of G_FLAG_LOADKLD flag,
1433 	 * module is already loaded.
1434 	 */
1435 	if ((flags & G_FLAG_VERBOSE) != 0)
1436 		printf("Module available.\n");
1437 }
1438 
1439 static int
1440 std_unload_available(void)
1441 {
1442 	char name[64];
1443 	int id;
1444 
1445 	snprintf(name, sizeof(name), "geom_%s", class_name);
1446 	id = kldfind(name);
1447 	if (id >= 0)
1448 		return (1);
1449 	return (0);
1450 }
1451 
1452 static void
1453 std_unload(struct gctl_req *req, unsigned flags __unused)
1454 {
1455 	char name[64];
1456 	int id;
1457 
1458 	snprintf(name, sizeof(name), "geom_%s", class_name);
1459 	id = kldfind(name);
1460 	if (id < 0) {
1461 		gctl_error(req, "Could not find module: %s.", strerror(errno));
1462 		return;
1463 	}
1464 	if (kldunload(id) < 0) {
1465 		gctl_error(req, "Could not unload module: %s.",
1466 		    strerror(errno));
1467 		return;
1468 	}
1469 }
1470 
1471 static int
1472 std_available(const char *name)
1473 {
1474 
1475 	if (strcmp(name, "help") == 0)
1476 		return (1);
1477 	else if (strcmp(name, "list") == 0)
1478 		return (std_list_available());
1479 	else if (strcmp(name, "status") == 0)
1480 		return (std_status_available());
1481 	else if (strcmp(name, "load") == 0)
1482 		return (std_load_available());
1483 	else if (strcmp(name, "unload") == 0)
1484 		return (std_unload_available());
1485 	else
1486 		assert(!"Unknown standard command.");
1487 	return (0);
1488 }
1489