]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/geom/core/geom.c
geom(8): list geoms with /dev/ prefix
[FreeBSD/FreeBSD.git] / sbin / geom / core / geom.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/linker.h>
34 #include <sys/module.h>
35 #include <sys/stat.h>
36 #include <sys/sysctl.h>
37 #include <ctype.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <paths.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <stdarg.h>
44 #include <stdbool.h>
45 #include <stdint.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <libgen.h>
49 #include <libutil.h>
50 #include <inttypes.h>
51 #include <dlfcn.h>
52 #include <assert.h>
53 #include <libgeom.h>
54 #include <geom.h>
55
56 #include "misc/subr.h"
57
58 #ifdef STATIC_GEOM_CLASSES
59 extern uint32_t gpart_version;
60 extern struct g_command gpart_class_commands[];
61 extern uint32_t glabel_version;
62 extern struct g_command glabel_class_commands[];
63 #endif
64
65 static char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL;
66 static uint32_t *version = NULL;
67 static int verbose = 0;
68 static struct g_command *class_commands = NULL;
69
70 #define GEOM_CLASS_CMDS         0x01
71 #define GEOM_STD_CMDS           0x02
72
73 #define GEOM_CLASS_WIDTH        10
74
75 static struct g_command *find_command(const char *cmdstr, int flags);
76 static void list_one_geom_by_provider(const char *provider_name);
77 static int std_available(const char *name);
78
79 static void std_help(struct gctl_req *req, unsigned flags);
80 static void std_list(struct gctl_req *req, unsigned flags);
81 static void std_status(struct gctl_req *req, unsigned flags);
82 static void std_load(struct gctl_req *req, unsigned flags);
83 static void std_unload(struct gctl_req *req, unsigned flags);
84
85 static struct g_command std_commands[] = {
86         { "help", 0, std_help, G_NULL_OPTS, NULL },
87         { "list", 0, std_list,
88             {
89                 { 'a', "all", NULL, G_TYPE_BOOL },
90                 G_OPT_SENTINEL
91             },
92             "[-a] [name ...]"
93         },
94         { "status", 0, std_status,
95             {
96                 { 'a', "all", NULL, G_TYPE_BOOL },
97                 { 'g', "geoms", NULL, G_TYPE_BOOL },
98                 { 's', "script", NULL, G_TYPE_BOOL },
99                 G_OPT_SENTINEL
100             },
101             "[-ags] [name ...]"
102         },
103         { "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS,
104             NULL },
105         { "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS, NULL },
106         G_CMD_SENTINEL
107 };
108
109 static void
110 usage_command(struct g_command *cmd, const char *prefix)
111 {
112         struct g_option *opt;
113         unsigned i;
114
115         if (cmd->gc_usage != NULL) {
116                 char *pos, *ptr, *sptr;
117
118                 sptr = ptr = strdup(cmd->gc_usage);
119                 while ((pos = strsep(&ptr, "\n")) != NULL) {
120                         if (*pos == '\0')
121                                 continue;
122                         fprintf(stderr, "%s %s %s %s\n", prefix, comm,
123                             cmd->gc_name, pos);
124                 }
125                 free(sptr);
126                 return;
127         }
128
129         fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name);
130         if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
131                 fprintf(stderr, " [-v]");
132         for (i = 0; ; i++) {
133                 opt = &cmd->gc_options[i];
134                 if (opt->go_name == NULL)
135                         break;
136                 if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
137                         fprintf(stderr, " [");
138                 else
139                         fprintf(stderr, " ");
140                 fprintf(stderr, "-%c", opt->go_char);
141                 if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
142                         fprintf(stderr, " %s", opt->go_name);
143                 if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL)
144                         fprintf(stderr, "]");
145         }
146         fprintf(stderr, "\n");
147 }
148
149 static void
150 usage(void)
151 {
152
153         if (class_name == NULL) {
154                 fprintf(stderr, "usage: geom <class> <command> [options]\n");
155                 fprintf(stderr, "       geom -p <provider-name>\n");
156                 fprintf(stderr, "       geom -t\n");
157                 exit(EXIT_FAILURE);
158         } else {
159                 struct g_command *cmd;
160                 const char *prefix;
161                 unsigned i;
162
163                 prefix = "usage:";
164                 if (class_commands != NULL) {
165                         for (i = 0; ; i++) {
166                                 cmd = &class_commands[i];
167                                 if (cmd->gc_name == NULL)
168                                         break;
169                                 usage_command(cmd, prefix);
170                                 prefix = "      ";
171                         }
172                 }
173                 for (i = 0; ; i++) {
174                         cmd = &std_commands[i];
175                         if (cmd->gc_name == NULL)
176                                 break;
177                         /*
178                          * If class defines command, which has the same name as
179                          * standard command, skip it, because it was already
180                          * shown on usage().
181                          */
182                         if (find_command(cmd->gc_name, GEOM_CLASS_CMDS) != NULL)
183                                 continue;
184                         usage_command(cmd, prefix);
185                         prefix = "      ";
186                 }
187                 exit(EXIT_FAILURE);
188         }
189 }
190
191 static void
192 load_module(void)
193 {
194         char name1[64], name2[64];
195
196         snprintf(name1, sizeof(name1), "g_%s", class_name);
197         snprintf(name2, sizeof(name2), "geom_%s", class_name);
198         if (modfind(name1) < 0) {
199                 /* Not present in kernel, try loading it. */
200                 if (kldload(name2) < 0 || modfind(name1) < 0) {
201                         if (errno != EEXIST) {
202                                 err(EXIT_FAILURE, "cannot load %s", name2);
203                         }
204                 }
205         }
206 }
207
208 static int
209 strlcatf(char *str, size_t size, const char *format, ...)
210 {
211         size_t len;
212         va_list ap;
213         int ret;
214
215         len = strlen(str);
216         str += len;
217         size -= len;
218
219         va_start(ap, format);
220         ret = vsnprintf(str, size, format, ap);
221         va_end(ap);
222
223         return (ret);
224 }
225
226 /*
227  * Find given option in options available for given command.
228  */
229 static struct g_option *
230 find_option(struct g_command *cmd, char ch)
231 {
232         struct g_option *opt;
233         unsigned i;
234
235         for (i = 0; ; i++) {
236                 opt = &cmd->gc_options[i];
237                 if (opt->go_name == NULL)
238                         return (NULL);
239                 if (opt->go_char == ch)
240                         return (opt);
241         }
242         /* NOTREACHED */
243         return (NULL);
244 }
245
246 /*
247  * Add given option to gctl_req.
248  */
249 static void
250 set_option(struct gctl_req *req, struct g_option *opt, const char *val)
251 {
252         const char *optname;
253         uint64_t number;
254         void *ptr;
255
256         if (G_OPT_ISMULTI(opt)) {
257                 size_t optnamesize;
258
259                 if (G_OPT_NUM(opt) == UCHAR_MAX)
260                         errx(EXIT_FAILURE, "Too many -%c options.", opt->go_char);
261
262                 /*
263                  * Base option name length plus 3 bytes for option number
264                  * (max. 255 options) plus 1 byte for terminating '\0'.
265                  */
266                 optnamesize = strlen(opt->go_name) + 3 + 1;
267                 ptr = malloc(optnamesize);
268                 if (ptr == NULL)
269                         errx(EXIT_FAILURE, "No memory.");
270                 snprintf(ptr, optnamesize, "%s%u", opt->go_name, G_OPT_NUM(opt));
271                 G_OPT_NUMINC(opt);
272                 optname = ptr;
273         } else {
274                 optname = opt->go_name;
275         }
276
277         if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) {
278                 if (expand_number(val, &number) == -1) {
279                         err(EXIT_FAILURE, "Invalid value for '%c' argument",
280                             opt->go_char);
281                 }
282                 ptr = malloc(sizeof(intmax_t));
283                 if (ptr == NULL)
284                         errx(EXIT_FAILURE, "No memory.");
285                 *(intmax_t *)ptr = number;
286                 opt->go_val = ptr;
287                 gctl_ro_param(req, optname, sizeof(intmax_t), opt->go_val);
288         } else if (G_OPT_TYPE(opt) == G_TYPE_STRING) {
289                 gctl_ro_param(req, optname, -1, val);
290         } else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
291                 ptr = malloc(sizeof(int));
292                 if (ptr == NULL)
293                         errx(EXIT_FAILURE, "No memory.");
294                 *(int *)ptr = *val - '0';
295                 opt->go_val = ptr;
296                 gctl_ro_param(req, optname, sizeof(int), opt->go_val);
297         } else {
298                 assert(!"Invalid type");
299         }
300
301         if (G_OPT_ISMULTI(opt))
302                 free(__DECONST(char *, optname));
303 }
304
305 /*
306  * 1. Add given argument by caller.
307  * 2. Add default values of not given arguments.
308  * 3. Add the rest of arguments.
309  */
310 static void
311 parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc,
312     char ***argv)
313 {
314         struct g_option *opt;
315         char opts[64];
316         unsigned i;
317         int ch;
318
319         *opts = '\0';
320         if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0)
321                 strlcat(opts, "v", sizeof(opts));
322         for (i = 0; ; i++) {
323                 opt = &cmd->gc_options[i];
324                 if (opt->go_name == NULL)
325                         break;
326                 assert(G_OPT_TYPE(opt) != 0);
327                 assert((opt->go_type & ~(G_TYPE_MASK | G_TYPE_MULTI)) == 0);
328                 /* Multiple bool arguments makes no sense. */
329                 assert(G_OPT_TYPE(opt) != G_TYPE_BOOL ||
330                     (opt->go_type & G_TYPE_MULTI) == 0);
331                 strlcatf(opts, sizeof(opts), "%c", opt->go_char);
332                 if (G_OPT_TYPE(opt) != G_TYPE_BOOL)
333                         strlcat(opts, ":", sizeof(opts));
334         }
335
336         /*
337          * Add specified arguments.
338          */
339         while ((ch = getopt(*argc, *argv, opts)) != -1) {
340                 /* Standard (not passed to kernel) options. */
341                 switch (ch) {
342                 case 'v':
343                         verbose = 1;
344                         continue;
345                 }
346                 /* Options passed to kernel. */
347                 opt = find_option(cmd, ch);
348                 if (opt == NULL)
349                         usage();
350                 if (!G_OPT_ISMULTI(opt) && G_OPT_ISDONE(opt)) {
351                         warnx("Option '%c' specified twice.", opt->go_char);
352                         usage();
353                 }
354                 G_OPT_DONE(opt);
355
356                 if (G_OPT_TYPE(opt) == G_TYPE_BOOL)
357                         set_option(req, opt, "1");
358                 else
359                         set_option(req, opt, optarg);
360         }
361         *argc -= optind;
362         *argv += optind;
363
364         /*
365          * Add not specified arguments, but with default values.
366          */
367         for (i = 0; ; i++) {
368                 opt = &cmd->gc_options[i];
369                 if (opt->go_name == NULL)
370                         break;
371                 if (G_OPT_ISDONE(opt))
372                         continue;
373
374                 if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
375                         assert(opt->go_val == NULL);
376                         set_option(req, opt, "0");
377                 } else {
378                         if (opt->go_val == NULL) {
379                                 warnx("Option '%c' not specified.",
380                                     opt->go_char);
381                                 usage();
382                         } else if (opt->go_val == G_VAL_OPTIONAL) {
383                                 /* add nothing. */
384                         } else {
385                                 set_option(req, opt, opt->go_val);
386                         }
387                 }
388         }
389
390         /*
391          * Add rest of given arguments.
392          */
393         gctl_ro_param(req, "nargs", sizeof(int), argc);
394         for (i = 0; i < (unsigned)*argc; i++) {
395                 char argname[16];
396
397                 snprintf(argname, sizeof(argname), "arg%u", i);
398                 gctl_ro_param(req, argname, -1, (*argv)[i]);
399         }
400 }
401
402 /*
403  * Find given command in commands available for given class.
404  */
405 static struct g_command *
406 find_command(const char *cmdstr, int flags)
407 {
408         struct g_command *cmd;
409         unsigned i;
410
411         /*
412          * First try to find command defined by loaded library.
413          */
414         if ((flags & GEOM_CLASS_CMDS) != 0 && class_commands != NULL) {
415                 for (i = 0; ; i++) {
416                         cmd = &class_commands[i];
417                         if (cmd->gc_name == NULL)
418                                 break;
419                         if (strcmp(cmd->gc_name, cmdstr) == 0)
420                                 return (cmd);
421                 }
422         }
423         /*
424          * Now try to find in standard commands.
425          */
426         if ((flags & GEOM_STD_CMDS) != 0) {
427                 for (i = 0; ; i++) {
428                         cmd = &std_commands[i];
429                         if (cmd->gc_name == NULL)
430                                 break;
431                         if (strcmp(cmd->gc_name, cmdstr) == 0)
432                                 return (cmd);
433                 }
434         }
435         return (NULL);
436 }
437
438 static unsigned
439 set_flags(struct g_command *cmd)
440 {
441         unsigned flags = 0;
442
443         if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
444                 flags |= G_FLAG_VERBOSE;
445
446         return (flags);
447 }
448
449 /*
450  * Run command.
451  */
452 static void
453 run_command(int argc, char *argv[])
454 {
455         struct g_command *cmd;
456         struct gctl_req *req;
457         const char *errstr;
458         char buf[4096];
459
460         /* First try to find a command defined by a class. */
461         cmd = find_command(argv[0], GEOM_CLASS_CMDS);
462         if (cmd == NULL) {
463                 /* Now, try to find a standard command. */
464                 cmd = find_command(argv[0], GEOM_STD_CMDS);
465                 if (cmd == NULL) {
466                         warnx("Unknown command: %s.", argv[0]);
467                         usage();
468                 }
469                 if (!std_available(cmd->gc_name)) {
470                         warnx("Command '%s' not available; "
471                             "try 'load' first.", argv[0]);
472                         exit(EXIT_FAILURE);
473                 }
474         }
475         if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
476                 load_module();
477
478         req = gctl_get_handle();
479         gctl_ro_param(req, "class", -1, gclass_name);
480         gctl_ro_param(req, "verb", -1, argv[0]);
481         if (version != NULL)
482                 gctl_ro_param(req, "version", sizeof(*version), version);
483         parse_arguments(cmd, req, &argc, &argv);
484
485         bzero(buf, sizeof(buf));
486         if (cmd->gc_func != NULL) {
487                 unsigned flags;
488
489                 flags = set_flags(cmd);
490                 cmd->gc_func(req, flags);
491                 errstr = req->error;
492         } else {
493                 gctl_rw_param(req, "output", sizeof(buf), buf);
494                 errstr = gctl_issue(req);
495         }
496         if (errstr != NULL && errstr[0] != '\0') {
497                 warnx("%s", errstr);
498                 if (strncmp(errstr, "warning: ", strlen("warning: ")) != 0) {
499                         gctl_free(req);
500                         exit(EXIT_FAILURE);
501                 }
502         }
503         if (buf[0] != '\0')
504                 printf("%s", buf);
505         gctl_free(req);
506         if (verbose)
507                 printf("Done.\n");
508         exit(EXIT_SUCCESS);
509 }
510
511 #ifndef STATIC_GEOM_CLASSES
512 static const char *
513 library_path(void)
514 {
515         const char *path;
516
517         path = getenv("GEOM_LIBRARY_PATH");
518         if (path == NULL)
519                 path = GEOM_CLASS_DIR;
520         return (path);
521 }
522
523 static void
524 load_library(void)
525 {
526         char *curpath, path[MAXPATHLEN], *tofree, *totalpath;
527         uint32_t *lib_version;
528         void *dlh;
529         int ret;
530
531         ret = 0;
532         tofree = totalpath = strdup(library_path());
533         if (totalpath == NULL)
534                 err(EXIT_FAILURE, "Not enough memory for library path");
535
536         if (strchr(totalpath, ':') != NULL)
537                 curpath = strsep(&totalpath, ":");
538         else
539                 curpath = totalpath;
540         /* Traverse the paths to find one that contains the library we want. */
541         while (curpath != NULL) {
542                 snprintf(path, sizeof(path), "%s/geom_%s.so", curpath,
543                     class_name);
544                 ret = access(path, F_OK);
545                 if (ret == -1) {
546                         if (errno == ENOENT) {
547                                 /*
548                                  * If we cannot find library, try the next
549                                  * path.
550                                  */
551                                 curpath = strsep(&totalpath, ":");
552                                 continue;
553                         }
554                         err(EXIT_FAILURE, "Cannot access library");
555                 }
556                 break;
557         }
558         free(tofree);
559         /* No library was found, but standard commands can still be used */
560         if (ret == -1)
561                 return;
562         dlh = dlopen(path, RTLD_NOW);
563         if (dlh == NULL)
564                 errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror());
565         lib_version = dlsym(dlh, "lib_version");
566         if (lib_version == NULL) {
567                 warnx("Cannot find symbol %s: %s.", "lib_version", dlerror());
568                 dlclose(dlh);
569                 exit(EXIT_FAILURE);
570         }
571         if (*lib_version != G_LIB_VERSION) {
572                 dlclose(dlh);
573                 errx(EXIT_FAILURE, "%s and %s are not synchronized.",
574                     getprogname(), path);
575         }
576         version = dlsym(dlh, "version");
577         if (version == NULL) {
578                 warnx("Cannot find symbol %s: %s.", "version", dlerror());
579                 dlclose(dlh);
580                 exit(EXIT_FAILURE);
581         }
582         class_commands = dlsym(dlh, "class_commands");
583         if (class_commands == NULL) {
584                 warnx("Cannot find symbol %s: %s.", "class_commands",
585                     dlerror());
586                 dlclose(dlh);
587                 exit(EXIT_FAILURE);
588         }
589 }
590 #endif  /* !STATIC_GEOM_CLASSES */
591
592 /*
593  * Class name should be all capital letters.
594  */
595 static void
596 set_class_name(void)
597 {
598         char *s1, *s2;
599
600         s1 = class_name;
601         for (; *s1 != '\0'; s1++)
602                 *s1 = tolower(*s1);
603         gclass_name = malloc(strlen(class_name) + 1);
604         if (gclass_name == NULL)
605                 errx(EXIT_FAILURE, "No memory");
606         s1 = gclass_name;
607         s2 = class_name;
608         for (; *s2 != '\0'; s2++)
609                 *s1++ = toupper(*s2);
610         *s1 = '\0';
611 }
612
613 static void
614 get_class(int *argc, char ***argv)
615 {
616
617         snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
618         if (strcmp(comm, "geom") == 0) {
619                 if (*argc < 2)
620                         usage();
621                 else if (*argc == 2) {
622                         if (strcmp((*argv)[1], "-h") == 0 ||
623                             strcmp((*argv)[1], "help") == 0) {
624                                 usage();
625                         }
626                 }
627                 strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
628                 class_name = (*argv)[1];
629                 *argc -= 2;
630                 *argv += 2;
631         } else if (*comm == 'g') {
632                 class_name = comm + 1;
633                 *argc -= 1;
634                 *argv += 1;
635         } else {
636                 errx(EXIT_FAILURE, "Invalid utility name.");
637         }
638
639 #ifndef STATIC_GEOM_CLASSES
640         load_library();
641 #else
642         if (!strcasecmp(class_name, "part")) {
643                 version = &gpart_version;
644                 class_commands = gpart_class_commands;
645         } else if (!strcasecmp(class_name, "label")) {
646                 version = &glabel_version;
647                 class_commands = glabel_class_commands;
648         }
649 #endif /* !STATIC_GEOM_CLASSES */
650
651         set_class_name();
652
653         /* If we can't load or list, it's not a class. */
654         if (!std_available("load") && !std_available("list"))
655                 errx(EXIT_FAILURE, "Invalid class name '%s'.", class_name);
656
657         if (*argc < 1)
658                 usage();
659 }
660
661 static struct ggeom *
662 find_geom_by_provider(struct gmesh *mesh, const char *name)
663 {
664         struct gclass *classp;
665         struct ggeom *gp;
666         struct gprovider *pp;
667
668         LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
669                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
670                         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
671                                 if (strcmp(pp->lg_name, name) == 0)
672                                         return (gp);
673                         }
674                 }
675         }
676
677         return (NULL);
678 }
679
680 static int
681 compute_tree_width_geom(struct gmesh *mesh, struct ggeom *gp, int indent)
682 {
683         struct gclass *classp2;
684         struct ggeom *gp2;
685         struct gconsumer *cp2;
686         struct gprovider *pp;
687         int max_width, width;
688
689         max_width = width = indent + strlen(gp->lg_name);
690
691         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
692                 LIST_FOREACH(classp2, &mesh->lg_class, lg_class) {
693                         LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) {
694                                 LIST_FOREACH(cp2,
695                                     &gp2->lg_consumer, lg_consumer) {
696                                         if (pp != cp2->lg_provider)
697                                                 continue;
698                                         width = compute_tree_width_geom(mesh,
699                                             gp2, indent + 2);
700                                         if (width > max_width)
701                                                 max_width = width;
702                                 }
703                         }
704                 }
705         }
706
707         return (max_width);
708 }
709
710 static int
711 compute_tree_width(struct gmesh *mesh)
712 {
713         struct gclass *classp;
714         struct ggeom *gp;
715         int max_width, width;
716
717         max_width = width = 0;
718
719         LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
720                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
721                         if (!LIST_EMPTY(&gp->lg_consumer))
722                                 continue;
723                         width = compute_tree_width_geom(mesh, gp, 0);
724                         if (width > max_width)
725                                 max_width = width;
726                 }
727         }
728
729         return (max_width);
730 }
731
732 static void
733 show_tree_geom(struct gmesh *mesh, struct ggeom *gp, int indent, int width)
734 {
735         struct gclass *classp2;
736         struct ggeom *gp2;
737         struct gconsumer *cp2;
738         struct gprovider *pp;
739
740         if (LIST_EMPTY(&gp->lg_provider)) {
741                 printf("%*s%-*.*s %-*.*s\n", indent, "",
742                     width - indent, width - indent, gp->lg_name,
743                     GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name);
744                 return;
745         }
746
747         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
748                 printf("%*s%-*.*s %-*.*s %s\n", indent, "",
749                     width - indent, width - indent, gp->lg_name,
750                     GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name,
751                     pp->lg_name);
752
753                 LIST_FOREACH(classp2, &mesh->lg_class, lg_class) {
754                         LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) {
755                                 LIST_FOREACH(cp2,
756                                     &gp2->lg_consumer, lg_consumer) {
757                                         if (pp != cp2->lg_provider)
758                                                 continue;
759                                         show_tree_geom(mesh, gp2,
760                                             indent + 2, width);
761                                 }
762                         }
763                 }
764         }
765 }
766
767 static void
768 show_tree(void)
769 {
770         struct gmesh mesh;
771         struct gclass *classp;
772         struct ggeom *gp;
773         int error, width;
774
775         error = geom_gettree(&mesh);
776         if (error != 0)
777                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
778
779         width = compute_tree_width(&mesh);
780
781         printf("%-*.*s %-*.*s %s\n",
782             width, width, "Geom",
783             GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, "Class",
784             "Provider");
785
786         LIST_FOREACH(classp, &mesh.lg_class, lg_class) {
787                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
788                         if (!LIST_EMPTY(&gp->lg_consumer))
789                                 continue;
790                         show_tree_geom(&mesh, gp, 0, width);
791                 }
792         }
793 }
794
795 int
796 main(int argc, char *argv[])
797 {
798         char *provider_name;
799         bool tflag;
800         int ch;
801
802         provider_name = NULL;
803         tflag = false;
804
805         if (strcmp(getprogname(), "geom") == 0) {
806                 while ((ch = getopt(argc, argv, "hp:t")) != -1) {
807                         switch (ch) {
808                         case 'p':
809                                 provider_name = strdup(optarg);
810                                 if (provider_name == NULL)
811                                         err(1, "strdup");
812                                 break;
813                         case 't':
814                                 tflag = true;
815                                 break;
816                         case 'h':
817                         default:
818                                 usage();
819                         }
820                 }
821
822                 /*
823                  * Don't adjust argc and argv, it would break get_class().
824                  */
825         }
826
827         if (tflag && provider_name != NULL) {
828                 errx(EXIT_FAILURE,
829                     "At most one of -P and -t may be specified.");
830         }
831
832         if (provider_name != NULL) {
833                 list_one_geom_by_provider(provider_name);
834                 return (0);
835         }
836
837         if (tflag) {
838                 show_tree();
839                 return (0);
840         }
841
842         get_class(&argc, &argv);
843         run_command(argc, argv);
844         /* NOTREACHED */
845
846         exit(EXIT_FAILURE);
847 }
848
849 static struct gclass *
850 find_class(struct gmesh *mesh, const char *name)
851 {
852         struct gclass *classp;
853
854         LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
855                 if (strcmp(classp->lg_name, name) == 0)
856                         return (classp);
857         }
858         return (NULL);
859 }
860
861 static struct ggeom *
862 find_geom(struct gclass *classp, const char *name)
863 {
864         struct ggeom *gp;
865
866         if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
867                 name += sizeof(_PATH_DEV) - 1;
868
869         LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
870                 if (strcmp(gp->lg_name, name) == 0)
871                         return (gp);
872         }
873         return (NULL);
874 }
875
876 static void
877 list_one_provider(struct gprovider *pp, const char *prefix)
878 {
879         struct gconfig *conf;
880         char buf[5];
881
882         printf("Name: %s\n", pp->lg_name);
883         humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
884             HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
885         printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
886             buf);
887         printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
888         if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
889                 printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
890                 printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
891         }
892         printf("%sMode: %s\n", prefix, pp->lg_mode);
893         LIST_FOREACH(conf, &pp->lg_config, lg_config) {
894                 printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
895         }
896 }
897
898 static void
899 list_one_consumer(struct gconsumer *cp, const char *prefix)
900 {
901         struct gprovider *pp;
902         struct gconfig *conf;
903
904         pp = cp->lg_provider;
905         if (pp == NULL)
906                 printf("[no provider]\n");
907         else {
908                 char buf[5];
909
910                 printf("Name: %s\n", pp->lg_name);
911                 humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
912                     HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
913                 printf("%sMediasize: %jd (%s)\n", prefix,
914                     (intmax_t)pp->lg_mediasize, buf);
915                 printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
916                 if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
917                         printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
918                         printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
919                 }
920                 printf("%sMode: %s\n", prefix, cp->lg_mode);
921         }
922         LIST_FOREACH(conf, &cp->lg_config, lg_config) {
923                 printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
924         }
925 }
926
927 static void
928 list_one_geom(struct ggeom *gp)
929 {
930         struct gprovider *pp;
931         struct gconsumer *cp;
932         struct gconfig *conf;
933         unsigned n;
934
935         printf("Geom name: %s\n", gp->lg_name);
936         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
937                 printf("%s: %s\n", conf->lg_name, conf->lg_val);
938         }
939         if (!LIST_EMPTY(&gp->lg_provider)) {
940                 printf("Providers:\n");
941                 n = 1;
942                 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
943                         printf("%u. ", n++);
944                         list_one_provider(pp, "   ");
945                 }
946         }
947         if (!LIST_EMPTY(&gp->lg_consumer)) {
948                 printf("Consumers:\n");
949                 n = 1;
950                 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
951                         printf("%u. ", n++);
952                         list_one_consumer(cp, "   ");
953                 }
954         }
955         printf("\n");
956 }
957
958 static void
959 list_one_geom_by_provider(const char *provider_name)
960 {
961         struct gmesh mesh;
962         struct ggeom *gp;
963         int error;
964
965         error = geom_gettree(&mesh);
966         if (error != 0)
967                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
968
969         gp = find_geom_by_provider(&mesh, provider_name);
970         if (gp == NULL)
971                 errx(EXIT_FAILURE, "Cannot find provider '%s'.", provider_name);
972
973         printf("Geom class: %s\n", gp->lg_class->lg_name);
974         list_one_geom(gp);
975 }
976
977 static void
978 std_help(struct gctl_req *req __unused, unsigned flags __unused)
979 {
980
981         usage();
982 }
983
984 static int
985 std_list_available(void)
986 {
987         struct gmesh mesh;
988         struct gclass *classp;
989         int error;
990
991         error = geom_gettree(&mesh);
992         if (error != 0)
993                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
994         classp = find_class(&mesh, gclass_name);
995         geom_deletetree(&mesh);
996         if (classp != NULL)
997                 return (1);
998         return (0);
999 }
1000
1001 static void
1002 std_list(struct gctl_req *req, unsigned flags __unused)
1003 {
1004         struct gmesh mesh;
1005         struct gclass *classp;
1006         struct ggeom *gp;
1007         const char *name;
1008         int all, error, i, nargs;
1009
1010         error = geom_gettree(&mesh);
1011         if (error != 0)
1012                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1013         classp = find_class(&mesh, gclass_name);
1014         if (classp == NULL) {
1015                 geom_deletetree(&mesh);
1016                 errx(EXIT_FAILURE, "Class '%s' not found.", gclass_name);
1017         }
1018         nargs = gctl_get_int(req, "nargs");
1019         all = gctl_get_int(req, "all");
1020         if (nargs > 0) {
1021                 for (i = 0; i < nargs; i++) {
1022                         name = gctl_get_ascii(req, "arg%d", i);
1023                         gp = find_geom(classp, name);
1024                         if (gp == NULL) {
1025                                 errx(EXIT_FAILURE, "Class '%s' does not have "
1026                                     "an instance named '%s'.",
1027                                     gclass_name, name);
1028                         }
1029                         list_one_geom(gp);
1030                 }
1031         } else {
1032                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1033                         if (LIST_EMPTY(&gp->lg_provider) && !all)
1034                                 continue;
1035                         list_one_geom(gp);
1036                 }
1037         }
1038         geom_deletetree(&mesh);
1039 }
1040
1041 static int
1042 std_status_available(void)
1043 {
1044
1045         /* 'status' command is available when 'list' command is. */
1046         return (std_list_available());
1047 }
1048
1049 static void
1050 status_update_len(struct ggeom *gp, int *name_len, int *status_len)
1051 {
1052         struct gconfig *conf;
1053         int len;
1054
1055         assert(gp != NULL);
1056         assert(name_len != NULL);
1057         assert(status_len != NULL);
1058
1059         len = strlen(gp->lg_name);
1060         if (*name_len < len)
1061                 *name_len = len;
1062         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1063                 if (strcasecmp(conf->lg_name, "state") == 0) {
1064                         len = strlen(conf->lg_val);
1065                         if (*status_len < len)
1066                                 *status_len = len;
1067                 }
1068         }
1069 }
1070
1071 static void
1072 status_update_len_prs(struct ggeom *gp, int *name_len, int *status_len)
1073 {
1074         struct gprovider *pp;
1075         struct gconfig *conf;
1076         int len, glen;
1077
1078         assert(gp != NULL);
1079         assert(name_len != NULL);
1080         assert(status_len != NULL);
1081
1082         glen = 0;
1083         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1084                 if (strcasecmp(conf->lg_name, "state") == 0) {
1085                         glen = strlen(conf->lg_val);
1086                         break;
1087                 }
1088         }
1089         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1090                 len = strlen(pp->lg_name);
1091                 if (*name_len < len)
1092                         *name_len = len;
1093                 len = glen;
1094                 LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1095                         if (strcasecmp(conf->lg_name, "state") == 0) {
1096                                 len = strlen(conf->lg_val);
1097                                 break;
1098                         }
1099                 }
1100                 if (*status_len < len)
1101                         *status_len = len;
1102         }
1103 }
1104
1105 static char *
1106 status_one_consumer(struct gconsumer *cp)
1107 {
1108         static char buf[256];
1109         struct gprovider *pp;
1110         struct gconfig *conf;
1111         const char *state, *syncr;
1112
1113         pp = cp->lg_provider;
1114         if (pp == NULL)
1115                 return (NULL);
1116         state = NULL;
1117         syncr = NULL;
1118         LIST_FOREACH(conf, &cp->lg_config, lg_config) {
1119                 if (strcasecmp(conf->lg_name, "state") == 0)
1120                         state = conf->lg_val;
1121                 if (strcasecmp(conf->lg_name, "synchronized") == 0)
1122                         syncr = conf->lg_val;
1123         }
1124         if (state == NULL && syncr == NULL)
1125                 snprintf(buf, sizeof(buf), "%s", pp->lg_name);
1126         else if (state != NULL && syncr != NULL) {
1127                 snprintf(buf, sizeof(buf), "%s (%s, %s)", pp->lg_name,
1128                     state, syncr);
1129         } else {
1130                 snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name,
1131                     state ? state : syncr);
1132         }
1133         return (buf);
1134 }
1135
1136 static void
1137 status_one_geom(struct ggeom *gp, int script, int name_len, int status_len)
1138 {
1139         struct gconsumer *cp;
1140         struct gconfig *conf;
1141         const char *name, *status, *component;
1142         int gotone;
1143
1144         name = gp->lg_name;
1145         status = "N/A";
1146         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1147                 if (strcasecmp(conf->lg_name, "state") == 0) {
1148                         status = conf->lg_val;
1149                         break;
1150                 }
1151         }
1152         gotone = 0;
1153         LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1154                 component = status_one_consumer(cp);
1155                 if (component == NULL)
1156                         continue;
1157                 gotone = 1;
1158                 printf("%*s  %*s  %s\n", name_len, name, status_len, status,
1159                     component);
1160                 if (!script)
1161                         name = status = "";
1162         }
1163         if (!gotone) {
1164                 printf("%*s  %*s  %s\n", name_len, name, status_len, status,
1165                     "N/A");
1166         }
1167 }
1168
1169 static void
1170 status_one_geom_prs(struct ggeom *gp, int script, int name_len, int status_len)
1171 {
1172         struct gprovider *pp;
1173         struct gconsumer *cp;
1174         struct gconfig *conf;
1175         const char *name, *status, *component;
1176         int gotone;
1177
1178         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1179                 name = pp->lg_name;
1180                 status = "N/A";
1181                 LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1182                         if (strcasecmp(conf->lg_name, "state") == 0) {
1183                                 status = conf->lg_val;
1184                                 break;
1185                         }
1186                 }
1187                 LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1188                         if (strcasecmp(conf->lg_name, "state") == 0) {
1189                                 status = conf->lg_val;
1190                                 break;
1191                         }
1192                 }
1193                 gotone = 0;
1194                 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1195                         component = status_one_consumer(cp);
1196                         if (component == NULL)
1197                                 continue;
1198                         gotone = 1;
1199                         printf("%*s  %*s  %s\n", name_len, name,
1200                             status_len, status, component);
1201                         if (!script)
1202                                 name = status = "";
1203                 }
1204                 if (!gotone) {
1205                         printf("%*s  %*s  %s\n", name_len, name,
1206                             status_len, status, "N/A");
1207                 }
1208         }
1209 }
1210
1211 static void
1212 std_status(struct gctl_req *req, unsigned flags __unused)
1213 {
1214         struct gmesh mesh;
1215         struct gclass *classp;
1216         struct ggeom *gp;
1217         const char *name;
1218         int name_len, status_len;
1219         int all, error, geoms, i, n, nargs, script;
1220
1221         error = geom_gettree(&mesh);
1222         if (error != 0)
1223                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1224         classp = find_class(&mesh, gclass_name);
1225         if (classp == NULL)
1226                 errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
1227         nargs = gctl_get_int(req, "nargs");
1228         all = gctl_get_int(req, "all");
1229         geoms = gctl_get_int(req, "geoms");
1230         script = gctl_get_int(req, "script");
1231         if (script) {
1232                 name_len = 0;
1233                 status_len = 0;
1234         } else {
1235                 name_len = strlen("Name");
1236                 status_len = strlen("Status");
1237         }
1238         if (nargs > 0) {
1239                 for (i = 0, n = 0; i < nargs; i++) {
1240                         name = gctl_get_ascii(req, "arg%d", i);
1241                         gp = find_geom(classp, name);
1242                         if (gp == NULL)
1243                                 errx(EXIT_FAILURE, "No such geom: %s.", name);
1244                         if (geoms) {
1245                                 status_update_len(gp,
1246                                     &name_len, &status_len);
1247                         } else {
1248                                 status_update_len_prs(gp,
1249                                     &name_len, &status_len);
1250                         }
1251                         n++;
1252                 }
1253                 if (n == 0)
1254                         goto end;
1255         } else {
1256                 n = 0;
1257                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1258                         if (LIST_EMPTY(&gp->lg_provider) && !all)
1259                                 continue;
1260                         if (geoms) {
1261                                 status_update_len(gp,
1262                                     &name_len, &status_len);
1263                         } else {
1264                                 status_update_len_prs(gp,
1265                                     &name_len, &status_len);
1266                         }
1267                         n++;
1268                 }
1269                 if (n == 0)
1270                         goto end;
1271         }
1272         if (!script) {
1273                 printf("%*s  %*s  %s\n", name_len, "Name", status_len, "Status",
1274                     "Components");
1275         }
1276         if (nargs > 0) {
1277                 for (i = 0; i < nargs; i++) {
1278                         name = gctl_get_ascii(req, "arg%d", i);
1279                         gp = find_geom(classp, name);
1280                         if (gp == NULL)
1281                                 continue;
1282                         if (geoms) {
1283                                 status_one_geom(gp, script, name_len,
1284                                     status_len);
1285                         } else {
1286                                 status_one_geom_prs(gp, script, name_len,
1287                                     status_len);
1288                         }
1289                 }
1290         } else {
1291                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1292                         if (LIST_EMPTY(&gp->lg_provider) && !all)
1293                                 continue;
1294                         if (geoms) {
1295                                 status_one_geom(gp, script, name_len,
1296                                     status_len);
1297                         } else {
1298                                 status_one_geom_prs(gp, script, name_len,
1299                                     status_len);
1300                         }
1301                 }
1302         }
1303 end:
1304         geom_deletetree(&mesh);
1305 }
1306
1307 static int
1308 std_load_available(void)
1309 {
1310         char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
1311         struct stat sb;
1312         size_t len;
1313
1314         snprintf(name, sizeof(name), "g_%s", class_name);
1315         /*
1316          * If already in kernel, "load" command is not available.
1317          */
1318         if (modfind(name) >= 0)
1319                 return (0);
1320         bzero(paths, sizeof(paths));
1321         len = sizeof(paths);
1322         if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
1323                 err(EXIT_FAILURE, "sysctl(kern.module_path)");
1324         for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
1325                 snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
1326                 /*
1327                  * If geom_<name>.ko file exists, "load" command is available.
1328                  */
1329                 if (stat(name, &sb) == 0)
1330                         return (1);
1331         }
1332         return (0);
1333 }
1334
1335 static void
1336 std_load(struct gctl_req *req __unused, unsigned flags)
1337 {
1338
1339         /*
1340          * Do nothing special here, because of G_FLAG_LOADKLD flag,
1341          * module is already loaded.
1342          */
1343         if ((flags & G_FLAG_VERBOSE) != 0)
1344                 printf("Module available.\n");
1345 }
1346
1347 static int
1348 std_unload_available(void)
1349 {
1350         char name[64];
1351         int id;
1352
1353         snprintf(name, sizeof(name), "geom_%s", class_name);
1354         id = kldfind(name);
1355         if (id >= 0)
1356                 return (1);
1357         return (0);
1358 }
1359
1360 static void
1361 std_unload(struct gctl_req *req, unsigned flags __unused)
1362 {
1363         char name[64];
1364         int id;
1365
1366         snprintf(name, sizeof(name), "geom_%s", class_name);
1367         id = kldfind(name);
1368         if (id < 0) {
1369                 gctl_error(req, "Could not find module: %s.", strerror(errno));
1370                 return;
1371         }
1372         if (kldunload(id) < 0) {
1373                 gctl_error(req, "Could not unload module: %s.",
1374                     strerror(errno));
1375                 return;
1376         }
1377 }
1378
1379 static int
1380 std_available(const char *name)
1381 {
1382
1383         if (strcmp(name, "help") == 0)
1384                 return (1);
1385         else if (strcmp(name, "list") == 0)
1386                 return (std_list_available());
1387         else if (strcmp(name, "status") == 0)
1388                 return (std_status_available());
1389         else if (strcmp(name, "load") == 0)
1390                 return (std_load_available());
1391         else if (strcmp(name, "unload") == 0)
1392                 return (std_unload_available());
1393         else
1394                 assert(!"Unknown standard command.");
1395         return (0);
1396 }