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