geom.c revision 129470
1129470Spjd/*- 2129470Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3129470Spjd * All rights reserved. 4129470Spjd * 5129470Spjd * Redistribution and use in source and binary forms, with or without 6129470Spjd * modification, are permitted provided that the following conditions 7129470Spjd * are met: 8129470Spjd * 1. Redistributions of source code must retain the above copyright 9129470Spjd * notice, this list of conditions and the following disclaimer. 10129470Spjd * 2. Redistributions in binary form must reproduce the above copyright 11129470Spjd * notice, this list of conditions and the following disclaimer in the 12129470Spjd * documentation and/or other materials provided with the distribution. 13129470Spjd * 14129470Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15129470Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16129470Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17129470Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18129470Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19129470Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20129470Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21129470Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22129470Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23129470Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24129470Spjd * SUCH DAMAGE. 25129470Spjd */ 26129470Spjd 27129470Spjd#include <sys/cdefs.h> 28129470Spjd__FBSDID("$FreeBSD: head/sbin/geom/core/geom.c 129470 2004-05-20 10:09:56Z pjd $"); 29129470Spjd 30129470Spjd#include <sys/param.h> 31129470Spjd#include <sys/linker.h> 32129470Spjd#include <sys/module.h> 33129470Spjd#include <sys/stat.h> 34129470Spjd#include <sys/sysctl.h> 35129470Spjd#include <ctype.h> 36129470Spjd#include <err.h> 37129470Spjd#include <errno.h> 38129470Spjd#include <stdio.h> 39129470Spjd#include <stdlib.h> 40129470Spjd#include <stdarg.h> 41129470Spjd#include <stdint.h> 42129470Spjd#include <string.h> 43129470Spjd#include <unistd.h> 44129470Spjd#include <libgen.h> 45129470Spjd#include <inttypes.h> 46129470Spjd#include <dlfcn.h> 47129470Spjd#include <assert.h> 48129470Spjd#include <libgeom.h> 49129470Spjd#include <geom.h> 50129470Spjd 51129470Spjd#include "misc/subr.h" 52129470Spjd 53129470Spjd 54129470Spjdstatic char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL; 55129470Spjdstatic uint32_t *version = NULL; 56129470Spjdstatic int verbose = 0; 57129470Spjdstatic struct g_command *class_commands = NULL; 58129470Spjdstatic void (*usage)(const char *name); 59129470Spjd 60129470Spjdstatic struct g_command *find_command(const char *cmdstr, int all); 61129470Spjdstatic int std_available(const char *name); 62129470Spjd 63129470Spjdstatic void std_list(struct gctl_req *req, unsigned flags); 64129470Spjdstatic void std_load(struct gctl_req *req, unsigned flags); 65129470Spjdstatic void std_unload(struct gctl_req *req, unsigned flags); 66129470Spjd 67129470Spjdstruct g_command std_commands[] = { 68129470Spjd { "list", 0, std_list, G_NULL_OPTS }, 69129470Spjd { "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS }, 70129470Spjd { "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS }, 71129470Spjd G_CMD_SENTINEL 72129470Spjd}; 73129470Spjd 74129470Spjdstatic void 75129470Spjdstd_usage(const char *name) 76129470Spjd{ 77129470Spjd struct g_command *cmd; 78129470Spjd struct g_option *opt; 79129470Spjd unsigned i, j; 80129470Spjd 81129470Spjd for (i = 0; ; i++) { 82129470Spjd cmd = &class_commands[i]; 83129470Spjd if (cmd->gc_name == NULL) 84129470Spjd break; 85129470Spjd fprintf(stderr, "%s %s %s %s", i == 0 ? "usage:" : " ", 86129470Spjd name, class_name, cmd->gc_name); 87129470Spjd if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0) 88129470Spjd fprintf(stderr, " [-v]"); 89129470Spjd for (j = 0; ; j++) { 90129470Spjd opt = &cmd->gc_options[j]; 91129470Spjd if (opt->go_name == NULL) 92129470Spjd break; 93129470Spjd if (opt->go_val != NULL || opt->go_type == G_TYPE_NONE) 94129470Spjd fprintf(stderr, " ["); 95129470Spjd else 96129470Spjd fprintf(stderr, " "); 97129470Spjd fprintf(stderr, "-%c", opt->go_char); 98129470Spjd if (opt->go_type != G_TYPE_NONE) 99129470Spjd fprintf(stderr, " %s", opt->go_name); 100129470Spjd if (opt->go_val != NULL || opt->go_type == G_TYPE_NONE) 101129470Spjd fprintf(stderr, "]"); 102129470Spjd } 103129470Spjd fprintf(stderr, " ...\n"); 104129470Spjd } 105129470Spjd exit(EXIT_FAILURE); 106129470Spjd} 107129470Spjd 108129470Spjdstatic void 109129470Spjdgeom_usage(void) 110129470Spjd{ 111129470Spjd 112129470Spjd if (class_name == NULL) { 113129470Spjd errx(EXIT_FAILURE, "usage: %s <class name> <command> " 114129470Spjd "[options]", "geom"); 115129470Spjd } else { 116129470Spjd const char *prefix; 117129470Spjd unsigned i; 118129470Spjd 119129470Spjd if (usage == NULL) 120129470Spjd prefix = "usage:"; 121129470Spjd else { 122129470Spjd usage(comm); 123129470Spjd prefix = " "; 124129470Spjd } 125129470Spjd for (i = 0; ; i++) { 126129470Spjd struct g_command *cmd; 127129470Spjd 128129470Spjd cmd = &std_commands[i]; 129129470Spjd if (cmd->gc_name == NULL) 130129470Spjd break; 131129470Spjd if (find_command(cmd->gc_name, 0) != NULL) 132129470Spjd continue; 133129470Spjd if (!std_available(cmd->gc_name)) 134129470Spjd continue; 135129470Spjd fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name); 136129470Spjd if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0) 137129470Spjd fprintf(stderr, " [-v]"); 138129470Spjd fprintf(stderr, "\n"); 139129470Spjd prefix = " "; 140129470Spjd } 141129470Spjd exit(EXIT_FAILURE); 142129470Spjd } 143129470Spjd} 144129470Spjd 145129470Spjdstatic void 146129470Spjdload_module(void) 147129470Spjd{ 148129470Spjd char name1[64], name2[64]; 149129470Spjd 150129470Spjd snprintf(name1, sizeof(name1), "g_%s", class_name); 151129470Spjd snprintf(name2, sizeof(name2), "geom_%s", class_name); 152129470Spjd if (modfind(name1) < 0) { 153129470Spjd /* Not present in kernel, try loading it. */ 154129470Spjd if (kldload(name2) < 0 || modfind(name1) < 0) { 155129470Spjd if (errno != EEXIST) { 156129470Spjd errx(EXIT_FAILURE, 157129470Spjd "%s module not available!", name2); 158129470Spjd } 159129470Spjd } 160129470Spjd } 161129470Spjd} 162129470Spjd 163129470Spjdstatic int 164129470Spjdstrlcatf(char *str, size_t size, const char *format, ...) 165129470Spjd{ 166129470Spjd size_t len; 167129470Spjd va_list ap; 168129470Spjd int ret; 169129470Spjd 170129470Spjd len = strlen(str); 171129470Spjd str += len; 172129470Spjd size -= len; 173129470Spjd 174129470Spjd va_start(ap, format); 175129470Spjd ret = vsnprintf(str, size, format, ap); 176129470Spjd va_end(ap); 177129470Spjd 178129470Spjd return (ret); 179129470Spjd} 180129470Spjd 181129470Spjd/* 182129470Spjd * Find given option in options available for given command. 183129470Spjd */ 184129470Spjdstatic struct g_option * 185129470Spjdfind_option(struct g_command *cmd, char ch) 186129470Spjd{ 187129470Spjd struct g_option *opt; 188129470Spjd unsigned i; 189129470Spjd 190129470Spjd for (i = 0; ; i++) { 191129470Spjd opt = &cmd->gc_options[i]; 192129470Spjd if (opt->go_name == NULL) 193129470Spjd return (NULL); 194129470Spjd if (opt->go_char == ch) 195129470Spjd return (opt); 196129470Spjd } 197129470Spjd /* NOTREACHED */ 198129470Spjd return (NULL); 199129470Spjd} 200129470Spjd 201129470Spjd/* 202129470Spjd * Add given option to gctl_req. 203129470Spjd */ 204129470Spjdstatic void 205129470Spjdset_option(struct gctl_req *req, struct g_option *opt, const char *val) 206129470Spjd{ 207129470Spjd 208129470Spjd if (opt->go_type == G_TYPE_NUMBER) { 209129470Spjd intmax_t number; 210129470Spjd 211129470Spjd errno = 0; 212129470Spjd number = strtoimax(optarg, NULL, 0); 213129470Spjd if (errno != 0) { 214129470Spjd err(EXIT_FAILURE, "Invalid value for '%c' argument.", 215129470Spjd opt->go_char); 216129470Spjd } 217129470Spjd opt->go_val = malloc(sizeof(intmax_t)); 218129470Spjd if (opt->go_val == NULL) 219129470Spjd errx(EXIT_FAILURE, "No memory."); 220129470Spjd *(intmax_t *)opt->go_val = number; 221129470Spjd 222129470Spjd gctl_ro_param(req, opt->go_name, sizeof(intmax_t), opt->go_val); 223129470Spjd } else if (opt->go_type == G_TYPE_STRING) { 224129470Spjd gctl_ro_param(req, opt->go_name, -1, optarg); 225129470Spjd } else /* if (opt->go_type == G_TYPE_NONE) */ { 226129470Spjd opt->go_val = malloc(sizeof(int)); 227129470Spjd if (opt->go_val == NULL) 228129470Spjd errx(EXIT_FAILURE, "No memory."); 229129470Spjd *(int *)opt->go_val = *val - '0'; 230129470Spjd 231129470Spjd gctl_ro_param(req, opt->go_name, sizeof(int), 232129470Spjd opt->go_val); 233129470Spjd } 234129470Spjd} 235129470Spjd 236129470Spjd/* 237129470Spjd * 1. Add given argument by caller. 238129470Spjd * 2. Add default values of not given arguments. 239129470Spjd * 3. Add the rest of arguments. 240129470Spjd */ 241129470Spjdstatic void 242129470Spjdparse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc, 243129470Spjd char ***argv) 244129470Spjd{ 245129470Spjd struct g_option *opt; 246129470Spjd char opts[64]; 247129470Spjd unsigned i; 248129470Spjd int ch; 249129470Spjd 250129470Spjd *opts = '\0'; 251129470Spjd if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0) 252129470Spjd strlcat(opts, "v", sizeof(opts)); 253129470Spjd for (i = 0; ; i++) { 254129470Spjd opt = &cmd->gc_options[i]; 255129470Spjd if (opt->go_name == NULL) 256129470Spjd break; 257129470Spjd strlcatf(opts, sizeof(opts), "%c", opt->go_char); 258129470Spjd if (opt->go_type != G_TYPE_NONE) 259129470Spjd strlcat(opts, ":", sizeof(opts)); 260129470Spjd } 261129470Spjd 262129470Spjd /* 263129470Spjd * Add specified arguments. 264129470Spjd */ 265129470Spjd while ((ch = getopt(*argc, *argv, opts)) != -1) { 266129470Spjd /* Standard (not passed to kernel) options. */ 267129470Spjd switch (ch) { 268129470Spjd case 'v': 269129470Spjd verbose = 1; 270129470Spjd continue; 271129470Spjd } 272129470Spjd /* Options passed to kernel. */ 273129470Spjd opt = find_option(cmd, ch); 274129470Spjd if (opt == NULL) 275129470Spjd geom_usage(); 276129470Spjd if (G_OPT_ISDONE(opt)) { 277129470Spjd fprintf(stderr, "Flag '%c' specified twice.\n", 278129470Spjd opt->go_char); 279129470Spjd geom_usage(); 280129470Spjd } 281129470Spjd G_OPT_DONE(opt); 282129470Spjd 283129470Spjd if (opt->go_type == G_TYPE_NONE) 284129470Spjd set_option(req, opt, "1"); 285129470Spjd else 286129470Spjd set_option(req, opt, optarg); 287129470Spjd } 288129470Spjd *argc -= optind; 289129470Spjd *argv += optind; 290129470Spjd 291129470Spjd /* 292129470Spjd * Add not specified arguments, but with default values. 293129470Spjd */ 294129470Spjd for (i = 0; ; i++) { 295129470Spjd opt = &cmd->gc_options[i]; 296129470Spjd if (opt->go_name == NULL) 297129470Spjd break; 298129470Spjd if (G_OPT_ISDONE(opt)) 299129470Spjd continue; 300129470Spjd 301129470Spjd if (opt->go_type == G_TYPE_NONE) { 302129470Spjd assert(opt->go_val == NULL); 303129470Spjd set_option(req, opt, "0"); 304129470Spjd } else { 305129470Spjd if (opt->go_val == NULL) { 306129470Spjd fprintf(stderr, "Flag '%c' not specified.\n", 307129470Spjd opt->go_char); 308129470Spjd geom_usage(); 309129470Spjd } else { 310129470Spjd if (opt->go_type == G_TYPE_NUMBER) { 311129470Spjd gctl_ro_param(req, opt->go_name, 312129470Spjd sizeof(intmax_t), opt->go_val); 313129470Spjd } else /* if (opt->go_type == G_TYPE_STRING)*/ { 314129470Spjd gctl_ro_param(req, opt->go_name, -1, 315129470Spjd opt->go_val); 316129470Spjd } 317129470Spjd } 318129470Spjd } 319129470Spjd } 320129470Spjd /* 321129470Spjd * Add rest of given arguments. 322129470Spjd */ 323129470Spjd gctl_ro_param(req, "nargs", sizeof(int), argc); 324129470Spjd for (i = 0; i < (unsigned)*argc; i++) { 325129470Spjd char argname[16]; 326129470Spjd 327129470Spjd snprintf(argname, sizeof(argname), "arg%u", i); 328129470Spjd gctl_ro_param(req, argname, -1, (*argv)[i]); 329129470Spjd } 330129470Spjd} 331129470Spjd 332129470Spjd/* 333129470Spjd * Find given command in commands available for given class. 334129470Spjd */ 335129470Spjdstatic struct g_command * 336129470Spjdfind_command(const char *cmdstr, int all) 337129470Spjd{ 338129470Spjd struct g_command *cmd; 339129470Spjd unsigned i; 340129470Spjd 341129470Spjd /* 342129470Spjd * First try to find command defined by loaded library. 343129470Spjd */ 344129470Spjd if (class_commands != NULL) { 345129470Spjd for (i = 0; ; i++) { 346129470Spjd cmd = &class_commands[i]; 347129470Spjd if (cmd->gc_name == NULL) 348129470Spjd break; 349129470Spjd if (strcmp(cmd->gc_name, cmdstr) == 0) 350129470Spjd return (cmd); 351129470Spjd } 352129470Spjd } 353129470Spjd if (!all) 354129470Spjd return (NULL); 355129470Spjd /* 356129470Spjd * Now try to find in standard commands. 357129470Spjd */ 358129470Spjd for (i = 0; ; i++) { 359129470Spjd cmd = &std_commands[i]; 360129470Spjd if (cmd->gc_name == NULL) 361129470Spjd break; 362129470Spjd if (!std_available(cmd->gc_name)) 363129470Spjd continue; 364129470Spjd if (strcmp(cmd->gc_name, cmdstr) == 0) 365129470Spjd return (cmd); 366129470Spjd } 367129470Spjd return (NULL); 368129470Spjd} 369129470Spjd 370129470Spjdstatic unsigned 371129470Spjdset_flags(struct g_command *cmd) 372129470Spjd{ 373129470Spjd unsigned flags = 0; 374129470Spjd 375129470Spjd if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose) 376129470Spjd flags |= G_FLAG_VERBOSE; 377129470Spjd 378129470Spjd return (flags); 379129470Spjd} 380129470Spjd 381129470Spjd/* 382129470Spjd * Run command. 383129470Spjd */ 384129470Spjdstatic void 385129470Spjdrun_command(int argc, char *argv[]) 386129470Spjd{ 387129470Spjd struct g_command *cmd; 388129470Spjd struct gctl_req *req; 389129470Spjd const char *errstr; 390129470Spjd char buf[4096]; 391129470Spjd 392129470Spjd cmd = find_command(argv[0], 1); 393129470Spjd if (cmd == NULL) { 394129470Spjd fprintf(stderr, "Unknown command: %s\n", argv[0]); 395129470Spjd geom_usage(); 396129470Spjd } 397129470Spjd if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0) 398129470Spjd load_module(); 399129470Spjd 400129470Spjd req = gctl_get_handle(); 401129470Spjd gctl_ro_param(req, "class", -1, gclass_name); 402129470Spjd gctl_ro_param(req, "verb", -1, argv[0]); 403129470Spjd if (version != NULL) 404129470Spjd gctl_ro_param(req, "version", sizeof(*version), version); 405129470Spjd parse_arguments(cmd, req, &argc, &argv); 406129470Spjd 407129470Spjd if (cmd->gc_func != NULL) { 408129470Spjd unsigned flags; 409129470Spjd 410129470Spjd flags = set_flags(cmd); 411129470Spjd cmd->gc_func(req, flags); 412129470Spjd errstr = req->error; 413129470Spjd } else { 414129470Spjd bzero(buf, sizeof(buf)); 415129470Spjd gctl_rw_param(req, "output", sizeof(buf), buf); 416129470Spjd errstr = gctl_issue(req); 417129470Spjd } 418129470Spjd if (errstr != NULL) { 419129470Spjd fprintf(stderr, "%s\n", errstr); 420129470Spjd gctl_free(req); 421129470Spjd exit(EXIT_FAILURE); 422129470Spjd } 423129470Spjd if (*buf != '\0') 424129470Spjd printf("%s", buf); 425129470Spjd gctl_free(req); 426129470Spjd if (verbose) 427129470Spjd printf("Done.\n"); 428129470Spjd exit(EXIT_SUCCESS); 429129470Spjd} 430129470Spjd 431129470Spjdstatic void 432129470Spjdload_library(void) 433129470Spjd{ 434129470Spjd char path[MAXPATHLEN]; 435129470Spjd uint32_t *lib_version; 436129470Spjd void *dlh; 437129470Spjd 438129470Spjd snprintf(path, sizeof(path), "%s/geom_%s.so", CLASSDIR, class_name); 439129470Spjd dlh = dlopen(path, RTLD_NOW); 440129470Spjd if (dlh == NULL) { 441129470Spjd#if 0 442129470Spjd fprintf(stderr, "Cannot open library %s, but continuing " 443129470Spjd "anyway.\n", path); 444129470Spjd#endif 445129470Spjd /* 446129470Spjd * Even if library cannot be loaded, standard commands are 447129470Spjd * available, so don't panic! 448129470Spjd */ 449129470Spjd return; 450129470Spjd } 451129470Spjd lib_version = dlsym(dlh, "lib_version"); 452129470Spjd if (lib_version == NULL) { 453129470Spjd fprintf(stderr, "Cannot find symbol %s: %s.\n", "lib_version", 454129470Spjd dlerror()); 455129470Spjd dlclose(dlh); 456129470Spjd exit(EXIT_FAILURE); 457129470Spjd } 458129470Spjd if (*lib_version != G_LIB_VERSION) { 459129470Spjd dlclose(dlh); 460129470Spjd errx(EXIT_FAILURE, "%s and %s are not synchronized.", comm, 461129470Spjd path); 462129470Spjd } 463129470Spjd version = dlsym(dlh, "version"); 464129470Spjd if (version == NULL) { 465129470Spjd fprintf(stderr, "Cannot find symbol %s: %s.\n", "version", 466129470Spjd dlerror()); 467129470Spjd dlclose(dlh); 468129470Spjd exit(EXIT_FAILURE); 469129470Spjd } 470129470Spjd class_commands = dlsym(dlh, "class_commands"); 471129470Spjd if (class_commands == NULL) { 472129470Spjd fprintf(stderr, "Cannot find symbol %s: %s.\n", 473129470Spjd "class_commands", dlerror()); 474129470Spjd dlclose(dlh); 475129470Spjd exit(EXIT_FAILURE); 476129470Spjd } 477129470Spjd usage = dlsym(dlh, "usage"); 478129470Spjd if (usage == NULL) 479129470Spjd usage = std_usage; 480129470Spjd} 481129470Spjd 482129470Spjd/* 483129470Spjd * Class name should be all capital letters. 484129470Spjd */ 485129470Spjdstatic void 486129470Spjdset_class_name(void) 487129470Spjd{ 488129470Spjd char *s1, *s2; 489129470Spjd 490129470Spjd gclass_name = malloc(strlen(class_name)); 491129470Spjd if (gclass_name == NULL) 492129470Spjd errx(EXIT_FAILURE, "No memory"); 493129470Spjd s1 = gclass_name; 494129470Spjd s2 = class_name; 495129470Spjd for (; *s2 != '\0'; s2++) 496129470Spjd *s1++ = toupper(*s2); 497129470Spjd *s1 = '\0'; 498129470Spjd} 499129470Spjd 500129470Spjdstatic void 501129470Spjdget_class(int *argc, char ***argv) 502129470Spjd{ 503129470Spjd 504129470Spjd snprintf(comm, sizeof(comm), "%s", basename((*argv)[0])); 505129470Spjd if (strcmp(comm, "geom") == 0) { 506129470Spjd if (*argc < 2) 507129470Spjd geom_usage(); 508129470Spjd strlcatf(comm, sizeof(comm), " %s", (*argv)[1]); 509129470Spjd class_name = (*argv)[1]; 510129470Spjd *argc -= 2; 511129470Spjd *argv += 2; 512129470Spjd } else if (*comm == 'g') { 513129470Spjd class_name = comm + 1; 514129470Spjd *argc -= 1; 515129470Spjd *argv += 1; 516129470Spjd } else { 517129470Spjd errx(EXIT_FAILURE, "Invalid utility name."); 518129470Spjd } 519129470Spjd set_class_name(); 520129470Spjd load_library(); 521129470Spjd if (*argc < 1) 522129470Spjd geom_usage(); 523129470Spjd} 524129470Spjd 525129470Spjdint 526129470Spjdmain(int argc, char *argv[]) 527129470Spjd{ 528129470Spjd 529129470Spjd get_class(&argc, &argv); 530129470Spjd run_command(argc, argv); 531129470Spjd /* NOTREACHED */ 532129470Spjd 533129470Spjd exit(EXIT_FAILURE); 534129470Spjd} 535129470Spjd 536129470Spjdstatic struct gclass * 537129470Spjdfind_class(struct gmesh *mesh, const char *name) 538129470Spjd{ 539129470Spjd struct gclass *classp; 540129470Spjd 541129470Spjd LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 542129470Spjd if (strcmp(classp->lg_name, name) == 0) 543129470Spjd return (classp); 544129470Spjd } 545129470Spjd return (NULL); 546129470Spjd} 547129470Spjd 548129470Spjdstatic struct gprovider * 549129470Spjdfind_provider(struct gclass *classp, const char *name) 550129470Spjd{ 551129470Spjd struct ggeom *gp; 552129470Spjd struct gprovider *pp; 553129470Spjd 554129470Spjd LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 555129470Spjd LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 556129470Spjd if (strcmp(pp->lg_name, name) == 0) 557129470Spjd return (pp); 558129470Spjd } 559129470Spjd } 560129470Spjd return (NULL); 561129470Spjd} 562129470Spjd 563129470Spjdstatic char * 564129470Spjdgenspaces(const char *text, size_t len) 565129470Spjd{ 566129470Spjd static char spaces[256]; 567129470Spjd size_t outlen; 568129470Spjd 569129470Spjd if (strlen(text) >= len) { 570129470Spjd spaces[0] = '\0'; 571129470Spjd return (spaces); 572129470Spjd } 573129470Spjd memset(spaces, ' ', sizeof(spaces)); 574129470Spjd outlen = len - strlen(text); 575129470Spjd if (outlen >= sizeof(spaces)) { 576129470Spjd spaces[sizeof(spaces) - 1] = '\0'; 577129470Spjd return (spaces); 578129470Spjd } 579129470Spjd spaces[outlen] = '\0'; 580129470Spjd return (spaces); 581129470Spjd} 582129470Spjd 583129470Spjdstatic void 584129470Spjdshow_one(struct gprovider *pp) 585129470Spjd{ 586129470Spjd struct gconfig *conf; 587129470Spjd 588129470Spjd printf(" NAME: %s\n", pp->lg_name); 589129470Spjd printf(" geom name: %s\n", pp->lg_geom->lg_name); 590129470Spjd printf(" mediasize: %jd\n", (intmax_t)pp->lg_mediasize); 591129470Spjd printf(" sectorsize: %u\n", pp->lg_sectorsize); 592129470Spjd printf(" mode: %s\n", pp->lg_mode); 593129470Spjd LIST_FOREACH(conf, &pp->lg_config, lg_config) { 594129470Spjd printf("%s%s: %s\n", genspaces(conf->lg_name, 11), 595129470Spjd conf->lg_name, conf->lg_val); 596129470Spjd } 597129470Spjd printf("\n"); 598129470Spjd} 599129470Spjd 600129470Spjdstatic int 601129470Spjdstd_list_available(void) 602129470Spjd{ 603129470Spjd struct gmesh mesh; 604129470Spjd struct gclass *classp; 605129470Spjd int error; 606129470Spjd 607129470Spjd error = geom_gettree(&mesh); 608129470Spjd if (error != 0) 609129470Spjd exit(EXIT_FAILURE); 610129470Spjd classp = find_class(&mesh, gclass_name); 611129470Spjd geom_deletetree(&mesh); 612129470Spjd if (classp != NULL) 613129470Spjd return (1); 614129470Spjd return (0); 615129470Spjd} 616129470Spjd 617129470Spjdstatic void 618129470Spjdstd_list(struct gctl_req *req, unsigned flags __unused) 619129470Spjd{ 620129470Spjd struct gmesh mesh; 621129470Spjd struct gclass *classp; 622129470Spjd struct gprovider *pp; 623129470Spjd int error, *nargs; 624129470Spjd 625129470Spjd error = geom_gettree(&mesh); 626129470Spjd if (error != 0) 627129470Spjd exit(EXIT_FAILURE); 628129470Spjd classp = find_class(&mesh, gclass_name); 629129470Spjd if (classp == NULL) { 630129470Spjd geom_deletetree(&mesh); 631129470Spjd fprintf(stderr, "Class %s not found.\n", gclass_name); 632129470Spjd return; 633129470Spjd } 634129470Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 635129470Spjd if (nargs == NULL) { 636129470Spjd gctl_error(req, "No '%s' argument.", "nargs"); 637129470Spjd geom_deletetree(&mesh); 638129470Spjd return; 639129470Spjd } 640129470Spjd if (*nargs > 0) { 641129470Spjd int i; 642129470Spjd 643129470Spjd for (i = 0; i < *nargs; i++) { 644129470Spjd const char *name; 645129470Spjd char param[16]; 646129470Spjd 647129470Spjd snprintf(param, sizeof(param), "arg%d", i); 648129470Spjd name = gctl_get_asciiparam(req, param); 649129470Spjd assert(name != NULL); 650129470Spjd pp = find_provider(classp, name); 651129470Spjd if (pp != NULL) 652129470Spjd show_one(pp); 653129470Spjd else { 654129470Spjd fprintf(stderr, "No such provider: %s.\n", 655129470Spjd name); 656129470Spjd } 657129470Spjd } 658129470Spjd } else { 659129470Spjd struct ggeom *gp; 660129470Spjd 661129470Spjd LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 662129470Spjd LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 663129470Spjd show_one(pp); 664129470Spjd } 665129470Spjd } 666129470Spjd } 667129470Spjd geom_deletetree(&mesh); 668129470Spjd} 669129470Spjd 670129470Spjdstatic int 671129470Spjdstd_load_available(void) 672129470Spjd{ 673129470Spjd char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p; 674129470Spjd struct stat sb; 675129470Spjd size_t len; 676129470Spjd 677129470Spjd snprintf(name, sizeof(name), "g_%s", class_name); 678129470Spjd /* 679129470Spjd * If already in kernel, "load" command is not available. 680129470Spjd */ 681129470Spjd if (modfind(name) >= 0) 682129470Spjd return (0); 683129470Spjd bzero(paths, sizeof(paths)); 684129470Spjd len = sizeof(paths); 685129470Spjd if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0) 686129470Spjd err(EXIT_FAILURE, "sysctl(kern.module_path)"); 687129470Spjd for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) { 688129470Spjd snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name); 689129470Spjd /* 690129470Spjd * If geom_<name>.ko file exists, "load" command is available. 691129470Spjd */ 692129470Spjd if (stat(name, &sb) == 0) 693129470Spjd return (1); 694129470Spjd } 695129470Spjd return (0); 696129470Spjd} 697129470Spjd 698129470Spjdstatic void 699129470Spjdstd_load(struct gctl_req *req __unused, unsigned flags) 700129470Spjd{ 701129470Spjd 702129470Spjd /* 703129470Spjd * Do nothing special here, because of G_FLAG_LOADKLD flag, 704129470Spjd * module is already loaded. 705129470Spjd */ 706129470Spjd if ((flags & G_FLAG_VERBOSE) != 0) 707129470Spjd printf("Module available.\n"); 708129470Spjd} 709129470Spjd 710129470Spjdstatic int 711129470Spjdstd_unload_available(void) 712129470Spjd{ 713129470Spjd char name[64]; 714129470Spjd int id; 715129470Spjd 716129470Spjd snprintf(name, sizeof(name), "geom_%s", class_name); 717129470Spjd id = kldfind(name); 718129470Spjd if (id >= 0) 719129470Spjd return (1); 720129470Spjd return (0); 721129470Spjd} 722129470Spjd 723129470Spjdstatic void 724129470Spjdstd_unload(struct gctl_req *req, unsigned flags __unused) 725129470Spjd{ 726129470Spjd char name[64]; 727129470Spjd int id; 728129470Spjd 729129470Spjd snprintf(name, sizeof(name), "geom_%s", class_name); 730129470Spjd id = kldfind(name); 731129470Spjd if (id < 0) { 732129470Spjd gctl_error(req, "Could not find module: %s.", strerror(errno)); 733129470Spjd return; 734129470Spjd } 735129470Spjd if (kldunload(id) < 0) { 736129470Spjd gctl_error(req, "Could not unload module: %s.", 737129470Spjd strerror(errno)); 738129470Spjd return; 739129470Spjd } 740129470Spjd} 741129470Spjd 742129470Spjdstatic int 743129470Spjdstd_available(const char *name) 744129470Spjd{ 745129470Spjd 746129470Spjd if (strcmp(name, "list") == 0) 747129470Spjd return (std_list_available()); 748129470Spjd else if (strcmp(name, "load") == 0) 749129470Spjd return (std_load_available()); 750129470Spjd else if (strcmp(name, "unload") == 0) 751129470Spjd return (std_unload_available()); 752129470Spjd else 753129470Spjd assert(!"Unknown standard command."); 754129470Spjd return (0); 755129470Spjd} 756