]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/geom/core/geom.c
mandoc: import version 1.14.6
[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, vcount;
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         vcount = 0;
340         while ((ch = getopt(*argc, *argv, opts)) != -1) {
341                 /* Standard (not passed to kernel) options. */
342                 if (ch == 'v' && (cmd->gc_flags & G_FLAG_VERBOSE) != 0)
343                         verbose = 1;
344                 /* Options passed to kernel. */
345                 opt = find_option(cmd, ch);
346                 if (opt == NULL) {
347                         if (ch == 'v' && (cmd->gc_flags & G_FLAG_VERBOSE) != 0){
348                                 if (++vcount < 2)
349                                         continue;
350                                 else
351                                         warnx("Option 'v' specified twice.");
352                         }
353                         usage();
354                 }
355                 if (!G_OPT_ISMULTI(opt) && G_OPT_ISDONE(opt)) {
356                         warnx("Option '%c' specified twice.", opt->go_char);
357                         usage();
358                 }
359                 G_OPT_DONE(opt);
360
361                 if (G_OPT_TYPE(opt) == G_TYPE_BOOL)
362                         set_option(req, opt, "1");
363                 else
364                         set_option(req, opt, optarg);
365         }
366         *argc -= optind;
367         *argv += optind;
368
369         /*
370          * Add not specified arguments, but with default values.
371          */
372         for (i = 0; ; i++) {
373                 opt = &cmd->gc_options[i];
374                 if (opt->go_name == NULL)
375                         break;
376                 if (G_OPT_ISDONE(opt))
377                         continue;
378
379                 if (G_OPT_TYPE(opt) == G_TYPE_BOOL) {
380                         assert(opt->go_val == NULL);
381                         set_option(req, opt, "0");
382                 } else {
383                         if (opt->go_val == NULL) {
384                                 warnx("Option '%c' not specified.",
385                                     opt->go_char);
386                                 usage();
387                         } else if (opt->go_val == G_VAL_OPTIONAL) {
388                                 /* add nothing. */
389                         } else {
390                                 set_option(req, opt, opt->go_val);
391                         }
392                 }
393         }
394
395         /*
396          * Add rest of given arguments.
397          */
398         gctl_ro_param(req, "nargs", sizeof(int), argc);
399         for (i = 0; i < (unsigned)*argc; i++) {
400                 char argname[16];
401
402                 snprintf(argname, sizeof(argname), "arg%u", i);
403                 gctl_ro_param(req, argname, -1, (*argv)[i]);
404         }
405 }
406
407 /*
408  * Find given command in commands available for given class.
409  */
410 static struct g_command *
411 find_command(const char *cmdstr, int flags)
412 {
413         struct g_command *cmd;
414         unsigned i;
415
416         /*
417          * First try to find command defined by loaded library.
418          */
419         if ((flags & GEOM_CLASS_CMDS) != 0 && class_commands != NULL) {
420                 for (i = 0; ; i++) {
421                         cmd = &class_commands[i];
422                         if (cmd->gc_name == NULL)
423                                 break;
424                         if (strcmp(cmd->gc_name, cmdstr) == 0)
425                                 return (cmd);
426                 }
427         }
428         /*
429          * Now try to find in standard commands.
430          */
431         if ((flags & GEOM_STD_CMDS) != 0) {
432                 for (i = 0; ; i++) {
433                         cmd = &std_commands[i];
434                         if (cmd->gc_name == NULL)
435                                 break;
436                         if (strcmp(cmd->gc_name, cmdstr) == 0)
437                                 return (cmd);
438                 }
439         }
440         return (NULL);
441 }
442
443 static unsigned
444 set_flags(struct g_command *cmd)
445 {
446         unsigned flags = 0;
447
448         if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose)
449                 flags |= G_FLAG_VERBOSE;
450
451         return (flags);
452 }
453
454 /*
455  * Run command.
456  */
457 static void
458 run_command(int argc, char *argv[])
459 {
460         struct g_command *cmd;
461         struct gctl_req *req;
462         const char *errstr;
463         char buf[4096];
464
465         /* First try to find a command defined by a class. */
466         cmd = find_command(argv[0], GEOM_CLASS_CMDS);
467         if (cmd == NULL) {
468                 /* Now, try to find a standard command. */
469                 cmd = find_command(argv[0], GEOM_STD_CMDS);
470                 if (cmd == NULL) {
471                         warnx("Unknown command: %s.", argv[0]);
472                         usage();
473                 }
474                 if (!std_available(cmd->gc_name)) {
475                         warnx("Command '%s' not available; "
476                             "try 'load' first.", argv[0]);
477                         exit(EXIT_FAILURE);
478                 }
479         }
480         if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0)
481                 load_module();
482
483         req = gctl_get_handle();
484         gctl_ro_param(req, "class", -1, gclass_name);
485         gctl_ro_param(req, "verb", -1, argv[0]);
486         if (version != NULL)
487                 gctl_ro_param(req, "version", sizeof(*version), version);
488         parse_arguments(cmd, req, &argc, &argv);
489
490         bzero(buf, sizeof(buf));
491         if (cmd->gc_func != NULL) {
492                 unsigned flags;
493
494                 flags = set_flags(cmd);
495                 cmd->gc_func(req, flags);
496                 errstr = req->error;
497         } else {
498                 gctl_rw_param(req, "output", sizeof(buf), buf);
499                 errstr = gctl_issue(req);
500         }
501         if (errstr != NULL && errstr[0] != '\0') {
502                 warnx("%s", errstr);
503                 if (strncmp(errstr, "warning: ", strlen("warning: ")) != 0) {
504                         gctl_free(req);
505                         exit(EXIT_FAILURE);
506                 }
507         }
508         if (buf[0] != '\0')
509                 printf("%s", buf);
510         gctl_free(req);
511         if (verbose)
512                 printf("Done.\n");
513         exit(EXIT_SUCCESS);
514 }
515
516 #ifndef STATIC_GEOM_CLASSES
517 static const char *
518 library_path(void)
519 {
520         const char *path;
521
522         path = getenv("GEOM_LIBRARY_PATH");
523         if (path == NULL)
524                 path = GEOM_CLASS_DIR;
525         return (path);
526 }
527
528 static void
529 load_library(void)
530 {
531         char *curpath, path[MAXPATHLEN], *tofree, *totalpath;
532         uint32_t *lib_version;
533         void *dlh;
534         int ret;
535
536         ret = 0;
537         tofree = totalpath = strdup(library_path());
538         if (totalpath == NULL)
539                 err(EXIT_FAILURE, "Not enough memory for library path");
540
541         if (strchr(totalpath, ':') != NULL)
542                 curpath = strsep(&totalpath, ":");
543         else
544                 curpath = totalpath;
545         /* Traverse the paths to find one that contains the library we want. */
546         while (curpath != NULL) {
547                 snprintf(path, sizeof(path), "%s/geom_%s.so", curpath,
548                     class_name);
549                 ret = access(path, F_OK);
550                 if (ret == -1) {
551                         if (errno == ENOENT) {
552                                 /*
553                                  * If we cannot find library, try the next
554                                  * path.
555                                  */
556                                 curpath = strsep(&totalpath, ":");
557                                 continue;
558                         }
559                         err(EXIT_FAILURE, "Cannot access library");
560                 }
561                 break;
562         }
563         free(tofree);
564         /* No library was found, but standard commands can still be used */
565         if (ret == -1)
566                 return;
567         dlh = dlopen(path, RTLD_NOW);
568         if (dlh == NULL)
569                 errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror());
570         lib_version = dlsym(dlh, "lib_version");
571         if (lib_version == NULL) {
572                 warnx("Cannot find symbol %s: %s.", "lib_version", dlerror());
573                 dlclose(dlh);
574                 exit(EXIT_FAILURE);
575         }
576         if (*lib_version != G_LIB_VERSION) {
577                 dlclose(dlh);
578                 errx(EXIT_FAILURE, "%s and %s are not synchronized.",
579                     getprogname(), path);
580         }
581         version = dlsym(dlh, "version");
582         if (version == NULL) {
583                 warnx("Cannot find symbol %s: %s.", "version", dlerror());
584                 dlclose(dlh);
585                 exit(EXIT_FAILURE);
586         }
587         class_commands = dlsym(dlh, "class_commands");
588         if (class_commands == NULL) {
589                 warnx("Cannot find symbol %s: %s.", "class_commands",
590                     dlerror());
591                 dlclose(dlh);
592                 exit(EXIT_FAILURE);
593         }
594 }
595 #endif  /* !STATIC_GEOM_CLASSES */
596
597 /*
598  * Class name should be all capital letters.
599  */
600 static void
601 set_class_name(void)
602 {
603         char *s1, *s2;
604
605         s1 = class_name;
606         for (; *s1 != '\0'; s1++)
607                 *s1 = tolower(*s1);
608         gclass_name = malloc(strlen(class_name) + 1);
609         if (gclass_name == NULL)
610                 errx(EXIT_FAILURE, "No memory");
611         s1 = gclass_name;
612         s2 = class_name;
613         for (; *s2 != '\0'; s2++)
614                 *s1++ = toupper(*s2);
615         *s1 = '\0';
616 }
617
618 static void
619 get_class(int *argc, char ***argv)
620 {
621
622         snprintf(comm, sizeof(comm), "%s", basename((*argv)[0]));
623         if (strcmp(comm, "geom") == 0) {
624                 if (*argc < 2)
625                         usage();
626                 else if (*argc == 2) {
627                         if (strcmp((*argv)[1], "-h") == 0 ||
628                             strcmp((*argv)[1], "help") == 0) {
629                                 usage();
630                         }
631                 }
632                 strlcatf(comm, sizeof(comm), " %s", (*argv)[1]);
633                 class_name = (*argv)[1];
634                 *argc -= 2;
635                 *argv += 2;
636         } else if (*comm == 'g') {
637                 class_name = comm + 1;
638                 *argc -= 1;
639                 *argv += 1;
640         } else {
641                 errx(EXIT_FAILURE, "Invalid utility name.");
642         }
643
644 #ifndef STATIC_GEOM_CLASSES
645         load_library();
646 #else
647         if (!strcasecmp(class_name, "part")) {
648                 version = &gpart_version;
649                 class_commands = gpart_class_commands;
650         } else if (!strcasecmp(class_name, "label")) {
651                 version = &glabel_version;
652                 class_commands = glabel_class_commands;
653         }
654 #endif /* !STATIC_GEOM_CLASSES */
655
656         set_class_name();
657
658         /* If we can't load or list, it's not a class. */
659         if (!std_available("load") && !std_available("list"))
660                 errx(EXIT_FAILURE, "Invalid class name '%s'.", class_name);
661
662         if (*argc < 1)
663                 usage();
664 }
665
666 static struct ggeom *
667 find_geom_by_provider(struct gmesh *mesh, const char *name)
668 {
669         struct gclass *classp;
670         struct ggeom *gp;
671         struct gprovider *pp;
672
673         LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
674                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
675                         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
676                                 if (strcmp(pp->lg_name, name) == 0)
677                                         return (gp);
678                         }
679                 }
680         }
681
682         return (NULL);
683 }
684
685 static int
686 compute_tree_width_geom(struct gmesh *mesh, struct ggeom *gp, int indent)
687 {
688         struct gclass *classp2;
689         struct ggeom *gp2;
690         struct gconsumer *cp2;
691         struct gprovider *pp;
692         int max_width, width;
693
694         max_width = width = indent + strlen(gp->lg_name);
695
696         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
697                 LIST_FOREACH(classp2, &mesh->lg_class, lg_class) {
698                         LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) {
699                                 LIST_FOREACH(cp2,
700                                     &gp2->lg_consumer, lg_consumer) {
701                                         if (pp != cp2->lg_provider)
702                                                 continue;
703                                         width = compute_tree_width_geom(mesh,
704                                             gp2, indent + 2);
705                                         if (width > max_width)
706                                                 max_width = width;
707                                 }
708                         }
709                 }
710         }
711
712         return (max_width);
713 }
714
715 static int
716 compute_tree_width(struct gmesh *mesh)
717 {
718         struct gclass *classp;
719         struct ggeom *gp;
720         int max_width, width;
721
722         max_width = width = 0;
723
724         LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
725                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
726                         if (!LIST_EMPTY(&gp->lg_consumer))
727                                 continue;
728                         width = compute_tree_width_geom(mesh, gp, 0);
729                         if (width > max_width)
730                                 max_width = width;
731                 }
732         }
733
734         return (max_width);
735 }
736
737 static void
738 show_tree_geom(struct gmesh *mesh, struct ggeom *gp, int indent, int width)
739 {
740         struct gclass *classp2;
741         struct ggeom *gp2;
742         struct gconsumer *cp2;
743         struct gprovider *pp;
744
745         if (LIST_EMPTY(&gp->lg_provider)) {
746                 printf("%*s%-*.*s %-*.*s\n", indent, "",
747                     width - indent, width - indent, gp->lg_name,
748                     GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name);
749                 return;
750         }
751
752         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
753                 printf("%*s%-*.*s %-*.*s %s\n", indent, "",
754                     width - indent, width - indent, gp->lg_name,
755                     GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, gp->lg_class->lg_name,
756                     pp->lg_name);
757
758                 LIST_FOREACH(classp2, &mesh->lg_class, lg_class) {
759                         LIST_FOREACH(gp2, &classp2->lg_geom, lg_geom) {
760                                 LIST_FOREACH(cp2,
761                                     &gp2->lg_consumer, lg_consumer) {
762                                         if (pp != cp2->lg_provider)
763                                                 continue;
764                                         show_tree_geom(mesh, gp2,
765                                             indent + 2, width);
766                                 }
767                         }
768                 }
769         }
770 }
771
772 static void
773 show_tree(void)
774 {
775         struct gmesh mesh;
776         struct gclass *classp;
777         struct ggeom *gp;
778         int error, width;
779
780         error = geom_gettree(&mesh);
781         if (error != 0)
782                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
783
784         width = compute_tree_width(&mesh);
785
786         printf("%-*.*s %-*.*s %s\n",
787             width, width, "Geom",
788             GEOM_CLASS_WIDTH, GEOM_CLASS_WIDTH, "Class",
789             "Provider");
790
791         LIST_FOREACH(classp, &mesh.lg_class, lg_class) {
792                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
793                         if (!LIST_EMPTY(&gp->lg_consumer))
794                                 continue;
795                         show_tree_geom(&mesh, gp, 0, width);
796                 }
797         }
798 }
799
800 int
801 main(int argc, char *argv[])
802 {
803         char *provider_name;
804         bool tflag;
805         int ch;
806
807         provider_name = NULL;
808         tflag = false;
809
810         if (strcmp(getprogname(), "geom") == 0) {
811                 while ((ch = getopt(argc, argv, "hp:t")) != -1) {
812                         switch (ch) {
813                         case 'p':
814                                 provider_name = strdup(optarg);
815                                 if (provider_name == NULL)
816                                         err(1, "strdup");
817                                 break;
818                         case 't':
819                                 tflag = true;
820                                 break;
821                         case 'h':
822                         default:
823                                 usage();
824                         }
825                 }
826
827                 /*
828                  * Don't adjust argc and argv, it would break get_class().
829                  */
830         }
831
832         if (tflag && provider_name != NULL) {
833                 errx(EXIT_FAILURE,
834                     "At most one of -P and -t may be specified.");
835         }
836
837         if (provider_name != NULL) {
838                 list_one_geom_by_provider(provider_name);
839                 return (0);
840         }
841
842         if (tflag) {
843                 show_tree();
844                 return (0);
845         }
846
847         get_class(&argc, &argv);
848         run_command(argc, argv);
849         /* NOTREACHED */
850
851         exit(EXIT_FAILURE);
852 }
853
854 static struct gclass *
855 find_class(struct gmesh *mesh, const char *name)
856 {
857         struct gclass *classp;
858
859         LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
860                 if (strcmp(classp->lg_name, name) == 0)
861                         return (classp);
862         }
863         return (NULL);
864 }
865
866 static struct ggeom *
867 find_geom(struct gclass *classp, const char *name)
868 {
869         struct ggeom *gp;
870
871         if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
872                 name += sizeof(_PATH_DEV) - 1;
873
874         LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
875                 if (strcmp(gp->lg_name, name) == 0)
876                         return (gp);
877         }
878         return (NULL);
879 }
880
881 static void
882 list_one_provider(struct gprovider *pp, const char *prefix)
883 {
884         struct gconfig *conf;
885         char buf[5];
886
887         printf("Name: %s\n", pp->lg_name);
888         humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
889             HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
890         printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
891             buf);
892         printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
893         if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
894                 printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
895                 printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
896         }
897         printf("%sMode: %s\n", prefix, pp->lg_mode);
898         LIST_FOREACH(conf, &pp->lg_config, lg_config) {
899                 printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
900         }
901 }
902
903 static void
904 list_one_consumer(struct gconsumer *cp, const char *prefix)
905 {
906         struct gprovider *pp;
907         struct gconfig *conf;
908
909         pp = cp->lg_provider;
910         if (pp == NULL)
911                 printf("[no provider]\n");
912         else {
913                 char buf[5];
914
915                 printf("Name: %s\n", pp->lg_name);
916                 humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
917                     HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
918                 printf("%sMediasize: %jd (%s)\n", prefix,
919                     (intmax_t)pp->lg_mediasize, buf);
920                 printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
921                 if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
922                         printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
923                         printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
924                 }
925                 printf("%sMode: %s\n", prefix, cp->lg_mode);
926         }
927         LIST_FOREACH(conf, &cp->lg_config, lg_config) {
928                 printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
929         }
930 }
931
932 static void
933 list_one_geom(struct ggeom *gp)
934 {
935         struct gprovider *pp;
936         struct gconsumer *cp;
937         struct gconfig *conf;
938         unsigned n;
939
940         printf("Geom name: %s\n", gp->lg_name);
941         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
942                 printf("%s: %s\n", conf->lg_name, conf->lg_val);
943         }
944         if (!LIST_EMPTY(&gp->lg_provider)) {
945                 printf("Providers:\n");
946                 n = 1;
947                 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
948                         printf("%u. ", n++);
949                         list_one_provider(pp, "   ");
950                 }
951         }
952         if (!LIST_EMPTY(&gp->lg_consumer)) {
953                 printf("Consumers:\n");
954                 n = 1;
955                 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
956                         printf("%u. ", n++);
957                         list_one_consumer(cp, "   ");
958                 }
959         }
960         printf("\n");
961 }
962
963 static void
964 list_one_geom_by_provider(const char *provider_name)
965 {
966         struct gmesh mesh;
967         struct ggeom *gp;
968         int error;
969
970         error = geom_gettree(&mesh);
971         if (error != 0)
972                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
973
974         gp = find_geom_by_provider(&mesh, provider_name);
975         if (gp == NULL)
976                 errx(EXIT_FAILURE, "Cannot find provider '%s'.", provider_name);
977
978         printf("Geom class: %s\n", gp->lg_class->lg_name);
979         list_one_geom(gp);
980 }
981
982 static void
983 std_help(struct gctl_req *req __unused, unsigned flags __unused)
984 {
985
986         usage();
987 }
988
989 static int
990 std_list_available(void)
991 {
992         struct gmesh mesh;
993         struct gclass *classp;
994         int error;
995
996         error = geom_gettree(&mesh);
997         if (error != 0)
998                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
999         classp = find_class(&mesh, gclass_name);
1000         geom_deletetree(&mesh);
1001         if (classp != NULL)
1002                 return (1);
1003         return (0);
1004 }
1005
1006 static void
1007 std_list(struct gctl_req *req, unsigned flags __unused)
1008 {
1009         struct gmesh mesh;
1010         struct gclass *classp;
1011         struct ggeom *gp;
1012         const char *name;
1013         int all, error, i, nargs;
1014
1015         error = geom_gettree(&mesh);
1016         if (error != 0)
1017                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1018         classp = find_class(&mesh, gclass_name);
1019         if (classp == NULL) {
1020                 geom_deletetree(&mesh);
1021                 errx(EXIT_FAILURE, "Class '%s' not found.", gclass_name);
1022         }
1023         nargs = gctl_get_int(req, "nargs");
1024         all = gctl_get_int(req, "all");
1025         if (nargs > 0) {
1026                 for (i = 0; i < nargs; i++) {
1027                         name = gctl_get_ascii(req, "arg%d", i);
1028                         gp = find_geom(classp, name);
1029                         if (gp == NULL) {
1030                                 errx(EXIT_FAILURE, "Class '%s' does not have "
1031                                     "an instance named '%s'.",
1032                                     gclass_name, name);
1033                         }
1034                         list_one_geom(gp);
1035                 }
1036         } else {
1037                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1038                         if (LIST_EMPTY(&gp->lg_provider) && !all)
1039                                 continue;
1040                         list_one_geom(gp);
1041                 }
1042         }
1043         geom_deletetree(&mesh);
1044 }
1045
1046 static int
1047 std_status_available(void)
1048 {
1049
1050         /* 'status' command is available when 'list' command is. */
1051         return (std_list_available());
1052 }
1053
1054 static void
1055 status_update_len(struct ggeom *gp, int *name_len, int *status_len)
1056 {
1057         struct gconfig *conf;
1058         int len;
1059
1060         assert(gp != NULL);
1061         assert(name_len != NULL);
1062         assert(status_len != NULL);
1063
1064         len = strlen(gp->lg_name);
1065         if (*name_len < len)
1066                 *name_len = len;
1067         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1068                 if (strcasecmp(conf->lg_name, "state") == 0) {
1069                         len = strlen(conf->lg_val);
1070                         if (*status_len < len)
1071                                 *status_len = len;
1072                 }
1073         }
1074 }
1075
1076 static void
1077 status_update_len_prs(struct ggeom *gp, int *name_len, int *status_len)
1078 {
1079         struct gprovider *pp;
1080         struct gconfig *conf;
1081         int len, glen;
1082
1083         assert(gp != NULL);
1084         assert(name_len != NULL);
1085         assert(status_len != NULL);
1086
1087         glen = 0;
1088         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1089                 if (strcasecmp(conf->lg_name, "state") == 0) {
1090                         glen = strlen(conf->lg_val);
1091                         break;
1092                 }
1093         }
1094         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1095                 len = strlen(pp->lg_name);
1096                 if (*name_len < len)
1097                         *name_len = len;
1098                 len = glen;
1099                 LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1100                         if (strcasecmp(conf->lg_name, "state") == 0) {
1101                                 len = strlen(conf->lg_val);
1102                                 break;
1103                         }
1104                 }
1105                 if (*status_len < len)
1106                         *status_len = len;
1107         }
1108 }
1109
1110 static char *
1111 status_one_consumer(struct gconsumer *cp)
1112 {
1113         static char buf[256];
1114         struct gprovider *pp;
1115         struct gconfig *conf;
1116         const char *state, *syncr;
1117
1118         pp = cp->lg_provider;
1119         if (pp == NULL)
1120                 return (NULL);
1121         state = NULL;
1122         syncr = NULL;
1123         LIST_FOREACH(conf, &cp->lg_config, lg_config) {
1124                 if (strcasecmp(conf->lg_name, "state") == 0)
1125                         state = conf->lg_val;
1126                 if (strcasecmp(conf->lg_name, "synchronized") == 0)
1127                         syncr = conf->lg_val;
1128         }
1129         if (state == NULL && syncr == NULL)
1130                 snprintf(buf, sizeof(buf), "%s", pp->lg_name);
1131         else if (state != NULL && syncr != NULL) {
1132                 snprintf(buf, sizeof(buf), "%s (%s, %s)", pp->lg_name,
1133                     state, syncr);
1134         } else {
1135                 snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name,
1136                     state ? state : syncr);
1137         }
1138         return (buf);
1139 }
1140
1141 static void
1142 status_one_geom(struct ggeom *gp, int script, int name_len, int status_len)
1143 {
1144         struct gconsumer *cp;
1145         struct gconfig *conf;
1146         const char *name, *status, *component;
1147         int gotone;
1148
1149         name = gp->lg_name;
1150         status = "N/A";
1151         LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1152                 if (strcasecmp(conf->lg_name, "state") == 0) {
1153                         status = conf->lg_val;
1154                         break;
1155                 }
1156         }
1157         gotone = 0;
1158         LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1159                 component = status_one_consumer(cp);
1160                 if (component == NULL)
1161                         continue;
1162                 gotone = 1;
1163                 printf("%*s  %*s  %s\n", name_len, name, status_len, status,
1164                     component);
1165                 if (!script)
1166                         name = status = "";
1167         }
1168         if (!gotone) {
1169                 printf("%*s  %*s  %s\n", name_len, name, status_len, status,
1170                     "N/A");
1171         }
1172 }
1173
1174 static void
1175 status_one_geom_prs(struct ggeom *gp, int script, int name_len, int status_len)
1176 {
1177         struct gprovider *pp;
1178         struct gconsumer *cp;
1179         struct gconfig *conf;
1180         const char *name, *status, *component;
1181         int gotone;
1182
1183         LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
1184                 name = pp->lg_name;
1185                 status = "N/A";
1186                 LIST_FOREACH(conf, &gp->lg_config, lg_config) {
1187                         if (strcasecmp(conf->lg_name, "state") == 0) {
1188                                 status = conf->lg_val;
1189                                 break;
1190                         }
1191                 }
1192                 LIST_FOREACH(conf, &pp->lg_config, lg_config) {
1193                         if (strcasecmp(conf->lg_name, "state") == 0) {
1194                                 status = conf->lg_val;
1195                                 break;
1196                         }
1197                 }
1198                 gotone = 0;
1199                 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
1200                         component = status_one_consumer(cp);
1201                         if (component == NULL)
1202                                 continue;
1203                         gotone = 1;
1204                         printf("%*s  %*s  %s\n", name_len, name,
1205                             status_len, status, component);
1206                         if (!script)
1207                                 name = status = "";
1208                 }
1209                 if (!gotone) {
1210                         printf("%*s  %*s  %s\n", name_len, name,
1211                             status_len, status, "N/A");
1212                 }
1213         }
1214 }
1215
1216 static void
1217 std_status(struct gctl_req *req, unsigned flags __unused)
1218 {
1219         struct gmesh mesh;
1220         struct gclass *classp;
1221         struct ggeom *gp;
1222         const char *name;
1223         int name_len, status_len;
1224         int all, error, geoms, i, n, nargs, script;
1225
1226         error = geom_gettree(&mesh);
1227         if (error != 0)
1228                 errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
1229         classp = find_class(&mesh, gclass_name);
1230         if (classp == NULL)
1231                 errx(EXIT_FAILURE, "Class %s not found.", gclass_name);
1232         nargs = gctl_get_int(req, "nargs");
1233         all = gctl_get_int(req, "all");
1234         geoms = gctl_get_int(req, "geoms");
1235         script = gctl_get_int(req, "script");
1236         if (script) {
1237                 name_len = 0;
1238                 status_len = 0;
1239         } else {
1240                 name_len = strlen("Name");
1241                 status_len = strlen("Status");
1242         }
1243         if (nargs > 0) {
1244                 for (i = 0, n = 0; i < nargs; i++) {
1245                         name = gctl_get_ascii(req, "arg%d", i);
1246                         gp = find_geom(classp, name);
1247                         if (gp == NULL)
1248                                 errx(EXIT_FAILURE, "No such geom: %s.", name);
1249                         if (geoms) {
1250                                 status_update_len(gp,
1251                                     &name_len, &status_len);
1252                         } else {
1253                                 status_update_len_prs(gp,
1254                                     &name_len, &status_len);
1255                         }
1256                         n++;
1257                 }
1258                 if (n == 0)
1259                         goto end;
1260         } else {
1261                 n = 0;
1262                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1263                         if (LIST_EMPTY(&gp->lg_provider) && !all)
1264                                 continue;
1265                         if (geoms) {
1266                                 status_update_len(gp,
1267                                     &name_len, &status_len);
1268                         } else {
1269                                 status_update_len_prs(gp,
1270                                     &name_len, &status_len);
1271                         }
1272                         n++;
1273                 }
1274                 if (n == 0)
1275                         goto end;
1276         }
1277         if (!script) {
1278                 printf("%*s  %*s  %s\n", name_len, "Name", status_len, "Status",
1279                     "Components");
1280         }
1281         if (nargs > 0) {
1282                 for (i = 0; i < nargs; i++) {
1283                         name = gctl_get_ascii(req, "arg%d", i);
1284                         gp = find_geom(classp, name);
1285                         if (gp == NULL)
1286                                 continue;
1287                         if (geoms) {
1288                                 status_one_geom(gp, script, name_len,
1289                                     status_len);
1290                         } else {
1291                                 status_one_geom_prs(gp, script, name_len,
1292                                     status_len);
1293                         }
1294                 }
1295         } else {
1296                 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
1297                         if (LIST_EMPTY(&gp->lg_provider) && !all)
1298                                 continue;
1299                         if (geoms) {
1300                                 status_one_geom(gp, script, name_len,
1301                                     status_len);
1302                         } else {
1303                                 status_one_geom_prs(gp, script, name_len,
1304                                     status_len);
1305                         }
1306                 }
1307         }
1308 end:
1309         geom_deletetree(&mesh);
1310 }
1311
1312 static int
1313 std_load_available(void)
1314 {
1315         char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p;
1316         struct stat sb;
1317         size_t len;
1318
1319         snprintf(name, sizeof(name), "g_%s", class_name);
1320         /*
1321          * If already in kernel, "load" command is not available.
1322          */
1323         if (modfind(name) >= 0)
1324                 return (0);
1325         bzero(paths, sizeof(paths));
1326         len = sizeof(paths);
1327         if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0)
1328                 err(EXIT_FAILURE, "sysctl(kern.module_path)");
1329         for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) {
1330                 snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name);
1331                 /*
1332                  * If geom_<name>.ko file exists, "load" command is available.
1333                  */
1334                 if (stat(name, &sb) == 0)
1335                         return (1);
1336         }
1337         return (0);
1338 }
1339
1340 static void
1341 std_load(struct gctl_req *req __unused, unsigned flags)
1342 {
1343
1344         /*
1345          * Do nothing special here, because of G_FLAG_LOADKLD flag,
1346          * module is already loaded.
1347          */
1348         if ((flags & G_FLAG_VERBOSE) != 0)
1349                 printf("Module available.\n");
1350 }
1351
1352 static int
1353 std_unload_available(void)
1354 {
1355         char name[64];
1356         int id;
1357
1358         snprintf(name, sizeof(name), "geom_%s", class_name);
1359         id = kldfind(name);
1360         if (id >= 0)
1361                 return (1);
1362         return (0);
1363 }
1364
1365 static void
1366 std_unload(struct gctl_req *req, unsigned flags __unused)
1367 {
1368         char name[64];
1369         int id;
1370
1371         snprintf(name, sizeof(name), "geom_%s", class_name);
1372         id = kldfind(name);
1373         if (id < 0) {
1374                 gctl_error(req, "Could not find module: %s.", strerror(errno));
1375                 return;
1376         }
1377         if (kldunload(id) < 0) {
1378                 gctl_error(req, "Could not unload module: %s.",
1379                     strerror(errno));
1380                 return;
1381         }
1382 }
1383
1384 static int
1385 std_available(const char *name)
1386 {
1387
1388         if (strcmp(name, "help") == 0)
1389                 return (1);
1390         else if (strcmp(name, "list") == 0)
1391                 return (std_list_available());
1392         else if (strcmp(name, "status") == 0)
1393                 return (std_status_available());
1394         else if (strcmp(name, "load") == 0)
1395                 return (std_load_available());
1396         else if (strcmp(name, "unload") == 0)
1397                 return (std_unload_available());
1398         else
1399                 assert(!"Unknown standard command.");
1400         return (0);
1401 }