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