xref: /freebsd/sbin/geom/core/geom.c (revision 38a52bd3b5cac3da6f7f6eef3dd050e6aa08ebb3)
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 		/* 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 	exit(EXIT_SUCCESS);
520 }
521 
522 #ifndef STATIC_GEOM_CLASSES
523 static const char *
524 library_path(void)
525 {
526 	const char *path;
527 
528 	path = getenv("GEOM_LIBRARY_PATH");
529 	if (path == NULL)
530 		path = GEOM_CLASS_DIR;
531 	return (path);
532 }
533 
534 static void
535 load_library(void)
536 {
537 	char *curpath, path[MAXPATHLEN], *tofree, *totalpath;
538 	uint32_t *lib_version;
539 	void *dlh;
540 	int ret;
541 
542 	ret = 0;
543 	tofree = totalpath = strdup(library_path());
544 	if (totalpath == NULL)
545 		err(EXIT_FAILURE, "Not enough memory for library path");
546 
547 	if (strchr(totalpath, ':') != NULL)
548 		curpath = strsep(&totalpath, ":");
549 	else
550 		curpath = totalpath;
551 	/* Traverse the paths to find one that contains the library we want. */
552 	while (curpath != NULL) {
553 		snprintf(path, sizeof(path), "%s/geom_%s.so", curpath,
554 		    class_name);
555 		ret = access(path, F_OK);
556 		if (ret == -1) {
557 			if (errno == ENOENT) {
558 				/*
559 				 * If we cannot find library, try the next
560 				 * path.
561 				 */
562 				curpath = strsep(&totalpath, ":");
563 				continue;
564 			}
565 			err(EXIT_FAILURE, "Cannot access library");
566 		}
567 		break;
568 	}
569 	free(tofree);
570 	/* No library was found, but standard commands can still be used */
571 	if (ret == -1)
572 		return;
573 	dlh = dlopen(path, RTLD_NOW);
574 	if (dlh == NULL)
575 		errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror());
576 	lib_version = dlsym(dlh, "lib_version");
577 	if (lib_version == NULL) {
578 		warnx("Cannot find symbol %s: %s.", "lib_version", dlerror());
579 		dlclose(dlh);
580 		exit(EXIT_FAILURE);
581 	}
582 	if (*lib_version != G_LIB_VERSION) {
583 		dlclose(dlh);
584 		errx(EXIT_FAILURE, "%s and %s are not synchronized.",
585 		    getprogname(), path);
586 	}
587 	version = dlsym(dlh, "version");
588 	if (version == NULL) {
589 		warnx("Cannot find symbol %s: %s.", "version", dlerror());
590 		dlclose(dlh);
591 		exit(EXIT_FAILURE);
592 	}
593 	class_commands = dlsym(dlh, "class_commands");
594 	if (class_commands == NULL) {
595 		warnx("Cannot find symbol %s: %s.", "class_commands",
596 		    dlerror());
597 		dlclose(dlh);
598 		exit(EXIT_FAILURE);
599 	}
600 }
601 #endif	/* !STATIC_GEOM_CLASSES */
602 
603 /*
604  * Class name should be all capital letters.
605  */
606 static void
607 set_class_name(void)
608 {
609 	char *s1, *s2;
610 
611 	s1 = class_name;
612 	for (; *s1 != '\0'; s1++)
613 		*s1 = tolower(*s1);
614 	gclass_name = malloc(strlen(class_name) + 1);
615 	if (gclass_name == NULL)
616 		errx(EXIT_FAILURE, "No memory");
617 	s1 = gclass_name;
618 	s2 = class_name;
619 	for (; *s2 != '\0'; s2++)
620 		*s1++ = toupper(*s2);
621 	*s1 = '\0';
622 }
623 
624 static void
625 get_class(int *argc, char ***argv)
626 {
627 
628 	snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
629 	if (strcmp(comm, "geom") == 0) {
630 		if (*argc < 2)
631 			usage();
632 		else if (*argc == 2) {
633 			if (strcmp((*argv)[1], "-h") == 0 ||
634 			    strcmp((*argv)[1], "help") == 0) {
635 				usage();
636 			}
637 		}
638 		strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
639 		class_name = (*argv)[1];
640 		*argc -= 2;
641 		*argv += 2;
642 	} else if (*comm == 'g') {
643 		class_name = comm + 1;
644 		*argc -= 1;
645 		*argv += 1;
646 	} else {
647 		errx(EXIT_FAILURE, "Invalid utility name.");
648 	}
649 
650 #ifndef STATIC_GEOM_CLASSES
651 	load_library();
652 #else
653 	if (!strcasecmp(class_name, "part")) {
654 		version = &gpart_version;
655 		class_commands = gpart_class_commands;
656 	} else if (!strcasecmp(class_name, "label")) {
657 		version = &glabel_version;
658 		class_commands = glabel_class_commands;
659 	}
660 #endif /* !STATIC_GEOM_CLASSES */
661 
662 	set_class_name();
663 
664 	/* If we can't load or list, it's not a class. */
665 	if (!std_load_available() && !std_list_available())
666 		errx(EXIT_FAILURE, "Invalid class name '%s'.", class_name);
667 
668 	if (*argc < 1)
669 		usage();
670 }
671 
672 static struct ggeom *
673 find_geom_by_provider(struct gmesh *mesh, const char *name)
674 {
675 	struct gclass *classp;
676 	struct ggeom *gp;
677 	struct gprovider *pp;
678 
679 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
680 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
681 			LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
682 				if (strcmp(pp->lg_name, name) == 0)
683 					return (gp);
684 			}
685 		}
686 	}
687 
688 	return (NULL);
689 }
690 
691 static int
692 compute_tree_width_geom(struct gmesh *mesh, struct ggeom *gp, int indent)
693 {
694 	struct gclass *classp2;
695 	struct ggeom *gp2;
696 	struct gconsumer *cp2;
697 	struct gprovider *pp;
698 	int max_width, width;
699 
700 	max_width = width = indent + strlen(gp->lg_name);
701 
702 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
703 		LIST_FOREACH(classp2, &mesh->lg_class, lg_class) {
704 			LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) {
705 				LIST_FOREACH(cp2,
706 				    &gp2->lg_consumer, lg_consumer) {
707 					if (pp != cp2->lg_provider)
708 						continue;
709 					width = compute_tree_width_geom(mesh,
710 					    gp2, indent + 2);
711 					if (width > max_width)
712 						max_width = width;
713 				}
714 			}
715 		}
716 	}
717 
718 	return (max_width);
719 }
720 
721 static int
722 compute_tree_width(struct gmesh *mesh)
723 {
724 	struct gclass *classp;
725 	struct ggeom *gp;
726 	int max_width, width;
727 
728 	max_width = width = 0;
729 
730 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
731 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
732 			if (!LIST_EMPTY(&gp->lg_consumer))
733 				continue;
734 			width = compute_tree_width_geom(mesh, gp, 0);
735 			if (width > max_width)
736 				max_width = width;
737 		}
738 	}
739 
740 	return (max_width);
741 }
742 
743 static void
744 show_tree_geom(struct gmesh *mesh, struct ggeom *gp, int indent, int width)
745 {
746 	struct gclass *classp2;
747 	struct ggeom *gp2;
748 	struct gconsumer *cp2;
749 	struct gprovider *pp;
750 
751 	if (LIST_EMPTY(&gp->lg_provider)) {
752 		printf("%*s%-*.*s %-*.*s\n", indent, "",
753 		    width - indent, width - indent, gp->lg_name,
754 		    GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name);
755 		return;
756 	}
757 
758 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
759 		printf("%*s%-*.*s %-*.*s %s\n", indent, "",
760 		    width - indent, width - indent, gp->lg_name,
761 		    GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name,
762 		    pp->lg_name);
763 
764 		LIST_FOREACH(classp2, &mesh->lg_class, lg_class) {
765 			LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) {
766 				LIST_FOREACH(cp2,
767 				    &gp2->lg_consumer, lg_consumer) {
768 					if (pp != cp2->lg_provider)
769 						continue;
770 					show_tree_geom(mesh, gp2,
771 					    indent + 2, width);
772 				}
773 			}
774 		}
775 	}
776 }
777 
778 static void
779 show_tree(void)
780 {
781 	struct gmesh mesh;
782 	struct gclass *classp;
783 	struct ggeom *gp;
784 	int error, width;
785 
786 	error = geom_gettree(&mesh);
787 	if (error != 0)
788 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
789 
790 	width = compute_tree_width(&mesh);
791 
792 	printf("%-*.*s %-*.*s %s\n",
793 	    width, width, "Geom",
794 	    GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, "Class",
795 	    "Provider");
796 
797 	LIST_FOREACH(classp, &mesh.lg_class, lg_class) {
798 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
799 			if (!LIST_EMPTY(&gp->lg_consumer))
800 				continue;
801 			show_tree_geom(&mesh, gp, 0, width);
802 		}
803 	}
804 }
805 
806 int
807 main(int argc, char *argv[])
808 {
809 	char *provider_name;
810 	bool tflag;
811 	int ch;
812 
813 	provider_name = NULL;
814 	tflag = false;
815 
816 	if (strcmp(getprogname(), "geom") == 0) {
817 		while ((ch = getopt(argc, argv, "hp:t")) != -1) {
818 			switch (ch) {
819 			case 'p':
820 				provider_name = strdup(optarg);
821 				if (provider_name == NULL)
822 					err(1, "strdup");
823 				break;
824 			case 't':
825 				tflag = true;
826 				break;
827 			case 'h':
828 			default:
829 				usage();
830 			}
831 		}
832 
833 		/*
834 		 * Don't adjust argc and argv, it would break get_class().
835 		 */
836 	}
837 
838 	if (tflag && provider_name != NULL) {
839 		errx(EXIT_FAILURE,
840 		    "At most one of -P and -t may be specified.");
841 	}
842 
843 	if (provider_name != NULL) {
844 		list_one_geom_by_provider(provider_name);
845 		return (0);
846 	}
847 
848 	if (tflag) {
849 		show_tree();
850 		return (0);
851 	}
852 
853 	get_class(&argc, &argv);
854 	run_command(argc, argv);
855 	/* NOTREACHED */
856 
857 	exit(EXIT_FAILURE);
858 }
859 
860 static struct gclass *
861 find_class(struct gmesh *mesh, const char *name)
862 {
863 	struct gclass *classp;
864 
865 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
866 		if (strcmp(classp->lg_name, name) == 0)
867 			return (classp);
868 	}
869 	return (NULL);
870 }
871 
872 static struct ggeom *
873 find_geom(struct gclass *classp, const char *name)
874 {
875 	struct ggeom *gp;
876 
877 	if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
878 		name += sizeof(_PATH_DEV) - 1;
879 
880 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
881 		if (strcmp(gp->lg_name, name) == 0)
882 			return (gp);
883 	}
884 	return (NULL);
885 }
886 
887 static void
888 list_one_provider(struct gprovider *pp, const char *prefix)
889 {
890 	struct gconfig *conf;
891 	char buf[5];
892 
893 	printf("Name: %s\n", pp->lg_name);
894 	humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
895 	    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
896 	printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
897 	    buf);
898 	printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
899 	if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
900 		printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
901 		printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
902 	}
903 	printf("%sMode: %s\n", prefix, pp->lg_mode);
904 	LIST_FOREACH(conf, &pp->lg_config, lg_config) {
905 		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
906 	}
907 }
908 
909 static void
910 list_one_consumer(struct gconsumer *cp, const char *prefix)
911 {
912 	struct gprovider *pp;
913 	struct gconfig *conf;
914 
915 	pp = cp->lg_provider;
916 	if (pp == NULL)
917 		printf("[no provider]\n");
918 	else {
919 		char buf[5];
920 
921 		printf("Name: %s\n", pp->lg_name);
922 		humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
923 		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
924 		printf("%sMediasize: %jd (%s)\n", prefix,
925 		    (intmax_t)pp->lg_mediasize, buf);
926 		printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
927 		if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
928 			printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
929 			printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
930 		}
931 		printf("%sMode: %s\n", prefix, cp->lg_mode);
932 	}
933 	LIST_FOREACH(conf, &cp->lg_config, lg_config) {
934 		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
935 	}
936 }
937 
938 static void
939 list_one_geom(struct ggeom *gp)
940 {
941 	struct gprovider *pp;
942 	struct gconsumer *cp;
943 	struct gconfig *conf;
944 	unsigned n;
945 
946 	printf("Geom name: %s\n", gp->lg_name);
947 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
948 		printf("%s: %s\n", conf->lg_name, conf->lg_val);
949 	}
950 	if (!LIST_EMPTY(&gp->lg_provider)) {
951 		printf("Providers:\n");
952 		n = 1;
953 		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
954 			printf("%u. ", n++);
955 			list_one_provider(pp, "   ");
956 		}
957 	}
958 	if (!LIST_EMPTY(&gp->lg_consumer)) {
959 		printf("Consumers:\n");
960 		n = 1;
961 		LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
962 			printf("%u. ", n++);
963 			list_one_consumer(cp, "   ");
964 		}
965 	}
966 	printf("\n");
967 }
968 
969 static void
970 list_one_geom_by_provider(const char *provider_name)
971 {
972 	struct gmesh mesh;
973 	struct ggeom *gp;
974 	int error;
975 
976 	error = geom_gettree(&mesh);
977 	if (error != 0)
978 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
979 
980 	gp = find_geom_by_provider(&mesh, provider_name);
981 	if (gp == NULL)
982 		errx(EXIT_FAILURE, "Cannot find provider '%s'.", provider_name);
983 
984 	printf("Geom class: %s\n", gp->lg_class->lg_name);
985 	list_one_geom(gp);
986 }
987 
988 static void
989 std_help(struct gctl_req *req __unused, unsigned flags __unused)
990 {
991 
992 	usage();
993 }
994 
995 static int
996 std_list_available(void)
997 {
998 	struct gmesh mesh;
999 	struct gclass *classp;
1000 	int error;
1001 
1002 	error = geom_gettree_geom(&mesh, gclass_name, "", 0);
1003 	if (error != 0)
1004 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1005 	classp = find_class(&mesh, gclass_name);
1006 	geom_deletetree(&mesh);
1007 	if (classp != NULL)
1008 		return (1);
1009 	return (0);
1010 }
1011 
1012 static void
1013 std_list(struct gctl_req *req, unsigned flags __unused)
1014 {
1015 	struct gmesh mesh;
1016 	struct gclass *classp;
1017 	struct ggeom *gp;
1018 	const char *name;
1019 	int all, error, i, nargs;
1020 
1021 	nargs = gctl_get_int(req, "nargs");
1022 	if (nargs == 1) {
1023 		error = geom_gettree_geom(&mesh, gclass_name,
1024 		    gctl_get_ascii(req, "arg0"), 1);
1025 	} else
1026 		error = geom_gettree(&mesh);
1027 	if (error != 0)
1028 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1029 	classp = find_class(&mesh, gclass_name);
1030 	if (classp == NULL) {
1031 		geom_deletetree(&mesh);
1032 		errx(EXIT_FAILURE, "Class '%s' not found.", gclass_name);
1033 	}
1034 	all = gctl_get_int(req, "all");
1035 	if (nargs > 0) {
1036 		for (i = 0; i < nargs; i++) {
1037 			name = gctl_get_ascii(req, "arg%d", i);
1038 			gp = find_geom(classp, name);
1039 			if (gp == NULL) {
1040 				errx(EXIT_FAILURE, "Class '%s' does not have "
1041 				    "an instance named '%s'.",
1042 				    gclass_name, name);
1043 			}
1044 			list_one_geom(gp);
1045 		}
1046 	} else {
1047 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1048 			if (LIST_EMPTY(&gp->lg_provider) && !all)
1049 				continue;
1050 			list_one_geom(gp);
1051 		}
1052 	}
1053 	geom_deletetree(&mesh);
1054 }
1055 
1056 static int
1057 std_status_available(void)
1058 {
1059 
1060 	/* 'status' command is available when 'list' command is. */
1061 	return (std_list_available());
1062 }
1063 
1064 static void
1065 status_update_len(struct ggeom *gp, int *name_len, int *status_len)
1066 {
1067 	struct gconfig *conf;
1068 	int len;
1069 
1070 	assert(gp != NULL);
1071 	assert(name_len != NULL);
1072 	assert(status_len != NULL);
1073 
1074 	len = strlen(gp->lg_name);
1075 	if (*name_len < len)
1076 		*name_len = len;
1077 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1078 		if (strcasecmp(conf->lg_name, "state") == 0) {
1079 			len = strlen(conf->lg_val);
1080 			if (*status_len < len)
1081 				*status_len = len;
1082 		}
1083 	}
1084 }
1085 
1086 static void
1087 status_update_len_prs(struct ggeom *gp, int *name_len, int *status_len)
1088 {
1089 	struct gprovider *pp;
1090 	struct gconfig *conf;
1091 	int len, glen;
1092 
1093 	assert(gp != NULL);
1094 	assert(name_len != NULL);
1095 	assert(status_len != NULL);
1096 
1097 	glen = 0;
1098 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1099 		if (strcasecmp(conf->lg_name, "state") == 0) {
1100 			glen = strlen(conf->lg_val);
1101 			break;
1102 		}
1103 	}
1104 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1105 		len = strlen(pp->lg_name);
1106 		if (*name_len < len)
1107 			*name_len = len;
1108 		len = glen;
1109 		LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1110 			if (strcasecmp(conf->lg_name, "state") == 0) {
1111 				len = strlen(conf->lg_val);
1112 				break;
1113 			}
1114 		}
1115 		if (*status_len < len)
1116 			*status_len = len;
1117 	}
1118 }
1119 
1120 static char *
1121 status_one_consumer(struct gconsumer *cp)
1122 {
1123 	static char buf[256];
1124 	struct gprovider *pp;
1125 	struct gconfig *conf;
1126 	const char *state, *syncr;
1127 
1128 	pp = cp->lg_provider;
1129 	if (pp == NULL)
1130 		return (NULL);
1131 	state = NULL;
1132 	syncr = NULL;
1133 	LIST_FOREACH(conf, &cp->lg_config, lg_config) {
1134 		if (strcasecmp(conf->lg_name, "state") == 0)
1135 			state = conf->lg_val;
1136 		if (strcasecmp(conf->lg_name, "synchronized") == 0)
1137 			syncr = conf->lg_val;
1138 	}
1139 	if (state == NULL && syncr == NULL)
1140 		snprintf(buf, sizeof(buf), "%s", pp->lg_name);
1141 	else if (state != NULL && syncr != NULL) {
1142 		snprintf(buf, sizeof(buf), "%s (%s, %s)", pp->lg_name,
1143 		    state, syncr);
1144 	} else {
1145 		snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name,
1146 		    state ? state : syncr);
1147 	}
1148 	return (buf);
1149 }
1150 
1151 static void
1152 status_one_geom(struct ggeom *gp, int script, int name_len, int status_len)
1153 {
1154 	struct gconsumer *cp;
1155 	struct gconfig *conf;
1156 	const char *name, *status, *component;
1157 	int gotone;
1158 
1159 	name = gp->lg_name;
1160 	status = "N/A";
1161 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1162 		if (strcasecmp(conf->lg_name, "state") == 0) {
1163 			status = conf->lg_val;
1164 			break;
1165 		}
1166 	}
1167 	gotone = 0;
1168 	LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1169 		component = status_one_consumer(cp);
1170 		if (component == NULL)
1171 			continue;
1172 		gotone = 1;
1173 		printf("%*s  %*s  %s\n", name_len, name, status_len, status,
1174 		    component);
1175 		if (!script)
1176 			name = status = "";
1177 	}
1178 	if (!gotone) {
1179 		printf("%*s  %*s  %s\n", name_len, name, status_len, status,
1180 		    "N/A");
1181 	}
1182 }
1183 
1184 static void
1185 status_one_geom_prs(struct ggeom *gp, int script, int name_len, int status_len)
1186 {
1187 	struct gprovider *pp;
1188 	struct gconsumer *cp;
1189 	struct gconfig *conf;
1190 	const char *name, *status, *component;
1191 	int gotone;
1192 
1193 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1194 		name = pp->lg_name;
1195 		status = "N/A";
1196 		LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1197 			if (strcasecmp(conf->lg_name, "state") == 0) {
1198 				status = conf->lg_val;
1199 				break;
1200 			}
1201 		}
1202 		LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1203 			if (strcasecmp(conf->lg_name, "state") == 0) {
1204 				status = conf->lg_val;
1205 				break;
1206 			}
1207 		}
1208 		gotone = 0;
1209 		LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1210 			component = status_one_consumer(cp);
1211 			if (component == NULL)
1212 				continue;
1213 			gotone = 1;
1214 			printf("%*s  %*s  %s\n", name_len, name,
1215 			    status_len, status, component);
1216 			if (!script)
1217 				name = status = "";
1218 		}
1219 		if (!gotone) {
1220 			printf("%*s  %*s  %s\n", name_len, name,
1221 			    status_len, status, "N/A");
1222 		}
1223 	}
1224 }
1225 
1226 static void
1227 std_status(struct gctl_req *req, unsigned flags __unused)
1228 {
1229 	struct gmesh mesh;
1230 	struct gclass *classp;
1231 	struct ggeom *gp;
1232 	const char *name;
1233 	int name_len, status_len;
1234 	int all, error, geoms, i, n, nargs, script;
1235 
1236 	error = geom_gettree(&mesh);
1237 	if (error != 0)
1238 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1239 	classp = find_class(&mesh, gclass_name);
1240 	if (classp == NULL)
1241 		errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
1242 	nargs = gctl_get_int(req, "nargs");
1243 	all = gctl_get_int(req, "all");
1244 	geoms = gctl_get_int(req, "geoms");
1245 	script = gctl_get_int(req, "script");
1246 	if (script) {
1247 		name_len = 0;
1248 		status_len = 0;
1249 	} else {
1250 		name_len = strlen("Name");
1251 		status_len = strlen("Status");
1252 	}
1253 	if (nargs > 0) {
1254 		for (i = 0, n = 0; i < nargs; i++) {
1255 			name = gctl_get_ascii(req, "arg%d", i);
1256 			gp = find_geom(classp, name);
1257 			if (gp == NULL)
1258 				errx(EXIT_FAILURE, "No such geom: %s.", name);
1259 			if (geoms) {
1260 				status_update_len(gp,
1261 				    &name_len, &status_len);
1262 			} else {
1263 				status_update_len_prs(gp,
1264 				    &name_len, &status_len);
1265 			}
1266 			n++;
1267 		}
1268 		if (n == 0)
1269 			goto end;
1270 	} else {
1271 		n = 0;
1272 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1273 			if (LIST_EMPTY(&gp->lg_provider) && !all)
1274 				continue;
1275 			if (geoms) {
1276 				status_update_len(gp,
1277 				    &name_len, &status_len);
1278 			} else {
1279 				status_update_len_prs(gp,
1280 				    &name_len, &status_len);
1281 			}
1282 			n++;
1283 		}
1284 		if (n == 0)
1285 			goto end;
1286 	}
1287 	if (!script) {
1288 		printf("%*s  %*s  %s\n", name_len, "Name", status_len, "Status",
1289 		    "Components");
1290 	}
1291 	if (nargs > 0) {
1292 		for (i = 0; i < nargs; i++) {
1293 			name = gctl_get_ascii(req, "arg%d", i);
1294 			gp = find_geom(classp, name);
1295 			if (gp == NULL)
1296 				continue;
1297 			if (geoms) {
1298 				status_one_geom(gp, script, name_len,
1299 				    status_len);
1300 			} else {
1301 				status_one_geom_prs(gp, script, name_len,
1302 				    status_len);
1303 			}
1304 		}
1305 	} else {
1306 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1307 			if (LIST_EMPTY(&gp->lg_provider) && !all)
1308 				continue;
1309 			if (geoms) {
1310 				status_one_geom(gp, script, name_len,
1311 				    status_len);
1312 			} else {
1313 				status_one_geom_prs(gp, script, name_len,
1314 				    status_len);
1315 			}
1316 		}
1317 	}
1318 end:
1319 	geom_deletetree(&mesh);
1320 }
1321 
1322 static int
1323 std_load_available(void)
1324 {
1325 	char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
1326 	struct stat sb;
1327 	size_t len;
1328 
1329 	snprintf(name, sizeof(name), "g_%s", class_name);
1330 	/*
1331 	 * If already in kernel, "load" command is NOP.
1332 	 */
1333 	if (modfind(name) >= 0)
1334 		return (1);
1335 	bzero(paths, sizeof(paths));
1336 	len = sizeof(paths);
1337 	if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
1338 		err(EXIT_FAILURE, "sysctl(kern.module_path)");
1339 	for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
1340 		snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
1341 		/*
1342 		 * If geom_<name>.ko file exists, "load" command is available.
1343 		 */
1344 		if (stat(name, &sb) == 0)
1345 			return (1);
1346 	}
1347 	return (0);
1348 }
1349 
1350 static void
1351 std_load(struct gctl_req *req __unused, unsigned flags)
1352 {
1353 
1354 	/*
1355 	 * Do nothing special here, because of G_FLAG_LOADKLD flag,
1356 	 * module is already loaded.
1357 	 */
1358 	if ((flags & G_FLAG_VERBOSE) != 0)
1359 		printf("Module available.\n");
1360 }
1361 
1362 static int
1363 std_unload_available(void)
1364 {
1365 	char name[64];
1366 	int id;
1367 
1368 	snprintf(name, sizeof(name), "geom_%s", class_name);
1369 	id = kldfind(name);
1370 	if (id >= 0)
1371 		return (1);
1372 	return (0);
1373 }
1374 
1375 static void
1376 std_unload(struct gctl_req *req, unsigned flags __unused)
1377 {
1378 	char name[64];
1379 	int id;
1380 
1381 	snprintf(name, sizeof(name), "geom_%s", class_name);
1382 	id = kldfind(name);
1383 	if (id < 0) {
1384 		gctl_error(req, "Could not find module: %s.", strerror(errno));
1385 		return;
1386 	}
1387 	if (kldunload(id) < 0) {
1388 		gctl_error(req, "Could not unload module: %s.",
1389 		    strerror(errno));
1390 		return;
1391 	}
1392 }
1393 
1394 static int
1395 std_available(const char *name)
1396 {
1397 
1398 	if (strcmp(name, "help") == 0)
1399 		return (1);
1400 	else if (strcmp(name, "list") == 0)
1401 		return (std_list_available());
1402 	else if (strcmp(name, "status") == 0)
1403 		return (std_status_available());
1404 	else if (strcmp(name, "load") == 0)
1405 		return (std_load_available());
1406 	else if (strcmp(name, "unload") == 0)
1407 		return (std_unload_available());
1408 	else
1409 		assert(!"Unknown standard command.");
1410 	return (0);
1411 }
1412