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