]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - sbin/geom/core/geom.c
MFC r296653: Allow standard commands for "unknown" classes in RESCUE mode.
[FreeBSD/stable/9.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 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         }
639 #endif /* !STATIC_GEOM_CLASSES */
640
641         set_class_name();
642         if (*argc < 1)
643                 usage();
644 }
645
646 int
647 main(int argc, char *argv[])
648 {
649
650         get_class(&argc, &argv);
651         run_command(argc, argv);
652         /* NOTREACHED */
653
654         exit(EXIT_FAILURE);
655 }
656
657 static struct gclass *
658 find_class(struct gmesh *mesh, const char *name)
659 {
660         struct gclass *classp;
661
662         LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
663                 if (strcmp(classp->lg_name, name) == 0)
664                         return (classp);
665         }
666         return (NULL);
667 }
668
669 static struct ggeom *
670 find_geom(struct gclass *classp, const char *name)
671 {
672         struct ggeom *gp;
673
674         LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
675                 if (strcmp(gp->lg_name, name) == 0)
676                         return (gp);
677         }
678         return (NULL);
679 }
680
681 static void
682 list_one_provider(struct gprovider *pp, const char *prefix)
683 {
684         struct gconfig *conf;
685         char buf[5];
686
687         printf("Name: %s\n", pp->lg_name);
688         humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
689             HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
690         printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
691             buf);
692         printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
693         if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
694                 printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
695                 printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
696         }
697         printf("%sMode: %s\n", prefix, pp->lg_mode);
698         LIST_FOREACH(conf, &pp->lg_config, lg_config) {
699                 printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
700         }
701 }
702
703 static void
704 list_one_consumer(struct gconsumer *cp, const char *prefix)
705 {
706         struct gprovider *pp;
707         struct gconfig *conf;
708
709         pp = cp->lg_provider;
710         if (pp == NULL)
711                 printf("[no provider]\n");
712         else {
713                 char buf[5];
714
715                 printf("Name: %s\n", pp->lg_name);
716                 humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
717                     HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
718                 printf("%sMediasize: %jd (%s)\n", prefix,
719                     (intmax_t)pp->lg_mediasize, buf);
720                 printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
721                 if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
722                         printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
723                         printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
724                 }
725                 printf("%sMode: %s\n", prefix, cp->lg_mode);
726         }
727         LIST_FOREACH(conf, &cp->lg_config, lg_config) {
728                 printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
729         }
730 }
731
732 static void
733 list_one_geom(struct ggeom *gp)
734 {
735         struct gprovider *pp;
736         struct gconsumer *cp;
737         struct gconfig *conf;
738         unsigned n;
739
740         printf("Geom name: %s\n", gp->lg_name);
741         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
742                 printf("%s: %s\n", conf->lg_name, conf->lg_val);
743         }
744         if (!LIST_EMPTY(&gp->lg_provider)) {
745                 printf("Providers:\n");
746                 n = 1;
747                 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
748                         printf("%u. ", n++);
749                         list_one_provider(pp, "   ");
750                 }
751         }
752         if (!LIST_EMPTY(&gp->lg_consumer)) {
753                 printf("Consumers:\n");
754                 n = 1;
755                 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
756                         printf("%u. ", n++);
757                         list_one_consumer(cp, "   ");
758                 }
759         }
760         printf("\n");
761 }
762
763 static void
764 std_help(struct gctl_req *req __unused, unsigned flags __unused)
765 {
766
767         usage();
768 }
769
770 static int
771 std_list_available(void)
772 {
773         struct gmesh mesh;
774         struct gclass *classp;
775         int error;
776
777         error = geom_gettree(&mesh);
778         if (error != 0)
779                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
780         classp = find_class(&mesh, gclass_name);
781         geom_deletetree(&mesh);
782         if (classp != NULL)
783                 return (1);
784         return (0);
785 }
786
787 static void
788 std_list(struct gctl_req *req, unsigned flags __unused)
789 {
790         struct gmesh mesh;
791         struct gclass *classp;
792         struct ggeom *gp;
793         const char *name;
794         int all, error, i, nargs;
795
796         error = geom_gettree(&mesh);
797         if (error != 0)
798                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
799         classp = find_class(&mesh, gclass_name);
800         if (classp == NULL) {
801                 geom_deletetree(&mesh);
802                 errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
803         }
804         nargs = gctl_get_int(req, "nargs");
805         all = gctl_get_int(req, "all");
806         if (nargs > 0) {
807                 for (i = 0; i < nargs; i++) {
808                         name = gctl_get_ascii(req, "arg%d", i);
809                         gp = find_geom(classp, name);
810                         if (gp == NULL)
811                                 errx(EXIT_FAILURE, "No such geom: %s.", name);
812                         list_one_geom(gp);
813                 }
814         } else {
815                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
816                         if (LIST_EMPTY(&gp->lg_provider) && !all)
817                                 continue;
818                         list_one_geom(gp);
819                 }
820         }
821         geom_deletetree(&mesh);
822 }
823
824 static int
825 std_status_available(void)
826 {
827
828         /* 'status' command is available when 'list' command is. */
829         return (std_list_available());
830 }
831
832 static void
833 status_update_len(struct ggeom *gp, int *name_len, int *status_len)
834 {
835         struct gconfig *conf;
836         int len;
837
838         assert(gp != NULL);
839         assert(name_len != NULL);
840         assert(status_len != NULL);
841
842         len = strlen(gp->lg_name);
843         if (*name_len < len)
844                 *name_len = len;
845         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
846                 if (strcasecmp(conf->lg_name, "state") == 0) {
847                         len = strlen(conf->lg_val);
848                         if (*status_len < len)
849                                 *status_len = len;
850                 }
851         }
852 }
853
854 static void
855 status_update_len_prs(struct ggeom *gp, int *name_len, int *status_len)
856 {
857         struct gprovider *pp;
858         struct gconfig *conf;
859         int len, glen;
860
861         assert(gp != NULL);
862         assert(name_len != NULL);
863         assert(status_len != NULL);
864
865         glen = 0;
866         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
867                 if (strcasecmp(conf->lg_name, "state") == 0) {
868                         glen = strlen(conf->lg_val);
869                         break;
870                 }
871         }
872         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
873                 len = strlen(pp->lg_name);
874                 if (*name_len < len)
875                         *name_len = len;
876                 len = glen;
877                 LIST_FOREACH(conf, &pp->lg_config, lg_config) {
878                         if (strcasecmp(conf->lg_name, "state") == 0) {
879                                 len = strlen(conf->lg_val);
880                                 break;
881                         }
882                 }
883                 if (*status_len < len)
884                         *status_len = len;
885         }
886 }
887
888 static char *
889 status_one_consumer(struct gconsumer *cp)
890 {
891         static char buf[256];
892         struct gprovider *pp;
893         struct gconfig *conf;
894         const char *state, *syncr;
895
896         pp = cp->lg_provider;
897         if (pp == NULL)
898                 return (NULL);
899         state = NULL;
900         syncr = NULL;
901         LIST_FOREACH(conf, &cp->lg_config, lg_config) {
902                 if (strcasecmp(conf->lg_name, "state") == 0)
903                         state = conf->lg_val;
904                 if (strcasecmp(conf->lg_name, "synchronized") == 0)
905                         syncr = conf->lg_val;
906         }
907         if (state == NULL && syncr == NULL)
908                 snprintf(buf, sizeof(buf), "%s", pp->lg_name);
909         else if (state != NULL && syncr != NULL) {
910                 snprintf(buf, sizeof(buf), "%s (%s, %s)", pp->lg_name,
911                     state, syncr);
912         } else {
913                 snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name,
914                     state ? state : syncr);
915         }
916         return (buf);
917 }
918
919 static void
920 status_one_geom(struct ggeom *gp, int script, int name_len, int status_len)
921 {
922         struct gconsumer *cp;
923         struct gconfig *conf;
924         const char *name, *status, *component;
925         int gotone;
926
927         name = gp->lg_name;
928         status = "N/A";
929         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
930                 if (strcasecmp(conf->lg_name, "state") == 0) {
931                         status = conf->lg_val;
932                         break;
933                 }
934         }
935         gotone = 0;
936         LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
937                 component = status_one_consumer(cp);
938                 if (component == NULL)
939                         continue;
940                 gotone = 1;
941                 printf("%*s  %*s  %s\n", name_len, name, status_len, status,
942                     component);
943                 if (!script)
944                         name = status = "";
945         }
946         if (!gotone) {
947                 printf("%*s  %*s  %s\n", name_len, name, status_len, status,
948                     "N/A");
949         }
950 }
951
952 static void
953 status_one_geom_prs(struct ggeom *gp, int script, int name_len, int status_len)
954 {
955         struct gprovider *pp;
956         struct gconsumer *cp;
957         struct gconfig *conf;
958         const char *name, *status, *component;
959         int gotone;
960
961         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
962                 name = pp->lg_name;
963                 status = "N/A";
964                 LIST_FOREACH(conf, &gp->lg_config, lg_config) {
965                         if (strcasecmp(conf->lg_name, "state") == 0) {
966                                 status = conf->lg_val;
967                                 break;
968                         }
969                 }
970                 LIST_FOREACH(conf, &pp->lg_config, lg_config) {
971                         if (strcasecmp(conf->lg_name, "state") == 0) {
972                                 status = conf->lg_val;
973                                 break;
974                         }
975                 }
976                 gotone = 0;
977                 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
978                         component = status_one_consumer(cp);
979                         if (component == NULL)
980                                 continue;
981                         gotone = 1;
982                         printf("%*s  %*s  %s\n", name_len, name,
983                             status_len, status, component);
984                         if (!script)
985                                 name = status = "";
986                 }
987                 if (!gotone) {
988                         printf("%*s  %*s  %s\n", name_len, name,
989                             status_len, status, "N/A");
990                 }
991         }
992 }
993
994 static void
995 std_status(struct gctl_req *req, unsigned flags __unused)
996 {
997         struct gmesh mesh;
998         struct gclass *classp;
999         struct ggeom *gp;
1000         const char *name;
1001         int name_len, status_len;
1002         int all, error, geoms, i, n, nargs, script;
1003
1004         error = geom_gettree(&mesh);
1005         if (error != 0)
1006                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1007         classp = find_class(&mesh, gclass_name);
1008         if (classp == NULL)
1009                 errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
1010         nargs = gctl_get_int(req, "nargs");
1011         all = gctl_get_int(req, "all");
1012         geoms = gctl_get_int(req, "geoms");
1013         script = gctl_get_int(req, "script");
1014         if (script) {
1015                 name_len = 0;
1016                 status_len = 0;
1017         } else {
1018                 name_len = strlen("Name");
1019                 status_len = strlen("Status");
1020         }
1021         if (nargs > 0) {
1022                 for (i = 0, n = 0; i < nargs; i++) {
1023                         name = gctl_get_ascii(req, "arg%d", i);
1024                         gp = find_geom(classp, name);
1025                         if (gp == NULL)
1026                                 errx(EXIT_FAILURE, "No such geom: %s.", name);
1027                         if (geoms) {
1028                                 status_update_len(gp,
1029                                     &name_len, &status_len);
1030                         } else {
1031                                 status_update_len_prs(gp,
1032                                     &name_len, &status_len);
1033                         }
1034                         n++;
1035                 }
1036                 if (n == 0)
1037                         goto end;
1038         } else {
1039                 n = 0;
1040                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1041                         if (LIST_EMPTY(&gp->lg_provider) && !all)
1042                                 continue;
1043                         if (geoms) {
1044                                 status_update_len(gp,
1045                                     &name_len, &status_len);
1046                         } else {
1047                                 status_update_len_prs(gp,
1048                                     &name_len, &status_len);
1049                         }
1050                         n++;
1051                 }
1052                 if (n == 0)
1053                         goto end;
1054         }
1055         if (!script) {
1056                 printf("%*s  %*s  %s\n", name_len, "Name", status_len, "Status",
1057                     "Components");
1058         }
1059         if (nargs > 0) {
1060                 for (i = 0; i < nargs; i++) {
1061                         name = gctl_get_ascii(req, "arg%d", i);
1062                         gp = find_geom(classp, name);
1063                         if (gp == NULL)
1064                                 continue;
1065                         if (geoms) {
1066                                 status_one_geom(gp, script, name_len,
1067                                     status_len);
1068                         } else {
1069                                 status_one_geom_prs(gp, script, name_len,
1070                                     status_len);
1071                         }
1072                 }
1073         } else {
1074                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1075                         if (LIST_EMPTY(&gp->lg_provider) && !all)
1076                                 continue;
1077                         if (geoms) {
1078                                 status_one_geom(gp, script, name_len,
1079                                     status_len);
1080                         } else {
1081                                 status_one_geom_prs(gp, script, name_len,
1082                                     status_len);
1083                         }
1084                 }
1085         }
1086 end:
1087         geom_deletetree(&mesh);
1088 }
1089
1090 static int
1091 std_load_available(void)
1092 {
1093         char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
1094         struct stat sb;
1095         size_t len;
1096
1097         snprintf(name, sizeof(name), "g_%s", class_name);
1098         /*
1099          * If already in kernel, "load" command is not available.
1100          */
1101         if (modfind(name) >= 0)
1102                 return (0);
1103         bzero(paths, sizeof(paths));
1104         len = sizeof(paths);
1105         if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
1106                 err(EXIT_FAILURE, "sysctl(kern.module_path)");
1107         for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
1108                 snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
1109                 /*
1110                  * If geom_<name>.ko file exists, "load" command is available.
1111                  */
1112                 if (stat(name, &sb) == 0)
1113                         return (1);
1114         }
1115         return (0);
1116 }
1117
1118 static void
1119 std_load(struct gctl_req *req __unused, unsigned flags)
1120 {
1121
1122         /*
1123          * Do nothing special here, because of G_FLAG_LOADKLD flag,
1124          * module is already loaded.
1125          */
1126         if ((flags & G_FLAG_VERBOSE) != 0)
1127                 printf("Module available.\n");
1128 }
1129
1130 static int
1131 std_unload_available(void)
1132 {
1133         char name[64];
1134         int id;
1135
1136         snprintf(name, sizeof(name), "geom_%s", class_name);
1137         id = kldfind(name);
1138         if (id >= 0)
1139                 return (1);
1140         return (0);
1141 }
1142
1143 static void
1144 std_unload(struct gctl_req *req, unsigned flags __unused)
1145 {
1146         char name[64];
1147         int id;
1148
1149         snprintf(name, sizeof(name), "geom_%s", class_name);
1150         id = kldfind(name);
1151         if (id < 0) {
1152                 gctl_error(req, "Could not find module: %s.", strerror(errno));
1153                 return;
1154         }
1155         if (kldunload(id) < 0) {
1156                 gctl_error(req, "Could not unload module: %s.",
1157                     strerror(errno));
1158                 return;
1159         }
1160 }
1161
1162 static int
1163 std_available(const char *name)
1164 {
1165
1166         if (strcmp(name, "help") == 0)
1167                 return (1);
1168         else if (strcmp(name, "list") == 0)
1169                 return (std_list_available());
1170         else if (strcmp(name, "status") == 0)
1171                 return (std_status_available());
1172         else if (strcmp(name, "load") == 0)
1173                 return (std_load_available());
1174         else if (strcmp(name, "unload") == 0)
1175                 return (std_unload_available());
1176         else
1177                 assert(!"Unknown standard command.");
1178         return (0);
1179 }