geom.c revision 129470
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 129470 2004-05-20 10:09:56Z 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>
45129470Spjd#include <inttypes.h>
46129470Spjd#include <dlfcn.h>
47129470Spjd#include <assert.h>
48129470Spjd#include <libgeom.h>
49129470Spjd#include <geom.h>
50129470Spjd
51129470Spjd#include "misc/subr.h"
52129470Spjd
53129470Spjd
54129470Spjdstatic char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL;
55129470Spjdstatic uint32_t *version = NULL;
56129470Spjdstatic int verbose = 0;
57129470Spjdstatic struct g_command *class_commands = NULL;
58129470Spjdstatic void (*usage)(const char *name);
59129470Spjd
60129470Spjdstatic struct g_command *find_command(const char *cmdstr, int all);
61129470Spjdstatic int std_available(const char *name);
62129470Spjd
63129470Spjdstatic void std_list(struct gctl_req *req, unsigned flags);
64129470Spjdstatic void std_load(struct gctl_req *req, unsigned flags);
65129470Spjdstatic void std_unload(struct gctl_req *req, unsigned flags);
66129470Spjd
67129470Spjdstruct g_command std_commands[] = {
68129470Spjd	{ "list", 0, std_list, G_NULL_OPTS },
69129470Spjd	{ "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS },
70129470Spjd	{ "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS },
71129470Spjd	G_CMD_SENTINEL
72129470Spjd};
73129470Spjd
74129470Spjdstatic void
75129470Spjdstd_usage(const char *name)
76129470Spjd{
77129470Spjd	struct g_command *cmd;
78129470Spjd	struct g_option *opt;
79129470Spjd	unsigned i, j;
80129470Spjd
81129470Spjd	for (i = 0; ; i++) {
82129470Spjd		cmd = &class_commands[i];
83129470Spjd		if (cmd->gc_name == NULL)
84129470Spjd			break;
85129470Spjd		fprintf(stderr, "%s %s %s %s", i == 0 ? "usage:" : "      ",
86129470Spjd		    name, class_name, cmd->gc_name);
87129470Spjd		if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
88129470Spjd			fprintf(stderr, " [-v]");
89129470Spjd		for (j = 0; ; j++) {
90129470Spjd			opt = &cmd->gc_options[j];
91129470Spjd			if (opt->go_name == NULL)
92129470Spjd				break;
93129470Spjd			if (opt->go_val != NULL || opt->go_type == G_TYPE_NONE)
94129470Spjd				fprintf(stderr, " [");
95129470Spjd			else
96129470Spjd				fprintf(stderr, " ");
97129470Spjd			fprintf(stderr, "-%c", opt->go_char);
98129470Spjd			if (opt->go_type != G_TYPE_NONE)
99129470Spjd				fprintf(stderr, " %s", opt->go_name);
100129470Spjd			if (opt->go_val != NULL || opt->go_type == G_TYPE_NONE)
101129470Spjd				fprintf(stderr, "]");
102129470Spjd		}
103129470Spjd		fprintf(stderr, " ...\n");
104129470Spjd	}
105129470Spjd	exit(EXIT_FAILURE);
106129470Spjd}
107129470Spjd
108129470Spjdstatic void
109129470Spjdgeom_usage(void)
110129470Spjd{
111129470Spjd
112129470Spjd	if (class_name == NULL) {
113129470Spjd		errx(EXIT_FAILURE, "usage: %s <class name> <command> "
114129470Spjd		    "[options]", "geom");
115129470Spjd	} else {
116129470Spjd		const char *prefix;
117129470Spjd		unsigned i;
118129470Spjd
119129470Spjd		if (usage == NULL)
120129470Spjd			prefix = "usage:";
121129470Spjd		else {
122129470Spjd			usage(comm);
123129470Spjd			prefix = "      ";
124129470Spjd		}
125129470Spjd		for (i = 0; ; i++) {
126129470Spjd			struct g_command *cmd;
127129470Spjd
128129470Spjd			cmd = &std_commands[i];
129129470Spjd			if (cmd->gc_name == NULL)
130129470Spjd				break;
131129470Spjd			if (find_command(cmd->gc_name, 0) != NULL)
132129470Spjd				continue;
133129470Spjd			if (!std_available(cmd->gc_name))
134129470Spjd				continue;
135129470Spjd			fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name);
136129470Spjd			if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
137129470Spjd				fprintf(stderr, " [-v]");
138129470Spjd			fprintf(stderr, "\n");
139129470Spjd			prefix = "      ";
140129470Spjd		}
141129470Spjd		exit(EXIT_FAILURE);
142129470Spjd	}
143129470Spjd}
144129470Spjd
145129470Spjdstatic void
146129470Spjdload_module(void)
147129470Spjd{
148129470Spjd	char name1[64], name2[64];
149129470Spjd
150129470Spjd	snprintf(name1, sizeof(name1), "g_%s", class_name);
151129470Spjd	snprintf(name2, sizeof(name2), "geom_%s", class_name);
152129470Spjd	if (modfind(name1) < 0) {
153129470Spjd		/* Not present in kernel, try loading it. */
154129470Spjd		if (kldload(name2) < 0 || modfind(name1) < 0) {
155129470Spjd			if (errno != EEXIST) {
156129470Spjd				errx(EXIT_FAILURE,
157129470Spjd				    "%s module not available!", name2);
158129470Spjd			}
159129470Spjd		}
160129470Spjd	}
161129470Spjd}
162129470Spjd
163129470Spjdstatic int
164129470Spjdstrlcatf(char *str, size_t size, const char *format, ...)
165129470Spjd{
166129470Spjd	size_t len;
167129470Spjd	va_list ap;
168129470Spjd	int ret;
169129470Spjd
170129470Spjd	len = strlen(str);
171129470Spjd	str += len;
172129470Spjd	size -= len;
173129470Spjd
174129470Spjd	va_start(ap, format);
175129470Spjd	ret = vsnprintf(str, size, format, ap);
176129470Spjd	va_end(ap);
177129470Spjd
178129470Spjd	return (ret);
179129470Spjd}
180129470Spjd
181129470Spjd/*
182129470Spjd * Find given option in options available for given command.
183129470Spjd */
184129470Spjdstatic struct g_option *
185129470Spjdfind_option(struct g_command *cmd, char ch)
186129470Spjd{
187129470Spjd	struct g_option *opt;
188129470Spjd	unsigned i;
189129470Spjd
190129470Spjd	for (i = 0; ; i++) {
191129470Spjd		opt = &cmd->gc_options[i];
192129470Spjd		if (opt->go_name == NULL)
193129470Spjd			return (NULL);
194129470Spjd		if (opt->go_char == ch)
195129470Spjd			return (opt);
196129470Spjd	}
197129470Spjd	/* NOTREACHED */
198129470Spjd	return (NULL);
199129470Spjd}
200129470Spjd
201129470Spjd/*
202129470Spjd * Add given option to gctl_req.
203129470Spjd */
204129470Spjdstatic void
205129470Spjdset_option(struct gctl_req *req, struct g_option *opt, const char *val)
206129470Spjd{
207129470Spjd
208129470Spjd	if (opt->go_type == G_TYPE_NUMBER) {
209129470Spjd		intmax_t number;
210129470Spjd
211129470Spjd		errno = 0;
212129470Spjd		number = strtoimax(optarg, NULL, 0);
213129470Spjd		if (errno != 0) {
214129470Spjd			err(EXIT_FAILURE, "Invalid value for '%c' argument.",
215129470Spjd			    opt->go_char);
216129470Spjd		}
217129470Spjd		opt->go_val = malloc(sizeof(intmax_t));
218129470Spjd		if (opt->go_val == NULL)
219129470Spjd			errx(EXIT_FAILURE, "No memory.");
220129470Spjd		*(intmax_t *)opt->go_val = number;
221129470Spjd
222129470Spjd		gctl_ro_param(req, opt->go_name, sizeof(intmax_t), opt->go_val);
223129470Spjd	} else if (opt->go_type == G_TYPE_STRING) {
224129470Spjd		gctl_ro_param(req, opt->go_name, -1, optarg);
225129470Spjd	} else /* if (opt->go_type == G_TYPE_NONE) */ {
226129470Spjd		opt->go_val = malloc(sizeof(int));
227129470Spjd		if (opt->go_val == NULL)
228129470Spjd			errx(EXIT_FAILURE, "No memory.");
229129470Spjd		*(int *)opt->go_val = *val - '0';
230129470Spjd
231129470Spjd		gctl_ro_param(req, opt->go_name, sizeof(int),
232129470Spjd		    opt->go_val);
233129470Spjd	}
234129470Spjd}
235129470Spjd
236129470Spjd/*
237129470Spjd * 1. Add given argument by caller.
238129470Spjd * 2. Add default values of not given arguments.
239129470Spjd * 3. Add the rest of arguments.
240129470Spjd */
241129470Spjdstatic void
242129470Spjdparse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
243129470Spjd    char ***argv)
244129470Spjd{
245129470Spjd	struct g_option *opt;
246129470Spjd	char opts[64];
247129470Spjd	unsigned i;
248129470Spjd	int ch;
249129470Spjd
250129470Spjd	*opts = '\0';
251129470Spjd	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
252129470Spjd		strlcat(opts, "v", sizeof(opts));
253129470Spjd	for (i = 0; ; i++) {
254129470Spjd		opt = &cmd->gc_options[i];
255129470Spjd		if (opt->go_name == NULL)
256129470Spjd			break;
257129470Spjd		strlcatf(opts, sizeof(opts), "%c", opt->go_char);
258129470Spjd		if (opt->go_type != G_TYPE_NONE)
259129470Spjd			strlcat(opts, ":", sizeof(opts));
260129470Spjd	}
261129470Spjd
262129470Spjd	/*
263129470Spjd	 * Add specified arguments.
264129470Spjd	 */
265129470Spjd	while ((ch = getopt(*argc, *argv, opts)) != -1) {
266129470Spjd		/* Standard (not passed to kernel) options. */
267129470Spjd		switch (ch) {
268129470Spjd		case 'v':
269129470Spjd			verbose = 1;
270129470Spjd			continue;
271129470Spjd		}
272129470Spjd		/* Options passed to kernel. */
273129470Spjd		opt = find_option(cmd, ch);
274129470Spjd		if (opt == NULL)
275129470Spjd			geom_usage();
276129470Spjd		if (G_OPT_ISDONE(opt)) {
277129470Spjd			fprintf(stderr, "Flag '%c' specified twice.\n",
278129470Spjd			    opt->go_char);
279129470Spjd			geom_usage();
280129470Spjd		}
281129470Spjd		G_OPT_DONE(opt);
282129470Spjd
283129470Spjd		if (opt->go_type == G_TYPE_NONE)
284129470Spjd			set_option(req, opt, "1");
285129470Spjd		else
286129470Spjd			set_option(req, opt, optarg);
287129470Spjd	}
288129470Spjd	*argc -= optind;
289129470Spjd	*argv += optind;
290129470Spjd
291129470Spjd	/*
292129470Spjd	 * Add not specified arguments, but with default values.
293129470Spjd	 */
294129470Spjd	for (i = 0; ; i++) {
295129470Spjd		opt = &cmd->gc_options[i];
296129470Spjd		if (opt->go_name == NULL)
297129470Spjd			break;
298129470Spjd		if (G_OPT_ISDONE(opt))
299129470Spjd			continue;
300129470Spjd
301129470Spjd		if (opt->go_type == G_TYPE_NONE) {
302129470Spjd			assert(opt->go_val == NULL);
303129470Spjd			set_option(req, opt, "0");
304129470Spjd		} else {
305129470Spjd			if (opt->go_val == NULL) {
306129470Spjd				fprintf(stderr, "Flag '%c' not specified.\n",
307129470Spjd				    opt->go_char);
308129470Spjd				geom_usage();
309129470Spjd			} else {
310129470Spjd				if (opt->go_type == G_TYPE_NUMBER) {
311129470Spjd					gctl_ro_param(req, opt->go_name,
312129470Spjd					    sizeof(intmax_t), opt->go_val);
313129470Spjd				} else /* if (opt->go_type == G_TYPE_STRING)*/ {
314129470Spjd					gctl_ro_param(req, opt->go_name, -1,
315129470Spjd					    opt->go_val);
316129470Spjd				}
317129470Spjd			}
318129470Spjd		}
319129470Spjd	}
320129470Spjd	/*
321129470Spjd	 * Add rest of given arguments.
322129470Spjd	 */
323129470Spjd	gctl_ro_param(req, "nargs", sizeof(int), argc);
324129470Spjd	for (i = 0; i < (unsigned)*argc; i++) {
325129470Spjd		char argname[16];
326129470Spjd
327129470Spjd		snprintf(argname, sizeof(argname), "arg%u", i);
328129470Spjd		gctl_ro_param(req, argname, -1, (*argv)[i]);
329129470Spjd	}
330129470Spjd}
331129470Spjd
332129470Spjd/*
333129470Spjd * Find given command in commands available for given class.
334129470Spjd */
335129470Spjdstatic struct g_command *
336129470Spjdfind_command(const char *cmdstr, int all)
337129470Spjd{
338129470Spjd	struct g_command *cmd;
339129470Spjd	unsigned i;
340129470Spjd
341129470Spjd	/*
342129470Spjd	 * First try to find command defined by loaded library.
343129470Spjd	 */
344129470Spjd	if (class_commands != NULL) {
345129470Spjd		for (i = 0; ; i++) {
346129470Spjd			cmd = &class_commands[i];
347129470Spjd			if (cmd->gc_name == NULL)
348129470Spjd				break;
349129470Spjd			if (strcmp(cmd->gc_name, cmdstr) == 0)
350129470Spjd				return (cmd);
351129470Spjd		}
352129470Spjd	}
353129470Spjd	if (!all)
354129470Spjd		return (NULL);
355129470Spjd	/*
356129470Spjd	 * Now try to find in standard commands.
357129470Spjd	 */
358129470Spjd	for (i = 0; ; i++) {
359129470Spjd		cmd = &std_commands[i];
360129470Spjd		if (cmd->gc_name == NULL)
361129470Spjd			break;
362129470Spjd		if (!std_available(cmd->gc_name))
363129470Spjd			continue;
364129470Spjd		if (strcmp(cmd->gc_name, cmdstr) == 0)
365129470Spjd			return (cmd);
366129470Spjd	}
367129470Spjd	return (NULL);
368129470Spjd}
369129470Spjd
370129470Spjdstatic unsigned
371129470Spjdset_flags(struct g_command *cmd)
372129470Spjd{
373129470Spjd	unsigned flags = 0;
374129470Spjd
375129470Spjd	if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
376129470Spjd		flags |= G_FLAG_VERBOSE;
377129470Spjd
378129470Spjd	return (flags);
379129470Spjd}
380129470Spjd
381129470Spjd/*
382129470Spjd * Run command.
383129470Spjd */
384129470Spjdstatic void
385129470Spjdrun_command(int argc, char *argv[])
386129470Spjd{
387129470Spjd	struct g_command *cmd;
388129470Spjd	struct gctl_req *req;
389129470Spjd	const char *errstr;
390129470Spjd	char buf[4096];
391129470Spjd
392129470Spjd	cmd = find_command(argv[0], 1);
393129470Spjd	if (cmd == NULL) {
394129470Spjd		fprintf(stderr, "Unknown command: %s\n", argv[0]);
395129470Spjd		geom_usage();
396129470Spjd	}
397129470Spjd	if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
398129470Spjd		load_module();
399129470Spjd
400129470Spjd	req = gctl_get_handle();
401129470Spjd	gctl_ro_param(req, "class", -1, gclass_name);
402129470Spjd	gctl_ro_param(req, "verb", -1, argv[0]);
403129470Spjd	if (version != NULL)
404129470Spjd		gctl_ro_param(req, "version", sizeof(*version), version);
405129470Spjd	parse_arguments(cmd, req, &argc, &argv);
406129470Spjd
407129470Spjd	if (cmd->gc_func != NULL) {
408129470Spjd		unsigned flags;
409129470Spjd
410129470Spjd		flags = set_flags(cmd);
411129470Spjd		cmd->gc_func(req, flags);
412129470Spjd		errstr = req->error;
413129470Spjd	} else {
414129470Spjd		bzero(buf, sizeof(buf));
415129470Spjd		gctl_rw_param(req, "output", sizeof(buf), buf);
416129470Spjd		errstr = gctl_issue(req);
417129470Spjd	}
418129470Spjd	if (errstr != NULL) {
419129470Spjd		fprintf(stderr, "%s\n", errstr);
420129470Spjd		gctl_free(req);
421129470Spjd		exit(EXIT_FAILURE);
422129470Spjd	}
423129470Spjd	if (*buf != '\0')
424129470Spjd		printf("%s", buf);
425129470Spjd	gctl_free(req);
426129470Spjd	if (verbose)
427129470Spjd		printf("Done.\n");
428129470Spjd	exit(EXIT_SUCCESS);
429129470Spjd}
430129470Spjd
431129470Spjdstatic void
432129470Spjdload_library(void)
433129470Spjd{
434129470Spjd	char path[MAXPATHLEN];
435129470Spjd	uint32_t *lib_version;
436129470Spjd	void *dlh;
437129470Spjd
438129470Spjd	snprintf(path, sizeof(path), "%s/geom_%s.so", CLASSDIR, class_name);
439129470Spjd	dlh = dlopen(path, RTLD_NOW);
440129470Spjd	if (dlh == NULL) {
441129470Spjd#if 0
442129470Spjd		fprintf(stderr, "Cannot open library %s, but continuing "
443129470Spjd		    "anyway.\n", path);
444129470Spjd#endif
445129470Spjd		/*
446129470Spjd		 * Even if library cannot be loaded, standard commands are
447129470Spjd		 * available, so don't panic!
448129470Spjd		 */
449129470Spjd		return;
450129470Spjd	}
451129470Spjd	lib_version = dlsym(dlh, "lib_version");
452129470Spjd	if (lib_version == NULL) {
453129470Spjd		fprintf(stderr, "Cannot find symbol %s: %s.\n", "lib_version",
454129470Spjd		    dlerror());
455129470Spjd		dlclose(dlh);
456129470Spjd		exit(EXIT_FAILURE);
457129470Spjd	}
458129470Spjd	if (*lib_version != G_LIB_VERSION) {
459129470Spjd		dlclose(dlh);
460129470Spjd		errx(EXIT_FAILURE, "%s and %s are not synchronized.", comm,
461129470Spjd		    path);
462129470Spjd	}
463129470Spjd	version = dlsym(dlh, "version");
464129470Spjd	if (version == NULL) {
465129470Spjd		fprintf(stderr, "Cannot find symbol %s: %s.\n", "version",
466129470Spjd		    dlerror());
467129470Spjd		dlclose(dlh);
468129470Spjd		exit(EXIT_FAILURE);
469129470Spjd	}
470129470Spjd	class_commands = dlsym(dlh, "class_commands");
471129470Spjd	if (class_commands == NULL) {
472129470Spjd		fprintf(stderr, "Cannot find symbol %s: %s.\n",
473129470Spjd		    "class_commands", dlerror());
474129470Spjd		dlclose(dlh);
475129470Spjd		exit(EXIT_FAILURE);
476129470Spjd	}
477129470Spjd	usage = dlsym(dlh, "usage");
478129470Spjd	if (usage == NULL)
479129470Spjd		usage = std_usage;
480129470Spjd}
481129470Spjd
482129470Spjd/*
483129470Spjd * Class name should be all capital letters.
484129470Spjd */
485129470Spjdstatic void
486129470Spjdset_class_name(void)
487129470Spjd{
488129470Spjd	char *s1, *s2;
489129470Spjd
490129470Spjd	gclass_name = malloc(strlen(class_name));
491129470Spjd	if (gclass_name == NULL)
492129470Spjd		errx(EXIT_FAILURE, "No memory");
493129470Spjd	s1 = gclass_name;
494129470Spjd	s2 = class_name;
495129470Spjd	for (; *s2 != '\0'; s2++)
496129470Spjd		*s1++ = toupper(*s2);
497129470Spjd	*s1 = '\0';
498129470Spjd}
499129470Spjd
500129470Spjdstatic void
501129470Spjdget_class(int *argc, char ***argv)
502129470Spjd{
503129470Spjd
504129470Spjd	snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
505129470Spjd	if (strcmp(comm, "geom") == 0) {
506129470Spjd		if (*argc < 2)
507129470Spjd			geom_usage();
508129470Spjd		strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
509129470Spjd		class_name = (*argv)[1];
510129470Spjd		*argc -= 2;
511129470Spjd		*argv += 2;
512129470Spjd	} else if (*comm == 'g') {
513129470Spjd		class_name = comm + 1;
514129470Spjd		*argc -= 1;
515129470Spjd		*argv += 1;
516129470Spjd	} else {
517129470Spjd		errx(EXIT_FAILURE, "Invalid utility name.");
518129470Spjd	}
519129470Spjd	set_class_name();
520129470Spjd	load_library();
521129470Spjd	if (*argc < 1)
522129470Spjd		geom_usage();
523129470Spjd}
524129470Spjd
525129470Spjdint
526129470Spjdmain(int argc, char *argv[])
527129470Spjd{
528129470Spjd
529129470Spjd	get_class(&argc, &argv);
530129470Spjd	run_command(argc, argv);
531129470Spjd	/* NOTREACHED */
532129470Spjd
533129470Spjd	exit(EXIT_FAILURE);
534129470Spjd}
535129470Spjd
536129470Spjdstatic struct gclass *
537129470Spjdfind_class(struct gmesh *mesh, const char *name)
538129470Spjd{
539129470Spjd	struct gclass *classp;
540129470Spjd
541129470Spjd	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
542129470Spjd		if (strcmp(classp->lg_name, name) == 0)
543129470Spjd			return (classp);
544129470Spjd	}
545129470Spjd	return (NULL);
546129470Spjd}
547129470Spjd
548129470Spjdstatic struct gprovider *
549129470Spjdfind_provider(struct gclass *classp, const char *name)
550129470Spjd{
551129470Spjd	struct ggeom *gp;
552129470Spjd	struct gprovider *pp;
553129470Spjd
554129470Spjd	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
555129470Spjd		LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
556129470Spjd			if (strcmp(pp->lg_name, name) == 0)
557129470Spjd				return (pp);
558129470Spjd		}
559129470Spjd	}
560129470Spjd	return (NULL);
561129470Spjd}
562129470Spjd
563129470Spjdstatic char *
564129470Spjdgenspaces(const char *text, size_t len)
565129470Spjd{
566129470Spjd	static char spaces[256];
567129470Spjd	size_t outlen;
568129470Spjd
569129470Spjd	if (strlen(text) >= len) {
570129470Spjd		spaces[0] = '\0';
571129470Spjd		return (spaces);
572129470Spjd	}
573129470Spjd	memset(spaces, ' ', sizeof(spaces));
574129470Spjd	outlen = len - strlen(text);
575129470Spjd	if (outlen >= sizeof(spaces)) {
576129470Spjd		spaces[sizeof(spaces) - 1] = '\0';
577129470Spjd		return (spaces);
578129470Spjd	}
579129470Spjd	spaces[outlen] = '\0';
580129470Spjd	return (spaces);
581129470Spjd}
582129470Spjd
583129470Spjdstatic void
584129470Spjdshow_one(struct gprovider *pp)
585129470Spjd{
586129470Spjd	struct gconfig *conf;
587129470Spjd
588129470Spjd	printf("       NAME: %s\n", pp->lg_name);
589129470Spjd	printf("  geom name: %s\n", pp->lg_geom->lg_name);
590129470Spjd	printf("  mediasize: %jd\n", (intmax_t)pp->lg_mediasize);
591129470Spjd	printf(" sectorsize: %u\n", pp->lg_sectorsize);
592129470Spjd	printf("       mode: %s\n", pp->lg_mode);
593129470Spjd	LIST_FOREACH(conf, &pp->lg_config, lg_config) {
594129470Spjd		printf("%s%s: %s\n", genspaces(conf->lg_name, 11),
595129470Spjd		    conf->lg_name, conf->lg_val);
596129470Spjd	}
597129470Spjd	printf("\n");
598129470Spjd}
599129470Spjd
600129470Spjdstatic int
601129470Spjdstd_list_available(void)
602129470Spjd{
603129470Spjd	struct gmesh mesh;
604129470Spjd	struct gclass *classp;
605129470Spjd	int error;
606129470Spjd
607129470Spjd	error = geom_gettree(&mesh);
608129470Spjd	if (error != 0)
609129470Spjd		exit(EXIT_FAILURE);
610129470Spjd	classp = find_class(&mesh, gclass_name);
611129470Spjd	geom_deletetree(&mesh);
612129470Spjd	if (classp != NULL)
613129470Spjd		return (1);
614129470Spjd	return (0);
615129470Spjd}
616129470Spjd
617129470Spjdstatic void
618129470Spjdstd_list(struct gctl_req *req, unsigned flags __unused)
619129470Spjd{
620129470Spjd	struct gmesh mesh;
621129470Spjd	struct gclass *classp;
622129470Spjd	struct gprovider *pp;
623129470Spjd	int error, *nargs;
624129470Spjd
625129470Spjd	error = geom_gettree(&mesh);
626129470Spjd	if (error != 0)
627129470Spjd		exit(EXIT_FAILURE);
628129470Spjd	classp = find_class(&mesh, gclass_name);
629129470Spjd	if (classp == NULL) {
630129470Spjd		geom_deletetree(&mesh);
631129470Spjd		fprintf(stderr, "Class %s not found.\n", gclass_name);
632129470Spjd		return;
633129470Spjd	}
634129470Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
635129470Spjd	if (nargs == NULL) {
636129470Spjd		gctl_error(req, "No '%s' argument.", "nargs");
637129470Spjd		geom_deletetree(&mesh);
638129470Spjd		return;
639129470Spjd	}
640129470Spjd	if (*nargs > 0) {
641129470Spjd		int i;
642129470Spjd
643129470Spjd		for (i = 0; i < *nargs; i++) {
644129470Spjd			const char *name;
645129470Spjd			char param[16];
646129470Spjd
647129470Spjd			snprintf(param, sizeof(param), "arg%d", i);
648129470Spjd			name = gctl_get_asciiparam(req, param);
649129470Spjd			assert(name != NULL);
650129470Spjd			pp = find_provider(classp, name);
651129470Spjd			if (pp != NULL)
652129470Spjd				show_one(pp);
653129470Spjd			else {
654129470Spjd				fprintf(stderr, "No such provider: %s.\n",
655129470Spjd				    name);
656129470Spjd			}
657129470Spjd		}
658129470Spjd	} else {
659129470Spjd		struct ggeom *gp;
660129470Spjd
661129470Spjd		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
662129470Spjd			LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
663129470Spjd				show_one(pp);
664129470Spjd			}
665129470Spjd		}
666129470Spjd	}
667129470Spjd	geom_deletetree(&mesh);
668129470Spjd}
669129470Spjd
670129470Spjdstatic int
671129470Spjdstd_load_available(void)
672129470Spjd{
673129470Spjd	char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
674129470Spjd	struct stat sb;
675129470Spjd	size_t len;
676129470Spjd
677129470Spjd	snprintf(name, sizeof(name), "g_%s", class_name);
678129470Spjd	/*
679129470Spjd	 * If already in kernel, "load" command is not available.
680129470Spjd	 */
681129470Spjd	if (modfind(name) >= 0)
682129470Spjd		return (0);
683129470Spjd	bzero(paths, sizeof(paths));
684129470Spjd	len = sizeof(paths);
685129470Spjd	if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
686129470Spjd		err(EXIT_FAILURE, "sysctl(kern.module_path)");
687129470Spjd	for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
688129470Spjd		snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
689129470Spjd		/*
690129470Spjd		 * If geom_<name>.ko file exists, "load" command is available.
691129470Spjd		 */
692129470Spjd		if (stat(name, &sb) == 0)
693129470Spjd			return (1);
694129470Spjd	}
695129470Spjd	return (0);
696129470Spjd}
697129470Spjd
698129470Spjdstatic void
699129470Spjdstd_load(struct gctl_req *req __unused, unsigned flags)
700129470Spjd{
701129470Spjd
702129470Spjd	/*
703129470Spjd	 * Do nothing special here, because of G_FLAG_LOADKLD flag,
704129470Spjd	 * module is already loaded.
705129470Spjd	 */
706129470Spjd	if ((flags & G_FLAG_VERBOSE) != 0)
707129470Spjd		printf("Module available.\n");
708129470Spjd}
709129470Spjd
710129470Spjdstatic int
711129470Spjdstd_unload_available(void)
712129470Spjd{
713129470Spjd	char name[64];
714129470Spjd	int id;
715129470Spjd
716129470Spjd	snprintf(name, sizeof(name), "geom_%s", class_name);
717129470Spjd	id = kldfind(name);
718129470Spjd	if (id >= 0)
719129470Spjd		return (1);
720129470Spjd	return (0);
721129470Spjd}
722129470Spjd
723129470Spjdstatic void
724129470Spjdstd_unload(struct gctl_req *req, unsigned flags __unused)
725129470Spjd{
726129470Spjd	char name[64];
727129470Spjd	int id;
728129470Spjd
729129470Spjd	snprintf(name, sizeof(name), "geom_%s", class_name);
730129470Spjd	id = kldfind(name);
731129470Spjd	if (id < 0) {
732129470Spjd		gctl_error(req, "Could not find module: %s.", strerror(errno));
733129470Spjd		return;
734129470Spjd	}
735129470Spjd	if (kldunload(id) < 0) {
736129470Spjd		gctl_error(req, "Could not unload module: %s.",
737129470Spjd		    strerror(errno));
738129470Spjd		return;
739129470Spjd	}
740129470Spjd}
741129470Spjd
742129470Spjdstatic int
743129470Spjdstd_available(const char *name)
744129470Spjd{
745129470Spjd
746129470Spjd	if (strcmp(name, "list") == 0)
747129470Spjd		return (std_list_available());
748129470Spjd	else if (strcmp(name, "load") == 0)
749129470Spjd		return (std_load_available());
750129470Spjd	else if (strcmp(name, "unload") == 0)
751129470Spjd		return (std_unload_available());
752129470Spjd	else
753129470Spjd		assert(!"Unknown standard command.");
754129470Spjd	return (0);
755129470Spjd}
756