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