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 path[MAXPATHLEN]; 489 uint32_t *lib_version; 490 void *dlh; 491 492 snprintf(path, sizeof(path), "%s/geom_%s.so", library_path(), 493 class_name); 494 if (access(path, F_OK) == -1) { 495 if (errno == ENOENT) { 496 /* 497 * If we cannot find library, that's ok, standard 498 * commands can still be used. 499 */ 500 return; 501 } 502 err(EXIT_FAILURE, "Cannot access library"); 503 } 504 dlh = dlopen(path, RTLD_NOW); 505 if (dlh == NULL) 506 errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror()); 507 lib_version = dlsym(dlh, "lib_version"); 508 if (lib_version == NULL) { 509 warnx("Cannot find symbol %s: %s.", "lib_version", dlerror()); 510 dlclose(dlh); 511 exit(EXIT_FAILURE); 512 } 513 if (*lib_version != G_LIB_VERSION) { 514 dlclose(dlh); 515 errx(EXIT_FAILURE, "%s and %s are not synchronized.", 516 getprogname(), path); 517 } 518 version = dlsym(dlh, "version"); 519 if (version == NULL) { 520 warnx("Cannot find symbol %s: %s.", "version", dlerror()); 521 dlclose(dlh); 522 exit(EXIT_FAILURE); 523 } 524 class_commands = dlsym(dlh, "class_commands"); 525 if (class_commands == NULL) { 526 warnx("Cannot find symbol %s: %s.", "class_commands", 527 dlerror()); 528 dlclose(dlh); 529 exit(EXIT_FAILURE); 530 } 531 } 532 #endif /* !RESCUE */ 533 534 /* 535 * Class name should be all capital letters. 536 */ 537 static void 538 set_class_name(void) 539 { 540 char *s1, *s2; 541 542 s1 = class_name; 543 for (; *s1 != '\0'; s1++) 544 *s1 = tolower(*s1); 545 gclass_name = malloc(strlen(class_name) + 1); 546 if (gclass_name == NULL) 547 errx(EXIT_FAILURE, "No memory"); 548 s1 = gclass_name; 549 s2 = class_name; 550 for (; *s2 != '\0'; s2++) 551 *s1++ = toupper(*s2); 552 *s1 = '\0'; 553 } 554 555 static void 556 get_class(int *argc, char ***argv) 557 { 558 559 snprintf(comm, sizeof(comm), "%s", basename((*argv)[0])); 560 if (strcmp(comm, "geom") == 0) { 561 if (*argc < 2) 562 usage(); 563 else if (*argc == 2) { 564 if (strcmp((*argv)[1], "-h") == 0 || 565 strcmp((*argv)[1], "help") == 0) { 566 usage(); 567 } 568 } 569 strlcatf(comm, sizeof(comm), " %s", (*argv)[1]); 570 class_name = (*argv)[1]; 571 *argc -= 2; 572 *argv += 2; 573 } else if (*comm == 'g') { 574 class_name = comm + 1; 575 *argc -= 1; 576 *argv += 1; 577 } else { 578 errx(EXIT_FAILURE, "Invalid utility name."); 579 } 580 581 #ifndef RESCUE 582 load_library(); 583 #else 584 if (!strcasecmp(class_name, "part")) { 585 version = &gpart_version; 586 class_commands = gpart_class_commands; 587 } else 588 errx(EXIT_FAILURE, "Invalid class name."); 589 #endif /* !RESCUE */ 590 591 set_class_name(); 592 if (*argc < 1) 593 usage(); 594 } 595 596 int 597 main(int argc, char *argv[]) 598 { 599 600 get_class(&argc, &argv); 601 run_command(argc, argv); 602 /* NOTREACHED */ 603 604 exit(EXIT_FAILURE); 605 } 606 607 static struct gclass * 608 find_class(struct gmesh *mesh, const char *name) 609 { 610 struct gclass *classp; 611 612 LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 613 if (strcmp(classp->lg_name, name) == 0) 614 return (classp); 615 } 616 return (NULL); 617 } 618 619 static struct ggeom * 620 find_geom(struct gclass *classp, const char *name) 621 { 622 struct ggeom *gp; 623 624 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 625 if (strcmp(gp->lg_name, name) == 0) 626 return (gp); 627 } 628 return (NULL); 629 } 630 631 static void 632 list_one_provider(struct gprovider *pp, const char *prefix) 633 { 634 struct gconfig *conf; 635 char buf[5]; 636 637 printf("Name: %s\n", pp->lg_name); 638 humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "", 639 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 640 printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize, 641 buf); 642 printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize); 643 printf("%sMode: %s\n", prefix, pp->lg_mode); 644 LIST_FOREACH(conf, &pp->lg_config, lg_config) { 645 printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val); 646 } 647 } 648 649 static void 650 list_one_consumer(struct gconsumer *cp, const char *prefix) 651 { 652 struct gprovider *pp; 653 struct gconfig *conf; 654 655 pp = cp->lg_provider; 656 if (pp == NULL) 657 printf("[no provider]\n"); 658 else { 659 char buf[5]; 660 661 printf("Name: %s\n", pp->lg_name); 662 humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "", 663 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 664 printf("%sMediasize: %jd (%s)\n", prefix, 665 (intmax_t)pp->lg_mediasize, buf); 666 printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize); 667 printf("%sMode: %s\n", prefix, cp->lg_mode); 668 } 669 LIST_FOREACH(conf, &cp->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_geom(struct ggeom *gp) 676 { 677 struct gprovider *pp; 678 struct gconsumer *cp; 679 struct gconfig *conf; 680 unsigned n; 681 682 printf("Geom name: %s\n", gp->lg_name); 683 LIST_FOREACH(conf, &gp->lg_config, lg_config) { 684 printf("%s: %s\n", conf->lg_name, conf->lg_val); 685 } 686 if (!LIST_EMPTY(&gp->lg_provider)) { 687 printf("Providers:\n"); 688 n = 1; 689 LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 690 printf("%u. ", n++); 691 list_one_provider(pp, " "); 692 } 693 } 694 if (!LIST_EMPTY(&gp->lg_consumer)) { 695 printf("Consumers:\n"); 696 n = 1; 697 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) { 698 printf("%u. ", n++); 699 list_one_consumer(cp, " "); 700 } 701 } 702 printf("\n"); 703 } 704 705 static void 706 std_help(struct gctl_req *req __unused, unsigned flags __unused) 707 { 708 709 usage(); 710 } 711 712 static int 713 std_list_available(void) 714 { 715 struct gmesh mesh; 716 struct gclass *classp; 717 int error; 718 719 error = geom_gettree(&mesh); 720 if (error != 0) 721 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 722 classp = find_class(&mesh, gclass_name); 723 geom_deletetree(&mesh); 724 if (classp != NULL) 725 return (1); 726 return (0); 727 } 728 729 static void 730 std_list(struct gctl_req *req, unsigned flags __unused) 731 { 732 struct gmesh mesh; 733 struct gclass *classp; 734 struct ggeom *gp; 735 const char *name; 736 int error, i, nargs; 737 738 error = geom_gettree(&mesh); 739 if (error != 0) 740 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 741 classp = find_class(&mesh, gclass_name); 742 if (classp == NULL) { 743 geom_deletetree(&mesh); 744 errx(EXIT_FAILURE, "Class %s not found.", gclass_name); 745 } 746 nargs = gctl_get_int(req, "nargs"); 747 if (nargs > 0) { 748 for (i = 0; i < nargs; i++) { 749 name = gctl_get_ascii(req, "arg%d", i); 750 gp = find_geom(classp, name); 751 if (gp != NULL) 752 list_one_geom(gp); 753 else 754 errx(EXIT_FAILURE, "No such geom: %s.", name); 755 } 756 } else { 757 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 758 if (LIST_EMPTY(&gp->lg_provider)) 759 continue; 760 list_one_geom(gp); 761 } 762 } 763 geom_deletetree(&mesh); 764 } 765 766 static int 767 std_status_available(void) 768 { 769 770 /* 'status' command is available when 'list' command is. */ 771 return (std_list_available()); 772 } 773 774 static void 775 status_update_len(struct ggeom *gp, int *name_len, int *status_len) 776 { 777 struct gprovider *pp; 778 struct gconfig *conf; 779 int len; 780 781 assert(gp != NULL); 782 assert(name_len != NULL); 783 assert(status_len != NULL); 784 785 pp = LIST_FIRST(&gp->lg_provider); 786 if (pp != NULL) 787 len = strlen(pp->lg_name); 788 else 789 len = strlen(gp->lg_name); 790 if (*name_len < len) 791 *name_len = len; 792 LIST_FOREACH(conf, &gp->lg_config, lg_config) { 793 if (strcasecmp(conf->lg_name, "state") == 0) { 794 len = strlen(conf->lg_val); 795 if (*status_len < len) 796 *status_len = len; 797 } 798 } 799 } 800 801 static char * 802 status_one_consumer(struct gconsumer *cp) 803 { 804 static char buf[256]; 805 struct gprovider *pp; 806 struct gconfig *conf; 807 808 pp = cp->lg_provider; 809 if (pp == NULL) 810 return (NULL); 811 LIST_FOREACH(conf, &cp->lg_config, lg_config) { 812 if (strcasecmp(conf->lg_name, "synchronized") == 0) 813 break; 814 } 815 if (conf == NULL) 816 snprintf(buf, sizeof(buf), "%s", pp->lg_name); 817 else { 818 snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name, 819 conf->lg_val); 820 } 821 return (buf); 822 } 823 824 static void 825 status_one_geom(struct ggeom *gp, int script, int name_len, int status_len) 826 { 827 struct gprovider *pp; 828 struct gconsumer *cp; 829 struct gconfig *conf; 830 const char *name, *status, *component; 831 int gotone; 832 833 pp = LIST_FIRST(&gp->lg_provider); 834 if (pp != NULL) 835 name = pp->lg_name; 836 else 837 name = gp->lg_name; 838 LIST_FOREACH(conf, &gp->lg_config, lg_config) { 839 if (strcasecmp(conf->lg_name, "state") == 0) 840 break; 841 } 842 if (conf == NULL) 843 status = "N/A"; 844 else 845 status = conf->lg_val; 846 gotone = 0; 847 LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) { 848 component = status_one_consumer(cp); 849 if (component == NULL) 850 continue; 851 gotone = 1; 852 printf("%*s %*s %s\n", name_len, name, status_len, status, 853 component); 854 if (!script) 855 name = status = ""; 856 } 857 if (!gotone) { 858 printf("%*s %*s %s\n", name_len, name, status_len, status, 859 "N/A"); 860 } 861 } 862 863 static void 864 std_status(struct gctl_req *req, unsigned flags __unused) 865 { 866 struct gmesh mesh; 867 struct gclass *classp; 868 struct ggeom *gp; 869 const char *name; 870 int name_len, status_len; 871 int error, i, n, nargs, script; 872 873 error = geom_gettree(&mesh); 874 if (error != 0) 875 errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 876 classp = find_class(&mesh, gclass_name); 877 if (classp == NULL) 878 errx(EXIT_FAILURE, "Class %s not found.", gclass_name); 879 nargs = gctl_get_int(req, "nargs"); 880 script = gctl_get_int(req, "script"); 881 name_len = strlen("Name"); 882 status_len = strlen("Status"); 883 if (nargs > 0) { 884 for (i = 0, n = 0; i < nargs; i++) { 885 name = gctl_get_ascii(req, "arg%d", i); 886 gp = find_geom(classp, name); 887 if (gp == NULL) 888 errx(EXIT_FAILURE, "No such geom: %s.", name); 889 else { 890 status_update_len(gp, &name_len, &status_len); 891 n++; 892 } 893 } 894 if (n == 0) 895 goto end; 896 } else { 897 n = 0; 898 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 899 if (LIST_EMPTY(&gp->lg_provider)) 900 continue; 901 status_update_len(gp, &name_len, &status_len); 902 n++; 903 } 904 if (n == 0) 905 goto end; 906 } 907 if (!script) { 908 printf("%*s %*s %s\n", name_len, "Name", status_len, "Status", 909 "Components"); 910 } 911 if (nargs > 0) { 912 for (i = 0; i < nargs; i++) { 913 name = gctl_get_ascii(req, "arg%d", i); 914 gp = find_geom(classp, name); 915 if (gp != NULL) { 916 status_one_geom(gp, script, name_len, 917 status_len); 918 } 919 } 920 } else { 921 LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 922 if (LIST_EMPTY(&gp->lg_provider)) 923 continue; 924 status_one_geom(gp, script, name_len, status_len); 925 } 926 } 927 end: 928 geom_deletetree(&mesh); 929 } 930 931 static int 932 std_load_available(void) 933 { 934 char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p; 935 struct stat sb; 936 size_t len; 937 938 snprintf(name, sizeof(name), "g_%s", class_name); 939 /* 940 * If already in kernel, "load" command is not available. 941 */ 942 if (modfind(name) >= 0) 943 return (0); 944 bzero(paths, sizeof(paths)); 945 len = sizeof(paths); 946 if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0) 947 err(EXIT_FAILURE, "sysctl(kern.module_path)"); 948 for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) { 949 snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name); 950 /* 951 * If geom_<name>.ko file exists, "load" command is available. 952 */ 953 if (stat(name, &sb) == 0) 954 return (1); 955 } 956 return (0); 957 } 958 959 static void 960 std_load(struct gctl_req *req __unused, unsigned flags) 961 { 962 963 /* 964 * Do nothing special here, because of G_FLAG_LOADKLD flag, 965 * module is already loaded. 966 */ 967 if ((flags & G_FLAG_VERBOSE) != 0) 968 printf("Module available.\n"); 969 } 970 971 static int 972 std_unload_available(void) 973 { 974 char name[64]; 975 int id; 976 977 snprintf(name, sizeof(name), "geom_%s", class_name); 978 id = kldfind(name); 979 if (id >= 0) 980 return (1); 981 return (0); 982 } 983 984 static void 985 std_unload(struct gctl_req *req, unsigned flags __unused) 986 { 987 char name[64]; 988 int id; 989 990 snprintf(name, sizeof(name), "geom_%s", class_name); 991 id = kldfind(name); 992 if (id < 0) { 993 gctl_error(req, "Could not find module: %s.", strerror(errno)); 994 return; 995 } 996 if (kldunload(id) < 0) { 997 gctl_error(req, "Could not unload module: %s.", 998 strerror(errno)); 999 return; 1000 } 1001 } 1002 1003 static int 1004 std_available(const char *name) 1005 { 1006 1007 if (strcmp(name, "help") == 0) 1008 return (1); 1009 else if (strcmp(name, "list") == 0) 1010 return (std_list_available()); 1011 else if (strcmp(name, "status") == 0) 1012 return (std_status_available()); 1013 else if (strcmp(name, "load") == 0) 1014 return (std_load_available()); 1015 else if (strcmp(name, "unload") == 0) 1016 return (std_unload_available()); 1017 else 1018 assert(!"Unknown standard command."); 1019 return (0); 1020 } 1021