xref: /freebsd/sbin/geom/core/geom.c (revision 1d723f1d518b79fdea655f82e5419ae4888ad78c)
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 ggeom *
552 find_geom(struct gclass *classp, const char *name)
553 {
554 	struct ggeom *gp;
555 
556 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
557 		if (strcmp(gp->lg_name, name) == 0)
558 			return (gp);
559 	}
560 	return (NULL);
561 }
562 
563 static void
564 show_one_provider(struct gprovider *pp, const char *prefix)
565 {
566 	struct gconfig *conf;
567 	char buf[5];
568 
569 	printf("Name: %s\n", pp->lg_name);
570 	humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
571 	    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
572 	printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
573 	    buf);
574 	printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
575 	printf("%sMode: %s\n", prefix, pp->lg_mode);
576 	LIST_FOREACH(conf, &pp->lg_config, lg_config) {
577 		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
578 	}
579 }
580 
581 static void
582 show_one_consumer(struct gconsumer *cp, const char *prefix)
583 {
584 	struct gprovider *pp;
585 	struct gconfig *conf;
586 
587 	pp = cp->lg_provider;
588 	if (pp == NULL)
589 		printf("[no provider]\n");
590 	else {
591 		char buf[5];
592 
593 		printf("Name: %s\n", pp->lg_name);
594 		humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
595 		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
596 		printf("%sMediasize: %jd (%s)\n", prefix,
597 		    (intmax_t)pp->lg_mediasize, buf);
598 		printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
599 		printf("%sMode: %s\n", prefix, cp->lg_mode);
600 	}
601 	LIST_FOREACH(conf, &cp->lg_config, lg_config) {
602 		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
603 	}
604 }
605 
606 static void
607 show_one_geom(struct ggeom *gp)
608 {
609 	struct gprovider *pp;
610 	struct gconsumer *cp;
611 	struct gconfig *conf;
612 	unsigned n;
613 
614 	printf("Geom name: %s\n", gp->lg_name);
615 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
616 		printf("%s: %s\n", conf->lg_name, conf->lg_val);
617 	}
618 	if (!LIST_EMPTY(&gp->lg_provider)) {
619 		printf("Providers:\n");
620 		n = 1;
621 		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
622 			printf("%u. ", n++);
623 			show_one_provider(pp, "   ");
624 		}
625 	}
626 	if (!LIST_EMPTY(&gp->lg_consumer)) {
627 		printf("Consumers:\n");
628 		n = 1;
629 		LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
630 			printf("%u. ", n++);
631 			show_one_consumer(cp, "   ");
632 		}
633 	}
634 	printf("\n");
635 }
636 
637 static void
638 std_help(struct gctl_req *req __unused, unsigned flags __unused)
639 {
640 
641 	geom_usage();
642 }
643 
644 static int
645 std_list_available(void)
646 {
647 	struct gmesh mesh;
648 	struct gclass *classp;
649 	int error;
650 
651 	error = geom_gettree(&mesh);
652 	if (error != 0)
653 		exit(EXIT_FAILURE);
654 	classp = find_class(&mesh, gclass_name);
655 	geom_deletetree(&mesh);
656 	if (classp != NULL)
657 		return (1);
658 	return (0);
659 }
660 
661 static void
662 std_list(struct gctl_req *req, unsigned flags __unused)
663 {
664 	struct gmesh mesh;
665 	struct gclass *classp;
666 	struct ggeom *gp;
667 	int error, *nargs;
668 
669 	error = geom_gettree(&mesh);
670 	if (error != 0)
671 		exit(EXIT_FAILURE);
672 	classp = find_class(&mesh, gclass_name);
673 	if (classp == NULL) {
674 		geom_deletetree(&mesh);
675 		fprintf(stderr, "Class %s not found.\n", gclass_name);
676 		return;
677 	}
678 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
679 	if (nargs == NULL) {
680 		gctl_error(req, "No '%s' argument.", "nargs");
681 		geom_deletetree(&mesh);
682 		return;
683 	}
684 	if (*nargs > 0) {
685 		int i;
686 
687 		for (i = 0; i < *nargs; i++) {
688 			const char *name;
689 			char param[16];
690 
691 			snprintf(param, sizeof(param), "arg%d", i);
692 			name = gctl_get_asciiparam(req, param);
693 			assert(name != NULL);
694 			gp = find_geom(classp, name);
695 			if (gp != NULL)
696 				show_one_geom(gp);
697 			else
698 				fprintf(stderr, "No such geom: %s.\n", name);
699 		}
700 	} else {
701 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
702 			show_one_geom(gp);
703 		}
704 	}
705 	geom_deletetree(&mesh);
706 }
707 
708 static int
709 std_load_available(void)
710 {
711 	char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
712 	struct stat sb;
713 	size_t len;
714 
715 	snprintf(name, sizeof(name), "g_%s", class_name);
716 	/*
717 	 * If already in kernel, "load" command is not available.
718 	 */
719 	if (modfind(name) >= 0)
720 		return (0);
721 	bzero(paths, sizeof(paths));
722 	len = sizeof(paths);
723 	if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
724 		err(EXIT_FAILURE, "sysctl(kern.module_path)");
725 	for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
726 		snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
727 		/*
728 		 * If geom_<name>.ko file exists, "load" command is available.
729 		 */
730 		if (stat(name, &sb) == 0)
731 			return (1);
732 	}
733 	return (0);
734 }
735 
736 static void
737 std_load(struct gctl_req *req __unused, unsigned flags)
738 {
739 
740 	/*
741 	 * Do nothing special here, because of G_FLAG_LOADKLD flag,
742 	 * module is already loaded.
743 	 */
744 	if ((flags & G_FLAG_VERBOSE) != 0)
745 		printf("Module available.\n");
746 }
747 
748 static int
749 std_unload_available(void)
750 {
751 	char name[64];
752 	int id;
753 
754 	snprintf(name, sizeof(name), "geom_%s", class_name);
755 	id = kldfind(name);
756 	if (id >= 0)
757 		return (1);
758 	return (0);
759 }
760 
761 static void
762 std_unload(struct gctl_req *req, unsigned flags __unused)
763 {
764 	char name[64];
765 	int id;
766 
767 	snprintf(name, sizeof(name), "geom_%s", class_name);
768 	id = kldfind(name);
769 	if (id < 0) {
770 		gctl_error(req, "Could not find module: %s.", strerror(errno));
771 		return;
772 	}
773 	if (kldunload(id) < 0) {
774 		gctl_error(req, "Could not unload module: %s.",
775 		    strerror(errno));
776 		return;
777 	}
778 }
779 
780 static int
781 std_available(const char *name)
782 {
783 
784 	if (strcmp(name, "help") == 0)
785 		return (1);
786 	else if (strcmp(name, "list") == 0)
787 		return (std_list_available());
788 	else if (strcmp(name, "load") == 0)
789 		return (std_load_available());
790 	else if (strcmp(name, "unload") == 0)
791 		return (std_unload_available());
792 	else
793 		assert(!"Unknown standard command.");
794 	return (0);
795 }
796