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