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