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