xref: /freebsd/sbin/geom/core/geom.c (revision 0f73f7016baa6015b1b0b582033af2f1c7760af5)
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 <stdio.h>
41 #include <stdlib.h>
42 #include <stdarg.h>
43 #include <stdbool.h>
44 #include <stdint.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <libgen.h>
48 #include <libutil.h>
49 #include <inttypes.h>
50 #include <dlfcn.h>
51 #include <assert.h>
52 #include <libgeom.h>
53 #include <geom.h>
54 
55 #include "misc/subr.h"
56 
57 #ifdef STATIC_GEOM_CLASSES
58 extern uint32_t gpart_version;
59 extern struct g_command gpart_class_commands[];
60 extern uint32_t glabel_version;
61 extern struct g_command glabel_class_commands[];
62 #endif
63 
64 static char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL;
65 static uint32_t *version = NULL;
66 static int verbose = 0;
67 static struct g_command *class_commands = NULL;
68 
69 #define	GEOM_CLASS_CMDS	0x01
70 #define	GEOM_STD_CMDS	0x02
71 static struct g_command *find_command(const char *cmdstr, int flags);
72 static void list_one_geom_by_provider(const char *provider_name);
73 static int std_available(const char *name);
74 
75 static void std_help(struct gctl_req *req, unsigned flags);
76 static void std_list(struct gctl_req *req, unsigned flags);
77 static void std_status(struct gctl_req *req, unsigned flags);
78 static void std_load(struct gctl_req *req, unsigned flags);
79 static void std_unload(struct gctl_req *req, unsigned flags);
80 
81 static struct g_command std_commands[] = {
82 	{ "help", 0, std_help, G_NULL_OPTS, NULL },
83 	{ "list", 0, std_list,
84 	    {
85 		{ 'a', "all", NULL, G_TYPE_BOOL },
86 		G_OPT_SENTINEL
87 	    },
88 	    "[-a] [name ...]"
89 	},
90 	{ "status", 0, std_status,
91 	    {
92 		{ 'a', "all", NULL, G_TYPE_BOOL },
93 		{ 'g', "geoms", NULL, G_TYPE_BOOL },
94 		{ 's', "script", NULL, G_TYPE_BOOL },
95 		G_OPT_SENTINEL
96 	    },
97 	    "[-ags] [name ...]"
98 	},
99 	{ "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS,
100 	    NULL },
101 	{ "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS, NULL },
102 	G_CMD_SENTINEL
103 };
104 
105 static void
106 usage_command(struct g_command *cmd, const char *prefix)
107 {
108 	struct g_option *opt;
109 	unsigned i;
110 
111 	if (cmd->gc_usage != NULL) {
112 		char *pos, *ptr, *sptr;
113 
114 		sptr = ptr = strdup(cmd->gc_usage);
115 		while ((pos = strsep(&ptr, "\n")) != NULL) {
116 			if (*pos == '\0')
117 				continue;
118 			fprintf(stderr, "%s %s %s %s\n", prefix, comm,
119 			    cmd->gc_name, pos);
120 		}
121 		free(sptr);
122 		return;
123 	}
124 
125 	fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name);
126 	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
127 		fprintf(stderr, " [-v]");
128 	for (i = 0; ; i++) {
129 		opt = &cmd->gc_options[i];
130 		if (opt->go_name == NULL)
131 			break;
132 		if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
133 			fprintf(stderr, " [");
134 		else
135 			fprintf(stderr, " ");
136 		fprintf(stderr, "-%c", opt->go_char);
137 		if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
138 			fprintf(stderr, " %s", opt->go_name);
139 		if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
140 			fprintf(stderr, "]");
141 	}
142 	fprintf(stderr, "\n");
143 }
144 
145 static void
146 usage(void)
147 {
148 
149 	if (class_name == NULL) {
150 		fprintf(stderr, "usage: geom <class> <command> [options]\n");
151 		fprintf(stderr, "       geom -p <provider-name>\n");
152 		exit(EXIT_FAILURE);
153 	} else {
154 		struct g_command *cmd;
155 		const char *prefix;
156 		unsigned i;
157 
158 		prefix = "usage:";
159 		if (class_commands != NULL) {
160 			for (i = 0; ; i++) {
161 				cmd = &class_commands[i];
162 				if (cmd->gc_name == NULL)
163 					break;
164 				usage_command(cmd, prefix);
165 				prefix = "      ";
166 			}
167 		}
168 		for (i = 0; ; i++) {
169 			cmd = &std_commands[i];
170 			if (cmd->gc_name == NULL)
171 				break;
172 			/*
173 			 * If class defines command, which has the same name as
174 			 * standard command, skip it, because it was already
175 			 * shown on usage().
176 			 */
177 			if (find_command(cmd->gc_name, GEOM_CLASS_CMDS) != NULL)
178 				continue;
179 			usage_command(cmd, prefix);
180 			prefix = "      ";
181 		}
182 		exit(EXIT_FAILURE);
183 	}
184 }
185 
186 static void
187 load_module(void)
188 {
189 	char name1[64], name2[64];
190 
191 	snprintf(name1, sizeof(name1), "g_%s", class_name);
192 	snprintf(name2, sizeof(name2), "geom_%s", class_name);
193 	if (modfind(name1) < 0) {
194 		/* Not present in kernel, try loading it. */
195 		if (kldload(name2) < 0 || modfind(name1) < 0) {
196 			if (errno != EEXIST) {
197 				err(EXIT_FAILURE, "cannot load %s", name2);
198 			}
199 		}
200 	}
201 }
202 
203 static int
204 strlcatf(char *str, size_t size, const char *format, ...)
205 {
206 	size_t len;
207 	va_list ap;
208 	int ret;
209 
210 	len = strlen(str);
211 	str += len;
212 	size -= len;
213 
214 	va_start(ap, format);
215 	ret = vsnprintf(str, size, format, ap);
216 	va_end(ap);
217 
218 	return (ret);
219 }
220 
221 /*
222  * Find given option in options available for given command.
223  */
224 static struct g_option *
225 find_option(struct g_command *cmd, char ch)
226 {
227 	struct g_option *opt;
228 	unsigned i;
229 
230 	for (i = 0; ; i++) {
231 		opt = &cmd->gc_options[i];
232 		if (opt->go_name == NULL)
233 			return (NULL);
234 		if (opt->go_char == ch)
235 			return (opt);
236 	}
237 	/* NOTREACHED */
238 	return (NULL);
239 }
240 
241 /*
242  * Add given option to gctl_req.
243  */
244 static void
245 set_option(struct gctl_req *req, struct g_option *opt, const char *val)
246 {
247 	const char *optname;
248 	uint64_t number;
249 	void *ptr;
250 
251 	if (G_OPT_ISMULTI(opt)) {
252 		size_t optnamesize;
253 
254 		if (G_OPT_NUM(opt) == UCHAR_MAX)
255 			errx(EXIT_FAILURE, "Too many -%c options.", opt->go_char);
256 
257 		/*
258 		 * Base option name length plus 3 bytes for option number
259 		 * (max. 255 options) plus 1 byte for terminating '\0'.
260 		 */
261 		optnamesize = strlen(opt->go_name) + 3 + 1;
262 		ptr = malloc(optnamesize);
263 		if (ptr == NULL)
264 			errx(EXIT_FAILURE, "No memory.");
265 		snprintf(ptr, optnamesize, "%s%u", opt->go_name, G_OPT_NUM(opt));
266 		G_OPT_NUMINC(opt);
267 		optname = ptr;
268 	} else {
269 		optname = opt->go_name;
270 	}
271 
272 	if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) {
273 		if (expand_number(val, &number) == -1) {
274 			err(EXIT_FAILURE, "Invalid value for '%c' argument",
275 			    opt->go_char);
276 		}
277 		ptr = malloc(sizeof(intmax_t));
278 		if (ptr == NULL)
279 			errx(EXIT_FAILURE, "No memory.");
280 		*(intmax_t *)ptr = number;
281 		opt->go_val = ptr;
282 		gctl_ro_param(req, optname, sizeof(intmax_t), opt->go_val);
283 	} else if (G_OPT_TYPE(opt) == G_TYPE_STRING) {
284 		gctl_ro_param(req, optname, -1, val);
285 	} else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
286 		ptr = malloc(sizeof(int));
287 		if (ptr == NULL)
288 			errx(EXIT_FAILURE, "No memory.");
289 		*(int *)ptr = *val - '0';
290 		opt->go_val = ptr;
291 		gctl_ro_param(req, optname, sizeof(int), opt->go_val);
292 	} else {
293 		assert(!"Invalid type");
294 	}
295 
296 	if (G_OPT_ISMULTI(opt))
297 		free(__DECONST(char *, optname));
298 }
299 
300 /*
301  * 1. Add given argument by caller.
302  * 2. Add default values of not given arguments.
303  * 3. Add the rest of arguments.
304  */
305 static void
306 parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
307     char ***argv)
308 {
309 	struct g_option *opt;
310 	char opts[64];
311 	unsigned i;
312 	int ch;
313 
314 	*opts = '\0';
315 	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
316 		strlcat(opts, "v", sizeof(opts));
317 	for (i = 0; ; i++) {
318 		opt = &cmd->gc_options[i];
319 		if (opt->go_name == NULL)
320 			break;
321 		assert(G_OPT_TYPE(opt) != 0);
322 		assert((opt->go_type & ~(G_TYPE_MASK | G_TYPE_MULTI)) == 0);
323 		/* Multiple bool arguments makes no sense. */
324 		assert(G_OPT_TYPE(opt) != G_TYPE_BOOL ||
325 		    (opt->go_type & G_TYPE_MULTI) == 0);
326 		strlcatf(opts, sizeof(opts), "%c", opt->go_char);
327 		if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
328 			strlcat(opts, ":", sizeof(opts));
329 	}
330 
331 	/*
332 	 * Add specified arguments.
333 	 */
334 	while ((ch = getopt(*argc, *argv, opts)) != -1) {
335 		/* Standard (not passed to kernel) options. */
336 		switch (ch) {
337 		case 'v':
338 			verbose = 1;
339 			continue;
340 		}
341 		/* Options passed to kernel. */
342 		opt = find_option(cmd, ch);
343 		if (opt == NULL)
344 			usage();
345 		if (!G_OPT_ISMULTI(opt) && G_OPT_ISDONE(opt)) {
346 			warnx("Option '%c' specified twice.", opt->go_char);
347 			usage();
348 		}
349 		G_OPT_DONE(opt);
350 
351 		if (G_OPT_TYPE(opt) == G_TYPE_BOOL)
352 			set_option(req, opt, "1");
353 		else
354 			set_option(req, opt, optarg);
355 	}
356 	*argc -= optind;
357 	*argv += optind;
358 
359 	/*
360 	 * Add not specified arguments, but with default values.
361 	 */
362 	for (i = 0; ; i++) {
363 		opt = &cmd->gc_options[i];
364 		if (opt->go_name == NULL)
365 			break;
366 		if (G_OPT_ISDONE(opt))
367 			continue;
368 
369 		if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
370 			assert(opt->go_val == NULL);
371 			set_option(req, opt, "0");
372 		} else {
373 			if (opt->go_val == NULL) {
374 				warnx("Option '%c' not specified.",
375 				    opt->go_char);
376 				usage();
377 			} else if (opt->go_val == G_VAL_OPTIONAL) {
378 				/* add nothing. */
379 			} else {
380 				set_option(req, opt, opt->go_val);
381 			}
382 		}
383 	}
384 
385 	/*
386 	 * Add rest of given arguments.
387 	 */
388 	gctl_ro_param(req, "nargs", sizeof(int), argc);
389 	for (i = 0; i < (unsigned)*argc; i++) {
390 		char argname[16];
391 
392 		snprintf(argname, sizeof(argname), "arg%u", i);
393 		gctl_ro_param(req, argname, -1, (*argv)[i]);
394 	}
395 }
396 
397 /*
398  * Find given command in commands available for given class.
399  */
400 static struct g_command *
401 find_command(const char *cmdstr, int flags)
402 {
403 	struct g_command *cmd;
404 	unsigned i;
405 
406 	/*
407 	 * First try to find command defined by loaded library.
408 	 */
409 	if ((flags & GEOM_CLASS_CMDS) != 0 && class_commands != NULL) {
410 		for (i = 0; ; i++) {
411 			cmd = &class_commands[i];
412 			if (cmd->gc_name == NULL)
413 				break;
414 			if (strcmp(cmd->gc_name, cmdstr) == 0)
415 				return (cmd);
416 		}
417 	}
418 	/*
419 	 * Now try to find in standard commands.
420 	 */
421 	if ((flags & GEOM_STD_CMDS) != 0) {
422 		for (i = 0; ; i++) {
423 			cmd = &std_commands[i];
424 			if (cmd->gc_name == NULL)
425 				break;
426 			if (strcmp(cmd->gc_name, cmdstr) == 0)
427 				return (cmd);
428 		}
429 	}
430 	return (NULL);
431 }
432 
433 static unsigned
434 set_flags(struct g_command *cmd)
435 {
436 	unsigned flags = 0;
437 
438 	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
439 		flags |= G_FLAG_VERBOSE;
440 
441 	return (flags);
442 }
443 
444 /*
445  * Run command.
446  */
447 static void
448 run_command(int argc, char *argv[])
449 {
450 	struct g_command *cmd;
451 	struct gctl_req *req;
452 	const char *errstr;
453 	char buf[4096];
454 
455 	/* First try to find a command defined by a class. */
456 	cmd = find_command(argv[0], GEOM_CLASS_CMDS);
457 	if (cmd == NULL) {
458 		/* Now, try to find a standard command. */
459 		cmd = find_command(argv[0], GEOM_STD_CMDS);
460 		if (cmd == NULL) {
461 			warnx("Unknown command: %s.", argv[0]);
462 			usage();
463 		}
464 		if (!std_available(cmd->gc_name)) {
465 			warnx("Command '%s' not available; "
466 			    "try 'load' first.", argv[0]);
467 			exit(EXIT_FAILURE);
468 		}
469 	}
470 	if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
471 		load_module();
472 
473 	req = gctl_get_handle();
474 	gctl_ro_param(req, "class", -1, gclass_name);
475 	gctl_ro_param(req, "verb", -1, argv[0]);
476 	if (version != NULL)
477 		gctl_ro_param(req, "version", sizeof(*version), version);
478 	parse_arguments(cmd, req, &argc, &argv);
479 
480 	bzero(buf, sizeof(buf));
481 	if (cmd->gc_func != NULL) {
482 		unsigned flags;
483 
484 		flags = set_flags(cmd);
485 		cmd->gc_func(req, flags);
486 		errstr = req->error;
487 	} else {
488 		gctl_rw_param(req, "output", sizeof(buf), buf);
489 		errstr = gctl_issue(req);
490 	}
491 	if (errstr != NULL && errstr[0] != '\0') {
492 		warnx("%s", errstr);
493 		if (strncmp(errstr, "warning: ", strlen("warning: ")) != 0) {
494 			gctl_free(req);
495 			exit(EXIT_FAILURE);
496 		}
497 	}
498 	if (buf[0] != '\0')
499 		printf("%s", buf);
500 	gctl_free(req);
501 	if (verbose)
502 		printf("Done.\n");
503 	exit(EXIT_SUCCESS);
504 }
505 
506 #ifndef STATIC_GEOM_CLASSES
507 static const char *
508 library_path(void)
509 {
510 	const char *path;
511 
512 	path = getenv("GEOM_LIBRARY_PATH");
513 	if (path == NULL)
514 		path = GEOM_CLASS_DIR;
515 	return (path);
516 }
517 
518 static void
519 load_library(void)
520 {
521 	char *curpath, path[MAXPATHLEN], *tofree, *totalpath;
522 	uint32_t *lib_version;
523 	void *dlh;
524 	int ret;
525 
526 	ret = 0;
527 	tofree = totalpath = strdup(library_path());
528 	if (totalpath == NULL)
529 		err(EXIT_FAILURE, "Not enough memory for library path");
530 
531 	if (strchr(totalpath, ':') != NULL)
532 		curpath = strsep(&totalpath, ":");
533 	else
534 		curpath = totalpath;
535 	/* Traverse the paths to find one that contains the library we want. */
536 	while (curpath != NULL) {
537 		snprintf(path, sizeof(path), "%s/geom_%s.so", curpath,
538 		    class_name);
539 		ret = access(path, F_OK);
540 		if (ret == -1) {
541 			if (errno == ENOENT) {
542 				/*
543 				 * If we cannot find library, try the next
544 				 * path.
545 				 */
546 				curpath = strsep(&totalpath, ":");
547 				continue;
548 			}
549 			err(EXIT_FAILURE, "Cannot access library");
550 		}
551 		break;
552 	}
553 	free(tofree);
554 	/* No library was found, but standard commands can still be used */
555 	if (ret == -1)
556 		return;
557 	dlh = dlopen(path, RTLD_NOW);
558 	if (dlh == NULL)
559 		errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror());
560 	lib_version = dlsym(dlh, "lib_version");
561 	if (lib_version == NULL) {
562 		warnx("Cannot find symbol %s: %s.", "lib_version", dlerror());
563 		dlclose(dlh);
564 		exit(EXIT_FAILURE);
565 	}
566 	if (*lib_version != G_LIB_VERSION) {
567 		dlclose(dlh);
568 		errx(EXIT_FAILURE, "%s and %s are not synchronized.",
569 		    getprogname(), path);
570 	}
571 	version = dlsym(dlh, "version");
572 	if (version == NULL) {
573 		warnx("Cannot find symbol %s: %s.", "version", dlerror());
574 		dlclose(dlh);
575 		exit(EXIT_FAILURE);
576 	}
577 	class_commands = dlsym(dlh, "class_commands");
578 	if (class_commands == NULL) {
579 		warnx("Cannot find symbol %s: %s.", "class_commands",
580 		    dlerror());
581 		dlclose(dlh);
582 		exit(EXIT_FAILURE);
583 	}
584 }
585 #endif	/* !STATIC_GEOM_CLASSES */
586 
587 /*
588  * Class name should be all capital letters.
589  */
590 static void
591 set_class_name(void)
592 {
593 	char *s1, *s2;
594 
595 	s1 = class_name;
596 	for (; *s1 != '\0'; s1++)
597 		*s1 = tolower(*s1);
598 	gclass_name = malloc(strlen(class_name) + 1);
599 	if (gclass_name == NULL)
600 		errx(EXIT_FAILURE, "No memory");
601 	s1 = gclass_name;
602 	s2 = class_name;
603 	for (; *s2 != '\0'; s2++)
604 		*s1++ = toupper(*s2);
605 	*s1 = '\0';
606 }
607 
608 static void
609 get_class(int *argc, char ***argv)
610 {
611 
612 	snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
613 	if (strcmp(comm, "geom") == 0) {
614 		if (*argc < 2)
615 			usage();
616 		else if (*argc == 2) {
617 			if (strcmp((*argv)[1], "-h") == 0 ||
618 			    strcmp((*argv)[1], "help") == 0) {
619 				usage();
620 			}
621 		}
622 		strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
623 		class_name = (*argv)[1];
624 		*argc -= 2;
625 		*argv += 2;
626 	} else if (*comm == 'g') {
627 		class_name = comm + 1;
628 		*argc -= 1;
629 		*argv += 1;
630 	} else {
631 		errx(EXIT_FAILURE, "Invalid utility name.");
632 	}
633 
634 #ifndef STATIC_GEOM_CLASSES
635 	load_library();
636 #else
637 	if (!strcasecmp(class_name, "part")) {
638 		version = &gpart_version;
639 		class_commands = gpart_class_commands;
640 	} else if (!strcasecmp(class_name, "label")) {
641 		version = &glabel_version;
642 		class_commands = glabel_class_commands;
643 	}
644 #endif /* !STATIC_GEOM_CLASSES */
645 
646 	set_class_name();
647 
648 	/* If we can't load or list, it's not a class. */
649 	if (!std_available("load") && !std_available("list"))
650 		errx(EXIT_FAILURE, "Invalid class name '%s'.", class_name);
651 
652 	if (*argc < 1)
653 		usage();
654 }
655 
656 static struct ggeom *
657 find_geom_by_provider(struct gmesh *mesh, const char *name)
658 {
659 	struct gclass *classp;
660 	struct ggeom *gp;
661 	struct gprovider *pp;
662 
663 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
664 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
665 			LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
666 				if (strcmp(pp->lg_name, name) == 0)
667 					return (gp);
668 			}
669 		}
670 	}
671 
672 	return (NULL);
673 }
674 
675 int
676 main(int argc, char *argv[])
677 {
678 	char *provider_name;
679 	int ch;
680 
681 	provider_name = NULL;
682 
683 	if (strcmp(getprogname(), "geom") == 0) {
684 		while ((ch = getopt(argc, argv, "hp:")) != -1) {
685 			switch (ch) {
686 			case 'p':
687 				provider_name = strdup(optarg);
688 				if (provider_name == NULL)
689 					err(1, "strdup");
690 				break;
691 			case 'h':
692 			default:
693 				usage();
694 			}
695 		}
696 
697 		/*
698 		 * Don't adjust argc and argv, it would break get_class().
699 		 */
700 	}
701 
702 	if (provider_name != NULL) {
703 		list_one_geom_by_provider(provider_name);
704 		return (0);
705 	}
706 
707 	get_class(&argc, &argv);
708 	run_command(argc, argv);
709 	/* NOTREACHED */
710 
711 	exit(EXIT_FAILURE);
712 }
713 
714 static struct gclass *
715 find_class(struct gmesh *mesh, const char *name)
716 {
717 	struct gclass *classp;
718 
719 	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
720 		if (strcmp(classp->lg_name, name) == 0)
721 			return (classp);
722 	}
723 	return (NULL);
724 }
725 
726 static struct ggeom *
727 find_geom(struct gclass *classp, const char *name)
728 {
729 	struct ggeom *gp;
730 
731 	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
732 		if (strcmp(gp->lg_name, name) == 0)
733 			return (gp);
734 	}
735 	return (NULL);
736 }
737 
738 static void
739 list_one_provider(struct gprovider *pp, const char *prefix)
740 {
741 	struct gconfig *conf;
742 	char buf[5];
743 
744 	printf("Name: %s\n", pp->lg_name);
745 	humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
746 	    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
747 	printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
748 	    buf);
749 	printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
750 	if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
751 		printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
752 		printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
753 	}
754 	printf("%sMode: %s\n", prefix, pp->lg_mode);
755 	LIST_FOREACH(conf, &pp->lg_config, lg_config) {
756 		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
757 	}
758 }
759 
760 static void
761 list_one_consumer(struct gconsumer *cp, const char *prefix)
762 {
763 	struct gprovider *pp;
764 	struct gconfig *conf;
765 
766 	pp = cp->lg_provider;
767 	if (pp == NULL)
768 		printf("[no provider]\n");
769 	else {
770 		char buf[5];
771 
772 		printf("Name: %s\n", pp->lg_name);
773 		humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
774 		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
775 		printf("%sMediasize: %jd (%s)\n", prefix,
776 		    (intmax_t)pp->lg_mediasize, buf);
777 		printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
778 		if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
779 			printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
780 			printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
781 		}
782 		printf("%sMode: %s\n", prefix, cp->lg_mode);
783 	}
784 	LIST_FOREACH(conf, &cp->lg_config, lg_config) {
785 		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
786 	}
787 }
788 
789 static void
790 list_one_geom(struct ggeom *gp)
791 {
792 	struct gprovider *pp;
793 	struct gconsumer *cp;
794 	struct gconfig *conf;
795 	unsigned n;
796 
797 	printf("Geom name: %s\n", gp->lg_name);
798 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
799 		printf("%s: %s\n", conf->lg_name, conf->lg_val);
800 	}
801 	if (!LIST_EMPTY(&gp->lg_provider)) {
802 		printf("Providers:\n");
803 		n = 1;
804 		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
805 			printf("%u. ", n++);
806 			list_one_provider(pp, "   ");
807 		}
808 	}
809 	if (!LIST_EMPTY(&gp->lg_consumer)) {
810 		printf("Consumers:\n");
811 		n = 1;
812 		LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
813 			printf("%u. ", n++);
814 			list_one_consumer(cp, "   ");
815 		}
816 	}
817 	printf("\n");
818 }
819 
820 static void
821 list_one_geom_by_provider(const char *provider_name)
822 {
823 	struct gmesh mesh;
824 	struct ggeom *gp;
825 	int error;
826 
827 	error = geom_gettree(&mesh);
828 	if (error != 0)
829 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
830 
831 	gp = find_geom_by_provider(&mesh, provider_name);
832 	if (gp == NULL)
833 		errx(EXIT_FAILURE, "Cannot find provider '%s'.", provider_name);
834 
835 	printf("Geom class: %s\n", gp->lg_class->lg_name);
836 	list_one_geom(gp);
837 }
838 
839 static void
840 std_help(struct gctl_req *req __unused, unsigned flags __unused)
841 {
842 
843 	usage();
844 }
845 
846 static int
847 std_list_available(void)
848 {
849 	struct gmesh mesh;
850 	struct gclass *classp;
851 	int error;
852 
853 	error = geom_gettree(&mesh);
854 	if (error != 0)
855 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
856 	classp = find_class(&mesh, gclass_name);
857 	geom_deletetree(&mesh);
858 	if (classp != NULL)
859 		return (1);
860 	return (0);
861 }
862 
863 static void
864 std_list(struct gctl_req *req, unsigned flags __unused)
865 {
866 	struct gmesh mesh;
867 	struct gclass *classp;
868 	struct ggeom *gp;
869 	const char *name;
870 	int all, error, i, nargs;
871 
872 	error = geom_gettree(&mesh);
873 	if (error != 0)
874 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
875 	classp = find_class(&mesh, gclass_name);
876 	if (classp == NULL) {
877 		geom_deletetree(&mesh);
878 		errx(EXIT_FAILURE, "Class '%s' not found.", gclass_name);
879 	}
880 	nargs = gctl_get_int(req, "nargs");
881 	all = gctl_get_int(req, "all");
882 	if (nargs > 0) {
883 		for (i = 0; i < nargs; i++) {
884 			name = gctl_get_ascii(req, "arg%d", i);
885 			gp = find_geom(classp, name);
886 			if (gp == NULL) {
887 				errx(EXIT_FAILURE, "Class '%s' does not have "
888 				    "an instance named '%s'.",
889 				    gclass_name, name);
890 			}
891 			list_one_geom(gp);
892 		}
893 	} else {
894 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
895 			if (LIST_EMPTY(&gp->lg_provider) && !all)
896 				continue;
897 			list_one_geom(gp);
898 		}
899 	}
900 	geom_deletetree(&mesh);
901 }
902 
903 static int
904 std_status_available(void)
905 {
906 
907 	/* 'status' command is available when 'list' command is. */
908 	return (std_list_available());
909 }
910 
911 static void
912 status_update_len(struct ggeom *gp, int *name_len, int *status_len)
913 {
914 	struct gconfig *conf;
915 	int len;
916 
917 	assert(gp != NULL);
918 	assert(name_len != NULL);
919 	assert(status_len != NULL);
920 
921 	len = strlen(gp->lg_name);
922 	if (*name_len < len)
923 		*name_len = len;
924 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
925 		if (strcasecmp(conf->lg_name, "state") == 0) {
926 			len = strlen(conf->lg_val);
927 			if (*status_len < len)
928 				*status_len = len;
929 		}
930 	}
931 }
932 
933 static void
934 status_update_len_prs(struct ggeom *gp, int *name_len, int *status_len)
935 {
936 	struct gprovider *pp;
937 	struct gconfig *conf;
938 	int len, glen;
939 
940 	assert(gp != NULL);
941 	assert(name_len != NULL);
942 	assert(status_len != NULL);
943 
944 	glen = 0;
945 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
946 		if (strcasecmp(conf->lg_name, "state") == 0) {
947 			glen = strlen(conf->lg_val);
948 			break;
949 		}
950 	}
951 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
952 		len = strlen(pp->lg_name);
953 		if (*name_len < len)
954 			*name_len = len;
955 		len = glen;
956 		LIST_FOREACH(conf, &pp->lg_config, lg_config) {
957 			if (strcasecmp(conf->lg_name, "state") == 0) {
958 				len = strlen(conf->lg_val);
959 				break;
960 			}
961 		}
962 		if (*status_len < len)
963 			*status_len = len;
964 	}
965 }
966 
967 static char *
968 status_one_consumer(struct gconsumer *cp)
969 {
970 	static char buf[256];
971 	struct gprovider *pp;
972 	struct gconfig *conf;
973 	const char *state, *syncr;
974 
975 	pp = cp->lg_provider;
976 	if (pp == NULL)
977 		return (NULL);
978 	state = NULL;
979 	syncr = NULL;
980 	LIST_FOREACH(conf, &cp->lg_config, lg_config) {
981 		if (strcasecmp(conf->lg_name, "state") == 0)
982 			state = conf->lg_val;
983 		if (strcasecmp(conf->lg_name, "synchronized") == 0)
984 			syncr = conf->lg_val;
985 	}
986 	if (state == NULL && syncr == NULL)
987 		snprintf(buf, sizeof(buf), "%s", pp->lg_name);
988 	else if (state != NULL && syncr != NULL) {
989 		snprintf(buf, sizeof(buf), "%s (%s, %s)", pp->lg_name,
990 		    state, syncr);
991 	} else {
992 		snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name,
993 		    state ? state : syncr);
994 	}
995 	return (buf);
996 }
997 
998 static void
999 status_one_geom(struct ggeom *gp, int script, int name_len, int status_len)
1000 {
1001 	struct gconsumer *cp;
1002 	struct gconfig *conf;
1003 	const char *name, *status, *component;
1004 	int gotone;
1005 
1006 	name = gp->lg_name;
1007 	status = "N/A";
1008 	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1009 		if (strcasecmp(conf->lg_name, "state") == 0) {
1010 			status = conf->lg_val;
1011 			break;
1012 		}
1013 	}
1014 	gotone = 0;
1015 	LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1016 		component = status_one_consumer(cp);
1017 		if (component == NULL)
1018 			continue;
1019 		gotone = 1;
1020 		printf("%*s  %*s  %s\n", name_len, name, status_len, status,
1021 		    component);
1022 		if (!script)
1023 			name = status = "";
1024 	}
1025 	if (!gotone) {
1026 		printf("%*s  %*s  %s\n", name_len, name, status_len, status,
1027 		    "N/A");
1028 	}
1029 }
1030 
1031 static void
1032 status_one_geom_prs(struct ggeom *gp, int script, int name_len, int status_len)
1033 {
1034 	struct gprovider *pp;
1035 	struct gconsumer *cp;
1036 	struct gconfig *conf;
1037 	const char *name, *status, *component;
1038 	int gotone;
1039 
1040 	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1041 		name = pp->lg_name;
1042 		status = "N/A";
1043 		LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1044 			if (strcasecmp(conf->lg_name, "state") == 0) {
1045 				status = conf->lg_val;
1046 				break;
1047 			}
1048 		}
1049 		LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1050 			if (strcasecmp(conf->lg_name, "state") == 0) {
1051 				status = conf->lg_val;
1052 				break;
1053 			}
1054 		}
1055 		gotone = 0;
1056 		LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1057 			component = status_one_consumer(cp);
1058 			if (component == NULL)
1059 				continue;
1060 			gotone = 1;
1061 			printf("%*s  %*s  %s\n", name_len, name,
1062 			    status_len, status, component);
1063 			if (!script)
1064 				name = status = "";
1065 		}
1066 		if (!gotone) {
1067 			printf("%*s  %*s  %s\n", name_len, name,
1068 			    status_len, status, "N/A");
1069 		}
1070 	}
1071 }
1072 
1073 static void
1074 std_status(struct gctl_req *req, unsigned flags __unused)
1075 {
1076 	struct gmesh mesh;
1077 	struct gclass *classp;
1078 	struct ggeom *gp;
1079 	const char *name;
1080 	int name_len, status_len;
1081 	int all, error, geoms, i, n, nargs, script;
1082 
1083 	error = geom_gettree(&mesh);
1084 	if (error != 0)
1085 		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1086 	classp = find_class(&mesh, gclass_name);
1087 	if (classp == NULL)
1088 		errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
1089 	nargs = gctl_get_int(req, "nargs");
1090 	all = gctl_get_int(req, "all");
1091 	geoms = gctl_get_int(req, "geoms");
1092 	script = gctl_get_int(req, "script");
1093 	if (script) {
1094 		name_len = 0;
1095 		status_len = 0;
1096 	} else {
1097 		name_len = strlen("Name");
1098 		status_len = strlen("Status");
1099 	}
1100 	if (nargs > 0) {
1101 		for (i = 0, n = 0; i < nargs; i++) {
1102 			name = gctl_get_ascii(req, "arg%d", i);
1103 			gp = find_geom(classp, name);
1104 			if (gp == NULL)
1105 				errx(EXIT_FAILURE, "No such geom: %s.", name);
1106 			if (geoms) {
1107 				status_update_len(gp,
1108 				    &name_len, &status_len);
1109 			} else {
1110 				status_update_len_prs(gp,
1111 				    &name_len, &status_len);
1112 			}
1113 			n++;
1114 		}
1115 		if (n == 0)
1116 			goto end;
1117 	} else {
1118 		n = 0;
1119 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1120 			if (LIST_EMPTY(&gp->lg_provider) && !all)
1121 				continue;
1122 			if (geoms) {
1123 				status_update_len(gp,
1124 				    &name_len, &status_len);
1125 			} else {
1126 				status_update_len_prs(gp,
1127 				    &name_len, &status_len);
1128 			}
1129 			n++;
1130 		}
1131 		if (n == 0)
1132 			goto end;
1133 	}
1134 	if (!script) {
1135 		printf("%*s  %*s  %s\n", name_len, "Name", status_len, "Status",
1136 		    "Components");
1137 	}
1138 	if (nargs > 0) {
1139 		for (i = 0; i < nargs; i++) {
1140 			name = gctl_get_ascii(req, "arg%d", i);
1141 			gp = find_geom(classp, name);
1142 			if (gp == NULL)
1143 				continue;
1144 			if (geoms) {
1145 				status_one_geom(gp, script, name_len,
1146 				    status_len);
1147 			} else {
1148 				status_one_geom_prs(gp, script, name_len,
1149 				    status_len);
1150 			}
1151 		}
1152 	} else {
1153 		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1154 			if (LIST_EMPTY(&gp->lg_provider) && !all)
1155 				continue;
1156 			if (geoms) {
1157 				status_one_geom(gp, script, name_len,
1158 				    status_len);
1159 			} else {
1160 				status_one_geom_prs(gp, script, name_len,
1161 				    status_len);
1162 			}
1163 		}
1164 	}
1165 end:
1166 	geom_deletetree(&mesh);
1167 }
1168 
1169 static int
1170 std_load_available(void)
1171 {
1172 	char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
1173 	struct stat sb;
1174 	size_t len;
1175 
1176 	snprintf(name, sizeof(name), "g_%s", class_name);
1177 	/*
1178 	 * If already in kernel, "load" command is not available.
1179 	 */
1180 	if (modfind(name) >= 0)
1181 		return (0);
1182 	bzero(paths, sizeof(paths));
1183 	len = sizeof(paths);
1184 	if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
1185 		err(EXIT_FAILURE, "sysctl(kern.module_path)");
1186 	for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
1187 		snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
1188 		/*
1189 		 * If geom_<name>.ko file exists, "load" command is available.
1190 		 */
1191 		if (stat(name, &sb) == 0)
1192 			return (1);
1193 	}
1194 	return (0);
1195 }
1196 
1197 static void
1198 std_load(struct gctl_req *req __unused, unsigned flags)
1199 {
1200 
1201 	/*
1202 	 * Do nothing special here, because of G_FLAG_LOADKLD flag,
1203 	 * module is already loaded.
1204 	 */
1205 	if ((flags & G_FLAG_VERBOSE) != 0)
1206 		printf("Module available.\n");
1207 }
1208 
1209 static int
1210 std_unload_available(void)
1211 {
1212 	char name[64];
1213 	int id;
1214 
1215 	snprintf(name, sizeof(name), "geom_%s", class_name);
1216 	id = kldfind(name);
1217 	if (id >= 0)
1218 		return (1);
1219 	return (0);
1220 }
1221 
1222 static void
1223 std_unload(struct gctl_req *req, unsigned flags __unused)
1224 {
1225 	char name[64];
1226 	int id;
1227 
1228 	snprintf(name, sizeof(name), "geom_%s", class_name);
1229 	id = kldfind(name);
1230 	if (id < 0) {
1231 		gctl_error(req, "Could not find module: %s.", strerror(errno));
1232 		return;
1233 	}
1234 	if (kldunload(id) < 0) {
1235 		gctl_error(req, "Could not unload module: %s.",
1236 		    strerror(errno));
1237 		return;
1238 	}
1239 }
1240 
1241 static int
1242 std_available(const char *name)
1243 {
1244 
1245 	if (strcmp(name, "help") == 0)
1246 		return (1);
1247 	else if (strcmp(name, "list") == 0)
1248 		return (std_list_available());
1249 	else if (strcmp(name, "status") == 0)
1250 		return (std_status_available());
1251 	else if (strcmp(name, "load") == 0)
1252 		return (std_load_available());
1253 	else if (strcmp(name, "unload") == 0)
1254 		return (std_unload_available());
1255 	else
1256 		assert(!"Unknown standard command.");
1257 	return (0);
1258 }
1259