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