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