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