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