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