1 /*- 2 * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/linker.h> 32 #include <sys/module.h> 33 #include <sys/stat.h> 34 #include <sys/sysctl.h> 35 #include <ctype.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <stdarg.h> 41 #include <stdint.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <libgen.h> 45 #include <libutil.h> 46 #include <inttypes.h> 47 #include <dlfcn.h> 48 #include <assert.h> 49 #include <libgeom.h> 50 #include <geom.h> 51 52 #include "misc/subr.h" 53 54 #ifdef RESCUE 55 extern uint32_t gpart_version; 56 extern struct g_command gpart_class_commands[]; 57 extern uint32_t glabel_version; 58 extern struct g_command glabel_class_commands[]; 59 #endif 60 61 static char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL; 62 static uint32_t *version = NULL; 63 static int verbose = 0; 64 static struct g_command *class_commands = NULL; 65 66 #define GEOM_CLASS_CMDS 0x01 67 #define GEOM_STD_CMDS 0x02 68 static struct g_command *find_command(const char *cmdstr, int flags); 69 static int std_available(const char *name); 70 71 static void std_help(struct gctl_req *req, unsigned flags); 72 static void std_list(struct gctl_req *req, unsigned flags); 73 static void std_status(struct gctl_req *req, unsigned flags); 74 static void std_load(struct gctl_req *req, unsigned flags); 75 static void std_unload(struct gctl_req *req, unsigned flags); 76 77 struct g_command std_commands[] = { 78 { "help", 0, std_help, G_NULL_OPTS, NULL, NULL }, 79 { "list", 0, std_list, G_NULL_OPTS, NULL, 80 "[name ...]" 81 }, 82 { "status", 0, std_status, 83 { 84 { 's', "script", NULL, G_TYPE_BOOL }, 85 G_OPT_SENTINEL 86 }, 87 NULL, "[-s] [name ...]" 88 }, 89 { "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS, 90 NULL, NULL }, 91 { "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS, NULL, NULL }, 92 G_CMD_SENTINEL 93 }; 94 95 static void 96 usage_command(struct g_command *cmd, const char *prefix) 97 { 98 struct g_option *opt; 99 unsigned i; 100 101 fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name); 102 if (cmd->gc_usage != NULL) { 103 fprintf(stderr, " %s\n", cmd->gc_usage); 104 return; 105 } 106 if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0) 107 fprintf(stderr, " [-v]"); 108 for (i = 0; ; i++) { 109 opt = &cmd->gc_options[i]; 110 if (opt->go_name == NULL) 111 break; 112 if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL) 113 fprintf(stderr, " ["); 114 else 115 fprintf(stderr, " "); 116 fprintf(stderr, "-%c", opt->go_char); 117 if (G_OPT_TYPE(opt) != G_TYPE_BOOL) 118 fprintf(stderr, " %s", opt->go_name); 119 if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL) 120 fprintf(stderr, "]"); 121 } 122 if (cmd->gc_argname) 123 fprintf(stderr, " %s", cmd->gc_argname); 124 fprintf(stderr, "\n"); 125 } 126 127 static void 128 usage(void) 129 { 130 131 if (class_name == NULL) { 132 errx(EXIT_FAILURE, "usage: %s <class> <command> [options]", 133 "geom"); 134 } else { 135 struct g_command *cmd; 136 const char *prefix; 137 unsigned i; 138 139 prefix = "usage:"; 140 if (class_commands != NULL) { 141 for (i = 0; ; i++) { 142 cmd = &class_commands[i]; 143 if (cmd->gc_name == NULL) 144 break; 145 usage_command(cmd, prefix); 146 prefix = " "; 147 } 148 } 149 for (i = 0; ; i++) { 150 cmd = &std_commands[i]; 151 if (cmd->gc_name == NULL) 152 break; 153 /* 154 * If class defines command, which has the same name as 155 * standard command, skip it, because it was already 156 * shown on usage(). 157 */ 158 if (find_command(cmd->gc_name, GEOM_CLASS_CMDS) != NULL) 159 continue; 160 usage_command(cmd, prefix); 161 prefix = " "; 162 } 163 exit(EXIT_FAILURE); 164 } 165 } 166 167 static void 168 load_module(void) 169 { 170 char name1[64], name2[64]; 171 172 snprintf(name1, sizeof(name1), "g_%s", class_name); 173 snprintf(name2, sizeof(name2), "geom_%s", class_name); 174 if (modfind(name1) < 0) { 175 /* Not present in kernel, try loading it. */ 176 if (kldload(name2) < 0 || modfind(name1) < 0) { 177 if (errno != EEXIST) { 178 errx(EXIT_FAILURE, 179 "%s module not available!", name2); 180 } 181 } 182 } 183 } 184 185 static int 186 strlcatf(char *str, size_t size, const char *format, ...) 187 { 188 size_t len; 189 va_list ap; 190 int ret; 191 192 len = strlen(str); 193 str += len; 194 size -= len; 195 196 va_start(ap, format); 197 ret = vsnprintf(str, size, format, ap); 198 va_end(ap); 199 200 return (ret); 201 } 202 203 /* 204 * Find given option in options available for given command. 205 */ 206 static struct g_option * 207 find_option(struct g_command *cmd, char ch) 208 { 209 struct g_option *opt; 210 unsigned i; 211 212 for (i = 0; ; i++) { 213 opt = &cmd->gc_options[i]; 214 if (opt->go_name == NULL) 215 return (NULL); 216 if (opt->go_char == ch) 217 return (opt); 218 } 219 /* NOTREACHED */ 220 return (NULL); 221 } 222 223 /* 224 * Add given option to gctl_req. 225 */ 226 static void 227 set_option(struct gctl_req *req, struct g_option *opt, const char *val) 228 { 229 230 if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) { 231 intmax_t number; 232 233 if (expand_number(val, &number) == -1) { 234 err(EXIT_FAILURE, "Invalid value for '%c' argument.", 235 opt->go_char); 236 } 237 opt->go_val = malloc(sizeof(intmax_t)); 238 if (opt->go_val == NULL) 239 errx(EXIT_FAILURE, "No memory."); 240 *(intmax_t *)opt->go_val = number; 241 242 gctl_ro_param(req, opt->go_name, sizeof(intmax_t), opt->go_val); 243 } else if (G_OPT_TYPE(opt) == G_TYPE_STRING) { 244 gctl_ro_param(req, opt->go_name, -1, val); 245 } else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) { 246 opt->go_val = malloc(sizeof(int)); 247 if (opt->go_val == NULL) 248 errx(EXIT_FAILURE, "No memory."); 249 *(int *)opt->go_val = *val - '0'; 250 251 gctl_ro_param(req, opt->go_name, sizeof(int), 252 opt->go_val); 253 } else { 254 assert(!"Invalid type"); 255 } 256 } 257 258 /* 259 * 1. Add given argument by caller. 260 * 2. Add default values of not given arguments. 261 * 3. Add the rest of arguments. 262 */ 263 static void 264 parse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc, 265 char ***argv) 266 { 267 struct g_option *opt; 268 char opts[64]; 269 unsigned i; 270 int ch; 271 272 *opts = '\0'; 273 if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0) 274 strlcat(opts, "v", sizeof(opts)); 275 for (i = 0; ; i++) { 276 opt = &cmd->gc_options[i]; 277 if (opt->go_name == NULL) 278 break; 279 assert(G_OPT_TYPE(opt) != 0); 280 assert((opt->go_type & ~G_TYPE_MASK) == 0); 281 strlcatf(opts, sizeof(opts), "%c", opt->go_char); 282 if (G_OPT_TYPE(opt) != G_TYPE_BOOL) 283 strlcat(opts, ":", sizeof(opts)); 284 } 285 286 /* 287 * Add specified arguments. 288 */ 289 while ((ch = getopt(*argc, *argv, opts)) != -1) { 290 /* Standard (not passed to kernel) options. */ 291 switch (ch) { 292 case 'v': 293 verbose = 1; 294 continue; 295 } 296 /* Options passed to kernel. */ 297 opt = find_option(cmd, ch); 298 if (opt == NULL) 299 usage(); 300 if (G_OPT_ISDONE(opt)) { 301 warnx("Option '%c' specified twice.", opt->go_char); 302 usage(); 303 } 304 G_OPT_DONE(opt); 305 306 if (G_OPT_TYPE(opt) == G_TYPE_BOOL) 307 set_option(req, opt, "1"); 308 else 309 set_option(req, opt, optarg); 310 } 311 *argc -= optind; 312 *argv += optind; 313 314 /* 315 * Add not specified arguments, but with default values. 316 */ 317 for (i = 0; ; i++) { 318 opt = &cmd->gc_options[i]; 319 if (opt->go_name == NULL) 320 break; 321 if (G_OPT_ISDONE(opt)) 322 continue; 323 324 if (G_OPT_TYPE(opt) == G_TYPE_BOOL) { 325 assert(opt->go_val == NULL); 326 set_option(req, opt, "0"); 327 } else { 328 if (opt->go_val == NULL) { 329 warnx("Option '%c' not specified.", 330 opt->go_char); 331 usage(); 332 } else { 333 if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) { 334 gctl_ro_param(req, opt->go_name, 335 sizeof(intmax_t), opt->go_val); 336 } else if (G_OPT_TYPE(opt) == G_TYPE_STRING) { 337 if (cmd->gc_argname == NULL || 338 opt->go_val == NULL || 339 *(char *)opt->go_val != '\0') 340 gctl_ro_param(req, opt->go_name, 341 -1, opt->go_val); 342 } else { 343 assert(!"Invalid type"); 344 } 345 } 346 } 347 } 348 349 if (cmd->gc_argname == NULL) { 350 /* 351 * Add rest of given arguments. 352 */ 353 gctl_ro_param(req, "nargs", sizeof(int), argc); 354 for (i = 0; i < (unsigned)*argc; i++) { 355 char argname[16]; 356 357 snprintf(argname, sizeof(argname), "arg%u", i); 358 gctl_ro_param(req, argname, -1, (*argv)[i]); 359 } 360 } else { 361 if (*argc != 1) 362 usage(); 363 gctl_ro_param(req, cmd->gc_argname, -1, (*argv)[0]); 364 } 365 } 366 367 /* 368 * Find given command in commands available for given class. 369 */ 370 static struct g_command * 371 find_command(const char *cmdstr, int flags) 372 { 373 struct g_command *cmd; 374 unsigned i; 375 376 /* 377 * First try to find command defined by loaded library. 378 */ 379 if ((flags & GEOM_CLASS_CMDS) != 0 && class_commands != NULL) { 380 for (i = 0; ; i++) { 381 cmd = &class_commands[i]; 382 if (cmd->gc_name == NULL) 383 break; 384 if (strcmp(cmd->gc_name, cmdstr) == 0) 385 return (cmd); 386 } 387 } 388 /* 389 * Now try to find in standard commands. 390 */ 391 if ((flags & GEOM_STD_CMDS) != 0) { 392 for (i = 0; ; i++) { 393 cmd = &std_commands[i]; 394 if (cmd->gc_name == NULL) 395 break; 396 if (strcmp(cmd->gc_name, cmdstr) == 0) 397 return (cmd); 398 } 399 } 400 return (NULL); 401 } 402 403 static unsigned 404 set_flags(struct g_command *cmd) 405 { 406 unsigned flags = 0; 407 408 if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose) 409 flags |= G_FLAG_VERBOSE; 410 411 return (flags); 412 } 413 414 /* 415 * Run command. 416 */ 417 static void 418 run_command(int argc, char *argv[]) 419 { 420 struct g_command *cmd; 421 struct gctl_req *req; 422 const char *errstr; 423 char buf[4096]; 424 425 /* First try to find a command defined by a class. */ 426 cmd = find_command(argv[0], GEOM_CLASS_CMDS); 427 if (cmd == NULL) { 428 /* Now, try to find a standard command. */ 429 cmd = find_command(argv[0], GEOM_STD_CMDS); 430 if (cmd == NULL) { 431 warnx("Unknown command: %s.", argv[0]); 432 usage(); 433 } 434 if (!std_available(cmd->gc_name)) { 435 warnx("Command '%s' not available.", argv[0]); 436 exit(EXIT_FAILURE); 437 } 438 } 439 if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0) 440 load_module(); 441 442 req = gctl_get_handle(); 443 gctl_ro_param(req, "class", -1, gclass_name); 444 gctl_ro_param(req, "verb", -1, argv[0]); 445 if (version != NULL) 446 gctl_ro_param(req, "version", sizeof(*version), version); 447 parse_arguments(cmd, req, &argc, &argv); 448 449 bzero(buf, sizeof(buf)); 450 if (cmd->gc_func != NULL) { 451 unsigned flags; 452 453 flags = set_flags(cmd); 454 cmd->gc_func(req, flags); 455 errstr = req->error; 456 } else { 457 gctl_rw_param(req, "output", sizeof(buf), buf); 458 errstr = gctl_issue(req); 459 } 460 if (errstr != NULL && errstr[0] != '\0') { 461 warnx("%s", errstr); 462 if (strncmp(errstr, "warning: ", strlen("warning: ")) != 0) { 463 gctl_free(req); 464 exit(EXIT_FAILURE); 465 } 466 } 467 if (buf[0] != '\0') 468 printf("%s", buf); 469 gctl_free(req); 470 if (verbose) 471 printf("Done.\n"); 472 exit(EXIT_SUCCESS); 473 } 474 475 #ifndef RESCUE 476 static const char * 477 library_path(void) 478 { 479 const char *path; 480 481 path = getenv("GEOM_LIBRARY_PATH"); 482 if (path == NULL) 483 path = CLASS_DIR; 484 return (path); 485 } 486 487 static void 488 load_library(void) 489 { 490 char *curpath, path[MAXPATHLEN], *totalpath; 491 uint32_t *lib_version; 492 void *dlh; 493 int ret; 494 495 ret = 0; 496 totalpath = strdup(library_path()); 497 if (totalpath == NULL) 498 err(EXIT_FAILURE, "Not enough memory for library path"); 499 500 if (strchr(totalpath, ':') != NULL) 501 curpath = strsep(&totalpath, ":"); 502 else 503 curpath = totalpath; 504 /* Traverse the paths to find one that contains the library we want. */ 505 while (curpath != NULL) { 506 snprintf(path, sizeof(path), "%s/geom_%s.so", curpath, 507 class_name); 508 ret = access(path, F_OK); 509 if (ret == -1) { 510 if (errno == ENOENT) { 511 /* 512 * If we cannot find library, try the next 513 * path. 514 */ 515 curpath = strsep(&totalpath, ":"); 516 continue; 517 } 518 err(EXIT_FAILURE, "Cannot access library"); 519 } 520 break; 521 } 522 free(totalpath); 523 /* No library was found, but standard commands can still be used */ 524 if (ret == -1) 525 return; 526 dlh = dlopen(path, RTLD_NOW); 527 if (dlh == NULL) 528 errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror()); 529 lib_version = dlsym(dlh, "lib_version"); 530 if (lib_version == NULL) { 531 warnx("Cannot find symbol %s: %s.", "lib_version", dlerror()); 532 dlclose(dlh); 533 exit(EXIT_FAILURE); 534 } 535 if (*lib_version != G_LIB_VERSION) { 536 dlclose(dlh); 537 errx(EXIT_FAILURE, "%s and %s are not synchronized.", 538 getprogname(), path); 539 } 540 version = dlsym(dlh, "version"); 541 if (version == NULL) { 542 warnx("Cannot find symbol %s: %s.", "version", dlerror()); 543 dlclose(dlh); 544 exit(EXIT_FAILURE); 545 } 546 class_commands = dlsym(dlh, "class_commands"); 547 if (class_commands == NULL) { 548 warnx("Cannot find symbol %s: %s.", "class_commands", 549 dlerror()); 550 dlclose(dlh); 551 exit(EXIT_FAILURE); 552 } 553 } 554 #endif /* !RESCUE */ 555 556 /* 557 * Class name should be all capital letters. 558 */ 559 static void 560 set_class_name(void) 561 { 562 char *s1, *s2; 563 564 s1 = class_name; 565 for (; *s1 != '\0'; s1++) 566 *s1 = tolower(*s1); 567 gclass_name = malloc(strlen(class_name) + 1); 568 if (gclass_name == NULL) 569 errx(EXIT_FAILURE, "No memory"); 570 s1 = gclass_name; 571 s2 = class_name; 572 for (; *s2 != '\0'; s2++) 573 *s1++ = toupper(*s2); 574 *s1 = '\0'; 575 } 576 577 static void 578 get_class(int *argc, char ***argv) 579 { 580 581 snprintf(comm, sizeof(comm), "%s", basename((*argv)[0])); 582 if (strcmp(comm, "geom") == 0) { 583 if (*argc < 2) 584 usage(); 585 else if (*argc == 2) { 586 if (strcmp((*argv)[1], "-h") == 0 || 587 strcmp((*argv)[1], "help") == 0) { 588 usage(); 589 } 590 } 591 strlcatf(comm, sizeof(comm), " %s", (*argv)[1]); 592 class_name = (*argv)[1]; 593 *argc -= 2; 594 *argv += 2; 595 } else if (*comm == 'g') { 596 class_name = comm + 1; 597 *argc -= 1; 598 *argv += 1; 599 } else { 600 errx(EXIT_FAILURE, "Invalid utility name."); 601 } 602 603 #ifndef RESCUE 604 load_library(); 605 #else 606 if (!strcasecmp(class_name, "part")) { 607 version = &gpart_version; 608 class_commands = gpart_class_commands; 609 } else if (!strcasecmp(class_name, "label")) { 610 version = &glabel_version; 611 class_commands = glabel_class_commands; 612 } else 613 errx(EXIT_FAILURE, "Invalid class name."); 614 #endif /* !RESCUE */ 615 616 set_class_name(); 617 if (*argc < 1) 618 usage(); 619 } 620 621 int 622 main(int argc, char *argv[]) 623 { 624 625 get_class(&argc, &argv); 626 run_command(argc, argv); 627 /* NOTREACHED */ 628 629 exit(EXIT_FAILURE); 630 } 631 632 static struct gclass * 633 find_class(struct gmesh *mesh, const char *name) 634 { 635 struct gclass *classp; 636 637 LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 638 if (strcmp(classp->lg_name, name) == 0) 639 return (classp); 640 } 641 return (NULL); 642 } 643 644 static struct ggeom * 645 find_geom(struct gclass *classp, const char *name) 646 { 647 struct ggeom *gp; 648 649 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 650 if (strcmp(gp->lg_name, name) == 0) 651 return (gp); 652 } 653 return (NULL); 654 } 655 656 static void 657 list_one_provider(struct gprovider *pp, const char *prefix) 658 { 659 struct gconfig *conf; 660 char buf[5]; 661 662 printf("Name: %s\n", pp->lg_name); 663 humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "", 664 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 665 printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize, 666 buf); 667 printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize); 668 printf("%sMode: %s\n", prefix, pp->lg_mode); 669 LIST_FOREACH(conf, &pp->lg_config, lg_config) { 670 printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val); 671 } 672 } 673 674 static void 675 list_one_consumer(struct gconsumer *cp, const char *prefix) 676 { 677 struct gprovider *pp; 678 struct gconfig *conf; 679 680 pp = cp->lg_provider; 681 if (pp == NULL) 682 printf("[no provider]\n"); 683 else { 684 char buf[5]; 685 686 printf("Name: %s\n", pp->lg_name); 687 humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "", 688 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 689 printf("%sMediasize: %jd (%s)\n", prefix, 690 (intmax_t)pp->lg_mediasize, buf); 691 printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize); 692 printf("%sMode: %s\n", prefix, cp->lg_mode); 693 } 694 LIST_FOREACH(conf, &cp->lg_config, lg_config) { 695 printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val); 696 } 697 } 698 699 static void 700 list_one_geom(struct ggeom *gp) 701 { 702 struct gprovider *pp; 703 struct gconsumer *cp; 704 struct gconfig *conf; 705 unsigned n; 706 707 printf("Geom name: %s\n", gp->lg_name); 708 LIST_FOREACH(conf, &gp->lg_config, lg_config) { 709 printf("%s: %s\n", conf->lg_name, conf->lg_val); 710 } 711 if (!LIST_EMPTY(&gp->lg_provider)) { 712 printf("Providers:\n"); 713 n = 1; 714 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 715 printf("%u. ", n++); 716 list_one_provider(pp, " "); 717 } 718 } 719 if (!LIST_EMPTY(&gp->lg_consumer)) { 720 printf("Consumers:\n"); 721 n = 1; 722 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) { 723 printf("%u. ", n++); 724 list_one_consumer(cp, " "); 725 } 726 } 727 printf("\n"); 728 } 729 730 static void 731 std_help(struct gctl_req *req __unused, unsigned flags __unused) 732 { 733 734 usage(); 735 } 736 737 static int 738 std_list_available(void) 739 { 740 struct gmesh mesh; 741 struct gclass *classp; 742 int error; 743 744 error = geom_gettree(&mesh); 745 if (error != 0) 746 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 747 classp = find_class(&mesh, gclass_name); 748 geom_deletetree(&mesh); 749 if (classp != NULL) 750 return (1); 751 return (0); 752 } 753 754 static void 755 std_list(struct gctl_req *req, unsigned flags __unused) 756 { 757 struct gmesh mesh; 758 struct gclass *classp; 759 struct ggeom *gp; 760 const char *name; 761 int error, i, nargs; 762 763 error = geom_gettree(&mesh); 764 if (error != 0) 765 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 766 classp = find_class(&mesh, gclass_name); 767 if (classp == NULL) { 768 geom_deletetree(&mesh); 769 errx(EXIT_FAILURE, "Class %s not found.", gclass_name); 770 } 771 nargs = gctl_get_int(req, "nargs"); 772 if (nargs > 0) { 773 for (i = 0; i < nargs; i++) { 774 name = gctl_get_ascii(req, "arg%d", i); 775 gp = find_geom(classp, name); 776 if (gp != NULL) 777 list_one_geom(gp); 778 else 779 errx(EXIT_FAILURE, "No such geom: %s.", name); 780 } 781 } else { 782 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 783 if (LIST_EMPTY(&gp->lg_provider)) 784 continue; 785 list_one_geom(gp); 786 } 787 } 788 geom_deletetree(&mesh); 789 } 790 791 static int 792 std_status_available(void) 793 { 794 795 /* 'status' command is available when 'list' command is. */ 796 return (std_list_available()); 797 } 798 799 static void 800 status_update_len(struct ggeom *gp, int *name_len, int *status_len) 801 { 802 struct gprovider *pp; 803 struct gconfig *conf; 804 int len; 805 806 assert(gp != NULL); 807 assert(name_len != NULL); 808 assert(status_len != NULL); 809 810 pp = LIST_FIRST(&gp->lg_provider); 811 if (pp != NULL) 812 len = strlen(pp->lg_name); 813 else 814 len = strlen(gp->lg_name); 815 if (*name_len < len) 816 *name_len = len; 817 LIST_FOREACH(conf, &gp->lg_config, lg_config) { 818 if (strcasecmp(conf->lg_name, "state") == 0) { 819 len = strlen(conf->lg_val); 820 if (*status_len < len) 821 *status_len = len; 822 } 823 } 824 } 825 826 static char * 827 status_one_consumer(struct gconsumer *cp) 828 { 829 static char buf[256]; 830 struct gprovider *pp; 831 struct gconfig *conf; 832 833 pp = cp->lg_provider; 834 if (pp == NULL) 835 return (NULL); 836 LIST_FOREACH(conf, &cp->lg_config, lg_config) { 837 if (strcasecmp(conf->lg_name, "synchronized") == 0) 838 break; 839 } 840 if (conf == NULL) 841 snprintf(buf, sizeof(buf), "%s", pp->lg_name); 842 else { 843 snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name, 844 conf->lg_val); 845 } 846 return (buf); 847 } 848 849 static void 850 status_one_geom(struct ggeom *gp, int script, int name_len, int status_len) 851 { 852 struct gprovider *pp; 853 struct gconsumer *cp; 854 struct gconfig *conf; 855 const char *name, *status, *component; 856 int gotone; 857 858 pp = LIST_FIRST(&gp->lg_provider); 859 if (pp != NULL) 860 name = pp->lg_name; 861 else 862 name = gp->lg_name; 863 LIST_FOREACH(conf, &gp->lg_config, lg_config) { 864 if (strcasecmp(conf->lg_name, "state") == 0) 865 break; 866 } 867 if (conf == NULL) 868 status = "N/A"; 869 else 870 status = conf->lg_val; 871 gotone = 0; 872 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) { 873 component = status_one_consumer(cp); 874 if (component == NULL) 875 continue; 876 gotone = 1; 877 printf("%*s %*s %s\n", name_len, name, status_len, status, 878 component); 879 if (!script) 880 name = status = ""; 881 } 882 if (!gotone) { 883 printf("%*s %*s %s\n", name_len, name, status_len, status, 884 "N/A"); 885 } 886 } 887 888 static void 889 std_status(struct gctl_req *req, unsigned flags __unused) 890 { 891 struct gmesh mesh; 892 struct gclass *classp; 893 struct ggeom *gp; 894 const char *name; 895 int name_len, status_len; 896 int error, i, n, nargs, script; 897 898 error = geom_gettree(&mesh); 899 if (error != 0) 900 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 901 classp = find_class(&mesh, gclass_name); 902 if (classp == NULL) 903 errx(EXIT_FAILURE, "Class %s not found.", gclass_name); 904 nargs = gctl_get_int(req, "nargs"); 905 script = gctl_get_int(req, "script"); 906 name_len = strlen("Name"); 907 status_len = strlen("Status"); 908 if (nargs > 0) { 909 for (i = 0, n = 0; i < nargs; i++) { 910 name = gctl_get_ascii(req, "arg%d", i); 911 gp = find_geom(classp, name); 912 if (gp == NULL) 913 errx(EXIT_FAILURE, "No such geom: %s.", name); 914 else { 915 status_update_len(gp, &name_len, &status_len); 916 n++; 917 } 918 } 919 if (n == 0) 920 goto end; 921 } else { 922 n = 0; 923 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 924 if (LIST_EMPTY(&gp->lg_provider)) 925 continue; 926 status_update_len(gp, &name_len, &status_len); 927 n++; 928 } 929 if (n == 0) 930 goto end; 931 } 932 if (!script) { 933 printf("%*s %*s %s\n", name_len, "Name", status_len, "Status", 934 "Components"); 935 } 936 if (nargs > 0) { 937 for (i = 0; i < nargs; i++) { 938 name = gctl_get_ascii(req, "arg%d", i); 939 gp = find_geom(classp, name); 940 if (gp != NULL) { 941 status_one_geom(gp, script, name_len, 942 status_len); 943 } 944 } 945 } else { 946 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 947 if (LIST_EMPTY(&gp->lg_provider)) 948 continue; 949 status_one_geom(gp, script, name_len, status_len); 950 } 951 } 952 end: 953 geom_deletetree(&mesh); 954 } 955 956 static int 957 std_load_available(void) 958 { 959 char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p; 960 struct stat sb; 961 size_t len; 962 963 snprintf(name, sizeof(name), "g_%s", class_name); 964 /* 965 * If already in kernel, "load" command is not available. 966 */ 967 if (modfind(name) >= 0) 968 return (0); 969 bzero(paths, sizeof(paths)); 970 len = sizeof(paths); 971 if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0) 972 err(EXIT_FAILURE, "sysctl(kern.module_path)"); 973 for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) { 974 snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name); 975 /* 976 * If geom_<name>.ko file exists, "load" command is available. 977 */ 978 if (stat(name, &sb) == 0) 979 return (1); 980 } 981 return (0); 982 } 983 984 static void 985 std_load(struct gctl_req *req __unused, unsigned flags) 986 { 987 988 /* 989 * Do nothing special here, because of G_FLAG_LOADKLD flag, 990 * module is already loaded. 991 */ 992 if ((flags & G_FLAG_VERBOSE) != 0) 993 printf("Module available.\n"); 994 } 995 996 static int 997 std_unload_available(void) 998 { 999 char name[64]; 1000 int id; 1001 1002 snprintf(name, sizeof(name), "geom_%s", class_name); 1003 id = kldfind(name); 1004 if (id >= 0) 1005 return (1); 1006 return (0); 1007 } 1008 1009 static void 1010 std_unload(struct gctl_req *req, unsigned flags __unused) 1011 { 1012 char name[64]; 1013 int id; 1014 1015 snprintf(name, sizeof(name), "geom_%s", class_name); 1016 id = kldfind(name); 1017 if (id < 0) { 1018 gctl_error(req, "Could not find module: %s.", strerror(errno)); 1019 return; 1020 } 1021 if (kldunload(id) < 0) { 1022 gctl_error(req, "Could not unload module: %s.", 1023 strerror(errno)); 1024 return; 1025 } 1026 } 1027 1028 static int 1029 std_available(const char *name) 1030 { 1031 1032 if (strcmp(name, "help") == 0) 1033 return (1); 1034 else if (strcmp(name, "list") == 0) 1035 return (std_list_available()); 1036 else if (strcmp(name, "status") == 0) 1037 return (std_status_available()); 1038 else if (strcmp(name, "load") == 0) 1039 return (std_load_available()); 1040 else if (strcmp(name, "unload") == 0) 1041 return (std_unload_available()); 1042 else 1043 assert(!"Unknown standard command."); 1044 return (0); 1045 } 1046