xref: /freebsd/sbin/geom/core/geom.c (revision dba6dd177bdee890cf445fbe21a5dccefd5de18e)
1 /*-
2  * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/param.h>
31 #include <sys/linker.h>
32 #include <sys/module.h>
33 #include <sys/stat.h>
34 #include <sys/sysctl.h>
35 #include <ctype.h>
36 #include <err.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <stdarg.h>
41 #include <stdint.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <libgen.h>
45 #include <inttypes.h>
46 #include <dlfcn.h>
47 #include <assert.h>
48 #include <libgeom.h>
49 #include <geom.h>
50 
51 #include "misc/subr.h"
52 
53 
54 static char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL;
55 static uint32_t *version = NULL;
56 static int verbose = 0;
57 static struct g_command *class_commands = NULL;
58 static void (*usage)(const char *name);
59 
60 static struct g_command *find_command(const char *cmdstr, int all);
61 static int std_available(const char *name);
62 
63 static void std_help(struct gctl_req *req, unsigned flags);
64 static void std_list(struct gctl_req *req, unsigned flags);
65 static void std_load(struct gctl_req *req, unsigned flags);
66 static void std_unload(struct gctl_req *req, unsigned flags);
67 
68 struct g_command std_commands[] = {
69 	{ "help", 0, std_help, G_NULL_OPTS },
70 	{ "list", 0, std_list, G_NULL_OPTS },
71 	{ "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS },
72 	{ "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS },
73 	G_CMD_SENTINEL
74 };
75 
76 static void
77 std_usage(const char *name)
78 {
79 	struct g_command *cmd;
80 	struct g_option *opt;
81 	unsigned i, j;
82 
83 	for (i = 0; ; i++) {
84 		cmd = &class_commands[i];
85 		if (cmd->gc_name == NULL)
86 			break;
87 		fprintf(stderr, "%s %s %s %s", i == 0 ? "usage:" : "      ",
88 		    name, class_name, cmd->gc_name);
89 		if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
90 			fprintf(stderr, " [-v]");
91 		for (j = 0; ; j++) {
92 			opt = &cmd->gc_options[j];
93 			if (opt->go_name == NULL)
94 				break;
95 			if (opt->go_val != NULL || opt->go_type == G_TYPE_NONE)
96 				fprintf(stderr, " [");
97 			else
98 				fprintf(stderr, " ");
99 			fprintf(stderr, "-%c", opt->go_char);
100 			if (opt->go_type != G_TYPE_NONE)
101 				fprintf(stderr, " %s", opt->go_name);
102 			if (opt->go_val != NULL || opt->go_type == G_TYPE_NONE)
103 				fprintf(stderr, "]");
104 		}
105 		fprintf(stderr, " ...\n");
106 	}
107 	exit(EXIT_FAILURE);
108 }
109 
110 static void
111 geom_usage(void)
112 {
113 
114 	if (class_name == NULL) {
115 		errx(EXIT_FAILURE, "usage: %s <class> <command> [options]",
116 		    "geom");
117 	} else {
118 		const char *prefix;
119 		unsigned i;
120 
121 		if (usage == NULL)
122 			prefix = "usage:";
123 		else {
124 			usage(comm);
125 			prefix = "      ";
126 		}
127 		for (i = 0; ; i++) {
128 			struct g_command *cmd;
129 
130 			cmd = &std_commands[i];
131 			if (cmd->gc_name == NULL)
132 				break;
133 			if (find_command(cmd->gc_name, 0) != NULL)
134 				continue;
135 			if (!std_available(cmd->gc_name))
136 				continue;
137 			fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name);
138 			if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
139 				fprintf(stderr, " [-v]");
140 			fprintf(stderr, "\n");
141 			prefix = "      ";
142 		}
143 		exit(EXIT_FAILURE);
144 	}
145 }
146 
147 static void
148 load_module(void)
149 {
150 	char name1[64], name2[64];
151 
152 	snprintf(name1, sizeof(name1), "g_%s", class_name);
153 	snprintf(name2, sizeof(name2), "geom_%s", class_name);
154 	if (modfind(name1) < 0) {
155 		/* Not present in kernel, try loading it. */
156 		if (kldload(name2) < 0 || modfind(name1) < 0) {
157 			if (errno != EEXIST) {
158 				errx(EXIT_FAILURE,
159 				    "%s module not available!", name2);
160 			}
161 		}
162 	}
163 }
164 
165 static int
166 strlcatf(char *str, size_t size, const char *format, ...)
167 {
168 	size_t len;
169 	va_list ap;
170 	int ret;
171 
172 	len = strlen(str);
173 	str += len;
174 	size -= len;
175 
176 	va_start(ap, format);
177 	ret = vsnprintf(str, size, format, ap);
178 	va_end(ap);
179 
180 	return (ret);
181 }
182 
183 /*
184  * Find given option in options available for given command.
185  */
186 static struct g_option *
187 find_option(struct g_command *cmd, char ch)
188 {
189 	struct g_option *opt;
190 	unsigned i;
191 
192 	for (i = 0; ; i++) {
193 		opt = &cmd->gc_options[i];
194 		if (opt->go_name == NULL)
195 			return (NULL);
196 		if (opt->go_char == ch)
197 			return (opt);
198 	}
199 	/* NOTREACHED */
200 	return (NULL);
201 }
202 
203 /*
204  * Add given option to gctl_req.
205  */
206 static void
207 set_option(struct gctl_req *req, struct g_option *opt, const char *val)
208 {
209 
210 	if (opt->go_type == G_TYPE_NUMBER) {
211 		intmax_t number;
212 
213 		errno = 0;
214 		number = strtoimax(optarg, NULL, 0);
215 		if (errno != 0) {
216 			err(EXIT_FAILURE, "Invalid value for '%c' argument.",
217 			    opt->go_char);
218 		}
219 		opt->go_val = malloc(sizeof(intmax_t));
220 		if (opt->go_val == NULL)
221 			errx(EXIT_FAILURE, "No memory.");
222 		*(intmax_t *)opt->go_val = number;
223 
224 		gctl_ro_param(req, opt->go_name, sizeof(intmax_t), opt->go_val);
225 	} else if (opt->go_type == G_TYPE_STRING) {
226 		gctl_ro_param(req, opt->go_name, -1, optarg);
227 	} else /* if (opt->go_type == G_TYPE_NONE) */ {
228 		opt->go_val = malloc(sizeof(int));
229 		if (opt->go_val == NULL)
230 			errx(EXIT_FAILURE, "No memory.");
231 		*(int *)opt->go_val = *val - '0';
232 
233 		gctl_ro_param(req, opt->go_name, sizeof(int),
234 		    opt->go_val);
235 	}
236 }
237 
238 /*
239  * 1. Add given argument by caller.
240  * 2. Add default values of not given arguments.
241  * 3. Add the rest of arguments.
242  */
243 static void
244 parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
245     char ***argv)
246 {
247 	struct g_option *opt;
248 	char opts[64];
249 	unsigned i;
250 	int ch;
251 
252 	*opts = '\0';
253 	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
254 		strlcat(opts, "v", sizeof(opts));
255 	for (i = 0; ; i++) {
256 		opt = &cmd->gc_options[i];
257 		if (opt->go_name == NULL)
258 			break;
259 		strlcatf(opts, sizeof(opts), "%c", opt->go_char);
260 		if (opt->go_type != G_TYPE_NONE)
261 			strlcat(opts, ":", sizeof(opts));
262 	}
263 
264 	/*
265 	 * Add specified arguments.
266 	 */
267 	while ((ch = getopt(*argc, *argv, opts)) != -1) {
268 		/* Standard (not passed to kernel) options. */
269 		switch (ch) {
270 		case 'v':
271 			verbose = 1;
272 			continue;
273 		}
274 		/* Options passed to kernel. */
275 		opt = find_option(cmd, ch);
276 		if (opt == NULL)
277 			geom_usage();
278 		if (G_OPT_ISDONE(opt)) {
279 			fprintf(stderr, "Flag '%c' specified twice.\n",
280 			    opt->go_char);
281 			geom_usage();
282 		}
283 		G_OPT_DONE(opt);
284 
285 		if (opt->go_type == G_TYPE_NONE)
286 			set_option(req, opt, "1");
287 		else
288 			set_option(req, opt, optarg);
289 	}
290 	*argc -= optind;
291 	*argv += optind;
292 
293 	/*
294 	 * Add not specified arguments, but with default values.
295 	 */
296 	for (i = 0; ; i++) {
297 		opt = &cmd->gc_options[i];
298 		if (opt->go_name == NULL)
299 			break;
300 		if (G_OPT_ISDONE(opt))
301 			continue;
302 
303 		if (opt->go_type == G_TYPE_NONE) {
304 			assert(opt->go_val == NULL);
305 			set_option(req, opt, "0");
306 		} else {
307 			if (opt->go_val == NULL) {
308 				fprintf(stderr, "Flag '%c' not specified.\n",
309 				    opt->go_char);
310 				geom_usage();
311 			} else {
312 				if (opt->go_type == G_TYPE_NUMBER) {
313 					gctl_ro_param(req, opt->go_name,
314 					    sizeof(intmax_t), opt->go_val);
315 				} else /* if (opt->go_type == G_TYPE_STRING)*/ {
316 					gctl_ro_param(req, opt->go_name, -1,
317 					    opt->go_val);
318 				}
319 			}
320 		}
321 	}
322 	/*
323 	 * Add rest of given arguments.
324 	 */
325 	gctl_ro_param(req, "nargs", sizeof(int), argc);
326 	for (i = 0; i < (unsigned)*argc; i++) {
327 		char argname[16];
328 
329 		snprintf(argname, sizeof(argname), "arg%u", i);
330 		gctl_ro_param(req, argname, -1, (*argv)[i]);
331 	}
332 }
333 
334 /*
335  * Find given command in commands available for given class.
336  */
337 static struct g_command *
338 find_command(const char *cmdstr, int all)
339 {
340 	struct g_command *cmd;
341 	unsigned i;
342 
343 	/*
344 	 * First try to find command defined by loaded library.
345 	 */
346 	if (class_commands != NULL) {
347 		for (i = 0; ; i++) {
348 			cmd = &class_commands[i];
349 			if (cmd->gc_name == NULL)
350 				break;
351 			if (strcmp(cmd->gc_name, cmdstr) == 0)
352 				return (cmd);
353 		}
354 	}
355 	if (!all)
356 		return (NULL);
357 	/*
358 	 * Now try to find in standard commands.
359 	 */
360 	for (i = 0; ; i++) {
361 		cmd = &std_commands[i];
362 		if (cmd->gc_name == NULL)
363 			break;
364 		if (!std_available(cmd->gc_name))
365 			continue;
366 		if (strcmp(cmd->gc_name, cmdstr) == 0)
367 			return (cmd);
368 	}
369 	return (NULL);
370 }
371 
372 static unsigned
373 set_flags(struct g_command *cmd)
374 {
375 	unsigned flags = 0;
376 
377 	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
378 		flags |= G_FLAG_VERBOSE;
379 
380 	return (flags);
381 }
382 
383 /*
384  * Run command.
385  */
386 static void
387 run_command(int argc, char *argv[])
388 {
389 	struct g_command *cmd;
390 	struct gctl_req *req;
391 	const char *errstr;
392 	char buf[4096];
393 
394 	cmd = find_command(argv[0], 1);
395 	if (cmd == NULL) {
396 		fprintf(stderr, "Unknown command: %s\n", argv[0]);
397 		geom_usage();
398 	}
399 	if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
400 		load_module();
401 
402 	req = gctl_get_handle();
403 	gctl_ro_param(req, "class", -1, gclass_name);
404 	gctl_ro_param(req, "verb", -1, argv[0]);
405 	if (version != NULL)
406 		gctl_ro_param(req, "version", sizeof(*version), version);
407 	parse_arguments(cmd, req, &argc, &argv);
408 
409 	if (cmd->gc_func != NULL) {
410 		unsigned flags;
411 
412 		flags = set_flags(cmd);
413 		cmd->gc_func(req, flags);
414 		errstr = req->error;
415 	} else {
416 		bzero(buf, sizeof(buf));
417 		gctl_rw_param(req, "output", sizeof(buf), buf);
418 		errstr = gctl_issue(req);
419 	}
420 	if (errstr != NULL) {
421 		fprintf(stderr, "%s\n", errstr);
422 		gctl_free(req);
423 		exit(EXIT_FAILURE);
424 	}
425 	if (*buf != '\0')
426 		printf("%s", buf);
427 	gctl_free(req);
428 	if (verbose)
429 		printf("Done.\n");
430 	exit(EXIT_SUCCESS);
431 }
432 
433 static void
434 load_library(void)
435 {
436 	char path[MAXPATHLEN];
437 	uint32_t *lib_version;
438 	void *dlh;
439 
440 	snprintf(path, sizeof(path), "%s/geom_%s.so", CLASSDIR, class_name);
441 	dlh = dlopen(path, RTLD_NOW);
442 	if (dlh == NULL) {
443 #if 0
444 		fprintf(stderr, "Cannot open library %s, but continuing "
445 		    "anyway.\n", path);
446 #endif
447 		/*
448 		 * Even if library cannot be loaded, standard commands are
449 		 * available, so don't panic!
450 		 */
451 		return;
452 	}
453 	lib_version = dlsym(dlh, "lib_version");
454 	if (lib_version == NULL) {
455 		fprintf(stderr, "Cannot find symbol %s: %s.\n", "lib_version",
456 		    dlerror());
457 		dlclose(dlh);
458 		exit(EXIT_FAILURE);
459 	}
460 	if (*lib_version != G_LIB_VERSION) {
461 		dlclose(dlh);
462 		errx(EXIT_FAILURE, "%s and %s are not synchronized.", comm,
463 		    path);
464 	}
465 	version = dlsym(dlh, "version");
466 	if (version == NULL) {
467 		fprintf(stderr, "Cannot find symbol %s: %s.\n", "version",
468 		    dlerror());
469 		dlclose(dlh);
470 		exit(EXIT_FAILURE);
471 	}
472 	class_commands = dlsym(dlh, "class_commands");
473 	if (class_commands == NULL) {
474 		fprintf(stderr, "Cannot find symbol %s: %s.\n",
475 		    "class_commands", dlerror());
476 		dlclose(dlh);
477 		exit(EXIT_FAILURE);
478 	}
479 	usage = dlsym(dlh, "usage");
480 	if (usage == NULL)
481 		usage = std_usage;
482 }
483 
484 /*
485  * Class name should be all capital letters.
486  */
487 static void
488 set_class_name(void)
489 {
490 	char *s1, *s2;
491 
492 	gclass_name = malloc(strlen(class_name));
493 	if (gclass_name == NULL)
494 		errx(EXIT_FAILURE, "No memory");
495 	s1 = gclass_name;
496 	s2 = class_name;
497 	for (; *s2 != '\0'; s2++)
498 		*s1++ = toupper(*s2);
499 	*s1 = '\0';
500 }
501 
502 static void
503 get_class(int *argc, char ***argv)
504 {
505 
506 	snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
507 	if (strcmp(comm, "geom") == 0) {
508 		if (*argc < 2)
509 			geom_usage();
510 		strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
511 		class_name = (*argv)[1];
512 		*argc -= 2;
513 		*argv += 2;
514 	} else if (*comm == 'g') {
515 		class_name = comm + 1;
516 		*argc -= 1;
517 		*argv += 1;
518 	} else {
519 		errx(EXIT_FAILURE, "Invalid utility name.");
520 	}
521 	set_class_name();
522 	load_library();
523 	if (*argc < 1)
524 		geom_usage();
525 }
526 
527 int
528 main(int argc, char *argv[])
529 {
530 
531 	get_class(&argc, &argv);
532 	run_command(argc, argv);
533 	/* NOTREACHED */
534 
535 	exit(EXIT_FAILURE);
536 }
537 
538 static struct gclass *
539 find_class(struct gmesh *mesh, const char *name)
540 {
541 	struct gclass *classp;
542 
543 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
544 		if (strcmp(classp->lg_name, name) == 0)
545 			return (classp);
546 	}
547 	return (NULL);
548 }
549 
550 static struct gprovider *
551 find_provider(struct gclass *classp, const char *name)
552 {
553 	struct ggeom *gp;
554 	struct gprovider *pp;
555 
556 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
557 		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
558 			if (strcmp(pp->lg_name, name) == 0)
559 				return (pp);
560 		}
561 	}
562 	return (NULL);
563 }
564 
565 static char *
566 genspaces(const char *text, size_t len)
567 {
568 	static char spaces[256];
569 	size_t outlen;
570 
571 	if (strlen(text) >= len) {
572 		spaces[0] = '\0';
573 		return (spaces);
574 	}
575 	memset(spaces, ' ', sizeof(spaces));
576 	outlen = len - strlen(text);
577 	if (outlen >= sizeof(spaces)) {
578 		spaces[sizeof(spaces) - 1] = '\0';
579 		return (spaces);
580 	}
581 	spaces[outlen] = '\0';
582 	return (spaces);
583 }
584 
585 static void
586 show_one(struct gprovider *pp)
587 {
588 	struct gconfig *conf;
589 
590 	printf("       NAME: %s\n", pp->lg_name);
591 	printf("  geom name: %s\n", pp->lg_geom->lg_name);
592 	printf("  mediasize: %jd\n", (intmax_t)pp->lg_mediasize);
593 	printf(" sectorsize: %u\n", pp->lg_sectorsize);
594 	printf("       mode: %s\n", pp->lg_mode);
595 	LIST_FOREACH(conf, &pp->lg_config, lg_config) {
596 		printf("%s%s: %s\n", genspaces(conf->lg_name, 11),
597 		    conf->lg_name, conf->lg_val);
598 	}
599 	printf("\n");
600 }
601 
602 static void
603 std_help(struct gctl_req *req __unused, unsigned flags __unused)
604 {
605 
606 	geom_usage();
607 }
608 
609 static int
610 std_list_available(void)
611 {
612 	struct gmesh mesh;
613 	struct gclass *classp;
614 	int error;
615 
616 	error = geom_gettree(&mesh);
617 	if (error != 0)
618 		exit(EXIT_FAILURE);
619 	classp = find_class(&mesh, gclass_name);
620 	geom_deletetree(&mesh);
621 	if (classp != NULL)
622 		return (1);
623 	return (0);
624 }
625 
626 static void
627 std_list(struct gctl_req *req, unsigned flags __unused)
628 {
629 	struct gmesh mesh;
630 	struct gclass *classp;
631 	struct gprovider *pp;
632 	int error, *nargs;
633 
634 	error = geom_gettree(&mesh);
635 	if (error != 0)
636 		exit(EXIT_FAILURE);
637 	classp = find_class(&mesh, gclass_name);
638 	if (classp == NULL) {
639 		geom_deletetree(&mesh);
640 		fprintf(stderr, "Class %s not found.\n", gclass_name);
641 		return;
642 	}
643 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
644 	if (nargs == NULL) {
645 		gctl_error(req, "No '%s' argument.", "nargs");
646 		geom_deletetree(&mesh);
647 		return;
648 	}
649 	if (*nargs > 0) {
650 		int i;
651 
652 		for (i = 0; i < *nargs; i++) {
653 			const char *name;
654 			char param[16];
655 
656 			snprintf(param, sizeof(param), "arg%d", i);
657 			name = gctl_get_asciiparam(req, param);
658 			assert(name != NULL);
659 			pp = find_provider(classp, name);
660 			if (pp != NULL)
661 				show_one(pp);
662 			else {
663 				fprintf(stderr, "No such provider: %s.\n",
664 				    name);
665 			}
666 		}
667 	} else {
668 		struct ggeom *gp;
669 
670 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
671 			LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
672 				show_one(pp);
673 			}
674 		}
675 	}
676 	geom_deletetree(&mesh);
677 }
678 
679 static int
680 std_load_available(void)
681 {
682 	char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
683 	struct stat sb;
684 	size_t len;
685 
686 	snprintf(name, sizeof(name), "g_%s", class_name);
687 	/*
688 	 * If already in kernel, "load" command is not available.
689 	 */
690 	if (modfind(name) >= 0)
691 		return (0);
692 	bzero(paths, sizeof(paths));
693 	len = sizeof(paths);
694 	if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
695 		err(EXIT_FAILURE, "sysctl(kern.module_path)");
696 	for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
697 		snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
698 		/*
699 		 * If geom_<name>.ko file exists, "load" command is available.
700 		 */
701 		if (stat(name, &sb) == 0)
702 			return (1);
703 	}
704 	return (0);
705 }
706 
707 static void
708 std_load(struct gctl_req *req __unused, unsigned flags)
709 {
710 
711 	/*
712 	 * Do nothing special here, because of G_FLAG_LOADKLD flag,
713 	 * module is already loaded.
714 	 */
715 	if ((flags & G_FLAG_VERBOSE) != 0)
716 		printf("Module available.\n");
717 }
718 
719 static int
720 std_unload_available(void)
721 {
722 	char name[64];
723 	int id;
724 
725 	snprintf(name, sizeof(name), "geom_%s", class_name);
726 	id = kldfind(name);
727 	if (id >= 0)
728 		return (1);
729 	return (0);
730 }
731 
732 static void
733 std_unload(struct gctl_req *req, unsigned flags __unused)
734 {
735 	char name[64];
736 	int id;
737 
738 	snprintf(name, sizeof(name), "geom_%s", class_name);
739 	id = kldfind(name);
740 	if (id < 0) {
741 		gctl_error(req, "Could not find module: %s.", strerror(errno));
742 		return;
743 	}
744 	if (kldunload(id) < 0) {
745 		gctl_error(req, "Could not unload module: %s.",
746 		    strerror(errno));
747 		return;
748 	}
749 }
750 
751 static int
752 std_available(const char *name)
753 {
754 
755 	if (strcmp(name, "help") == 0)
756 		return (1);
757 	else if (strcmp(name, "list") == 0)
758 		return (std_list_available());
759 	else if (strcmp(name, "load") == 0)
760 		return (std_load_available());
761 	else if (strcmp(name, "unload") == 0)
762 		return (std_unload_available());
763 	else
764 		assert(!"Unknown standard command.");
765 	return (0);
766 }
767