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