geom.c revision 134419
1129470Spjd/*-
2129470Spjd * Copyright (c) 2004 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.
13129470Spjd *
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: head/sbin/geom/core/geom.c 134419 2004-08-28 02:29:40Z pjd $");
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
54129470Spjd
55129470Spjdstatic char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL;
56129470Spjdstatic uint32_t *version = NULL;
57129470Spjdstatic int verbose = 0;
58129470Spjdstatic struct g_command *class_commands = NULL;
59129470Spjdstatic void (*usage)(const char *name);
60129470Spjd
61129470Spjdstatic struct g_command *find_command(const char *cmdstr, int all);
62129470Spjdstatic int std_available(const char *name);
63129470Spjd
64129591Spjdstatic void std_help(struct gctl_req *req, unsigned flags);
65129470Spjdstatic void std_list(struct gctl_req *req, unsigned flags);
66129470Spjdstatic void std_load(struct gctl_req *req, unsigned flags);
67129470Spjdstatic void std_unload(struct gctl_req *req, unsigned flags);
68129470Spjd
69129470Spjdstruct g_command std_commands[] = {
70129591Spjd	{ "help", 0, std_help, G_NULL_OPTS },
71129470Spjd	{ "list", 0, std_list, G_NULL_OPTS },
72129470Spjd	{ "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS },
73129470Spjd	{ "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS },
74129470Spjd	G_CMD_SENTINEL
75129470Spjd};
76129470Spjd
77129470Spjdstatic void
78129470Spjdstd_usage(const char *name)
79129470Spjd{
80129470Spjd	struct g_command *cmd;
81129470Spjd	struct g_option *opt;
82129470Spjd	unsigned i, j;
83129470Spjd
84129470Spjd	for (i = 0; ; i++) {
85129470Spjd		cmd = &class_commands[i];
86129470Spjd		if (cmd->gc_name == NULL)
87129470Spjd			break;
88129470Spjd		fprintf(stderr, "%s %s %s %s", i == 0 ? "usage:" : "      ",
89129470Spjd		    name, class_name, cmd->gc_name);
90129470Spjd		if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
91129470Spjd			fprintf(stderr, " [-v]");
92129470Spjd		for (j = 0; ; j++) {
93129470Spjd			opt = &cmd->gc_options[j];
94129470Spjd			if (opt->go_name == NULL)
95129470Spjd				break;
96129470Spjd			if (opt->go_val != NULL || opt->go_type == G_TYPE_NONE)
97129470Spjd				fprintf(stderr, " [");
98129470Spjd			else
99129470Spjd				fprintf(stderr, " ");
100129470Spjd			fprintf(stderr, "-%c", opt->go_char);
101129470Spjd			if (opt->go_type != G_TYPE_NONE)
102129470Spjd				fprintf(stderr, " %s", opt->go_name);
103129470Spjd			if (opt->go_val != NULL || opt->go_type == G_TYPE_NONE)
104129470Spjd				fprintf(stderr, "]");
105129470Spjd		}
106129470Spjd		fprintf(stderr, " ...\n");
107129470Spjd	}
108129470Spjd	exit(EXIT_FAILURE);
109129470Spjd}
110129470Spjd
111129470Spjdstatic void
112129470Spjdgeom_usage(void)
113129470Spjd{
114129470Spjd
115129470Spjd	if (class_name == NULL) {
116129591Spjd		errx(EXIT_FAILURE, "usage: %s <class> <command> [options]",
117129591Spjd		    "geom");
118129470Spjd	} else {
119129470Spjd		const char *prefix;
120129470Spjd		unsigned i;
121129470Spjd
122129470Spjd		if (usage == NULL)
123129470Spjd			prefix = "usage:";
124129470Spjd		else {
125129470Spjd			usage(comm);
126129470Spjd			prefix = "      ";
127129470Spjd		}
128129470Spjd		for (i = 0; ; i++) {
129129470Spjd			struct g_command *cmd;
130129470Spjd
131129470Spjd			cmd = &std_commands[i];
132129470Spjd			if (cmd->gc_name == NULL)
133129470Spjd				break;
134129470Spjd			if (find_command(cmd->gc_name, 0) != NULL)
135129470Spjd				continue;
136129470Spjd			if (!std_available(cmd->gc_name))
137129470Spjd				continue;
138129470Spjd			fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name);
139129470Spjd			if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
140129470Spjd				fprintf(stderr, " [-v]");
141129470Spjd			fprintf(stderr, "\n");
142129470Spjd			prefix = "      ";
143129470Spjd		}
144129470Spjd		exit(EXIT_FAILURE);
145129470Spjd	}
146129470Spjd}
147129470Spjd
148129470Spjdstatic void
149129470Spjdload_module(void)
150129470Spjd{
151129470Spjd	char name1[64], name2[64];
152129470Spjd
153129470Spjd	snprintf(name1, sizeof(name1), "g_%s", class_name);
154129470Spjd	snprintf(name2, sizeof(name2), "geom_%s", class_name);
155129470Spjd	if (modfind(name1) < 0) {
156129470Spjd		/* Not present in kernel, try loading it. */
157129470Spjd		if (kldload(name2) < 0 || modfind(name1) < 0) {
158129470Spjd			if (errno != EEXIST) {
159129470Spjd				errx(EXIT_FAILURE,
160129470Spjd				    "%s module not available!", name2);
161129470Spjd			}
162129470Spjd		}
163129470Spjd	}
164129470Spjd}
165129470Spjd
166129470Spjdstatic int
167129470Spjdstrlcatf(char *str, size_t size, const char *format, ...)
168129470Spjd{
169129470Spjd	size_t len;
170129470Spjd	va_list ap;
171129470Spjd	int ret;
172129470Spjd
173129470Spjd	len = strlen(str);
174129470Spjd	str += len;
175129470Spjd	size -= len;
176129470Spjd
177129470Spjd	va_start(ap, format);
178129470Spjd	ret = vsnprintf(str, size, format, ap);
179129470Spjd	va_end(ap);
180129470Spjd
181129470Spjd	return (ret);
182129470Spjd}
183129470Spjd
184129470Spjd/*
185129470Spjd * Find given option in options available for given command.
186129470Spjd */
187129470Spjdstatic struct g_option *
188129470Spjdfind_option(struct g_command *cmd, char ch)
189129470Spjd{
190129470Spjd	struct g_option *opt;
191129470Spjd	unsigned i;
192129470Spjd
193129470Spjd	for (i = 0; ; i++) {
194129470Spjd		opt = &cmd->gc_options[i];
195129470Spjd		if (opt->go_name == NULL)
196129470Spjd			return (NULL);
197129470Spjd		if (opt->go_char == ch)
198129470Spjd			return (opt);
199129470Spjd	}
200129470Spjd	/* NOTREACHED */
201129470Spjd	return (NULL);
202129470Spjd}
203129470Spjd
204129470Spjd/*
205129470Spjd * Add given option to gctl_req.
206129470Spjd */
207129470Spjdstatic void
208129470Spjdset_option(struct gctl_req *req, struct g_option *opt, const char *val)
209129470Spjd{
210129470Spjd
211129470Spjd	if (opt->go_type == G_TYPE_NUMBER) {
212129470Spjd		intmax_t number;
213129470Spjd
214129470Spjd		errno = 0;
215129470Spjd		number = strtoimax(optarg, NULL, 0);
216129470Spjd		if (errno != 0) {
217129470Spjd			err(EXIT_FAILURE, "Invalid value for '%c' argument.",
218129470Spjd			    opt->go_char);
219129470Spjd		}
220129470Spjd		opt->go_val = malloc(sizeof(intmax_t));
221129470Spjd		if (opt->go_val == NULL)
222129470Spjd			errx(EXIT_FAILURE, "No memory.");
223129470Spjd		*(intmax_t *)opt->go_val = number;
224129470Spjd
225129470Spjd		gctl_ro_param(req, opt->go_name, sizeof(intmax_t), opt->go_val);
226129470Spjd	} else if (opt->go_type == G_TYPE_STRING) {
227129470Spjd		gctl_ro_param(req, opt->go_name, -1, optarg);
228129470Spjd	} else /* if (opt->go_type == G_TYPE_NONE) */ {
229129470Spjd		opt->go_val = malloc(sizeof(int));
230129470Spjd		if (opt->go_val == NULL)
231129470Spjd			errx(EXIT_FAILURE, "No memory.");
232129470Spjd		*(int *)opt->go_val = *val - '0';
233129470Spjd
234129470Spjd		gctl_ro_param(req, opt->go_name, sizeof(int),
235129470Spjd		    opt->go_val);
236129470Spjd	}
237129470Spjd}
238129470Spjd
239129470Spjd/*
240129470Spjd * 1. Add given argument by caller.
241129470Spjd * 2. Add default values of not given arguments.
242129470Spjd * 3. Add the rest of arguments.
243129470Spjd */
244129470Spjdstatic void
245129470Spjdparse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
246129470Spjd    char ***argv)
247129470Spjd{
248129470Spjd	struct g_option *opt;
249129470Spjd	char opts[64];
250129470Spjd	unsigned i;
251129470Spjd	int ch;
252129470Spjd
253129470Spjd	*opts = '\0';
254129470Spjd	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
255129470Spjd		strlcat(opts, "v", sizeof(opts));
256129470Spjd	for (i = 0; ; i++) {
257129470Spjd		opt = &cmd->gc_options[i];
258129470Spjd		if (opt->go_name == NULL)
259129470Spjd			break;
260129470Spjd		strlcatf(opts, sizeof(opts), "%c", opt->go_char);
261129470Spjd		if (opt->go_type != G_TYPE_NONE)
262129470Spjd			strlcat(opts, ":", sizeof(opts));
263129470Spjd	}
264129470Spjd
265129470Spjd	/*
266129470Spjd	 * Add specified arguments.
267129470Spjd	 */
268129470Spjd	while ((ch = getopt(*argc, *argv, opts)) != -1) {
269129470Spjd		/* Standard (not passed to kernel) options. */
270129470Spjd		switch (ch) {
271129470Spjd		case 'v':
272129470Spjd			verbose = 1;
273129470Spjd			continue;
274129470Spjd		}
275129470Spjd		/* Options passed to kernel. */
276129470Spjd		opt = find_option(cmd, ch);
277129470Spjd		if (opt == NULL)
278129470Spjd			geom_usage();
279129470Spjd		if (G_OPT_ISDONE(opt)) {
280129470Spjd			fprintf(stderr, "Flag '%c' specified twice.\n",
281129470Spjd			    opt->go_char);
282129470Spjd			geom_usage();
283129470Spjd		}
284129470Spjd		G_OPT_DONE(opt);
285129470Spjd
286129470Spjd		if (opt->go_type == G_TYPE_NONE)
287129470Spjd			set_option(req, opt, "1");
288129470Spjd		else
289129470Spjd			set_option(req, opt, optarg);
290129470Spjd	}
291129470Spjd	*argc -= optind;
292129470Spjd	*argv += optind;
293129470Spjd
294129470Spjd	/*
295129470Spjd	 * Add not specified arguments, but with default values.
296129470Spjd	 */
297129470Spjd	for (i = 0; ; i++) {
298129470Spjd		opt = &cmd->gc_options[i];
299129470Spjd		if (opt->go_name == NULL)
300129470Spjd			break;
301129470Spjd		if (G_OPT_ISDONE(opt))
302129470Spjd			continue;
303129470Spjd
304129470Spjd		if (opt->go_type == G_TYPE_NONE) {
305129470Spjd			assert(opt->go_val == NULL);
306129470Spjd			set_option(req, opt, "0");
307129470Spjd		} else {
308129470Spjd			if (opt->go_val == NULL) {
309129470Spjd				fprintf(stderr, "Flag '%c' not specified.\n",
310129470Spjd				    opt->go_char);
311129470Spjd				geom_usage();
312129470Spjd			} else {
313129470Spjd				if (opt->go_type == G_TYPE_NUMBER) {
314129470Spjd					gctl_ro_param(req, opt->go_name,
315129470Spjd					    sizeof(intmax_t), opt->go_val);
316129470Spjd				} else /* if (opt->go_type == G_TYPE_STRING)*/ {
317129470Spjd					gctl_ro_param(req, opt->go_name, -1,
318129470Spjd					    opt->go_val);
319129470Spjd				}
320129470Spjd			}
321129470Spjd		}
322129470Spjd	}
323129470Spjd	/*
324129470Spjd	 * Add rest of given arguments.
325129470Spjd	 */
326129470Spjd	gctl_ro_param(req, "nargs", sizeof(int), argc);
327129470Spjd	for (i = 0; i < (unsigned)*argc; i++) {
328129470Spjd		char argname[16];
329129470Spjd
330129470Spjd		snprintf(argname, sizeof(argname), "arg%u", i);
331129470Spjd		gctl_ro_param(req, argname, -1, (*argv)[i]);
332129470Spjd	}
333129470Spjd}
334129470Spjd
335129470Spjd/*
336129470Spjd * Find given command in commands available for given class.
337129470Spjd */
338129470Spjdstatic struct g_command *
339129470Spjdfind_command(const char *cmdstr, int all)
340129470Spjd{
341129470Spjd	struct g_command *cmd;
342129470Spjd	unsigned i;
343129470Spjd
344129470Spjd	/*
345129470Spjd	 * First try to find command defined by loaded library.
346129470Spjd	 */
347129470Spjd	if (class_commands != NULL) {
348129470Spjd		for (i = 0; ; i++) {
349129470Spjd			cmd = &class_commands[i];
350129470Spjd			if (cmd->gc_name == NULL)
351129470Spjd				break;
352129470Spjd			if (strcmp(cmd->gc_name, cmdstr) == 0)
353129470Spjd				return (cmd);
354129470Spjd		}
355129470Spjd	}
356129470Spjd	if (!all)
357129470Spjd		return (NULL);
358129470Spjd	/*
359129470Spjd	 * Now try to find in standard commands.
360129470Spjd	 */
361129470Spjd	for (i = 0; ; i++) {
362129470Spjd		cmd = &std_commands[i];
363129470Spjd		if (cmd->gc_name == NULL)
364129470Spjd			break;
365129470Spjd		if (!std_available(cmd->gc_name))
366129470Spjd			continue;
367129470Spjd		if (strcmp(cmd->gc_name, cmdstr) == 0)
368129470Spjd			return (cmd);
369129470Spjd	}
370129470Spjd	return (NULL);
371129470Spjd}
372129470Spjd
373129470Spjdstatic unsigned
374129470Spjdset_flags(struct g_command *cmd)
375129470Spjd{
376129470Spjd	unsigned flags = 0;
377129470Spjd
378129470Spjd	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
379129470Spjd		flags |= G_FLAG_VERBOSE;
380129470Spjd
381129470Spjd	return (flags);
382129470Spjd}
383129470Spjd
384129470Spjd/*
385129470Spjd * Run command.
386129470Spjd */
387129470Spjdstatic void
388129470Spjdrun_command(int argc, char *argv[])
389129470Spjd{
390129470Spjd	struct g_command *cmd;
391129470Spjd	struct gctl_req *req;
392129470Spjd	const char *errstr;
393129470Spjd	char buf[4096];
394129470Spjd
395129470Spjd	cmd = find_command(argv[0], 1);
396129470Spjd	if (cmd == NULL) {
397129470Spjd		fprintf(stderr, "Unknown command: %s\n", argv[0]);
398129470Spjd		geom_usage();
399129470Spjd	}
400129470Spjd	if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
401129470Spjd		load_module();
402129470Spjd
403129470Spjd	req = gctl_get_handle();
404129470Spjd	gctl_ro_param(req, "class", -1, gclass_name);
405129470Spjd	gctl_ro_param(req, "verb", -1, argv[0]);
406129470Spjd	if (version != NULL)
407129470Spjd		gctl_ro_param(req, "version", sizeof(*version), version);
408129470Spjd	parse_arguments(cmd, req, &argc, &argv);
409129470Spjd
410129470Spjd	if (cmd->gc_func != NULL) {
411129470Spjd		unsigned flags;
412129470Spjd
413129470Spjd		flags = set_flags(cmd);
414129470Spjd		cmd->gc_func(req, flags);
415129470Spjd		errstr = req->error;
416129470Spjd	} else {
417129470Spjd		bzero(buf, sizeof(buf));
418129470Spjd		gctl_rw_param(req, "output", sizeof(buf), buf);
419129470Spjd		errstr = gctl_issue(req);
420129470Spjd	}
421129470Spjd	if (errstr != NULL) {
422129470Spjd		fprintf(stderr, "%s\n", errstr);
423134419Spjd		if (strncmp(errstr, "warning: ", strlen("warning: ")) != 0) {
424134419Spjd			gctl_free(req);
425134419Spjd			exit(EXIT_FAILURE);
426134419Spjd		}
427129470Spjd	}
428129470Spjd	if (*buf != '\0')
429129470Spjd		printf("%s", buf);
430129470Spjd	gctl_free(req);
431129470Spjd	if (verbose)
432129470Spjd		printf("Done.\n");
433129470Spjd	exit(EXIT_SUCCESS);
434129470Spjd}
435129470Spjd
436129470Spjdstatic void
437129470Spjdload_library(void)
438129470Spjd{
439129470Spjd	char path[MAXPATHLEN];
440129470Spjd	uint32_t *lib_version;
441129470Spjd	void *dlh;
442129470Spjd
443133005Spjd	snprintf(path, sizeof(path), "%s/geom_%s.so", CLASS_DIR, class_name);
444129470Spjd	dlh = dlopen(path, RTLD_NOW);
445129470Spjd	if (dlh == NULL) {
446129470Spjd#if 0
447129470Spjd		fprintf(stderr, "Cannot open library %s, but continuing "
448129470Spjd		    "anyway.\n", path);
449129470Spjd#endif
450129470Spjd		/*
451129470Spjd		 * Even if library cannot be loaded, standard commands are
452129470Spjd		 * available, so don't panic!
453129470Spjd		 */
454129470Spjd		return;
455129470Spjd	}
456129470Spjd	lib_version = dlsym(dlh, "lib_version");
457129470Spjd	if (lib_version == NULL) {
458129470Spjd		fprintf(stderr, "Cannot find symbol %s: %s.\n", "lib_version",
459129470Spjd		    dlerror());
460129470Spjd		dlclose(dlh);
461129470Spjd		exit(EXIT_FAILURE);
462129470Spjd	}
463129470Spjd	if (*lib_version != G_LIB_VERSION) {
464129470Spjd		dlclose(dlh);
465134419Spjd		errx(EXIT_FAILURE, "%s and %s are not synchronized.",
466134419Spjd		    getprogname(), path);
467129470Spjd	}
468129470Spjd	version = dlsym(dlh, "version");
469129470Spjd	if (version == NULL) {
470129470Spjd		fprintf(stderr, "Cannot find symbol %s: %s.\n", "version",
471129470Spjd		    dlerror());
472129470Spjd		dlclose(dlh);
473129470Spjd		exit(EXIT_FAILURE);
474129470Spjd	}
475129470Spjd	class_commands = dlsym(dlh, "class_commands");
476129470Spjd	if (class_commands == NULL) {
477129470Spjd		fprintf(stderr, "Cannot find symbol %s: %s.\n",
478129470Spjd		    "class_commands", dlerror());
479129470Spjd		dlclose(dlh);
480129470Spjd		exit(EXIT_FAILURE);
481129470Spjd	}
482129470Spjd	usage = dlsym(dlh, "usage");
483129470Spjd	if (usage == NULL)
484129470Spjd		usage = std_usage;
485129470Spjd}
486129470Spjd
487129470Spjd/*
488129470Spjd * Class name should be all capital letters.
489129470Spjd */
490129470Spjdstatic void
491129470Spjdset_class_name(void)
492129470Spjd{
493129470Spjd	char *s1, *s2;
494129470Spjd
495129470Spjd	gclass_name = malloc(strlen(class_name));
496129470Spjd	if (gclass_name == NULL)
497129470Spjd		errx(EXIT_FAILURE, "No memory");
498129470Spjd	s1 = gclass_name;
499129470Spjd	s2 = class_name;
500129470Spjd	for (; *s2 != '\0'; s2++)
501129470Spjd		*s1++ = toupper(*s2);
502129470Spjd	*s1 = '\0';
503129470Spjd}
504129470Spjd
505129470Spjdstatic void
506129470Spjdget_class(int *argc, char ***argv)
507129470Spjd{
508129470Spjd
509129470Spjd	snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
510129470Spjd	if (strcmp(comm, "geom") == 0) {
511129470Spjd		if (*argc < 2)
512129470Spjd			geom_usage();
513129470Spjd		strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
514129470Spjd		class_name = (*argv)[1];
515129470Spjd		*argc -= 2;
516129470Spjd		*argv += 2;
517129470Spjd	} else if (*comm == 'g') {
518129470Spjd		class_name = comm + 1;
519129470Spjd		*argc -= 1;
520129470Spjd		*argv += 1;
521129470Spjd	} else {
522129470Spjd		errx(EXIT_FAILURE, "Invalid utility name.");
523129470Spjd	}
524129470Spjd	set_class_name();
525129470Spjd	load_library();
526129470Spjd	if (*argc < 1)
527129470Spjd		geom_usage();
528129470Spjd}
529129470Spjd
530129470Spjdint
531129470Spjdmain(int argc, char *argv[])
532129470Spjd{
533129470Spjd
534129470Spjd	get_class(&argc, &argv);
535129470Spjd	run_command(argc, argv);
536129470Spjd	/* NOTREACHED */
537129470Spjd
538129470Spjd	exit(EXIT_FAILURE);
539129470Spjd}
540129470Spjd
541129470Spjdstatic struct gclass *
542129470Spjdfind_class(struct gmesh *mesh, const char *name)
543129470Spjd{
544129470Spjd	struct gclass *classp;
545129470Spjd
546129470Spjd	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
547129470Spjd		if (strcmp(classp->lg_name, name) == 0)
548129470Spjd			return (classp);
549129470Spjd	}
550129470Spjd	return (NULL);
551129470Spjd}
552129470Spjd
553132665Spjdstatic struct ggeom *
554132665Spjdfind_geom(struct gclass *classp, const char *name)
555129470Spjd{
556129470Spjd	struct ggeom *gp;
557129470Spjd
558129470Spjd	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
559132665Spjd		if (strcmp(gp->lg_name, name) == 0)
560132665Spjd			return (gp);
561129470Spjd	}
562129470Spjd	return (NULL);
563129470Spjd}
564129470Spjd
565132665Spjdstatic void
566132665Spjdshow_one_provider(struct gprovider *pp, const char *prefix)
567129470Spjd{
568132665Spjd	struct gconfig *conf;
569132665Spjd	char buf[5];
570129470Spjd
571132665Spjd	printf("Name: %s\n", pp->lg_name);
572132665Spjd	humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
573132665Spjd	    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
574132665Spjd	printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
575132665Spjd	    buf);
576132665Spjd	printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
577132665Spjd	printf("%sMode: %s\n", prefix, pp->lg_mode);
578132665Spjd	LIST_FOREACH(conf, &pp->lg_config, lg_config) {
579132665Spjd		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
580129470Spjd	}
581132665Spjd}
582132665Spjd
583132665Spjdstatic void
584132665Spjdshow_one_consumer(struct gconsumer *cp, const char *prefix)
585132665Spjd{
586132665Spjd	struct gprovider *pp;
587132665Spjd	struct gconfig *conf;
588132665Spjd
589132665Spjd	pp = cp->lg_provider;
590132665Spjd	if (pp == NULL)
591132665Spjd		printf("[no provider]\n");
592132665Spjd	else {
593132665Spjd		char buf[5];
594132665Spjd
595132665Spjd		printf("Name: %s\n", pp->lg_name);
596132665Spjd		humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
597132665Spjd		    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
598132665Spjd		printf("%sMediasize: %jd (%s)\n", prefix,
599132665Spjd		    (intmax_t)pp->lg_mediasize, buf);
600132665Spjd		printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
601132665Spjd		printf("%sMode: %s\n", prefix, cp->lg_mode);
602129470Spjd	}
603132665Spjd	LIST_FOREACH(conf, &cp->lg_config, lg_config) {
604132665Spjd		printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
605132665Spjd	}
606129470Spjd}
607129470Spjd
608129470Spjdstatic void
609132665Spjdshow_one_geom(struct ggeom *gp)
610129470Spjd{
611132665Spjd	struct gprovider *pp;
612132665Spjd	struct gconsumer *cp;
613129470Spjd	struct gconfig *conf;
614132665Spjd	unsigned n;
615129470Spjd
616132665Spjd	printf("Geom name: %s\n", gp->lg_name);
617132665Spjd	LIST_FOREACH(conf, &gp->lg_config, lg_config) {
618132665Spjd		printf("%s: %s\n", conf->lg_name, conf->lg_val);
619129470Spjd	}
620132665Spjd	if (!LIST_EMPTY(&gp->lg_provider)) {
621132665Spjd		printf("Providers:\n");
622132665Spjd		n = 1;
623132665Spjd		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
624132665Spjd			printf("%u. ", n++);
625132665Spjd			show_one_provider(pp, "   ");
626132665Spjd		}
627132665Spjd	}
628132665Spjd	if (!LIST_EMPTY(&gp->lg_consumer)) {
629132665Spjd		printf("Consumers:\n");
630132665Spjd		n = 1;
631132665Spjd		LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
632132665Spjd			printf("%u. ", n++);
633132665Spjd			show_one_consumer(cp, "   ");
634132665Spjd		}
635132665Spjd	}
636129470Spjd	printf("\n");
637129470Spjd}
638129470Spjd
639129591Spjdstatic void
640129591Spjdstd_help(struct gctl_req *req __unused, unsigned flags __unused)
641129591Spjd{
642129591Spjd
643129591Spjd	geom_usage();
644129591Spjd}
645129591Spjd
646129470Spjdstatic int
647129470Spjdstd_list_available(void)
648129470Spjd{
649129470Spjd	struct gmesh mesh;
650129470Spjd	struct gclass *classp;
651129470Spjd	int error;
652129470Spjd
653129470Spjd	error = geom_gettree(&mesh);
654129470Spjd	if (error != 0)
655129470Spjd		exit(EXIT_FAILURE);
656129470Spjd	classp = find_class(&mesh, gclass_name);
657129470Spjd	geom_deletetree(&mesh);
658129470Spjd	if (classp != NULL)
659129470Spjd		return (1);
660129470Spjd	return (0);
661129470Spjd}
662129470Spjd
663129470Spjdstatic void
664129470Spjdstd_list(struct gctl_req *req, unsigned flags __unused)
665129470Spjd{
666129470Spjd	struct gmesh mesh;
667129470Spjd	struct gclass *classp;
668132665Spjd	struct ggeom *gp;
669129470Spjd	int error, *nargs;
670129470Spjd
671129470Spjd	error = geom_gettree(&mesh);
672129470Spjd	if (error != 0)
673129470Spjd		exit(EXIT_FAILURE);
674129470Spjd	classp = find_class(&mesh, gclass_name);
675129470Spjd	if (classp == NULL) {
676129470Spjd		geom_deletetree(&mesh);
677129470Spjd		fprintf(stderr, "Class %s not found.\n", gclass_name);
678129470Spjd		return;
679129470Spjd	}
680129470Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
681129470Spjd	if (nargs == NULL) {
682129470Spjd		gctl_error(req, "No '%s' argument.", "nargs");
683129470Spjd		geom_deletetree(&mesh);
684129470Spjd		return;
685129470Spjd	}
686129470Spjd	if (*nargs > 0) {
687129470Spjd		int i;
688129470Spjd
689129470Spjd		for (i = 0; i < *nargs; i++) {
690129470Spjd			const char *name;
691129470Spjd			char param[16];
692129470Spjd
693129470Spjd			snprintf(param, sizeof(param), "arg%d", i);
694129470Spjd			name = gctl_get_asciiparam(req, param);
695129470Spjd			assert(name != NULL);
696132665Spjd			gp = find_geom(classp, name);
697132665Spjd			if (gp != NULL)
698132665Spjd				show_one_geom(gp);
699132665Spjd			else
700132665Spjd				fprintf(stderr, "No such geom: %s.\n", name);
701129470Spjd		}
702129470Spjd	} else {
703129470Spjd		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
704132665Spjd			show_one_geom(gp);
705129470Spjd		}
706129470Spjd	}
707129470Spjd	geom_deletetree(&mesh);
708129470Spjd}
709129470Spjd
710129470Spjdstatic int
711129470Spjdstd_load_available(void)
712129470Spjd{
713129470Spjd	char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
714129470Spjd	struct stat sb;
715129470Spjd	size_t len;
716129470Spjd
717129470Spjd	snprintf(name, sizeof(name), "g_%s", class_name);
718129470Spjd	/*
719129470Spjd	 * If already in kernel, "load" command is not available.
720129470Spjd	 */
721129470Spjd	if (modfind(name) >= 0)
722129470Spjd		return (0);
723129470Spjd	bzero(paths, sizeof(paths));
724129470Spjd	len = sizeof(paths);
725129470Spjd	if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
726129470Spjd		err(EXIT_FAILURE, "sysctl(kern.module_path)");
727129470Spjd	for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
728129470Spjd		snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
729129470Spjd		/*
730129470Spjd		 * If geom_<name>.ko file exists, "load" command is available.
731129470Spjd		 */
732129470Spjd		if (stat(name, &sb) == 0)
733129470Spjd			return (1);
734129470Spjd	}
735129470Spjd	return (0);
736129470Spjd}
737129470Spjd
738129470Spjdstatic void
739129470Spjdstd_load(struct gctl_req *req __unused, unsigned flags)
740129470Spjd{
741129470Spjd
742129470Spjd	/*
743129470Spjd	 * Do nothing special here, because of G_FLAG_LOADKLD flag,
744129470Spjd	 * module is already loaded.
745129470Spjd	 */
746129470Spjd	if ((flags & G_FLAG_VERBOSE) != 0)
747129470Spjd		printf("Module available.\n");
748129470Spjd}
749129470Spjd
750129470Spjdstatic int
751129470Spjdstd_unload_available(void)
752129470Spjd{
753129470Spjd	char name[64];
754129470Spjd	int id;
755129470Spjd
756129470Spjd	snprintf(name, sizeof(name), "geom_%s", class_name);
757129470Spjd	id = kldfind(name);
758129470Spjd	if (id >= 0)
759129470Spjd		return (1);
760129470Spjd	return (0);
761129470Spjd}
762129470Spjd
763129470Spjdstatic void
764129470Spjdstd_unload(struct gctl_req *req, unsigned flags __unused)
765129470Spjd{
766129470Spjd	char name[64];
767129470Spjd	int id;
768129470Spjd
769129470Spjd	snprintf(name, sizeof(name), "geom_%s", class_name);
770129470Spjd	id = kldfind(name);
771129470Spjd	if (id < 0) {
772129470Spjd		gctl_error(req, "Could not find module: %s.", strerror(errno));
773129470Spjd		return;
774129470Spjd	}
775129470Spjd	if (kldunload(id) < 0) {
776129470Spjd		gctl_error(req, "Could not unload module: %s.",
777129470Spjd		    strerror(errno));
778129470Spjd		return;
779129470Spjd	}
780129470Spjd}
781129470Spjd
782129470Spjdstatic int
783129470Spjdstd_available(const char *name)
784129470Spjd{
785129470Spjd
786129591Spjd	if (strcmp(name, "help") == 0)
787129591Spjd		return (1);
788129591Spjd	else if (strcmp(name, "list") == 0)
789129470Spjd		return (std_list_available());
790129470Spjd	else if (strcmp(name, "load") == 0)
791129470Spjd		return (std_load_available());
792129470Spjd	else if (strcmp(name, "unload") == 0)
793129470Spjd		return (std_unload_available());
794129470Spjd	else
795129470Spjd		assert(!"Unknown standard command.");
796129470Spjd	return (0);
797129470Spjd}
798