1129470Spjd/*- 2196878Spjd * Copyright (c) 2004-2009 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. 13155175Spjd * 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$"); 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> 45129745Spjd#include <libutil.h> 46129470Spjd#include <inttypes.h> 47129470Spjd#include <dlfcn.h> 48129470Spjd#include <assert.h> 49129470Spjd#include <libgeom.h> 50129470Spjd#include <geom.h> 51129470Spjd 52129470Spjd#include "misc/subr.h" 53129470Spjd 54179550Smarcel#ifdef STATIC_GEOM_CLASSES 55173313Smarcelextern uint32_t gpart_version; 56173313Smarcelextern struct g_command gpart_class_commands[]; 57176852Sdelphijextern uint32_t glabel_version; 58176852Sdelphijextern struct g_command glabel_class_commands[]; 59173313Smarcel#endif 60129470Spjd 61129470Spjdstatic char comm[MAXPATHLEN], *class_name = NULL, *gclass_name = NULL; 62129470Spjdstatic uint32_t *version = NULL; 63129470Spjdstatic int verbose = 0; 64129470Spjdstatic struct g_command *class_commands = NULL; 65129470Spjd 66135369Spjd#define GEOM_CLASS_CMDS 0x01 67135369Spjd#define GEOM_STD_CMDS 0x02 68135369Spjdstatic struct g_command *find_command(const char *cmdstr, int flags); 69129470Spjdstatic int std_available(const char *name); 70129470Spjd 71129591Spjdstatic void std_help(struct gctl_req *req, unsigned flags); 72129470Spjdstatic void std_list(struct gctl_req *req, unsigned flags); 73143534Spjdstatic void std_status(struct gctl_req *req, unsigned flags); 74129470Spjdstatic void std_load(struct gctl_req *req, unsigned flags); 75129470Spjdstatic void std_unload(struct gctl_req *req, unsigned flags); 76129470Spjd 77241737Sedstatic struct g_command std_commands[] = { 78212554Spjd { "help", 0, std_help, G_NULL_OPTS, NULL }, 79219969Smav { "list", 0, std_list, 80219969Smav { 81219969Smav { 'a', "all", NULL, G_TYPE_BOOL }, 82219969Smav G_OPT_SENTINEL 83219969Smav }, 84219969Smav "[-a] [name ...]" 85143585Spjd }, 86143572Spjd { "status", 0, std_status, 87143572Spjd { 88219969Smav { 'a', "all", NULL, G_TYPE_BOOL }, 89219969Smav { 'g', "geoms", NULL, G_TYPE_BOOL }, 90162867Spjd { 's', "script", NULL, G_TYPE_BOOL }, 91143572Spjd G_OPT_SENTINEL 92143585Spjd }, 93219969Smav "[-ags] [name ...]" 94143572Spjd }, 95169586Smarcel { "load", G_FLAG_VERBOSE | G_FLAG_LOADKLD, std_load, G_NULL_OPTS, 96212554Spjd NULL }, 97212554Spjd { "unload", G_FLAG_VERBOSE, std_unload, G_NULL_OPTS, NULL }, 98129470Spjd G_CMD_SENTINEL 99129470Spjd}; 100129470Spjd 101129470Spjdstatic void 102143585Spjdusage_command(struct g_command *cmd, const char *prefix) 103129470Spjd{ 104129470Spjd struct g_option *opt; 105143585Spjd unsigned i; 106129470Spjd 107143585Spjd if (cmd->gc_usage != NULL) { 108196877Spjd char *pos, *ptr, *sptr; 109196877Spjd 110196877Spjd sptr = ptr = strdup(cmd->gc_usage); 111196877Spjd while ((pos = strsep(&ptr, "\n")) != NULL) { 112196877Spjd if (*pos == '\0') 113196877Spjd continue; 114196877Spjd fprintf(stderr, "%s %s %s %s\n", prefix, comm, 115196877Spjd cmd->gc_name, pos); 116196877Spjd } 117196877Spjd free(sptr); 118143585Spjd return; 119143585Spjd } 120196877Spjd 121196877Spjd fprintf(stderr, "%s %s %s", prefix, comm, cmd->gc_name); 122143585Spjd if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0) 123143585Spjd fprintf(stderr, " [-v]"); 124129470Spjd for (i = 0; ; i++) { 125143585Spjd opt = &cmd->gc_options[i]; 126143585Spjd if (opt->go_name == NULL) 127129470Spjd break; 128162867Spjd if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL) 129143585Spjd fprintf(stderr, " ["); 130143585Spjd else 131143585Spjd fprintf(stderr, " "); 132143585Spjd fprintf(stderr, "-%c", opt->go_char); 133162867Spjd if (G_OPT_TYPE(opt) != G_TYPE_BOOL) 134143585Spjd fprintf(stderr, " %s", opt->go_name); 135162867Spjd if (opt->go_val != NULL || G_OPT_TYPE(opt) == G_TYPE_BOOL) 136143585Spjd fprintf(stderr, "]"); 137129470Spjd } 138143585Spjd fprintf(stderr, "\n"); 139129470Spjd} 140129470Spjd 141129470Spjdstatic void 142143585Spjdusage(void) 143129470Spjd{ 144129470Spjd 145129470Spjd if (class_name == NULL) { 146129591Spjd errx(EXIT_FAILURE, "usage: %s <class> <command> [options]", 147129591Spjd "geom"); 148129470Spjd } else { 149143585Spjd struct g_command *cmd; 150129470Spjd const char *prefix; 151129470Spjd unsigned i; 152129470Spjd 153143585Spjd prefix = "usage:"; 154143585Spjd if (class_commands != NULL) { 155143585Spjd for (i = 0; ; i++) { 156143585Spjd cmd = &class_commands[i]; 157143585Spjd if (cmd->gc_name == NULL) 158143585Spjd break; 159143585Spjd usage_command(cmd, prefix); 160143585Spjd prefix = " "; 161143585Spjd } 162129470Spjd } 163129470Spjd for (i = 0; ; i++) { 164129470Spjd cmd = &std_commands[i]; 165129470Spjd if (cmd->gc_name == NULL) 166129470Spjd break; 167135369Spjd /* 168135369Spjd * If class defines command, which has the same name as 169135369Spjd * standard command, skip it, because it was already 170135369Spjd * shown on usage(). 171135369Spjd */ 172135369Spjd if (find_command(cmd->gc_name, GEOM_CLASS_CMDS) != NULL) 173129470Spjd continue; 174143585Spjd usage_command(cmd, prefix); 175129470Spjd prefix = " "; 176129470Spjd } 177129470Spjd exit(EXIT_FAILURE); 178129470Spjd } 179129470Spjd} 180129470Spjd 181129470Spjdstatic void 182129470Spjdload_module(void) 183129470Spjd{ 184129470Spjd char name1[64], name2[64]; 185129470Spjd 186129470Spjd snprintf(name1, sizeof(name1), "g_%s", class_name); 187129470Spjd snprintf(name2, sizeof(name2), "geom_%s", class_name); 188129470Spjd if (modfind(name1) < 0) { 189129470Spjd /* Not present in kernel, try loading it. */ 190129470Spjd if (kldload(name2) < 0 || modfind(name1) < 0) { 191129470Spjd if (errno != EEXIST) { 192129470Spjd errx(EXIT_FAILURE, 193129470Spjd "%s module not available!", name2); 194129470Spjd } 195129470Spjd } 196129470Spjd } 197129470Spjd} 198129470Spjd 199129470Spjdstatic int 200129470Spjdstrlcatf(char *str, size_t size, const char *format, ...) 201129470Spjd{ 202129470Spjd size_t len; 203129470Spjd va_list ap; 204129470Spjd int ret; 205129470Spjd 206129470Spjd len = strlen(str); 207129470Spjd str += len; 208129470Spjd size -= len; 209129470Spjd 210129470Spjd va_start(ap, format); 211129470Spjd ret = vsnprintf(str, size, format, ap); 212129470Spjd va_end(ap); 213129470Spjd 214129470Spjd return (ret); 215129470Spjd} 216129470Spjd 217129470Spjd/* 218129470Spjd * Find given option in options available for given command. 219129470Spjd */ 220129470Spjdstatic struct g_option * 221129470Spjdfind_option(struct g_command *cmd, char ch) 222129470Spjd{ 223129470Spjd struct g_option *opt; 224129470Spjd unsigned i; 225129470Spjd 226129470Spjd for (i = 0; ; i++) { 227129470Spjd opt = &cmd->gc_options[i]; 228129470Spjd if (opt->go_name == NULL) 229129470Spjd return (NULL); 230129470Spjd if (opt->go_char == ch) 231129470Spjd return (opt); 232129470Spjd } 233129470Spjd /* NOTREACHED */ 234129470Spjd return (NULL); 235129470Spjd} 236129470Spjd 237129470Spjd/* 238129470Spjd * Add given option to gctl_req. 239129470Spjd */ 240129470Spjdstatic void 241129470Spjdset_option(struct gctl_req *req, struct g_option *opt, const char *val) 242129470Spjd{ 243212555Spjd const char *optname; 244211500Sdes uint64_t number; 245212547Spjd void *ptr; 246129470Spjd 247212555Spjd if (G_OPT_ISMULTI(opt)) { 248212555Spjd size_t optnamesize; 249212555Spjd 250212555Spjd if (G_OPT_NUM(opt) == UCHAR_MAX) 251212555Spjd errx(EXIT_FAILURE, "Too many -%c options.", opt->go_char); 252212555Spjd 253212555Spjd /* 254212555Spjd * Base option name length plus 3 bytes for option number 255212555Spjd * (max. 255 options) plus 1 byte for terminating '\0'. 256212555Spjd */ 257212555Spjd optnamesize = strlen(opt->go_name) + 3 + 1; 258212555Spjd ptr = malloc(optnamesize); 259212555Spjd if (ptr == NULL) 260212555Spjd errx(EXIT_FAILURE, "No memory."); 261212555Spjd snprintf(ptr, optnamesize, "%s%u", opt->go_name, G_OPT_NUM(opt)); 262212555Spjd G_OPT_NUMINC(opt); 263212555Spjd optname = ptr; 264212555Spjd } else { 265212555Spjd optname = opt->go_name; 266212555Spjd } 267212555Spjd 268212615Spjd if (G_OPT_TYPE(opt) == G_TYPE_NUMBER) { 269172273Spjd if (expand_number(val, &number) == -1) { 270212607Spjd err(EXIT_FAILURE, "Invalid value for '%c' argument", 271129470Spjd opt->go_char); 272129470Spjd } 273212622Spjd ptr = malloc(sizeof(intmax_t)); 274212622Spjd if (ptr == NULL) 275212622Spjd errx(EXIT_FAILURE, "No memory."); 276212622Spjd *(intmax_t *)ptr = number; 277212622Spjd opt->go_val = ptr; 278212622Spjd gctl_ro_param(req, optname, sizeof(intmax_t), opt->go_val); 279162867Spjd } else if (G_OPT_TYPE(opt) == G_TYPE_STRING) { 280212555Spjd gctl_ro_param(req, optname, -1, val); 281162867Spjd } else if (G_OPT_TYPE(opt) == G_TYPE_BOOL) { 282212547Spjd ptr = malloc(sizeof(int)); 283212547Spjd if (ptr == NULL) 284129470Spjd errx(EXIT_FAILURE, "No memory."); 285212547Spjd *(int *)ptr = *val - '0'; 286212547Spjd opt->go_val = ptr; 287212555Spjd gctl_ro_param(req, optname, sizeof(int), opt->go_val); 288162867Spjd } else { 289162867Spjd assert(!"Invalid type"); 290129470Spjd } 291212555Spjd 292212555Spjd if (G_OPT_ISMULTI(opt)) 293212555Spjd free(__DECONST(char *, optname)); 294129470Spjd} 295129470Spjd 296129470Spjd/* 297129470Spjd * 1. Add given argument by caller. 298129470Spjd * 2. Add default values of not given arguments. 299129470Spjd * 3. Add the rest of arguments. 300129470Spjd */ 301129470Spjdstatic void 302129470Spjdparse_arguments(struct g_command *cmd, struct gctl_req *req, int *argc, 303129470Spjd char ***argv) 304129470Spjd{ 305129470Spjd struct g_option *opt; 306129470Spjd char opts[64]; 307129470Spjd unsigned i; 308129470Spjd int ch; 309129470Spjd 310129470Spjd *opts = '\0'; 311129470Spjd if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0) 312129470Spjd strlcat(opts, "v", sizeof(opts)); 313129470Spjd for (i = 0; ; i++) { 314129470Spjd opt = &cmd->gc_options[i]; 315129470Spjd if (opt->go_name == NULL) 316129470Spjd break; 317162867Spjd assert(G_OPT_TYPE(opt) != 0); 318212555Spjd assert((opt->go_type & ~(G_TYPE_MASK | G_TYPE_MULTI)) == 0); 319212555Spjd /* Multiple bool arguments makes no sense. */ 320212555Spjd assert(G_OPT_TYPE(opt) != G_TYPE_BOOL || 321212555Spjd (opt->go_type & G_TYPE_MULTI) == 0); 322129470Spjd strlcatf(opts, sizeof(opts), "%c", opt->go_char); 323162867Spjd if (G_OPT_TYPE(opt) != G_TYPE_BOOL) 324129470Spjd strlcat(opts, ":", sizeof(opts)); 325129470Spjd } 326129470Spjd 327129470Spjd /* 328129470Spjd * Add specified arguments. 329129470Spjd */ 330129470Spjd while ((ch = getopt(*argc, *argv, opts)) != -1) { 331129470Spjd /* Standard (not passed to kernel) options. */ 332129470Spjd switch (ch) { 333129470Spjd case 'v': 334129470Spjd verbose = 1; 335129470Spjd continue; 336129470Spjd } 337129470Spjd /* Options passed to kernel. */ 338129470Spjd opt = find_option(cmd, ch); 339129470Spjd if (opt == NULL) 340143585Spjd usage(); 341212555Spjd if (!G_OPT_ISMULTI(opt) && G_OPT_ISDONE(opt)) { 342162867Spjd warnx("Option '%c' specified twice.", opt->go_char); 343143585Spjd usage(); 344129470Spjd } 345129470Spjd G_OPT_DONE(opt); 346129470Spjd 347162867Spjd if (G_OPT_TYPE(opt) == G_TYPE_BOOL) 348129470Spjd set_option(req, opt, "1"); 349129470Spjd else 350129470Spjd set_option(req, opt, optarg); 351129470Spjd } 352129470Spjd *argc -= optind; 353129470Spjd *argv += optind; 354129470Spjd 355129470Spjd /* 356129470Spjd * Add not specified arguments, but with default values. 357129470Spjd */ 358129470Spjd for (i = 0; ; i++) { 359129470Spjd opt = &cmd->gc_options[i]; 360129470Spjd if (opt->go_name == NULL) 361129470Spjd break; 362129470Spjd if (G_OPT_ISDONE(opt)) 363129470Spjd continue; 364129470Spjd 365162867Spjd if (G_OPT_TYPE(opt) == G_TYPE_BOOL) { 366129470Spjd assert(opt->go_val == NULL); 367129470Spjd set_option(req, opt, "0"); 368129470Spjd } else { 369129470Spjd if (opt->go_val == NULL) { 370162867Spjd warnx("Option '%c' not specified.", 371129470Spjd opt->go_char); 372143585Spjd usage(); 373212606Spjd } else if (opt->go_val == G_VAL_OPTIONAL) { 374212606Spjd /* add nothing. */ 375129470Spjd } else { 376212554Spjd set_option(req, opt, opt->go_val); 377129470Spjd } 378129470Spjd } 379129470Spjd } 380129470Spjd 381212554Spjd /* 382212554Spjd * Add rest of given arguments. 383212554Spjd */ 384212554Spjd gctl_ro_param(req, "nargs", sizeof(int), argc); 385212554Spjd for (i = 0; i < (unsigned)*argc; i++) { 386212554Spjd char argname[16]; 387169586Smarcel 388212554Spjd snprintf(argname, sizeof(argname), "arg%u", i); 389212554Spjd gctl_ro_param(req, argname, -1, (*argv)[i]); 390129470Spjd } 391129470Spjd} 392129470Spjd 393129470Spjd/* 394129470Spjd * Find given command in commands available for given class. 395129470Spjd */ 396129470Spjdstatic struct g_command * 397135369Spjdfind_command(const char *cmdstr, int flags) 398129470Spjd{ 399129470Spjd struct g_command *cmd; 400129470Spjd unsigned i; 401129470Spjd 402129470Spjd /* 403129470Spjd * First try to find command defined by loaded library. 404129470Spjd */ 405135369Spjd if ((flags & GEOM_CLASS_CMDS) != 0 && class_commands != NULL) { 406129470Spjd for (i = 0; ; i++) { 407129470Spjd cmd = &class_commands[i]; 408129470Spjd if (cmd->gc_name == NULL) 409129470Spjd break; 410129470Spjd if (strcmp(cmd->gc_name, cmdstr) == 0) 411129470Spjd return (cmd); 412129470Spjd } 413129470Spjd } 414129470Spjd /* 415129470Spjd * Now try to find in standard commands. 416129470Spjd */ 417135369Spjd if ((flags & GEOM_STD_CMDS) != 0) { 418135369Spjd for (i = 0; ; i++) { 419135369Spjd cmd = &std_commands[i]; 420135369Spjd if (cmd->gc_name == NULL) 421135369Spjd break; 422135369Spjd if (strcmp(cmd->gc_name, cmdstr) == 0) 423135369Spjd return (cmd); 424135369Spjd } 425129470Spjd } 426129470Spjd return (NULL); 427129470Spjd} 428129470Spjd 429129470Spjdstatic unsigned 430129470Spjdset_flags(struct g_command *cmd) 431129470Spjd{ 432129470Spjd unsigned flags = 0; 433129470Spjd 434129470Spjd if ((cmd->gc_flags & G_FLAG_VERBOSE) != 0 && verbose) 435129470Spjd flags |= G_FLAG_VERBOSE; 436129470Spjd 437129470Spjd return (flags); 438129470Spjd} 439129470Spjd 440129470Spjd/* 441129470Spjd * Run command. 442129470Spjd */ 443129470Spjdstatic void 444129470Spjdrun_command(int argc, char *argv[]) 445129470Spjd{ 446129470Spjd struct g_command *cmd; 447129470Spjd struct gctl_req *req; 448129470Spjd const char *errstr; 449129470Spjd char buf[4096]; 450129470Spjd 451135369Spjd /* First try to find a command defined by a class. */ 452135369Spjd cmd = find_command(argv[0], GEOM_CLASS_CMDS); 453129470Spjd if (cmd == NULL) { 454135369Spjd /* Now, try to find a standard command. */ 455135369Spjd cmd = find_command(argv[0], GEOM_STD_CMDS); 456135369Spjd if (cmd == NULL) { 457162867Spjd warnx("Unknown command: %s.", argv[0]); 458143585Spjd usage(); 459135369Spjd } 460135369Spjd if (!std_available(cmd->gc_name)) { 461162867Spjd warnx("Command '%s' not available.", argv[0]); 462135369Spjd exit(EXIT_FAILURE); 463135369Spjd } 464129470Spjd } 465129470Spjd if ((cmd->gc_flags & G_FLAG_LOADKLD) != 0) 466129470Spjd load_module(); 467129470Spjd 468129470Spjd req = gctl_get_handle(); 469129470Spjd gctl_ro_param(req, "class", -1, gclass_name); 470129470Spjd gctl_ro_param(req, "verb", -1, argv[0]); 471129470Spjd if (version != NULL) 472129470Spjd gctl_ro_param(req, "version", sizeof(*version), version); 473129470Spjd parse_arguments(cmd, req, &argc, &argv); 474129470Spjd 475143998Spjd bzero(buf, sizeof(buf)); 476129470Spjd if (cmd->gc_func != NULL) { 477129470Spjd unsigned flags; 478129470Spjd 479129470Spjd flags = set_flags(cmd); 480129470Spjd cmd->gc_func(req, flags); 481129470Spjd errstr = req->error; 482129470Spjd } else { 483129470Spjd gctl_rw_param(req, "output", sizeof(buf), buf); 484129470Spjd errstr = gctl_issue(req); 485129470Spjd } 486145662Spjd if (errstr != NULL && errstr[0] != '\0') { 487162867Spjd warnx("%s", errstr); 488134419Spjd if (strncmp(errstr, "warning: ", strlen("warning: ")) != 0) { 489134419Spjd gctl_free(req); 490134419Spjd exit(EXIT_FAILURE); 491134419Spjd } 492129470Spjd } 493143998Spjd if (buf[0] != '\0') 494129470Spjd printf("%s", buf); 495129470Spjd gctl_free(req); 496129470Spjd if (verbose) 497129470Spjd printf("Done.\n"); 498129470Spjd exit(EXIT_SUCCESS); 499129470Spjd} 500129470Spjd 501179550Smarcel#ifndef STATIC_GEOM_CLASSES 502142691Spjdstatic const char * 503142691Spjdlibrary_path(void) 504142691Spjd{ 505142691Spjd const char *path; 506142691Spjd 507142691Spjd path = getenv("GEOM_LIBRARY_PATH"); 508142691Spjd if (path == NULL) 509216470Sobrien path = GEOM_CLASS_DIR; 510142691Spjd return (path); 511142691Spjd} 512142691Spjd 513129470Spjdstatic void 514129470Spjdload_library(void) 515129470Spjd{ 516188017Slulf char *curpath, path[MAXPATHLEN], *tofree, *totalpath; 517129470Spjd uint32_t *lib_version; 518129470Spjd void *dlh; 519175967Slulf int ret; 520129470Spjd 521175967Slulf ret = 0; 522188017Slulf tofree = totalpath = strdup(library_path()); 523175967Slulf if (totalpath == NULL) 524175967Slulf err(EXIT_FAILURE, "Not enough memory for library path"); 525175967Slulf 526175967Slulf if (strchr(totalpath, ':') != NULL) 527175967Slulf curpath = strsep(&totalpath, ":"); 528175967Slulf else 529175967Slulf curpath = totalpath; 530175967Slulf /* Traverse the paths to find one that contains the library we want. */ 531175967Slulf while (curpath != NULL) { 532175967Slulf snprintf(path, sizeof(path), "%s/geom_%s.so", curpath, 533175967Slulf class_name); 534175967Slulf ret = access(path, F_OK); 535175967Slulf if (ret == -1) { 536175967Slulf if (errno == ENOENT) { 537175967Slulf /* 538175967Slulf * If we cannot find library, try the next 539175967Slulf * path. 540175967Slulf */ 541175967Slulf curpath = strsep(&totalpath, ":"); 542175967Slulf continue; 543175967Slulf } 544175967Slulf err(EXIT_FAILURE, "Cannot access library"); 545149059Spjd } 546175967Slulf break; 547149059Spjd } 548188017Slulf free(tofree); 549175967Slulf /* No library was found, but standard commands can still be used */ 550175967Slulf if (ret == -1) 551175967Slulf return; 552129470Spjd dlh = dlopen(path, RTLD_NOW); 553149059Spjd if (dlh == NULL) 554149059Spjd errx(EXIT_FAILURE, "Cannot open library: %s.", dlerror()); 555129470Spjd lib_version = dlsym(dlh, "lib_version"); 556129470Spjd if (lib_version == NULL) { 557162867Spjd warnx("Cannot find symbol %s: %s.", "lib_version", dlerror()); 558129470Spjd dlclose(dlh); 559129470Spjd exit(EXIT_FAILURE); 560129470Spjd } 561129470Spjd if (*lib_version != G_LIB_VERSION) { 562129470Spjd dlclose(dlh); 563134419Spjd errx(EXIT_FAILURE, "%s and %s are not synchronized.", 564134419Spjd getprogname(), path); 565129470Spjd } 566129470Spjd version = dlsym(dlh, "version"); 567129470Spjd if (version == NULL) { 568162867Spjd warnx("Cannot find symbol %s: %s.", "version", dlerror()); 569129470Spjd dlclose(dlh); 570129470Spjd exit(EXIT_FAILURE); 571129470Spjd } 572129470Spjd class_commands = dlsym(dlh, "class_commands"); 573129470Spjd if (class_commands == NULL) { 574162867Spjd warnx("Cannot find symbol %s: %s.", "class_commands", 575162867Spjd dlerror()); 576129470Spjd dlclose(dlh); 577129470Spjd exit(EXIT_FAILURE); 578129470Spjd } 579129470Spjd} 580179550Smarcel#endif /* !STATIC_GEOM_CLASSES */ 581129470Spjd 582129470Spjd/* 583129470Spjd * Class name should be all capital letters. 584129470Spjd */ 585129470Spjdstatic void 586129470Spjdset_class_name(void) 587129470Spjd{ 588129470Spjd char *s1, *s2; 589129470Spjd 590143589Spjd s1 = class_name; 591143589Spjd for (; *s1 != '\0'; s1++) 592143589Spjd *s1 = tolower(*s1); 593157580Spjd gclass_name = malloc(strlen(class_name) + 1); 594129470Spjd if (gclass_name == NULL) 595129470Spjd errx(EXIT_FAILURE, "No memory"); 596129470Spjd s1 = gclass_name; 597129470Spjd s2 = class_name; 598129470Spjd for (; *s2 != '\0'; s2++) 599129470Spjd *s1++ = toupper(*s2); 600129470Spjd *s1 = '\0'; 601129470Spjd} 602129470Spjd 603129470Spjdstatic void 604129470Spjdget_class(int *argc, char ***argv) 605129470Spjd{ 606129470Spjd 607129470Spjd snprintf(comm, sizeof(comm), "%s", basename((*argv)[0])); 608129470Spjd if (strcmp(comm, "geom") == 0) { 609129470Spjd if (*argc < 2) 610143585Spjd usage(); 611139377Spjd else if (*argc == 2) { 612139377Spjd if (strcmp((*argv)[1], "-h") == 0 || 613139377Spjd strcmp((*argv)[1], "help") == 0) { 614143585Spjd usage(); 615139377Spjd } 616139377Spjd } 617129470Spjd strlcatf(comm, sizeof(comm), " %s", (*argv)[1]); 618129470Spjd class_name = (*argv)[1]; 619129470Spjd *argc -= 2; 620129470Spjd *argv += 2; 621129470Spjd } else if (*comm == 'g') { 622129470Spjd class_name = comm + 1; 623129470Spjd *argc -= 1; 624129470Spjd *argv += 1; 625129470Spjd } else { 626129470Spjd errx(EXIT_FAILURE, "Invalid utility name."); 627129470Spjd } 628173313Smarcel 629179550Smarcel#ifndef STATIC_GEOM_CLASSES 630173313Smarcel load_library(); 631173313Smarcel#else 632173313Smarcel if (!strcasecmp(class_name, "part")) { 633173313Smarcel version = &gpart_version; 634173313Smarcel class_commands = gpart_class_commands; 635176852Sdelphij } else if (!strcasecmp(class_name, "label")) { 636176852Sdelphij version = &glabel_version; 637176852Sdelphij class_commands = glabel_class_commands; 638173313Smarcel } else 639173313Smarcel errx(EXIT_FAILURE, "Invalid class name."); 640179550Smarcel#endif /* !STATIC_GEOM_CLASSES */ 641173313Smarcel 642129470Spjd set_class_name(); 643129470Spjd if (*argc < 1) 644143585Spjd usage(); 645129470Spjd} 646129470Spjd 647129470Spjdint 648129470Spjdmain(int argc, char *argv[]) 649129470Spjd{ 650129470Spjd 651129470Spjd get_class(&argc, &argv); 652129470Spjd run_command(argc, argv); 653129470Spjd /* NOTREACHED */ 654129470Spjd 655129470Spjd exit(EXIT_FAILURE); 656129470Spjd} 657129470Spjd 658129470Spjdstatic struct gclass * 659129470Spjdfind_class(struct gmesh *mesh, const char *name) 660129470Spjd{ 661129470Spjd struct gclass *classp; 662129470Spjd 663129470Spjd LIST_FOREACH(classp, &mesh->lg_class, lg_class) { 664129470Spjd if (strcmp(classp->lg_name, name) == 0) 665129470Spjd return (classp); 666129470Spjd } 667129470Spjd return (NULL); 668129470Spjd} 669129470Spjd 670132665Spjdstatic struct ggeom * 671132665Spjdfind_geom(struct gclass *classp, const char *name) 672129470Spjd{ 673129470Spjd struct ggeom *gp; 674129470Spjd 675129470Spjd LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 676132665Spjd if (strcmp(gp->lg_name, name) == 0) 677132665Spjd return (gp); 678129470Spjd } 679129470Spjd return (NULL); 680129470Spjd} 681129470Spjd 682132665Spjdstatic void 683143532Spjdlist_one_provider(struct gprovider *pp, const char *prefix) 684129470Spjd{ 685132665Spjd struct gconfig *conf; 686132665Spjd char buf[5]; 687129470Spjd 688132665Spjd printf("Name: %s\n", pp->lg_name); 689132665Spjd humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "", 690132665Spjd HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 691132665Spjd printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize, 692132665Spjd buf); 693132665Spjd printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize); 694202457Sdelphij if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) { 695202454Sdelphij printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize); 696202454Sdelphij printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset); 697202454Sdelphij } 698132665Spjd printf("%sMode: %s\n", prefix, pp->lg_mode); 699132665Spjd LIST_FOREACH(conf, &pp->lg_config, lg_config) { 700132665Spjd printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val); 701129470Spjd } 702132665Spjd} 703132665Spjd 704132665Spjdstatic void 705143532Spjdlist_one_consumer(struct gconsumer *cp, const char *prefix) 706132665Spjd{ 707132665Spjd struct gprovider *pp; 708132665Spjd struct gconfig *conf; 709132665Spjd 710132665Spjd pp = cp->lg_provider; 711132665Spjd if (pp == NULL) 712132665Spjd printf("[no provider]\n"); 713132665Spjd else { 714132665Spjd char buf[5]; 715132665Spjd 716132665Spjd printf("Name: %s\n", pp->lg_name); 717132665Spjd humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "", 718132665Spjd HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 719132665Spjd printf("%sMediasize: %jd (%s)\n", prefix, 720132665Spjd (intmax_t)pp->lg_mediasize, buf); 721132665Spjd printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize); 722202586Sdelphij if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) { 723202454Sdelphij printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize); 724202454Sdelphij printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset); 725202454Sdelphij } 726132665Spjd printf("%sMode: %s\n", prefix, cp->lg_mode); 727129470Spjd } 728132665Spjd LIST_FOREACH(conf, &cp->lg_config, lg_config) { 729132665Spjd printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val); 730132665Spjd } 731129470Spjd} 732129470Spjd 733129470Spjdstatic void 734143532Spjdlist_one_geom(struct ggeom *gp) 735129470Spjd{ 736132665Spjd struct gprovider *pp; 737132665Spjd struct gconsumer *cp; 738129470Spjd struct gconfig *conf; 739132665Spjd unsigned n; 740129470Spjd 741132665Spjd printf("Geom name: %s\n", gp->lg_name); 742132665Spjd LIST_FOREACH(conf, &gp->lg_config, lg_config) { 743132665Spjd printf("%s: %s\n", conf->lg_name, conf->lg_val); 744129470Spjd } 745132665Spjd if (!LIST_EMPTY(&gp->lg_provider)) { 746132665Spjd printf("Providers:\n"); 747132665Spjd n = 1; 748132665Spjd LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 749132665Spjd printf("%u. ", n++); 750143532Spjd list_one_provider(pp, " "); 751132665Spjd } 752132665Spjd } 753132665Spjd if (!LIST_EMPTY(&gp->lg_consumer)) { 754132665Spjd printf("Consumers:\n"); 755132665Spjd n = 1; 756132665Spjd LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) { 757132665Spjd printf("%u. ", n++); 758143532Spjd list_one_consumer(cp, " "); 759132665Spjd } 760132665Spjd } 761129470Spjd printf("\n"); 762129470Spjd} 763129470Spjd 764129591Spjdstatic void 765129591Spjdstd_help(struct gctl_req *req __unused, unsigned flags __unused) 766129591Spjd{ 767129591Spjd 768143585Spjd usage(); 769129591Spjd} 770129591Spjd 771129470Spjdstatic int 772129470Spjdstd_list_available(void) 773129470Spjd{ 774129470Spjd struct gmesh mesh; 775129470Spjd struct gclass *classp; 776129470Spjd int error; 777129470Spjd 778129470Spjd error = geom_gettree(&mesh); 779162867Spjd if (error != 0) 780162867Spjd errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 781129470Spjd classp = find_class(&mesh, gclass_name); 782129470Spjd geom_deletetree(&mesh); 783129470Spjd if (classp != NULL) 784129470Spjd return (1); 785129470Spjd return (0); 786129470Spjd} 787129470Spjd 788129470Spjdstatic void 789129470Spjdstd_list(struct gctl_req *req, unsigned flags __unused) 790129470Spjd{ 791129470Spjd struct gmesh mesh; 792129470Spjd struct gclass *classp; 793132665Spjd struct ggeom *gp; 794153190Spjd const char *name; 795219969Smav int all, error, i, nargs; 796129470Spjd 797129470Spjd error = geom_gettree(&mesh); 798162867Spjd if (error != 0) 799162867Spjd errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 800129470Spjd classp = find_class(&mesh, gclass_name); 801129470Spjd if (classp == NULL) { 802129470Spjd geom_deletetree(&mesh); 803167842Spjd errx(EXIT_FAILURE, "Class %s not found.", gclass_name); 804129470Spjd } 805153190Spjd nargs = gctl_get_int(req, "nargs"); 806219969Smav all = gctl_get_int(req, "all"); 807153190Spjd if (nargs > 0) { 808153190Spjd for (i = 0; i < nargs; i++) { 809153190Spjd name = gctl_get_ascii(req, "arg%d", i); 810132665Spjd gp = find_geom(classp, name); 811219969Smav if (gp == NULL) 812167842Spjd errx(EXIT_FAILURE, "No such geom: %s.", name); 813219969Smav list_one_geom(gp); 814129470Spjd } 815129470Spjd } else { 816129470Spjd LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 817219969Smav if (LIST_EMPTY(&gp->lg_provider) && !all) 818143522Spjd continue; 819143532Spjd list_one_geom(gp); 820129470Spjd } 821129470Spjd } 822129470Spjd geom_deletetree(&mesh); 823129470Spjd} 824129470Spjd 825129470Spjdstatic int 826143534Spjdstd_status_available(void) 827143534Spjd{ 828143534Spjd 829143534Spjd /* 'status' command is available when 'list' command is. */ 830143534Spjd return (std_list_available()); 831143534Spjd} 832143534Spjd 833143534Spjdstatic void 834143558Spjdstatus_update_len(struct ggeom *gp, int *name_len, int *status_len) 835143534Spjd{ 836143534Spjd struct gconfig *conf; 837143558Spjd int len; 838143534Spjd 839143534Spjd assert(gp != NULL); 840143534Spjd assert(name_len != NULL); 841143534Spjd assert(status_len != NULL); 842143534Spjd 843219969Smav len = strlen(gp->lg_name); 844143534Spjd if (*name_len < len) 845143534Spjd *name_len = len; 846143534Spjd LIST_FOREACH(conf, &gp->lg_config, lg_config) { 847143534Spjd if (strcasecmp(conf->lg_name, "state") == 0) { 848143534Spjd len = strlen(conf->lg_val); 849143534Spjd if (*status_len < len) 850143534Spjd *status_len = len; 851143534Spjd } 852143534Spjd } 853143534Spjd} 854143534Spjd 855219969Smavstatic void 856219969Smavstatus_update_len_prs(struct ggeom *gp, int *name_len, int *status_len) 857219969Smav{ 858219969Smav struct gprovider *pp; 859219969Smav struct gconfig *conf; 860219969Smav int len, glen; 861219969Smav 862219969Smav assert(gp != NULL); 863219969Smav assert(name_len != NULL); 864219969Smav assert(status_len != NULL); 865219969Smav 866219969Smav glen = 0; 867219969Smav LIST_FOREACH(conf, &gp->lg_config, lg_config) { 868219969Smav if (strcasecmp(conf->lg_name, "state") == 0) { 869219969Smav glen = strlen(conf->lg_val); 870219969Smav break; 871219969Smav } 872219969Smav } 873219969Smav LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 874219969Smav len = strlen(pp->lg_name); 875219969Smav if (*name_len < len) 876219969Smav *name_len = len; 877219969Smav len = glen; 878219969Smav LIST_FOREACH(conf, &pp->lg_config, lg_config) { 879219969Smav if (strcasecmp(conf->lg_name, "state") == 0) { 880219969Smav len = strlen(conf->lg_val); 881219969Smav break; 882219969Smav } 883219969Smav } 884219969Smav if (*status_len < len) 885219969Smav *status_len = len; 886219969Smav } 887219969Smav} 888219969Smav 889143572Spjdstatic char * 890143534Spjdstatus_one_consumer(struct gconsumer *cp) 891143534Spjd{ 892143572Spjd static char buf[256]; 893143534Spjd struct gprovider *pp; 894143534Spjd struct gconfig *conf; 895219969Smav const char *state, *syncr; 896143534Spjd 897143534Spjd pp = cp->lg_provider; 898143534Spjd if (pp == NULL) 899143572Spjd return (NULL); 900219969Smav state = NULL; 901219969Smav syncr = NULL; 902143534Spjd LIST_FOREACH(conf, &cp->lg_config, lg_config) { 903219969Smav if (strcasecmp(conf->lg_name, "state") == 0) 904219969Smav state = conf->lg_val; 905143534Spjd if (strcasecmp(conf->lg_name, "synchronized") == 0) 906219969Smav syncr = conf->lg_val; 907143534Spjd } 908219969Smav if (state == NULL && syncr == NULL) 909143572Spjd snprintf(buf, sizeof(buf), "%s", pp->lg_name); 910219969Smav else if (state != NULL && syncr != NULL) { 911219969Smav snprintf(buf, sizeof(buf), "%s (%s, %s)", pp->lg_name, 912219969Smav state, syncr); 913219969Smav } else { 914143572Spjd snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name, 915219969Smav state ? state : syncr); 916143572Spjd } 917143572Spjd return (buf); 918143534Spjd} 919143534Spjd 920143534Spjdstatic void 921143572Spjdstatus_one_geom(struct ggeom *gp, int script, int name_len, int status_len) 922143534Spjd{ 923143534Spjd struct gconsumer *cp; 924143534Spjd struct gconfig *conf; 925143572Spjd const char *name, *status, *component; 926143572Spjd int gotone; 927143534Spjd 928219969Smav name = gp->lg_name; 929219969Smav status = "N/A"; 930143534Spjd LIST_FOREACH(conf, &gp->lg_config, lg_config) { 931219969Smav if (strcasecmp(conf->lg_name, "state") == 0) { 932219969Smav status = conf->lg_val; 933143534Spjd break; 934219969Smav } 935143534Spjd } 936143572Spjd gotone = 0; 937143534Spjd LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) { 938143572Spjd component = status_one_consumer(cp); 939143572Spjd if (component == NULL) 940143572Spjd continue; 941143572Spjd gotone = 1; 942143572Spjd printf("%*s %*s %s\n", name_len, name, status_len, status, 943143572Spjd component); 944143572Spjd if (!script) 945143572Spjd name = status = ""; 946143534Spjd } 947143572Spjd if (!gotone) { 948143572Spjd printf("%*s %*s %s\n", name_len, name, status_len, status, 949143572Spjd "N/A"); 950143572Spjd } 951143534Spjd} 952143534Spjd 953143534Spjdstatic void 954219969Smavstatus_one_geom_prs(struct ggeom *gp, int script, int name_len, int status_len) 955219969Smav{ 956219969Smav struct gprovider *pp; 957219969Smav struct gconsumer *cp; 958219969Smav struct gconfig *conf; 959219969Smav const char *name, *status, *component; 960219969Smav int gotone; 961219969Smav 962219969Smav LIST_FOREACH(pp, &gp->lg_provider, lg_provider) { 963219969Smav name = pp->lg_name; 964219969Smav status = "N/A"; 965219969Smav LIST_FOREACH(conf, &gp->lg_config, lg_config) { 966219969Smav if (strcasecmp(conf->lg_name, "state") == 0) { 967219969Smav status = conf->lg_val; 968219969Smav break; 969219969Smav } 970219969Smav } 971219969Smav LIST_FOREACH(conf, &pp->lg_config, lg_config) { 972219969Smav if (strcasecmp(conf->lg_name, "state") == 0) { 973219969Smav status = conf->lg_val; 974219969Smav break; 975219969Smav } 976219969Smav } 977219969Smav gotone = 0; 978219969Smav LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) { 979219969Smav component = status_one_consumer(cp); 980219969Smav if (component == NULL) 981219969Smav continue; 982219969Smav gotone = 1; 983219969Smav printf("%*s %*s %s\n", name_len, name, 984219969Smav status_len, status, component); 985219969Smav if (!script) 986219969Smav name = status = ""; 987219969Smav } 988219969Smav if (!gotone) { 989219969Smav printf("%*s %*s %s\n", name_len, name, 990219969Smav status_len, status, "N/A"); 991219969Smav } 992219969Smav } 993219969Smav} 994219969Smav 995219969Smavstatic void 996143534Spjdstd_status(struct gctl_req *req, unsigned flags __unused) 997143534Spjd{ 998143534Spjd struct gmesh mesh; 999143534Spjd struct gclass *classp; 1000143534Spjd struct ggeom *gp; 1001153190Spjd const char *name; 1002143558Spjd int name_len, status_len; 1003219969Smav int all, error, geoms, i, n, nargs, script; 1004143534Spjd 1005143534Spjd error = geom_gettree(&mesh); 1006162867Spjd if (error != 0) 1007162867Spjd errc(EXIT_FAILURE, error, "Cannot get GEOM tree"); 1008143534Spjd classp = find_class(&mesh, gclass_name); 1009167842Spjd if (classp == NULL) 1010167842Spjd errx(EXIT_FAILURE, "Class %s not found.", gclass_name); 1011153190Spjd nargs = gctl_get_int(req, "nargs"); 1012219969Smav all = gctl_get_int(req, "all"); 1013219969Smav geoms = gctl_get_int(req, "geoms"); 1014153190Spjd script = gctl_get_int(req, "script"); 1015219969Smav if (script) { 1016219969Smav name_len = 0; 1017219969Smav status_len = 0; 1018219969Smav } else { 1019219969Smav name_len = strlen("Name"); 1020219969Smav status_len = strlen("Status"); 1021219969Smav } 1022153190Spjd if (nargs > 0) { 1023153190Spjd for (i = 0, n = 0; i < nargs; i++) { 1024153190Spjd name = gctl_get_ascii(req, "arg%d", i); 1025143534Spjd gp = find_geom(classp, name); 1026143534Spjd if (gp == NULL) 1027167842Spjd errx(EXIT_FAILURE, "No such geom: %s.", name); 1028219969Smav if (geoms) { 1029219969Smav status_update_len(gp, 1030219969Smav &name_len, &status_len); 1031219969Smav } else { 1032219969Smav status_update_len_prs(gp, 1033219969Smav &name_len, &status_len); 1034143534Spjd } 1035219969Smav n++; 1036143534Spjd } 1037143534Spjd if (n == 0) 1038143534Spjd goto end; 1039143534Spjd } else { 1040153190Spjd n = 0; 1041143534Spjd LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 1042219969Smav if (LIST_EMPTY(&gp->lg_provider) && !all) 1043143534Spjd continue; 1044219969Smav if (geoms) { 1045219969Smav status_update_len(gp, 1046219969Smav &name_len, &status_len); 1047219969Smav } else { 1048219969Smav status_update_len_prs(gp, 1049219969Smav &name_len, &status_len); 1050219969Smav } 1051143534Spjd n++; 1052143534Spjd } 1053143534Spjd if (n == 0) 1054143534Spjd goto end; 1055143534Spjd } 1056153190Spjd if (!script) { 1057143572Spjd printf("%*s %*s %s\n", name_len, "Name", status_len, "Status", 1058143572Spjd "Components"); 1059143572Spjd } 1060153190Spjd if (nargs > 0) { 1061153190Spjd for (i = 0; i < nargs; i++) { 1062153190Spjd name = gctl_get_ascii(req, "arg%d", i); 1063143534Spjd gp = find_geom(classp, name); 1064219969Smav if (gp == NULL) 1065219969Smav continue; 1066219969Smav if (geoms) { 1067153190Spjd status_one_geom(gp, script, name_len, 1068143572Spjd status_len); 1069219969Smav } else { 1070219969Smav status_one_geom_prs(gp, script, name_len, 1071219969Smav status_len); 1072143534Spjd } 1073143534Spjd } 1074143534Spjd } else { 1075143534Spjd LIST_FOREACH(gp, &classp->lg_geom, lg_geom) { 1076219969Smav if (LIST_EMPTY(&gp->lg_provider) && !all) 1077143534Spjd continue; 1078219969Smav if (geoms) { 1079219969Smav status_one_geom(gp, script, name_len, 1080219969Smav status_len); 1081219969Smav } else { 1082219969Smav status_one_geom_prs(gp, script, name_len, 1083219969Smav status_len); 1084219969Smav } 1085143534Spjd } 1086143534Spjd } 1087143534Spjdend: 1088143534Spjd geom_deletetree(&mesh); 1089143534Spjd} 1090143534Spjd 1091143534Spjdstatic int 1092129470Spjdstd_load_available(void) 1093129470Spjd{ 1094129470Spjd char name[MAXPATHLEN], paths[MAXPATHLEN * 8], *p; 1095129470Spjd struct stat sb; 1096129470Spjd size_t len; 1097129470Spjd 1098129470Spjd snprintf(name, sizeof(name), "g_%s", class_name); 1099129470Spjd /* 1100129470Spjd * If already in kernel, "load" command is not available. 1101129470Spjd */ 1102129470Spjd if (modfind(name) >= 0) 1103129470Spjd return (0); 1104129470Spjd bzero(paths, sizeof(paths)); 1105129470Spjd len = sizeof(paths); 1106129470Spjd if (sysctlbyname("kern.module_path", paths, &len, NULL, 0) < 0) 1107129470Spjd err(EXIT_FAILURE, "sysctl(kern.module_path)"); 1108129470Spjd for (p = strtok(paths, ";"); p != NULL; p = strtok(NULL, ";")) { 1109129470Spjd snprintf(name, sizeof(name), "%s/geom_%s.ko", p, class_name); 1110129470Spjd /* 1111129470Spjd * If geom_<name>.ko file exists, "load" command is available. 1112129470Spjd */ 1113129470Spjd if (stat(name, &sb) == 0) 1114129470Spjd return (1); 1115129470Spjd } 1116129470Spjd return (0); 1117129470Spjd} 1118129470Spjd 1119129470Spjdstatic void 1120129470Spjdstd_load(struct gctl_req *req __unused, unsigned flags) 1121129470Spjd{ 1122129470Spjd 1123129470Spjd /* 1124129470Spjd * Do nothing special here, because of G_FLAG_LOADKLD flag, 1125129470Spjd * module is already loaded. 1126129470Spjd */ 1127129470Spjd if ((flags & G_FLAG_VERBOSE) != 0) 1128129470Spjd printf("Module available.\n"); 1129129470Spjd} 1130129470Spjd 1131129470Spjdstatic int 1132129470Spjdstd_unload_available(void) 1133129470Spjd{ 1134129470Spjd char name[64]; 1135129470Spjd int id; 1136129470Spjd 1137129470Spjd snprintf(name, sizeof(name), "geom_%s", class_name); 1138129470Spjd id = kldfind(name); 1139129470Spjd if (id >= 0) 1140129470Spjd return (1); 1141129470Spjd return (0); 1142129470Spjd} 1143129470Spjd 1144129470Spjdstatic void 1145129470Spjdstd_unload(struct gctl_req *req, unsigned flags __unused) 1146129470Spjd{ 1147129470Spjd char name[64]; 1148129470Spjd int id; 1149129470Spjd 1150129470Spjd snprintf(name, sizeof(name), "geom_%s", class_name); 1151129470Spjd id = kldfind(name); 1152129470Spjd if (id < 0) { 1153129470Spjd gctl_error(req, "Could not find module: %s.", strerror(errno)); 1154129470Spjd return; 1155129470Spjd } 1156129470Spjd if (kldunload(id) < 0) { 1157129470Spjd gctl_error(req, "Could not unload module: %s.", 1158129470Spjd strerror(errno)); 1159129470Spjd return; 1160129470Spjd } 1161129470Spjd} 1162129470Spjd 1163129470Spjdstatic int 1164129470Spjdstd_available(const char *name) 1165129470Spjd{ 1166129470Spjd 1167129591Spjd if (strcmp(name, "help") == 0) 1168129591Spjd return (1); 1169129591Spjd else if (strcmp(name, "list") == 0) 1170129470Spjd return (std_list_available()); 1171143534Spjd else if (strcmp(name, "status") == 0) 1172143534Spjd return (std_status_available()); 1173129470Spjd else if (strcmp(name, "load") == 0) 1174129470Spjd return (std_load_available()); 1175129470Spjd else if (strcmp(name, "unload") == 0) 1176129470Spjd return (std_unload_available()); 1177129470Spjd else 1178129470Spjd assert(!"Unknown standard command."); 1179129470Spjd return (0); 1180129470Spjd} 1181