1129470Spjd/*-
2196878Spjd * Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3129470Spjd * All rights reserved.
4129470Spjd *
5129470Spjd * Redistribution and use in source and binary forms, with or without
6129470Spjd * modification, are permitted provided that the following conditions
7129470Spjd * are met:
8129470Spjd * 1. Redistributions of source code must retain the above copyright
9129470Spjd *    notice, this list of conditions and the following disclaimer.
10129470Spjd * 2. Redistributions in binary form must reproduce the above copyright
11129470Spjd *    notice, this list of conditions and the following disclaimer in the
12129470Spjd *    documentation and/or other materials provided with the distribution.
13155175Spjd *
14129470Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15129470Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16129470Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17129470Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18129470Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19129470Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20129470Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21129470Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22129470Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23129470Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24129470Spjd * SUCH DAMAGE.
25129470Spjd */
26129470Spjd
27129470Spjd#include <sys/cdefs.h>
28129470Spjd__FBSDID("$FreeBSD$");
29129470Spjd
30129470Spjd#include <sys/param.h>
31129470Spjd#include <sys/linker.h>
32129470Spjd#include <sys/module.h>
33129470Spjd#include <sys/stat.h>
34129470Spjd#include <sys/sysctl.h>
35129470Spjd#include <ctype.h>
36129470Spjd#include <err.h>
37129470Spjd#include <errno.h>
38129470Spjd#include <stdio.h>
39129470Spjd#include <stdlib.h>
40129470Spjd#include <stdarg.h>
41129470Spjd#include <stdint.h>
42129470Spjd#include <string.h>
43129470Spjd#include <unistd.h>
44129470Spjd#include <libgen.h>
45129745Spjd#include <libutil.h>
46129470Spjd#include <inttypes.h>
47129470Spjd#include <dlfcn.h>
48129470Spjd#include <assert.h>
49129470Spjd#include <libgeom.h>
50129470Spjd#include <geom.h>
51129470Spjd
52129470Spjd#include "misc/subr.h"
53129470Spjd
54179550Smarcel#ifdef STATIC_GEOM_CLASSES
55173313Smarcelextern uint32_t gpart_version;
56173313Smarcelextern struct g_command gpart_class_commands[];
57176852Sdelphijextern uint32_t glabel_version;
58176852Sdelphijextern struct g_command glabel_class_commands[];
59173313Smarcel#endif
60129470Spjd
61129470Spjdstatic char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL;
62129470Spjdstatic uint32_t *version = NULL;
63129470Spjdstatic int verbose = 0;
64129470Spjdstatic struct g_command *class_commands = NULL;
65129470Spjd
66135369Spjd#define	GEOM_CLASS_CMDS	0x01
67135369Spjd#define	GEOM_STD_CMDS	0x02
68135369Spjdstatic struct g_command *find_command(const char *cmdstr, int flags);
69129470Spjdstatic int std_available(const char *name);
70129470Spjd
71129591Spjdstatic void std_help(struct gctl_req *req, unsigned flags);
72129470Spjdstatic void std_list(struct gctl_req *req, unsigned flags);
73143534Spjdstatic void std_status(struct gctl_req *req, unsigned flags);
74129470Spjdstatic void std_load(struct gctl_req *req, unsigned flags);
75129470Spjdstatic void std_unload(struct gctl_req *req, unsigned flags);
76129470Spjd
77241737Sedstatic struct g_command std_commands[] = {
78212554Spjd	{ "help", 0, std_help, G_NULL_OPTS, NULL },
79219969Smav	{ "list", 0, std_list,
80219969Smav	    {
81219969Smav		{ 'a', "all", NULL, G_TYPE_BOOL },
82219969Smav		G_OPT_SENTINEL
83219969Smav	    },
84219969Smav	    "[-a] [name ...]"
85143585Spjd	},
86143572Spjd	{ "status", 0, std_status,
87143572Spjd	    {
88219969Smav		{ 'a', "all", NULL, G_TYPE_BOOL },
89219969Smav		{ 'g', "geoms", NULL, G_TYPE_BOOL },
90162867Spjd		{ 's', "script", NULL, G_TYPE_BOOL },
91143572Spjd		G_OPT_SENTINEL
92143585Spjd	    },
93219969Smav	    "[-ags] [name ...]"
94143572Spjd	},
95169586Smarcel	{ "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS,
96212554Spjd	    NULL },
97212554Spjd	{ "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS, NULL },
98129470Spjd	G_CMD_SENTINEL
99129470Spjd};
100129470Spjd
101129470Spjdstatic void
102143585Spjdusage_command(struct g_command *cmd, const char *prefix)
103129470Spjd{
104129470Spjd	struct g_option *opt;
105143585Spjd	unsigned i;
106129470Spjd
107143585Spjd	if (cmd->gc_usage != NULL) {
108196877Spjd		char *pos, *ptr, *sptr;
109196877Spjd
110196877Spjd		sptr = ptr = strdup(cmd->gc_usage);
111196877Spjd		while ((pos = strsep(&ptr, "\n")) != NULL) {
112196877Spjd			if (*pos == '\0')
113196877Spjd				continue;
114196877Spjd			fprintf(stderr, "%s %s %s %s\n", prefix, comm,
115196877Spjd			    cmd->gc_name, pos);
116196877Spjd		}
117196877Spjd		free(sptr);
118143585Spjd		return;
119143585Spjd	}
120196877Spjd
121196877Spjd	fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name);
122143585Spjd	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
123143585Spjd		fprintf(stderr, " [-v]");
124129470Spjd	for (i = 0; ; i++) {
125143585Spjd		opt = &cmd->gc_options[i];
126143585Spjd		if (opt->go_name == NULL)
127129470Spjd			break;
128162867Spjd		if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
129143585Spjd			fprintf(stderr, " [");
130143585Spjd		else
131143585Spjd			fprintf(stderr, " ");
132143585Spjd		fprintf(stderr, "-%c", opt->go_char);
133162867Spjd		if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
134143585Spjd			fprintf(stderr, " %s", opt->go_name);
135162867Spjd		if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
136143585Spjd			fprintf(stderr, "]");
137129470Spjd	}
138143585Spjd	fprintf(stderr, "\n");
139129470Spjd}
140129470Spjd
141129470Spjdstatic void
142143585Spjdusage(void)
143129470Spjd{
144129470Spjd
145129470Spjd	if (class_name == NULL) {
146129591Spjd		errx(EXIT_FAILURE, "usage: %s <class> <command> [options]",
147129591Spjd		    "geom");
148129470Spjd	} else {
149143585Spjd		struct g_command *cmd;
150129470Spjd		const char *prefix;
151129470Spjd		unsigned i;
152129470Spjd
153143585Spjd		prefix = "usage:";
154143585Spjd		if (class_commands != NULL) {
155143585Spjd			for (i = 0; ; i++) {
156143585Spjd				cmd = &class_commands[i];
157143585Spjd				if (cmd->gc_name == NULL)
158143585Spjd					break;
159143585Spjd				usage_command(cmd, prefix);
160143585Spjd				prefix = "      ";
161143585Spjd			}
162129470Spjd		}
163129470Spjd		for (i = 0; ; i++) {
164129470Spjd			cmd = &std_commands[i];
165129470Spjd			if (cmd->gc_name == NULL)
166129470Spjd				break;
167135369Spjd			/*
168135369Spjd			 * If class defines command, which has the same name as
169135369Spjd			 * standard command, skip it, because it was already
170135369Spjd			 * shown on usage().
171135369Spjd			 */
172135369Spjd			if (find_command(cmd->gc_name, GEOM_CLASS_CMDS) != NULL)
173129470Spjd				continue;
174143585Spjd			usage_command(cmd, prefix);
175129470Spjd			prefix = "      ";
176129470Spjd		}
177129470Spjd		exit(EXIT_FAILURE);
178129470Spjd	}
179129470Spjd}
180129470Spjd
181129470Spjdstatic void
182129470Spjdload_module(void)
183129470Spjd{
184129470Spjd	char name1[64], name2[64];
185129470Spjd
186129470Spjd	snprintf(name1, sizeof(name1), "g_%s", class_name);
187129470Spjd	snprintf(name2, sizeof(name2), "geom_%s", class_name);
188129470Spjd	if (modfind(name1) < 0) {
189129470Spjd		/* Not present in kernel, try loading it. */
190129470Spjd		if (kldload(name2) < 0 || modfind(name1) < 0) {
191129470Spjd			if (errno != EEXIST) {
192129470Spjd				errx(EXIT_FAILURE,
193129470Spjd				    "%s module not available!", name2);
194129470Spjd			}
195129470Spjd		}
196129470Spjd	}
197129470Spjd}
198129470Spjd
199129470Spjdstatic int
200129470Spjdstrlcatf(char *str, size_t size, const char *format, ...)
201129470Spjd{
202129470Spjd	size_t len;
203129470Spjd	va_list ap;
204129470Spjd	int ret;
205129470Spjd
206129470Spjd	len = strlen(str);
207129470Spjd	str += len;
208129470Spjd	size -= len;
209129470Spjd
210129470Spjd	va_start(ap, format);
211129470Spjd	ret = vsnprintf(str, size, format, ap);
212129470Spjd	va_end(ap);
213129470Spjd
214129470Spjd	return (ret);
215129470Spjd}
216129470Spjd
217129470Spjd/*
218129470Spjd * Find given option in options available for given command.
219129470Spjd */
220129470Spjdstatic struct g_option *
221129470Spjdfind_option(struct g_command *cmd, char ch)
222129470Spjd{
223129470Spjd	struct g_option *opt;
224129470Spjd	unsigned i;
225129470Spjd
226129470Spjd	for (i = 0; ; i++) {
227129470Spjd		opt = &cmd->gc_options[i];
228129470Spjd		if (opt->go_name == NULL)
229129470Spjd			return (NULL);
230129470Spjd		if (opt->go_char == ch)
231129470Spjd			return (opt);
232129470Spjd	}
233129470Spjd	/* NOTREACHED */
234129470Spjd	return (NULL);
235129470Spjd}
236129470Spjd
237129470Spjd/*
238129470Spjd * Add given option to gctl_req.
239129470Spjd */
240129470Spjdstatic void
241129470Spjdset_option(struct gctl_req *req, struct g_option *opt, const char *val)
242129470Spjd{
243212555Spjd	const char *optname;
244211500Sdes	uint64_t number;
245212547Spjd	void *ptr;
246129470Spjd
247212555Spjd	if (G_OPT_ISMULTI(opt)) {
248212555Spjd		size_t optnamesize;
249212555Spjd
250212555Spjd		if (G_OPT_NUM(opt) == UCHAR_MAX)
251212555Spjd			errx(EXIT_FAILURE, "Too many -%c options.", opt->go_char);
252212555Spjd
253212555Spjd		/*
254212555Spjd		 * Base option name length plus 3 bytes for option number
255212555Spjd		 * (max. 255 options) plus 1 byte for terminating '\0'.
256212555Spjd		 */
257212555Spjd		optnamesize = strlen(opt->go_name) + 3 + 1;
258212555Spjd		ptr = malloc(optnamesize);
259212555Spjd		if (ptr == NULL)
260212555Spjd			errx(EXIT_FAILURE, "No memory.");
261212555Spjd		snprintf(ptr, optnamesize, "%s%u", opt->go_name, G_OPT_NUM(opt));
262212555Spjd		G_OPT_NUMINC(opt);
263212555Spjd		optname = ptr;
264212555Spjd	} else {
265212555Spjd		optname = opt->go_name;
266212555Spjd	}
267212555Spjd
268212615Spjd	if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) {
269172273Spjd		if (expand_number(val, &number) == -1) {
270212607Spjd			err(EXIT_FAILURE, "Invalid value for '%c' argument",
271129470Spjd			    opt->go_char);
272129470Spjd		}
273212622Spjd		ptr = malloc(sizeof(intmax_t));
274212622Spjd		if (ptr == NULL)
275212622Spjd			errx(EXIT_FAILURE, "No memory.");
276212622Spjd		*(intmax_t *)ptr = number;
277212622Spjd		opt->go_val = ptr;
278212622Spjd		gctl_ro_param(req, optname, sizeof(intmax_t), opt->go_val);
279162867Spjd	} else if (G_OPT_TYPE(opt) == G_TYPE_STRING) {
280212555Spjd		gctl_ro_param(req, optname, -1, val);
281162867Spjd	} else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
282212547Spjd		ptr = malloc(sizeof(int));
283212547Spjd		if (ptr == NULL)
284129470Spjd			errx(EXIT_FAILURE, "No memory.");
285212547Spjd		*(int *)ptr = *val - '0';
286212547Spjd		opt->go_val = ptr;
287212555Spjd		gctl_ro_param(req, optname, sizeof(int), opt->go_val);
288162867Spjd	} else {
289162867Spjd		assert(!"Invalid type");
290129470Spjd	}
291212555Spjd
292212555Spjd	if (G_OPT_ISMULTI(opt))
293212555Spjd		free(__DECONST(char *, optname));
294129470Spjd}
295129470Spjd
296129470Spjd/*
297129470Spjd * 1. Add given argument by caller.
298129470Spjd * 2. Add default values of not given arguments.
299129470Spjd * 3. Add the rest of arguments.
300129470Spjd */
301129470Spjdstatic void
302129470Spjdparse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
303129470Spjd    char ***argv)
304129470Spjd{
305129470Spjd	struct g_option *opt;
306129470Spjd	char opts[64];
307129470Spjd	unsigned i;
308129470Spjd	int ch;
309129470Spjd
310129470Spjd	*opts = '\0';
311129470Spjd	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
312129470Spjd		strlcat(opts, "v", sizeof(opts));
313129470Spjd	for (i = 0; ; i++) {
314129470Spjd		opt = &cmd->gc_options[i];
315129470Spjd		if (opt->go_name == NULL)
316129470Spjd			break;
317162867Spjd		assert(G_OPT_TYPE(opt) != 0);
318212555Spjd		assert((opt->go_type & ~(G_TYPE_MASK | G_TYPE_MULTI)) == 0);
319212555Spjd		/* Multiple bool arguments makes no sense. */
320212555Spjd		assert(G_OPT_TYPE(opt) != G_TYPE_BOOL ||
321212555Spjd		    (opt->go_type & G_TYPE_MULTI) == 0);
322129470Spjd		strlcatf(opts, sizeof(opts), "%c", opt->go_char);
323162867Spjd		if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
324129470Spjd			strlcat(opts, ":", sizeof(opts));
325129470Spjd	}
326129470Spjd
327129470Spjd	/*
328129470Spjd	 * Add specified arguments.
329129470Spjd	 */
330129470Spjd	while ((ch = getopt(*argc, *argv, opts)) != -1) {
331129470Spjd		/* Standard (not passed to kernel) options. */
332129470Spjd		switch (ch) {
333129470Spjd		case 'v':
334129470Spjd			verbose = 1;
335129470Spjd			continue;
336129470Spjd		}
337129470Spjd		/* Options passed to kernel. */
338129470Spjd		opt = find_option(cmd, ch);
339129470Spjd		if (opt == NULL)
340143585Spjd			usage();
341212555Spjd		if (!G_OPT_ISMULTI(opt) && G_OPT_ISDONE(opt)) {
342162867Spjd			warnx("Option '%c' specified twice.", opt->go_char);
343143585Spjd			usage();
344129470Spjd		}
345129470Spjd		G_OPT_DONE(opt);
346129470Spjd
347162867Spjd		if (G_OPT_TYPE(opt) == G_TYPE_BOOL)
348129470Spjd			set_option(req, opt, "1");
349129470Spjd		else
350129470Spjd			set_option(req, opt, optarg);
351129470Spjd	}
352129470Spjd	*argc -= optind;
353129470Spjd	*argv += optind;
354129470Spjd
355129470Spjd	/*
356129470Spjd	 * Add not specified arguments, but with default values.
357129470Spjd	 */
358129470Spjd	for (i = 0; ; i++) {
359129470Spjd		opt = &cmd->gc_options[i];
360129470Spjd		if (opt->go_name == NULL)
361129470Spjd			break;
362129470Spjd		if (G_OPT_ISDONE(opt))
363129470Spjd			continue;
364129470Spjd
365162867Spjd		if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
366129470Spjd			assert(opt->go_val == NULL);
367129470Spjd			set_option(req, opt, "0");
368129470Spjd		} else {
369129470Spjd			if (opt->go_val == NULL) {
370162867Spjd				warnx("Option '%c' not specified.",
371129470Spjd				    opt->go_char);
372143585Spjd				usage();
373212606Spjd			} else if (opt->go_val == G_VAL_OPTIONAL) {
374212606Spjd				/* add nothing. */
375129470Spjd			} else {
376212554Spjd				set_option(req, opt, opt->go_val);
377129470Spjd			}
378129470Spjd		}
379129470Spjd	}
380129470Spjd
381212554Spjd	/*
382212554Spjd	 * Add rest of given arguments.
383212554Spjd	 */
384212554Spjd	gctl_ro_param(req, "nargs", sizeof(int), argc);
385212554Spjd	for (i = 0; i < (unsigned)*argc; i++) {
386212554Spjd		char argname[16];
387169586Smarcel
388212554Spjd		snprintf(argname, sizeof(argname), "arg%u", i);
389212554Spjd		gctl_ro_param(req, argname, -1, (*argv)[i]);
390129470Spjd	}
391129470Spjd}
392129470Spjd
393129470Spjd/*
394129470Spjd * Find given command in commands available for given class.
395129470Spjd */
396129470Spjdstatic struct g_command *
397135369Spjdfind_command(const char *cmdstr, int flags)
398129470Spjd{
399129470Spjd	struct g_command *cmd;
400129470Spjd	unsigned i;
401129470Spjd
402129470Spjd	/*
403129470Spjd	 * First try to find command defined by loaded library.
404129470Spjd	 */
405135369Spjd	if ((flags & GEOM_CLASS_CMDS) != 0 && class_commands != NULL) {
406129470Spjd		for (i = 0; ; i++) {
407129470Spjd			cmd = &class_commands[i];
408129470Spjd			if (cmd->gc_name == NULL)
409129470Spjd				break;
410129470Spjd			if (strcmp(cmd->gc_name, cmdstr) == 0)
411129470Spjd				return (cmd);
412129470Spjd		}
413129470Spjd	}
414129470Spjd	/*
415129470Spjd	 * Now try to find in standard commands.
416129470Spjd	 */
417135369Spjd	if ((flags & GEOM_STD_CMDS) != 0) {
418135369Spjd		for (i = 0; ; i++) {
419135369Spjd			cmd = &std_commands[i];
420135369Spjd			if (cmd->gc_name == NULL)
421135369Spjd				break;
422135369Spjd			if (strcmp(cmd->gc_name, cmdstr) == 0)
423135369Spjd				return (cmd);
424135369Spjd		}
425129470Spjd	}
426129470Spjd	return (NULL);
427129470Spjd}
428129470Spjd
429129470Spjdstatic unsigned
430129470Spjdset_flags(struct g_command *cmd)
431129470Spjd{
432129470Spjd	unsigned flags = 0;
433129470Spjd
434129470Spjd	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
435129470Spjd		flags |= G_FLAG_VERBOSE;
436129470Spjd
437129470Spjd	return (flags);
438129470Spjd}
439129470Spjd
440129470Spjd/*
441129470Spjd * Run command.
442129470Spjd */
443129470Spjdstatic void
444129470Spjdrun_command(int argc, char *argv[])
445129470Spjd{
446129470Spjd	struct g_command *cmd;
447129470Spjd	struct gctl_req *req;
448129470Spjd	const char *errstr;
449129470Spjd	char buf[4096];
450129470Spjd
451135369Spjd	/* First try to find a command defined by a class. */
452135369Spjd	cmd = find_command(argv[0], GEOM_CLASS_CMDS);
453129470Spjd	if (cmd == NULL) {
454135369Spjd		/* Now, try to find a standard command. */
455135369Spjd		cmd = find_command(argv[0], GEOM_STD_CMDS);
456135369Spjd		if (cmd == NULL) {
457162867Spjd			warnx("Unknown command: %s.", argv[0]);
458143585Spjd			usage();
459135369Spjd		}
460135369Spjd		if (!std_available(cmd->gc_name)) {
461162867Spjd			warnx("Command '%s' not available.", argv[0]);
462135369Spjd			exit(EXIT_FAILURE);
463135369Spjd		}
464129470Spjd	}
465129470Spjd	if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
466129470Spjd		load_module();
467129470Spjd
468129470Spjd	req = gctl_get_handle();
469129470Spjd	gctl_ro_param(req, "class", -1, gclass_name);
470129470Spjd	gctl_ro_param(req, "verb", -1, argv[0]);
471129470Spjd	if (version != NULL)
472129470Spjd		gctl_ro_param(req, "version", sizeof(*version), version);
473129470Spjd	parse_arguments(cmd, req, &argc, &argv);
474129470Spjd
475143998Spjd	bzero(buf, sizeof(buf));
476129470Spjd	if (cmd->gc_func != NULL) {
477129470Spjd		unsigned flags;
478129470Spjd
479129470Spjd		flags = set_flags(cmd);
480129470Spjd		cmd->gc_func(req, flags);
481129470Spjd		errstr = req->error;
482129470Spjd	} else {
483129470Spjd		gctl_rw_param(req, "output", sizeof(buf), buf);
484129470Spjd		errstr = gctl_issue(req);
485129470Spjd	}
486145662Spjd	if (errstr != NULL && errstr[0] != '\0') {
487162867Spjd		warnx("%s", errstr);
488134419Spjd		if (strncmp(errstr, "warning: ", strlen("warning: ")) != 0) {
489134419Spjd			gctl_free(req);
490134419Spjd			exit(EXIT_FAILURE);
491134419Spjd		}
492129470Spjd	}
493143998Spjd	if (buf[0] != '\0')
494129470Spjd		printf("%s", buf);
495129470Spjd	gctl_free(req);
496129470Spjd	if (verbose)
497129470Spjd		printf("Done.\n");
498129470Spjd	exit(EXIT_SUCCESS);
499129470Spjd}
500129470Spjd
501179550Smarcel#ifndef STATIC_GEOM_CLASSES
502142691Spjdstatic const char *
503142691Spjdlibrary_path(void)
504142691Spjd{
505142691Spjd	const char *path;
506142691Spjd
507142691Spjd	path = getenv("GEOM_LIBRARY_PATH");
508142691Spjd	if (path == NULL)
509216470Sobrien		path = GEOM_CLASS_DIR;
510142691Spjd	return (path);
511142691Spjd}
512142691Spjd
513129470Spjdstatic void
514129470Spjdload_library(void)
515129470Spjd{
516188017Slulf	char *curpath, path[MAXPATHLEN], *tofree, *totalpath;
517129470Spjd	uint32_t *lib_version;
518129470Spjd	void *dlh;
519175967Slulf	int ret;
520129470Spjd
521175967Slulf	ret = 0;
522188017Slulf	tofree = totalpath = strdup(library_path());
523175967Slulf	if (totalpath == NULL)
524175967Slulf		err(EXIT_FAILURE, "Not enough memory for library path");
525175967Slulf
526175967Slulf	if (strchr(totalpath, ':') != NULL)
527175967Slulf		curpath = strsep(&totalpath, ":");
528175967Slulf	else
529175967Slulf		curpath = totalpath;
530175967Slulf	/* Traverse the paths to find one that contains the library we want. */
531175967Slulf	while (curpath != NULL) {
532175967Slulf		snprintf(path, sizeof(path), "%s/geom_%s.so", curpath,
533175967Slulf		    class_name);
534175967Slulf		ret = access(path, F_OK);
535175967Slulf		if (ret == -1) {
536175967Slulf			if (errno == ENOENT) {
537175967Slulf				/*
538175967Slulf				 * If we cannot find library, try the next
539175967Slulf				 * path.
540175967Slulf				 */
541175967Slulf				curpath = strsep(&totalpath, ":");
542175967Slulf				continue;
543175967Slulf			}
544175967Slulf			err(EXIT_FAILURE, "Cannot access library");
545149059Spjd		}
546175967Slulf		break;
547149059Spjd	}
548188017Slulf	free(tofree);
549175967Slulf	/* No library was found, but standard commands can still be used */
550175967Slulf	if (ret == -1)
551175967Slulf		return;
552129470Spjd	dlh = dlopen(path, RTLD_NOW);
553149059Spjd	if (dlh == NULL)
554149059Spjd		errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror());
555129470Spjd	lib_version = dlsym(dlh, "lib_version");
556129470Spjd	if (lib_version == NULL) {
557162867Spjd		warnx("Cannot find symbol %s: %s.", "lib_version", dlerror());
558129470Spjd		dlclose(dlh);
559129470Spjd		exit(EXIT_FAILURE);
560129470Spjd	}
561129470Spjd	if (*lib_version != G_LIB_VERSION) {
562129470Spjd		dlclose(dlh);
563134419Spjd		errx(EXIT_FAILURE, "%s and %s are not synchronized.",
564134419Spjd		    getprogname(), path);
565129470Spjd	}
566129470Spjd	version = dlsym(dlh, "version");
567129470Spjd	if (version == NULL) {
568162867Spjd		warnx("Cannot find symbol %s: %s.", "version", dlerror());
569129470Spjd		dlclose(dlh);
570129470Spjd		exit(EXIT_FAILURE);
571129470Spjd	}
572129470Spjd	class_commands = dlsym(dlh, "class_commands");
573129470Spjd	if (class_commands == NULL) {
574162867Spjd		warnx("Cannot find symbol %s: %s.", "class_commands",
575162867Spjd		    dlerror());
576129470Spjd		dlclose(dlh);
577129470Spjd		exit(EXIT_FAILURE);
578129470Spjd	}
579129470Spjd}
580179550Smarcel#endif	/* !STATIC_GEOM_CLASSES */
581129470Spjd
582129470Spjd/*
583129470Spjd * Class name should be all capital letters.
584129470Spjd */
585129470Spjdstatic void
586129470Spjdset_class_name(void)
587129470Spjd{
588129470Spjd	char *s1, *s2;
589129470Spjd
590143589Spjd	s1 = class_name;
591143589Spjd	for (; *s1 != '\0'; s1++)
592143589Spjd		*s1 = tolower(*s1);
593157580Spjd	gclass_name = malloc(strlen(class_name) + 1);
594129470Spjd	if (gclass_name == NULL)
595129470Spjd		errx(EXIT_FAILURE, "No memory");
596129470Spjd	s1 = gclass_name;
597129470Spjd	s2 = class_name;
598129470Spjd	for (; *s2 != '\0'; s2++)
599129470Spjd		*s1++ = toupper(*s2);
600129470Spjd	*s1 = '\0';
601129470Spjd}
602129470Spjd
603129470Spjdstatic void
604129470Spjdget_class(int *argc, char ***argv)
605129470Spjd{
606129470Spjd
607129470Spjd	snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
608129470Spjd	if (strcmp(comm, "geom") == 0) {
609129470Spjd		if (*argc < 2)
610143585Spjd			usage();
611139377Spjd		else if (*argc == 2) {
612139377Spjd			if (strcmp((*argv)[1], "-h") == 0 ||
613139377Spjd			    strcmp((*argv)[1], "help") == 0) {
614143585Spjd				usage();
615139377Spjd			}
616139377Spjd		}
617129470Spjd		strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
618129470Spjd		class_name = (*argv)[1];
619129470Spjd		*argc -= 2;
620129470Spjd		*argv += 2;
621129470Spjd	} else if (*comm == 'g') {
622129470Spjd		class_name = comm + 1;
623129470Spjd		*argc -= 1;
624129470Spjd		*argv += 1;
625129470Spjd	} else {
626129470Spjd		errx(EXIT_FAILURE, "Invalid utility name.");
627129470Spjd	}
628173313Smarcel
629179550Smarcel#ifndef STATIC_GEOM_CLASSES
630173313Smarcel	load_library();
631173313Smarcel#else
632173313Smarcel	if (!strcasecmp(class_name, "part")) {
633173313Smarcel		version = &gpart_version;
634173313Smarcel		class_commands = gpart_class_commands;
635176852Sdelphij	} else if (!strcasecmp(class_name, "label")) {
636176852Sdelphij		version = &glabel_version;
637176852Sdelphij		class_commands = glabel_class_commands;
638173313Smarcel	} else
639173313Smarcel		errx(EXIT_FAILURE, "Invalid class name.");
640179550Smarcel#endif /* !STATIC_GEOM_CLASSES */
641173313Smarcel
642129470Spjd	set_class_name();
643129470Spjd	if (*argc < 1)
644143585Spjd		usage();
645129470Spjd}
646129470Spjd
647129470Spjdint
648129470Spjdmain(int argc, char *argv[])
649129470Spjd{
650129470Spjd
651129470Spjd	get_class(&argc, &argv);
652129470Spjd	run_command(argc, argv);
653129470Spjd	/* NOTREACHED */
654129470Spjd
655129470Spjd	exit(EXIT_FAILURE);
656129470Spjd}
657129470Spjd
658129470Spjdstatic struct gclass *
659129470Spjdfind_class(struct gmesh *mesh, const char *name)
660129470Spjd{
661129470Spjd	struct gclass *classp;
662129470Spjd
663129470Spjd	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
664129470Spjd		if (strcmp(classp->lg_name, name) == 0)
665129470Spjd			return (classp);
666129470Spjd	}
667129470Spjd	return (NULL);
668129470Spjd}
669129470Spjd
670132665Spjdstatic struct ggeom *
671132665Spjdfind_geom(struct gclass *classp, const char *name)
672129470Spjd{
673129470Spjd	struct ggeom *gp;
674129470Spjd
675129470Spjd	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
676132665Spjd		if (strcmp(gp->lg_name, name) == 0)
677132665Spjd			return (gp);
678129470Spjd	}
679129470Spjd	return (NULL);
680129470Spjd}
681129470Spjd
682132665Spjdstatic void
683143532Spjdlist_one_provider(struct gprovider *pp, const char *prefix)
684129470Spjd{
685132665Spjd	struct gconfig *conf;
686132665Spjd	char buf[5];
687129470Spjd
688132665Spjd	printf("Name: %s\n", pp->lg_name);
689132665Spjd	humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
690132665Spjd	    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
691132665Spjd	printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
692132665Spjd	    buf);
693132665Spjd	printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
694202457Sdelphij	if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
695202454Sdelphij		printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
696202454Sdelphij		printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
697202454Sdelphij	}
698132665Spjd	printf("%sMode: %s\n", prefix, pp->lg_mode);
699132665Spjd	LIST_FOREACH(conf, &pp->lg_config, lg_config) {
700132665Spjd		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
701129470Spjd	}
702132665Spjd}
703132665Spjd
704132665Spjdstatic void
705143532Spjdlist_one_consumer(struct gconsumer *cp, const char *prefix)
706132665Spjd{
707132665Spjd	struct gprovider *pp;
708132665Spjd	struct gconfig *conf;
709132665Spjd
710132665Spjd	pp = cp->lg_provider;
711132665Spjd	if (pp == NULL)
712132665Spjd		printf("[no provider]\n");
713132665Spjd	else {
714132665Spjd		char buf[5];
715132665Spjd
716132665Spjd		printf("Name: %s\n", pp->lg_name);
717132665Spjd		humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
718132665Spjd		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
719132665Spjd		printf("%sMediasize: %jd (%s)\n", prefix,
720132665Spjd		    (intmax_t)pp->lg_mediasize, buf);
721132665Spjd		printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
722202586Sdelphij		if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
723202454Sdelphij			printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
724202454Sdelphij			printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
725202454Sdelphij		}
726132665Spjd		printf("%sMode: %s\n", prefix, cp->lg_mode);
727129470Spjd	}
728132665Spjd	LIST_FOREACH(conf, &cp->lg_config, lg_config) {
729132665Spjd		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
730132665Spjd	}
731129470Spjd}
732129470Spjd
733129470Spjdstatic void
734143532Spjdlist_one_geom(struct ggeom *gp)
735129470Spjd{
736132665Spjd	struct gprovider *pp;
737132665Spjd	struct gconsumer *cp;
738129470Spjd	struct gconfig *conf;
739132665Spjd	unsigned n;
740129470Spjd
741132665Spjd	printf("Geom name: %s\n", gp->lg_name);
742132665Spjd	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
743132665Spjd		printf("%s: %s\n", conf->lg_name, conf->lg_val);
744129470Spjd	}
745132665Spjd	if (!LIST_EMPTY(&gp->lg_provider)) {
746132665Spjd		printf("Providers:\n");
747132665Spjd		n = 1;
748132665Spjd		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
749132665Spjd			printf("%u. ", n++);
750143532Spjd			list_one_provider(pp, "   ");
751132665Spjd		}
752132665Spjd	}
753132665Spjd	if (!LIST_EMPTY(&gp->lg_consumer)) {
754132665Spjd		printf("Consumers:\n");
755132665Spjd		n = 1;
756132665Spjd		LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
757132665Spjd			printf("%u. ", n++);
758143532Spjd			list_one_consumer(cp, "   ");
759132665Spjd		}
760132665Spjd	}
761129470Spjd	printf("\n");
762129470Spjd}
763129470Spjd
764129591Spjdstatic void
765129591Spjdstd_help(struct gctl_req *req __unused, unsigned flags __unused)
766129591Spjd{
767129591Spjd
768143585Spjd	usage();
769129591Spjd}
770129591Spjd
771129470Spjdstatic int
772129470Spjdstd_list_available(void)
773129470Spjd{
774129470Spjd	struct gmesh mesh;
775129470Spjd	struct gclass *classp;
776129470Spjd	int error;
777129470Spjd
778129470Spjd	error = geom_gettree(&mesh);
779162867Spjd	if (error != 0)
780162867Spjd		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
781129470Spjd	classp = find_class(&mesh, gclass_name);
782129470Spjd	geom_deletetree(&mesh);
783129470Spjd	if (classp != NULL)
784129470Spjd		return (1);
785129470Spjd	return (0);
786129470Spjd}
787129470Spjd
788129470Spjdstatic void
789129470Spjdstd_list(struct gctl_req *req, unsigned flags __unused)
790129470Spjd{
791129470Spjd	struct gmesh mesh;
792129470Spjd	struct gclass *classp;
793132665Spjd	struct ggeom *gp;
794153190Spjd	const char *name;
795219969Smav	int all, error, i, nargs;
796129470Spjd
797129470Spjd	error = geom_gettree(&mesh);
798162867Spjd	if (error != 0)
799162867Spjd		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
800129470Spjd	classp = find_class(&mesh, gclass_name);
801129470Spjd	if (classp == NULL) {
802129470Spjd		geom_deletetree(&mesh);
803167842Spjd		errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
804129470Spjd	}
805153190Spjd	nargs = gctl_get_int(req, "nargs");
806219969Smav	all = gctl_get_int(req, "all");
807153190Spjd	if (nargs > 0) {
808153190Spjd		for (i = 0; i < nargs; i++) {
809153190Spjd			name = gctl_get_ascii(req, "arg%d", i);
810132665Spjd			gp = find_geom(classp, name);
811219969Smav			if (gp == NULL)
812167842Spjd				errx(EXIT_FAILURE, "No such geom: %s.", name);
813219969Smav			list_one_geom(gp);
814129470Spjd		}
815129470Spjd	} else {
816129470Spjd		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
817219969Smav			if (LIST_EMPTY(&gp->lg_provider) && !all)
818143522Spjd				continue;
819143532Spjd			list_one_geom(gp);
820129470Spjd		}
821129470Spjd	}
822129470Spjd	geom_deletetree(&mesh);
823129470Spjd}
824129470Spjd
825129470Spjdstatic int
826143534Spjdstd_status_available(void)
827143534Spjd{
828143534Spjd
829143534Spjd	/* 'status' command is available when 'list' command is. */
830143534Spjd	return (std_list_available());
831143534Spjd}
832143534Spjd
833143534Spjdstatic void
834143558Spjdstatus_update_len(struct ggeom *gp, int *name_len, int *status_len)
835143534Spjd{
836143534Spjd	struct gconfig *conf;
837143558Spjd	int len;
838143534Spjd
839143534Spjd	assert(gp != NULL);
840143534Spjd	assert(name_len != NULL);
841143534Spjd	assert(status_len != NULL);
842143534Spjd
843219969Smav	len = strlen(gp->lg_name);
844143534Spjd	if (*name_len < len)
845143534Spjd		*name_len = len;
846143534Spjd	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
847143534Spjd		if (strcasecmp(conf->lg_name, "state") == 0) {
848143534Spjd			len = strlen(conf->lg_val);
849143534Spjd			if (*status_len < len)
850143534Spjd				*status_len = len;
851143534Spjd		}
852143534Spjd	}
853143534Spjd}
854143534Spjd
855219969Smavstatic void
856219969Smavstatus_update_len_prs(struct ggeom *gp, int *name_len, int *status_len)
857219969Smav{
858219969Smav	struct gprovider *pp;
859219969Smav	struct gconfig *conf;
860219969Smav	int len, glen;
861219969Smav
862219969Smav	assert(gp != NULL);
863219969Smav	assert(name_len != NULL);
864219969Smav	assert(status_len != NULL);
865219969Smav
866219969Smav	glen = 0;
867219969Smav	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
868219969Smav		if (strcasecmp(conf->lg_name, "state") == 0) {
869219969Smav			glen = strlen(conf->lg_val);
870219969Smav			break;
871219969Smav		}
872219969Smav	}
873219969Smav	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
874219969Smav		len = strlen(pp->lg_name);
875219969Smav		if (*name_len < len)
876219969Smav			*name_len = len;
877219969Smav		len = glen;
878219969Smav		LIST_FOREACH(conf, &pp->lg_config, lg_config) {
879219969Smav			if (strcasecmp(conf->lg_name, "state") == 0) {
880219969Smav				len = strlen(conf->lg_val);
881219969Smav				break;
882219969Smav			}
883219969Smav		}
884219969Smav		if (*status_len < len)
885219969Smav			*status_len = len;
886219969Smav	}
887219969Smav}
888219969Smav
889143572Spjdstatic char *
890143534Spjdstatus_one_consumer(struct gconsumer *cp)
891143534Spjd{
892143572Spjd	static char buf[256];
893143534Spjd	struct gprovider *pp;
894143534Spjd	struct gconfig *conf;
895219969Smav	const char *state, *syncr;
896143534Spjd
897143534Spjd	pp = cp->lg_provider;
898143534Spjd	if (pp == NULL)
899143572Spjd		return (NULL);
900219969Smav	state = NULL;
901219969Smav	syncr = NULL;
902143534Spjd	LIST_FOREACH(conf, &cp->lg_config, lg_config) {
903219969Smav		if (strcasecmp(conf->lg_name, "state") == 0)
904219969Smav			state = conf->lg_val;
905143534Spjd		if (strcasecmp(conf->lg_name, "synchronized") == 0)
906219969Smav			syncr = conf->lg_val;
907143534Spjd	}
908219969Smav	if (state == NULL && syncr == NULL)
909143572Spjd		snprintf(buf, sizeof(buf), "%s", pp->lg_name);
910219969Smav	else if (state != NULL && syncr != NULL) {
911219969Smav		snprintf(buf, sizeof(buf), "%s (%s, %s)", pp->lg_name,
912219969Smav		    state, syncr);
913219969Smav	} else {
914143572Spjd		snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name,
915219969Smav		    state ? state : syncr);
916143572Spjd	}
917143572Spjd	return (buf);
918143534Spjd}
919143534Spjd
920143534Spjdstatic void
921143572Spjdstatus_one_geom(struct ggeom *gp, int script, int name_len, int status_len)
922143534Spjd{
923143534Spjd	struct gconsumer *cp;
924143534Spjd	struct gconfig *conf;
925143572Spjd	const char *name, *status, *component;
926143572Spjd	int gotone;
927143534Spjd
928219969Smav	name = gp->lg_name;
929219969Smav	status = "N/A";
930143534Spjd	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
931219969Smav		if (strcasecmp(conf->lg_name, "state") == 0) {
932219969Smav			status = conf->lg_val;
933143534Spjd			break;
934219969Smav		}
935143534Spjd	}
936143572Spjd	gotone = 0;
937143534Spjd	LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
938143572Spjd		component = status_one_consumer(cp);
939143572Spjd		if (component == NULL)
940143572Spjd			continue;
941143572Spjd		gotone = 1;
942143572Spjd		printf("%*s  %*s  %s\n", name_len, name, status_len, status,
943143572Spjd		    component);
944143572Spjd		if (!script)
945143572Spjd			name = status = "";
946143534Spjd	}
947143572Spjd	if (!gotone) {
948143572Spjd		printf("%*s  %*s  %s\n", name_len, name, status_len, status,
949143572Spjd		    "N/A");
950143572Spjd	}
951143534Spjd}
952143534Spjd
953143534Spjdstatic void
954219969Smavstatus_one_geom_prs(struct ggeom *gp, int script, int name_len, int status_len)
955219969Smav{
956219969Smav	struct gprovider *pp;
957219969Smav	struct gconsumer *cp;
958219969Smav	struct gconfig *conf;
959219969Smav	const char *name, *status, *component;
960219969Smav	int gotone;
961219969Smav
962219969Smav	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
963219969Smav		name = pp->lg_name;
964219969Smav		status = "N/A";
965219969Smav		LIST_FOREACH(conf, &gp->lg_config, lg_config) {
966219969Smav			if (strcasecmp(conf->lg_name, "state") == 0) {
967219969Smav				status = conf->lg_val;
968219969Smav				break;
969219969Smav			}
970219969Smav		}
971219969Smav		LIST_FOREACH(conf, &pp->lg_config, lg_config) {
972219969Smav			if (strcasecmp(conf->lg_name, "state") == 0) {
973219969Smav				status = conf->lg_val;
974219969Smav				break;
975219969Smav			}
976219969Smav		}
977219969Smav		gotone = 0;
978219969Smav		LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
979219969Smav			component = status_one_consumer(cp);
980219969Smav			if (component == NULL)
981219969Smav				continue;
982219969Smav			gotone = 1;
983219969Smav			printf("%*s  %*s  %s\n", name_len, name,
984219969Smav			    status_len, status, component);
985219969Smav			if (!script)
986219969Smav				name = status = "";
987219969Smav		}
988219969Smav		if (!gotone) {
989219969Smav			printf("%*s  %*s  %s\n", name_len, name,
990219969Smav			    status_len, status, "N/A");
991219969Smav		}
992219969Smav	}
993219969Smav}
994219969Smav
995219969Smavstatic void
996143534Spjdstd_status(struct gctl_req *req, unsigned flags __unused)
997143534Spjd{
998143534Spjd	struct gmesh mesh;
999143534Spjd	struct gclass *classp;
1000143534Spjd	struct ggeom *gp;
1001153190Spjd	const char *name;
1002143558Spjd	int name_len, status_len;
1003219969Smav	int all, error, geoms, i, n, nargs, script;
1004143534Spjd
1005143534Spjd	error = geom_gettree(&mesh);
1006162867Spjd	if (error != 0)
1007162867Spjd		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1008143534Spjd	classp = find_class(&mesh, gclass_name);
1009167842Spjd	if (classp == NULL)
1010167842Spjd		errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
1011153190Spjd	nargs = gctl_get_int(req, "nargs");
1012219969Smav	all = gctl_get_int(req, "all");
1013219969Smav	geoms = gctl_get_int(req, "geoms");
1014153190Spjd	script = gctl_get_int(req, "script");
1015219969Smav	if (script) {
1016219969Smav		name_len = 0;
1017219969Smav		status_len = 0;
1018219969Smav	} else {
1019219969Smav		name_len = strlen("Name");
1020219969Smav		status_len = strlen("Status");
1021219969Smav	}
1022153190Spjd	if (nargs > 0) {
1023153190Spjd		for (i = 0, n = 0; i < nargs; i++) {
1024153190Spjd			name = gctl_get_ascii(req, "arg%d", i);
1025143534Spjd			gp = find_geom(classp, name);
1026143534Spjd			if (gp == NULL)
1027167842Spjd				errx(EXIT_FAILURE, "No such geom: %s.", name);
1028219969Smav			if (geoms) {
1029219969Smav				status_update_len(gp,
1030219969Smav				    &name_len, &status_len);
1031219969Smav			} else {
1032219969Smav				status_update_len_prs(gp,
1033219969Smav				    &name_len, &status_len);
1034143534Spjd			}
1035219969Smav			n++;
1036143534Spjd		}
1037143534Spjd		if (n == 0)
1038143534Spjd			goto end;
1039143534Spjd	} else {
1040153190Spjd		n = 0;
1041143534Spjd		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1042219969Smav			if (LIST_EMPTY(&gp->lg_provider) && !all)
1043143534Spjd				continue;
1044219969Smav			if (geoms) {
1045219969Smav				status_update_len(gp,
1046219969Smav				    &name_len, &status_len);
1047219969Smav			} else {
1048219969Smav				status_update_len_prs(gp,
1049219969Smav				    &name_len, &status_len);
1050219969Smav			}
1051143534Spjd			n++;
1052143534Spjd		}
1053143534Spjd		if (n == 0)
1054143534Spjd			goto end;
1055143534Spjd	}
1056153190Spjd	if (!script) {
1057143572Spjd		printf("%*s  %*s  %s\n", name_len, "Name", status_len, "Status",
1058143572Spjd		    "Components");
1059143572Spjd	}
1060153190Spjd	if (nargs > 0) {
1061153190Spjd		for (i = 0; i < nargs; i++) {
1062153190Spjd			name = gctl_get_ascii(req, "arg%d", i);
1063143534Spjd			gp = find_geom(classp, name);
1064219969Smav			if (gp == NULL)
1065219969Smav				continue;
1066219969Smav			if (geoms) {
1067153190Spjd				status_one_geom(gp, script, name_len,
1068143572Spjd				    status_len);
1069219969Smav			} else {
1070219969Smav				status_one_geom_prs(gp, script, name_len,
1071219969Smav				    status_len);
1072143534Spjd			}
1073143534Spjd		}
1074143534Spjd	} else {
1075143534Spjd		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1076219969Smav			if (LIST_EMPTY(&gp->lg_provider) && !all)
1077143534Spjd				continue;
1078219969Smav			if (geoms) {
1079219969Smav				status_one_geom(gp, script, name_len,
1080219969Smav				    status_len);
1081219969Smav			} else {
1082219969Smav				status_one_geom_prs(gp, script, name_len,
1083219969Smav				    status_len);
1084219969Smav			}
1085143534Spjd		}
1086143534Spjd	}
1087143534Spjdend:
1088143534Spjd	geom_deletetree(&mesh);
1089143534Spjd}
1090143534Spjd
1091143534Spjdstatic int
1092129470Spjdstd_load_available(void)
1093129470Spjd{
1094129470Spjd	char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
1095129470Spjd	struct stat sb;
1096129470Spjd	size_t len;
1097129470Spjd
1098129470Spjd	snprintf(name, sizeof(name), "g_%s", class_name);
1099129470Spjd	/*
1100129470Spjd	 * If already in kernel, "load" command is not available.
1101129470Spjd	 */
1102129470Spjd	if (modfind(name) >= 0)
1103129470Spjd		return (0);
1104129470Spjd	bzero(paths, sizeof(paths));
1105129470Spjd	len = sizeof(paths);
1106129470Spjd	if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
1107129470Spjd		err(EXIT_FAILURE, "sysctl(kern.module_path)");
1108129470Spjd	for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
1109129470Spjd		snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
1110129470Spjd		/*
1111129470Spjd		 * If geom_<name>.ko file exists, "load" command is available.
1112129470Spjd		 */
1113129470Spjd		if (stat(name, &sb) == 0)
1114129470Spjd			return (1);
1115129470Spjd	}
1116129470Spjd	return (0);
1117129470Spjd}
1118129470Spjd
1119129470Spjdstatic void
1120129470Spjdstd_load(struct gctl_req *req __unused, unsigned flags)
1121129470Spjd{
1122129470Spjd
1123129470Spjd	/*
1124129470Spjd	 * Do nothing special here, because of G_FLAG_LOADKLD flag,
1125129470Spjd	 * module is already loaded.
1126129470Spjd	 */
1127129470Spjd	if ((flags & G_FLAG_VERBOSE) != 0)
1128129470Spjd		printf("Module available.\n");
1129129470Spjd}
1130129470Spjd
1131129470Spjdstatic int
1132129470Spjdstd_unload_available(void)
1133129470Spjd{
1134129470Spjd	char name[64];
1135129470Spjd	int id;
1136129470Spjd
1137129470Spjd	snprintf(name, sizeof(name), "geom_%s", class_name);
1138129470Spjd	id = kldfind(name);
1139129470Spjd	if (id >= 0)
1140129470Spjd		return (1);
1141129470Spjd	return (0);
1142129470Spjd}
1143129470Spjd
1144129470Spjdstatic void
1145129470Spjdstd_unload(struct gctl_req *req, unsigned flags __unused)
1146129470Spjd{
1147129470Spjd	char name[64];
1148129470Spjd	int id;
1149129470Spjd
1150129470Spjd	snprintf(name, sizeof(name), "geom_%s", class_name);
1151129470Spjd	id = kldfind(name);
1152129470Spjd	if (id < 0) {
1153129470Spjd		gctl_error(req, "Could not find module: %s.", strerror(errno));
1154129470Spjd		return;
1155129470Spjd	}
1156129470Spjd	if (kldunload(id) < 0) {
1157129470Spjd		gctl_error(req, "Could not unload module: %s.",
1158129470Spjd		    strerror(errno));
1159129470Spjd		return;
1160129470Spjd	}
1161129470Spjd}
1162129470Spjd
1163129470Spjdstatic int
1164129470Spjdstd_available(const char *name)
1165129470Spjd{
1166129470Spjd
1167129591Spjd	if (strcmp(name, "help") == 0)
1168129591Spjd		return (1);
1169129591Spjd	else if (strcmp(name, "list") == 0)
1170129470Spjd		return (std_list_available());
1171143534Spjd	else if (strcmp(name, "status") == 0)
1172143534Spjd		return (std_status_available());
1173129470Spjd	else if (strcmp(name, "load") == 0)
1174129470Spjd		return (std_load_available());
1175129470Spjd	else if (strcmp(name, "unload") == 0)
1176129470Spjd		return (std_unload_available());
1177129470Spjd	else
1178129470Spjd		assert(!"Unknown standard command.");
1179129470Spjd	return (0);
1180129470Spjd}
1181