xref: /freebsd/sbin/geom/core/geom.c (revision d5566384042fa631ffe7916fd89bcb4669ad12a7)
1 /*-
2  * Copyright (c) 2004-2005 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 
60 #define	GEOM_CLASS_CMDS	0x01
61 #define	GEOM_STD_CMDS	0x02
62 static struct g_command *find_command(const char *cmdstr, int flags);
63 static int std_available(const char *name);
64 
65 static void std_help(struct gctl_req *req, unsigned flags);
66 static void std_list(struct gctl_req *req, unsigned flags);
67 static void std_status(struct gctl_req *req, unsigned flags);
68 static void std_load(struct gctl_req *req, unsigned flags);
69 static void std_unload(struct gctl_req *req, unsigned flags);
70 
71 struct g_command std_commands[] = {
72 	{ "help", 0, std_help, G_NULL_OPTS, NULL, NULL },
73 	{ "list", 0, std_list, G_NULL_OPTS, NULL,
74 	    "[name ...]"
75 	},
76 	{ "status", 0, std_status,
77 	    {
78 		{ 's', "script", NULL, G_TYPE_BOOL },
79 		G_OPT_SENTINEL
80 	    },
81 	    NULL, "[-s] [name ...]"
82 	},
83 	{ "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS,
84 	    NULL, NULL },
85 	{ "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS, NULL, NULL },
86 	G_CMD_SENTINEL
87 };
88 
89 static void
90 usage_command(struct g_command *cmd, const char *prefix)
91 {
92 	struct g_option *opt;
93 	unsigned i;
94 
95 	fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name);
96 	if (cmd->gc_usage != NULL) {
97 		fprintf(stderr, " %s\n", cmd->gc_usage);
98 		return;
99 	}
100 	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
101 		fprintf(stderr, " [-v]");
102 	for (i = 0; ; i++) {
103 		opt = &cmd->gc_options[i];
104 		if (opt->go_name == NULL)
105 			break;
106 		if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
107 			fprintf(stderr, " [");
108 		else
109 			fprintf(stderr, " ");
110 		fprintf(stderr, "-%c", opt->go_char);
111 		if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
112 			fprintf(stderr, " %s", opt->go_name);
113 		if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
114 			fprintf(stderr, "]");
115 	}
116 	if (cmd->gc_argname)
117 		fprintf(stderr, " %s", cmd->gc_argname);
118 	fprintf(stderr, "\n");
119 }
120 
121 static void
122 usage(void)
123 {
124 
125 	if (class_name == NULL) {
126 		errx(EXIT_FAILURE, "usage: %s <class> <command> [options]",
127 		    "geom");
128 	} else {
129 		struct g_command *cmd;
130 		const char *prefix;
131 		unsigned i;
132 
133 		prefix = "usage:";
134 		if (class_commands != NULL) {
135 			for (i = 0; ; i++) {
136 				cmd = &class_commands[i];
137 				if (cmd->gc_name == NULL)
138 					break;
139 				usage_command(cmd, prefix);
140 				prefix = "      ";
141 			}
142 		}
143 		for (i = 0; ; i++) {
144 			cmd = &std_commands[i];
145 			if (cmd->gc_name == NULL)
146 				break;
147 			/*
148 			 * If class defines command, which has the same name as
149 			 * standard command, skip it, because it was already
150 			 * shown on usage().
151 			 */
152 			if (find_command(cmd->gc_name, GEOM_CLASS_CMDS) != NULL)
153 				continue;
154 			usage_command(cmd, prefix);
155 			prefix = "      ";
156 		}
157 		exit(EXIT_FAILURE);
158 	}
159 }
160 
161 static void
162 load_module(void)
163 {
164 	char name1[64], name2[64];
165 
166 	snprintf(name1, sizeof(name1), "g_%s", class_name);
167 	snprintf(name2, sizeof(name2), "geom_%s", class_name);
168 	if (modfind(name1) < 0) {
169 		/* Not present in kernel, try loading it. */
170 		if (kldload(name2) < 0 || modfind(name1) < 0) {
171 			if (errno != EEXIST) {
172 				errx(EXIT_FAILURE,
173 				    "%s module not available!", name2);
174 			}
175 		}
176 	}
177 }
178 
179 static int
180 strlcatf(char *str, size_t size, const char *format, ...)
181 {
182 	size_t len;
183 	va_list ap;
184 	int ret;
185 
186 	len = strlen(str);
187 	str += len;
188 	size -= len;
189 
190 	va_start(ap, format);
191 	ret = vsnprintf(str, size, format, ap);
192 	va_end(ap);
193 
194 	return (ret);
195 }
196 
197 /*
198  * Find given option in options available for given command.
199  */
200 static struct g_option *
201 find_option(struct g_command *cmd, char ch)
202 {
203 	struct g_option *opt;
204 	unsigned i;
205 
206 	for (i = 0; ; i++) {
207 		opt = &cmd->gc_options[i];
208 		if (opt->go_name == NULL)
209 			return (NULL);
210 		if (opt->go_char == ch)
211 			return (opt);
212 	}
213 	/* NOTREACHED */
214 	return (NULL);
215 }
216 
217 /*
218  * Add given option to gctl_req.
219  */
220 static void
221 set_option(struct gctl_req *req, struct g_option *opt, const char *val)
222 {
223 
224 	if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) {
225 		intmax_t number;
226 
227 		if (expand_number(val, &number) == -1) {
228 			err(EXIT_FAILURE, "Invalid value for '%c' argument.",
229 			    opt->go_char);
230 		}
231 		opt->go_val = malloc(sizeof(intmax_t));
232 		if (opt->go_val == NULL)
233 			errx(EXIT_FAILURE, "No memory.");
234 		*(intmax_t *)opt->go_val = number;
235 
236 		gctl_ro_param(req, opt->go_name, sizeof(intmax_t), opt->go_val);
237 	} else if (G_OPT_TYPE(opt) == G_TYPE_STRING) {
238 		gctl_ro_param(req, opt->go_name, -1, val);
239 	} else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
240 		opt->go_val = malloc(sizeof(int));
241 		if (opt->go_val == NULL)
242 			errx(EXIT_FAILURE, "No memory.");
243 		*(int *)opt->go_val = *val - '0';
244 
245 		gctl_ro_param(req, opt->go_name, sizeof(int),
246 		    opt->go_val);
247 	} else {
248 		assert(!"Invalid type");
249 	}
250 }
251 
252 /*
253  * 1. Add given argument by caller.
254  * 2. Add default values of not given arguments.
255  * 3. Add the rest of arguments.
256  */
257 static void
258 parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
259     char ***argv)
260 {
261 	struct g_option *opt;
262 	char opts[64];
263 	unsigned i;
264 	int ch;
265 
266 	*opts = '\0';
267 	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
268 		strlcat(opts, "v", sizeof(opts));
269 	for (i = 0; ; i++) {
270 		opt = &cmd->gc_options[i];
271 		if (opt->go_name == NULL)
272 			break;
273 		assert(G_OPT_TYPE(opt) != 0);
274 		assert((opt->go_type & ~G_TYPE_MASK) == 0);
275 		strlcatf(opts, sizeof(opts), "%c", opt->go_char);
276 		if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
277 			strlcat(opts, ":", sizeof(opts));
278 	}
279 
280 	/*
281 	 * Add specified arguments.
282 	 */
283 	while ((ch = getopt(*argc, *argv, opts)) != -1) {
284 		/* Standard (not passed to kernel) options. */
285 		switch (ch) {
286 		case 'v':
287 			verbose = 1;
288 			continue;
289 		}
290 		/* Options passed to kernel. */
291 		opt = find_option(cmd, ch);
292 		if (opt == NULL)
293 			usage();
294 		if (G_OPT_ISDONE(opt)) {
295 			warnx("Option '%c' specified twice.", opt->go_char);
296 			usage();
297 		}
298 		G_OPT_DONE(opt);
299 
300 		if (G_OPT_TYPE(opt) == G_TYPE_BOOL)
301 			set_option(req, opt, "1");
302 		else
303 			set_option(req, opt, optarg);
304 	}
305 	*argc -= optind;
306 	*argv += optind;
307 
308 	/*
309 	 * Add not specified arguments, but with default values.
310 	 */
311 	for (i = 0; ; i++) {
312 		opt = &cmd->gc_options[i];
313 		if (opt->go_name == NULL)
314 			break;
315 		if (G_OPT_ISDONE(opt))
316 			continue;
317 
318 		if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
319 			assert(opt->go_val == NULL);
320 			set_option(req, opt, "0");
321 		} else {
322 			if (opt->go_val == NULL) {
323 				warnx("Option '%c' not specified.",
324 				    opt->go_char);
325 				usage();
326 			} else {
327 				if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) {
328 					gctl_ro_param(req, opt->go_name,
329 					    sizeof(intmax_t), opt->go_val);
330 				} else if (G_OPT_TYPE(opt) == G_TYPE_STRING) {
331 					if (cmd->gc_argname == NULL ||
332 					    opt->go_val == NULL ||
333 					    *(char *)opt->go_val != '\0')
334 						gctl_ro_param(req, opt->go_name,
335 						    -1, opt->go_val);
336 				} else {
337 					assert(!"Invalid type");
338 				}
339 			}
340 		}
341 	}
342 
343 	if (cmd->gc_argname == NULL) {
344 		/*
345 		 * Add rest of given arguments.
346 		 */
347 		gctl_ro_param(req, "nargs", sizeof(int), argc);
348 		for (i = 0; i < (unsigned)*argc; i++) {
349 			char argname[16];
350 
351 			snprintf(argname, sizeof(argname), "arg%u", i);
352 			gctl_ro_param(req, argname, -1, (*argv)[i]);
353 		}
354 	} else {
355 		if (*argc != 1)
356 			usage();
357 		gctl_ro_param(req, cmd->gc_argname, -1, (*argv)[0]);
358 	}
359 }
360 
361 /*
362  * Find given command in commands available for given class.
363  */
364 static struct g_command *
365 find_command(const char *cmdstr, int flags)
366 {
367 	struct g_command *cmd;
368 	unsigned i;
369 
370 	/*
371 	 * First try to find command defined by loaded library.
372 	 */
373 	if ((flags & GEOM_CLASS_CMDS) != 0 && class_commands != NULL) {
374 		for (i = 0; ; i++) {
375 			cmd = &class_commands[i];
376 			if (cmd->gc_name == NULL)
377 				break;
378 			if (strcmp(cmd->gc_name, cmdstr) == 0)
379 				return (cmd);
380 		}
381 	}
382 	/*
383 	 * Now try to find in standard commands.
384 	 */
385 	if ((flags & GEOM_STD_CMDS) != 0) {
386 		for (i = 0; ; i++) {
387 			cmd = &std_commands[i];
388 			if (cmd->gc_name == NULL)
389 				break;
390 			if (strcmp(cmd->gc_name, cmdstr) == 0)
391 				return (cmd);
392 		}
393 	}
394 	return (NULL);
395 }
396 
397 static unsigned
398 set_flags(struct g_command *cmd)
399 {
400 	unsigned flags = 0;
401 
402 	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
403 		flags |= G_FLAG_VERBOSE;
404 
405 	return (flags);
406 }
407 
408 /*
409  * Run command.
410  */
411 static void
412 run_command(int argc, char *argv[])
413 {
414 	struct g_command *cmd;
415 	struct gctl_req *req;
416 	const char *errstr;
417 	char buf[4096];
418 
419 	/* First try to find a command defined by a class. */
420 	cmd = find_command(argv[0], GEOM_CLASS_CMDS);
421 	if (cmd == NULL) {
422 		/* Now, try to find a standard command. */
423 		cmd = find_command(argv[0], GEOM_STD_CMDS);
424 		if (cmd == NULL) {
425 			warnx("Unknown command: %s.", argv[0]);
426 			usage();
427 		}
428 		if (!std_available(cmd->gc_name)) {
429 			warnx("Command '%s' not available.", argv[0]);
430 			exit(EXIT_FAILURE);
431 		}
432 	}
433 	if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
434 		load_module();
435 
436 	req = gctl_get_handle();
437 	gctl_ro_param(req, "class", -1, gclass_name);
438 	gctl_ro_param(req, "verb", -1, argv[0]);
439 	if (version != NULL)
440 		gctl_ro_param(req, "version", sizeof(*version), version);
441 	parse_arguments(cmd, req, &argc, &argv);
442 
443 	bzero(buf, sizeof(buf));
444 	if (cmd->gc_func != NULL) {
445 		unsigned flags;
446 
447 		flags = set_flags(cmd);
448 		cmd->gc_func(req, flags);
449 		errstr = req->error;
450 	} else {
451 		gctl_rw_param(req, "output", sizeof(buf), buf);
452 		errstr = gctl_issue(req);
453 	}
454 	if (errstr != NULL && errstr[0] != '\0') {
455 		warnx("%s", errstr);
456 		if (strncmp(errstr, "warning: ", strlen("warning: ")) != 0) {
457 			gctl_free(req);
458 			exit(EXIT_FAILURE);
459 		}
460 	}
461 	if (buf[0] != '\0')
462 		printf("%s", buf);
463 	gctl_free(req);
464 	if (verbose)
465 		printf("Done.\n");
466 	exit(EXIT_SUCCESS);
467 }
468 
469 static const char *
470 library_path(void)
471 {
472 	const char *path;
473 
474 	path = getenv("GEOM_LIBRARY_PATH");
475 	if (path == NULL)
476 		path = CLASS_DIR;
477 	return (path);
478 }
479 
480 static void
481 load_library(void)
482 {
483 	char path[MAXPATHLEN];
484 	uint32_t *lib_version;
485 	void *dlh;
486 
487 	snprintf(path, sizeof(path), "%s/geom_%s.so", library_path(),
488 	    class_name);
489 	if (access(path, F_OK) == -1) {
490 		if (errno == ENOENT) {
491 			/*
492 			 * If we cannot find library, that's ok, standard
493 			 * commands can still be used.
494 			 */
495 			return;
496 		}
497 		err(EXIT_FAILURE, "Cannot access library");
498 	}
499 	dlh = dlopen(path, RTLD_NOW);
500 	if (dlh == NULL)
501 		errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror());
502 	lib_version = dlsym(dlh, "lib_version");
503 	if (lib_version == NULL) {
504 		warnx("Cannot find symbol %s: %s.", "lib_version", dlerror());
505 		dlclose(dlh);
506 		exit(EXIT_FAILURE);
507 	}
508 	if (*lib_version != G_LIB_VERSION) {
509 		dlclose(dlh);
510 		errx(EXIT_FAILURE, "%s and %s are not synchronized.",
511 		    getprogname(), path);
512 	}
513 	version = dlsym(dlh, "version");
514 	if (version == NULL) {
515 		warnx("Cannot find symbol %s: %s.", "version", dlerror());
516 		dlclose(dlh);
517 		exit(EXIT_FAILURE);
518 	}
519 	class_commands = dlsym(dlh, "class_commands");
520 	if (class_commands == NULL) {
521 		warnx("Cannot find symbol %s: %s.", "class_commands",
522 		    dlerror());
523 		dlclose(dlh);
524 		exit(EXIT_FAILURE);
525 	}
526 }
527 
528 /*
529  * Class name should be all capital letters.
530  */
531 static void
532 set_class_name(void)
533 {
534 	char *s1, *s2;
535 
536 	s1 = class_name;
537 	for (; *s1 != '\0'; s1++)
538 		*s1 = tolower(*s1);
539 	gclass_name = malloc(strlen(class_name) + 1);
540 	if (gclass_name == NULL)
541 		errx(EXIT_FAILURE, "No memory");
542 	s1 = gclass_name;
543 	s2 = class_name;
544 	for (; *s2 != '\0'; s2++)
545 		*s1++ = toupper(*s2);
546 	*s1 = '\0';
547 }
548 
549 static void
550 get_class(int *argc, char ***argv)
551 {
552 
553 	snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
554 	if (strcmp(comm, "geom") == 0) {
555 		if (*argc < 2)
556 			usage();
557 		else if (*argc == 2) {
558 			if (strcmp((*argv)[1], "-h") == 0 ||
559 			    strcmp((*argv)[1], "help") == 0) {
560 				usage();
561 			}
562 		}
563 		strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
564 		class_name = (*argv)[1];
565 		*argc -= 2;
566 		*argv += 2;
567 	} else if (*comm == 'g') {
568 		class_name = comm + 1;
569 		*argc -= 1;
570 		*argv += 1;
571 	} else {
572 		errx(EXIT_FAILURE, "Invalid utility name.");
573 	}
574 	set_class_name();
575 	load_library();
576 	if (*argc < 1)
577 		usage();
578 }
579 
580 int
581 main(int argc, char *argv[])
582 {
583 
584 	get_class(&argc, &argv);
585 	run_command(argc, argv);
586 	/* NOTREACHED */
587 
588 	exit(EXIT_FAILURE);
589 }
590 
591 static struct gclass *
592 find_class(struct gmesh *mesh, const char *name)
593 {
594 	struct gclass *classp;
595 
596 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
597 		if (strcmp(classp->lg_name, name) == 0)
598 			return (classp);
599 	}
600 	return (NULL);
601 }
602 
603 static struct ggeom *
604 find_geom(struct gclass *classp, const char *name)
605 {
606 	struct ggeom *gp;
607 
608 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
609 		if (strcmp(gp->lg_name, name) == 0)
610 			return (gp);
611 	}
612 	return (NULL);
613 }
614 
615 static void
616 list_one_provider(struct gprovider *pp, const char *prefix)
617 {
618 	struct gconfig *conf;
619 	char buf[5];
620 
621 	printf("Name: %s\n", pp->lg_name);
622 	humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
623 	    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
624 	printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
625 	    buf);
626 	printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
627 	printf("%sMode: %s\n", prefix, pp->lg_mode);
628 	LIST_FOREACH(conf, &pp->lg_config, lg_config) {
629 		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
630 	}
631 }
632 
633 static void
634 list_one_consumer(struct gconsumer *cp, const char *prefix)
635 {
636 	struct gprovider *pp;
637 	struct gconfig *conf;
638 
639 	pp = cp->lg_provider;
640 	if (pp == NULL)
641 		printf("[no provider]\n");
642 	else {
643 		char buf[5];
644 
645 		printf("Name: %s\n", pp->lg_name);
646 		humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
647 		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
648 		printf("%sMediasize: %jd (%s)\n", prefix,
649 		    (intmax_t)pp->lg_mediasize, buf);
650 		printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
651 		printf("%sMode: %s\n", prefix, cp->lg_mode);
652 	}
653 	LIST_FOREACH(conf, &cp->lg_config, lg_config) {
654 		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
655 	}
656 }
657 
658 static void
659 list_one_geom(struct ggeom *gp)
660 {
661 	struct gprovider *pp;
662 	struct gconsumer *cp;
663 	struct gconfig *conf;
664 	unsigned n;
665 
666 	printf("Geom name: %s\n", gp->lg_name);
667 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
668 		printf("%s: %s\n", conf->lg_name, conf->lg_val);
669 	}
670 	if (!LIST_EMPTY(&gp->lg_provider)) {
671 		printf("Providers:\n");
672 		n = 1;
673 		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
674 			printf("%u. ", n++);
675 			list_one_provider(pp, "   ");
676 		}
677 	}
678 	if (!LIST_EMPTY(&gp->lg_consumer)) {
679 		printf("Consumers:\n");
680 		n = 1;
681 		LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
682 			printf("%u. ", n++);
683 			list_one_consumer(cp, "   ");
684 		}
685 	}
686 	printf("\n");
687 }
688 
689 static void
690 std_help(struct gctl_req *req __unused, unsigned flags __unused)
691 {
692 
693 	usage();
694 }
695 
696 static int
697 std_list_available(void)
698 {
699 	struct gmesh mesh;
700 	struct gclass *classp;
701 	int error;
702 
703 	error = geom_gettree(&mesh);
704 	if (error != 0)
705 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
706 	classp = find_class(&mesh, gclass_name);
707 	geom_deletetree(&mesh);
708 	if (classp != NULL)
709 		return (1);
710 	return (0);
711 }
712 
713 static void
714 std_list(struct gctl_req *req, unsigned flags __unused)
715 {
716 	struct gmesh mesh;
717 	struct gclass *classp;
718 	struct ggeom *gp;
719 	const char *name;
720 	int error, i, nargs;
721 
722 	error = geom_gettree(&mesh);
723 	if (error != 0)
724 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
725 	classp = find_class(&mesh, gclass_name);
726 	if (classp == NULL) {
727 		geom_deletetree(&mesh);
728 		errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
729 	}
730 	nargs = gctl_get_int(req, "nargs");
731 	if (nargs > 0) {
732 		for (i = 0; i < nargs; i++) {
733 			name = gctl_get_ascii(req, "arg%d", i);
734 			gp = find_geom(classp, name);
735 			if (gp != NULL)
736 				list_one_geom(gp);
737 			else
738 				errx(EXIT_FAILURE, "No such geom: %s.", name);
739 		}
740 	} else {
741 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
742 			if (LIST_EMPTY(&gp->lg_provider))
743 				continue;
744 			list_one_geom(gp);
745 		}
746 	}
747 	geom_deletetree(&mesh);
748 }
749 
750 static int
751 std_status_available(void)
752 {
753 
754 	/* 'status' command is available when 'list' command is. */
755 	return (std_list_available());
756 }
757 
758 static void
759 status_update_len(struct ggeom *gp, int *name_len, int *status_len)
760 {
761 	struct gprovider *pp;
762 	struct gconfig *conf;
763 	int len;
764 
765 	assert(gp != NULL);
766 	assert(name_len != NULL);
767 	assert(status_len != NULL);
768 
769 	pp = LIST_FIRST(&gp->lg_provider);
770 	if (pp != NULL)
771 		len = strlen(pp->lg_name);
772 	else
773 		len = strlen(gp->lg_name);
774 	if (*name_len < len)
775 		*name_len = len;
776 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
777 		if (strcasecmp(conf->lg_name, "state") == 0) {
778 			len = strlen(conf->lg_val);
779 			if (*status_len < len)
780 				*status_len = len;
781 		}
782 	}
783 }
784 
785 static char *
786 status_one_consumer(struct gconsumer *cp)
787 {
788 	static char buf[256];
789 	struct gprovider *pp;
790 	struct gconfig *conf;
791 
792 	pp = cp->lg_provider;
793 	if (pp == NULL)
794 		return (NULL);
795 	LIST_FOREACH(conf, &cp->lg_config, lg_config) {
796 		if (strcasecmp(conf->lg_name, "synchronized") == 0)
797 			break;
798 	}
799 	if (conf == NULL)
800 		snprintf(buf, sizeof(buf), "%s", pp->lg_name);
801 	else {
802 		snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name,
803 		    conf->lg_val);
804 	}
805 	return (buf);
806 }
807 
808 static void
809 status_one_geom(struct ggeom *gp, int script, int name_len, int status_len)
810 {
811 	struct gprovider *pp;
812 	struct gconsumer *cp;
813 	struct gconfig *conf;
814 	const char *name, *status, *component;
815 	int gotone;
816 
817 	pp = LIST_FIRST(&gp->lg_provider);
818 	if (pp != NULL)
819 		name = pp->lg_name;
820 	else
821 		name = gp->lg_name;
822 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
823 		if (strcasecmp(conf->lg_name, "state") == 0)
824 			break;
825 	}
826 	if (conf == NULL)
827 		status = "N/A";
828 	else
829 		status = conf->lg_val;
830 	gotone = 0;
831 	LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
832 		component = status_one_consumer(cp);
833 		if (component == NULL)
834 			continue;
835 		gotone = 1;
836 		printf("%*s  %*s  %s\n", name_len, name, status_len, status,
837 		    component);
838 		if (!script)
839 			name = status = "";
840 	}
841 	if (!gotone) {
842 		printf("%*s  %*s  %s\n", name_len, name, status_len, status,
843 		    "N/A");
844 	}
845 }
846 
847 static void
848 std_status(struct gctl_req *req, unsigned flags __unused)
849 {
850 	struct gmesh mesh;
851 	struct gclass *classp;
852 	struct ggeom *gp;
853 	const char *name;
854 	int name_len, status_len;
855 	int error, i, n, nargs, script;
856 
857 	error = geom_gettree(&mesh);
858 	if (error != 0)
859 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
860 	classp = find_class(&mesh, gclass_name);
861 	if (classp == NULL)
862 		errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
863 	nargs = gctl_get_int(req, "nargs");
864 	script = gctl_get_int(req, "script");
865 	name_len = strlen("Name");
866 	status_len = strlen("Status");
867 	if (nargs > 0) {
868 		for (i = 0, n = 0; i < nargs; i++) {
869 			name = gctl_get_ascii(req, "arg%d", i);
870 			gp = find_geom(classp, name);
871 			if (gp == NULL)
872 				errx(EXIT_FAILURE, "No such geom: %s.", name);
873 			else {
874 				status_update_len(gp, &name_len, &status_len);
875 				n++;
876 			}
877 		}
878 		if (n == 0)
879 			goto end;
880 	} else {
881 		n = 0;
882 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
883 			if (LIST_EMPTY(&gp->lg_provider))
884 				continue;
885 			status_update_len(gp, &name_len, &status_len);
886 			n++;
887 		}
888 		if (n == 0)
889 			goto end;
890 	}
891 	if (!script) {
892 		printf("%*s  %*s  %s\n", name_len, "Name", status_len, "Status",
893 		    "Components");
894 	}
895 	if (nargs > 0) {
896 		for (i = 0; i < nargs; i++) {
897 			name = gctl_get_ascii(req, "arg%d", i);
898 			gp = find_geom(classp, name);
899 			if (gp != NULL) {
900 				status_one_geom(gp, script, name_len,
901 				    status_len);
902 			}
903 		}
904 	} else {
905 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
906 			if (LIST_EMPTY(&gp->lg_provider))
907 				continue;
908 			status_one_geom(gp, script, name_len, status_len);
909 		}
910 	}
911 end:
912 	geom_deletetree(&mesh);
913 }
914 
915 static int
916 std_load_available(void)
917 {
918 	char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
919 	struct stat sb;
920 	size_t len;
921 
922 	snprintf(name, sizeof(name), "g_%s", class_name);
923 	/*
924 	 * If already in kernel, "load" command is not available.
925 	 */
926 	if (modfind(name) >= 0)
927 		return (0);
928 	bzero(paths, sizeof(paths));
929 	len = sizeof(paths);
930 	if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
931 		err(EXIT_FAILURE, "sysctl(kern.module_path)");
932 	for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
933 		snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
934 		/*
935 		 * If geom_<name>.ko file exists, "load" command is available.
936 		 */
937 		if (stat(name, &sb) == 0)
938 			return (1);
939 	}
940 	return (0);
941 }
942 
943 static void
944 std_load(struct gctl_req *req __unused, unsigned flags)
945 {
946 
947 	/*
948 	 * Do nothing special here, because of G_FLAG_LOADKLD flag,
949 	 * module is already loaded.
950 	 */
951 	if ((flags & G_FLAG_VERBOSE) != 0)
952 		printf("Module available.\n");
953 }
954 
955 static int
956 std_unload_available(void)
957 {
958 	char name[64];
959 	int id;
960 
961 	snprintf(name, sizeof(name), "geom_%s", class_name);
962 	id = kldfind(name);
963 	if (id >= 0)
964 		return (1);
965 	return (0);
966 }
967 
968 static void
969 std_unload(struct gctl_req *req, unsigned flags __unused)
970 {
971 	char name[64];
972 	int id;
973 
974 	snprintf(name, sizeof(name), "geom_%s", class_name);
975 	id = kldfind(name);
976 	if (id < 0) {
977 		gctl_error(req, "Could not find module: %s.", strerror(errno));
978 		return;
979 	}
980 	if (kldunload(id) < 0) {
981 		gctl_error(req, "Could not unload module: %s.",
982 		    strerror(errno));
983 		return;
984 	}
985 }
986 
987 static int
988 std_available(const char *name)
989 {
990 
991 	if (strcmp(name, "help") == 0)
992 		return (1);
993 	else if (strcmp(name, "list") == 0)
994 		return (std_list_available());
995 	else if (strcmp(name, "status") == 0)
996 		return (std_status_available());
997 	else if (strcmp(name, "load") == 0)
998 		return (std_load_available());
999 	else if (strcmp(name, "unload") == 0)
1000 		return (std_unload_available());
1001 	else
1002 		assert(!"Unknown standard command.");
1003 	return (0);
1004 }
1005