xref: /freebsd/sbin/geom/core/geom.c (revision bc7512cc58af2e8bbe5bbf5ca0059b1daa1da897)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include <sys/param.h>
33 #include <sys/linker.h>
34 #include <sys/module.h>
35 #include <sys/stat.h>
36 #include <sys/sysctl.h>
37 #include <ctype.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <paths.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <stdarg.h>
44 #include <stdbool.h>
45 #include <stdint.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <libgen.h>
49 #include <libutil.h>
50 #include <inttypes.h>
51 #include <dlfcn.h>
52 #include <assert.h>
53 #include <libgeom.h>
54 #include <geom.h>
55 
56 #include "misc/subr.h"
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 	uint64_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 		if (strncmp(errstr, "warning: ", strlen("warning: ")) != 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