gvinum.c revision 133097
1130391Sle/* 2130391Sle * Copyright (c) 2004 Lukas Ertl 3130391Sle * All rights reserved. 4130391Sle * 5130391Sle * Redistribution and use in source and binary forms, with or without 6130391Sle * modification, are permitted provided that the following conditions 7130391Sle * are met: 8130391Sle * 1. Redistributions of source code must retain the above copyright 9130391Sle * notice, this list of conditions and the following disclaimer. 10130391Sle * 2. Redistributions in binary form must reproduce the above copyright 11130391Sle * notice, this list of conditions and the following disclaimer in the 12130391Sle * documentation and/or other materials provided with the distribution. 13130391Sle * 14130391Sle * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15130391Sle * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16130391Sle * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17130391Sle * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 18130391Sle * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19130391Sle * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20130391Sle * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21130391Sle * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22130391Sle * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23130391Sle * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24130391Sle * SUCH DAMAGE. 25130391Sle * 26130391Sle * $FreeBSD: head/sbin/gvinum/gvinum.c 133097 2004-08-04 00:23:00Z le $ 27130391Sle */ 28130391Sle 29130391Sle#include <sys/param.h> 30130391Sle#include <sys/linker.h> 31130391Sle#include <sys/lock.h> 32130391Sle#include <sys/module.h> 33130391Sle#include <sys/mutex.h> 34130391Sle#include <sys/queue.h> 35130391Sle#include <sys/utsname.h> 36130391Sle 37130391Sle#include <geom/vinum/geom_vinum_var.h> 38130391Sle#include <geom/vinum/geom_vinum_share.h> 39130391Sle 40130391Sle#include <ctype.h> 41130391Sle#include <err.h> 42130391Sle#include <libgeom.h> 43130391Sle#include <stdint.h> 44130391Sle#include <stdio.h> 45130391Sle#include <stdlib.h> 46130391Sle#include <paths.h> 47130391Sle#include <readline/readline.h> 48130391Sle#include <readline/history.h> 49130391Sle#include <unistd.h> 50130391Sle 51130391Sle#include "gvinum.h" 52130391Sle 53130391Slevoid gvinum_cancelinit(int, char **); 54130391Slevoid gvinum_create(int, char **); 55130391Slevoid gvinum_help(void); 56130391Slevoid gvinum_init(int, char **); 57130391Slevoid gvinum_list(int, char **); 58130391Slevoid gvinum_printconfig(int, char **); 59130391Slevoid gvinum_rm(int, char **); 60130391Slevoid gvinum_saveconfig(void); 61130391Slevoid gvinum_start(int, char **); 62130391Slevoid gvinum_stop(int, char **); 63130391Slevoid parseline(int, char **); 64130391Slevoid printconfig(FILE *, char *); 65130391Sle 66130391Sleint 67130391Slemain(int argc, char **argv) 68130391Sle{ 69130391Sle int line, tokens; 70130391Sle char buffer[BUFSIZ], *inputline, *token[GV_MAXARGS]; 71130391Sle 72130391Sle /* Load the module if necessary. */ 73130391Sle if (kldfind(GVINUMMOD) < 0 && kldload(GVINUMMOD) < 0) 74130391Sle err(1, GVINUMMOD ": Kernel module not available"); 75130391Sle 76130391Sle /* Arguments given on the command line. */ 77130391Sle if (argc > 1) { 78130391Sle argc--; 79130391Sle argv++; 80130391Sle parseline(argc, argv); 81130391Sle 82130391Sle /* Interactive mode. */ 83130391Sle } else { 84130391Sle for (;;) { 85130391Sle inputline = readline("gvinum -> "); 86130391Sle if (inputline == NULL) { 87130391Sle if (ferror(stdin)) { 88130391Sle err(1, "can't read input"); 89130391Sle } else { 90130391Sle printf("\n"); 91130391Sle exit(0); 92130391Sle } 93130391Sle } else if (*inputline) { 94130391Sle add_history(inputline); 95130391Sle strcpy(buffer, inputline); 96130391Sle free(inputline); 97130391Sle line++; /* count the lines */ 98130391Sle tokens = gv_tokenize(buffer, token, GV_MAXARGS); 99130391Sle if (tokens) 100130391Sle parseline(tokens, token); 101130391Sle } 102130391Sle } 103130391Sle } 104130391Sle exit(0); 105130391Sle} 106130391Sle 107130391Slevoid 108130391Slegvinum_cancelinit(int argc, char **argv) 109130391Sle{ 110130391Sle struct gctl_req *req; 111130391Sle int i; 112130391Sle const char *errstr; 113130391Sle char buf[20]; 114130391Sle 115130391Sle if (argc == 1) 116130391Sle return; 117130391Sle 118130391Sle argc--; 119130391Sle argv++; 120130391Sle 121130391Sle req = gctl_get_handle(); 122130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 123130391Sle gctl_ro_param(req, "verb", -1, "cancelinit"); 124130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 125130391Sle if (argc) { 126130391Sle for (i = 0; i < argc; i++) { 127130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 128130391Sle gctl_ro_param(req, buf, -1, argv[i]); 129130391Sle } 130130391Sle } 131130391Sle errstr = gctl_issue(req); 132130391Sle if (errstr != NULL) { 133130391Sle warnx("can't init: %s", errstr); 134130391Sle gctl_free(req); 135130391Sle return; 136130391Sle } 137130391Sle 138130391Sle gctl_free(req); 139130391Sle gvinum_list(0, NULL); 140130391Sle} 141130391Sle 142130391Slevoid 143130391Slegvinum_create(int argc, char **argv) 144130391Sle{ 145130391Sle struct gctl_req *req; 146130391Sle struct gv_drive *d; 147130391Sle struct gv_plex *p; 148130391Sle struct gv_sd *s; 149130391Sle struct gv_volume *v; 150130391Sle FILE *tmp; 151130391Sle int drives, errors, fd, line, plexes, plex_in_volume; 152130391Sle int sd_in_plex, status, subdisks, tokens, volumes; 153130391Sle const char *errstr; 154130391Sle char buf[BUFSIZ], buf1[BUFSIZ], commandline[BUFSIZ], *ed; 155130391Sle char original[BUFSIZ], tmpfile[20], *token[GV_MAXARGS]; 156130391Sle char plex[GV_MAXPLEXNAME], volume[GV_MAXVOLNAME]; 157130391Sle 158133097Sle if (argc == 2) { 159133097Sle if ((tmp = fopen(argv[1], "r")) == NULL) { 160133097Sle warn("can't open '%s' for reading", argv[1]); 161133097Sle return; 162133097Sle } 163133097Sle } else { 164133097Sle snprintf(tmpfile, sizeof(tmpfile), "/tmp/gvinum.XXXXXX"); 165133097Sle 166133097Sle if ((fd = mkstemp(tmpfile)) == -1) { 167133097Sle warn("temporary file not accessible"); 168133097Sle return; 169133097Sle } 170133097Sle if ((tmp = fdopen(fd, "w")) == NULL) { 171133097Sle warn("can't open '%s' for writing", tmpfile); 172133097Sle return; 173133097Sle } 174133097Sle printconfig(tmp, "# "); 175133097Sle fclose(tmp); 176133097Sle 177133097Sle ed = getenv("EDITOR"); 178133097Sle if (ed == NULL) 179133097Sle ed = _PATH_VI; 180133097Sle 181133097Sle snprintf(commandline, sizeof(commandline), "%s %s", ed, 182133097Sle tmpfile); 183133097Sle status = system(commandline); 184133097Sle if (status != 0) { 185133097Sle warn("couldn't exec %s; status: %d", ed, status); 186133097Sle return; 187133097Sle } 188133097Sle 189133097Sle if ((tmp = fopen(tmpfile, "r")) == NULL) { 190133097Sle warn("can't open '%s' for reading", tmpfile); 191133097Sle return; 192133097Sle } 193130391Sle } 194130391Sle 195130391Sle req = gctl_get_handle(); 196130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 197130391Sle gctl_ro_param(req, "verb", -1, "create"); 198130391Sle 199130391Sle drives = volumes = plexes = subdisks = 0; 200130391Sle plex_in_volume = sd_in_plex = 0; 201130391Sle errors = 0; 202130391Sle line = 1; 203130391Sle while ((fgets(buf, BUFSIZ, tmp)) != NULL) { 204130391Sle 205130391Sle /* Skip empty lines and comments. */ 206130391Sle if (*buf == '\0' || *buf == '#') { 207130391Sle line++; 208130391Sle continue; 209130391Sle } 210130391Sle 211130391Sle /* Kill off the newline. */ 212130391Sle buf[strlen(buf) - 1] = '\0'; 213130391Sle 214130391Sle /* 215130391Sle * Copy the original input line in case we need it for error 216130391Sle * output. 217130391Sle */ 218130391Sle strncpy(original, buf, sizeof(buf)); 219130391Sle 220130391Sle tokens = gv_tokenize(buf, token, GV_MAXARGS); 221130391Sle 222130391Sle if (tokens > 0) { 223130391Sle /* Volume definition. */ 224130391Sle if (!strcmp(token[0], "volume")) { 225130391Sle v = gv_new_volume(tokens, token); 226130391Sle if (v == NULL) { 227130391Sle warnx("line %d: invalid volume " 228130391Sle "definition", line); 229130391Sle warnx("line %d: '%s'", line, original); 230130391Sle errors++; 231130391Sle } else { 232130391Sle /* Reset plex count for this volume. */ 233130391Sle plex_in_volume = 0; 234130391Sle 235130391Sle /* 236130391Sle * Set default volume name for 237130391Sle * following plex definitions. 238130391Sle */ 239130391Sle strncpy(volume, v->name, 240130391Sle sizeof(volume)); 241130391Sle 242130391Sle snprintf(buf1, sizeof(buf1), "volume%d", 243130391Sle volumes); 244130391Sle gctl_ro_param(req, buf1, sizeof(*v), v); 245130391Sle volumes++; 246130391Sle } 247130391Sle 248130391Sle /* Plex definition. */ 249130391Sle } else if (!strcmp(token[0], "plex")) { 250130391Sle p = gv_new_plex(tokens, token); 251130391Sle if (p == NULL) { 252130391Sle warnx("line %d: invalid plex " 253130391Sle "definition", line); 254130391Sle warnx("line %d: '%s'", line, original); 255130391Sle errors++; 256130391Sle } else { 257130391Sle /* Reset subdisk count for this plex. */ 258130391Sle sd_in_plex = 0; 259130391Sle 260130391Sle /* Default name. */ 261130391Sle if (strlen(p->name) == 0) { 262130391Sle snprintf(p->name, 263130391Sle GV_MAXPLEXNAME, 264130391Sle "%s.p%d", volume, 265130391Sle plex_in_volume++); 266130391Sle } 267130391Sle 268130391Sle /* Default volume. */ 269130391Sle if (strlen(p->volume) == 0) { 270130391Sle snprintf(p->volume, 271130391Sle GV_MAXVOLNAME, "%s", 272130391Sle volume); 273130391Sle } 274130391Sle 275130391Sle /* 276130391Sle * Set default plex name for following 277130391Sle * subdisk definitions. 278130391Sle */ 279130391Sle strncpy(plex, p->name, GV_MAXPLEXNAME); 280130391Sle 281130391Sle snprintf(buf1, sizeof(buf1), "plex%d", 282130391Sle plexes); 283130391Sle gctl_ro_param(req, buf1, sizeof(*p), p); 284130391Sle plexes++; 285130391Sle } 286130391Sle 287130391Sle /* Subdisk definition. */ 288130391Sle } else if (!strcmp(token[0], "sd")) { 289130391Sle s = gv_new_sd(tokens, token); 290130391Sle if (s == NULL) { 291130391Sle warnx("line %d: invalid subdisk " 292130391Sle "definition:", line); 293130391Sle warnx("line %d: '%s'", line, original); 294130391Sle errors++; 295130391Sle } else { 296130391Sle /* Default name. */ 297130391Sle if (strlen(s->name) == 0) { 298130391Sle snprintf(s->name, GV_MAXSDNAME, 299130391Sle "%s.s%d", plex, 300130391Sle sd_in_plex++); 301130391Sle } 302130391Sle 303130391Sle /* Default plex. */ 304130391Sle if (strlen(s->plex) == 0) { 305130391Sle snprintf(s->plex, 306130391Sle GV_MAXPLEXNAME, "%s", plex); 307130391Sle } 308130391Sle 309130391Sle snprintf(buf1, sizeof(buf1), "sd%d", 310130391Sle subdisks); 311130391Sle gctl_ro_param(req, buf1, sizeof(*s), s); 312130391Sle subdisks++; 313130391Sle } 314130391Sle 315130391Sle /* Subdisk definition. */ 316130391Sle } else if (!strcmp(token[0], "drive")) { 317130391Sle d = gv_new_drive(tokens, token); 318130391Sle if (d == NULL) { 319130391Sle warnx("line %d: invalid drive " 320130391Sle "definition:", line); 321130391Sle warnx("line %d: '%s'", line, original); 322130391Sle errors++; 323130391Sle } else { 324130391Sle snprintf(buf1, sizeof(buf1), "drive%d", 325130391Sle drives); 326130391Sle gctl_ro_param(req, buf1, sizeof(*d), d); 327130391Sle drives++; 328130391Sle } 329130391Sle 330130391Sle /* Everything else is bogus. */ 331130391Sle } else { 332130391Sle warnx("line %d: invalid definition:", line); 333130391Sle warnx("line %d: '%s'", line, original); 334130391Sle errors++; 335130391Sle } 336130391Sle } 337130391Sle line++; 338130391Sle } 339130391Sle 340130391Sle fclose(tmp); 341130391Sle unlink(tmpfile); 342130391Sle 343130391Sle if (!errors && (volumes || plexes || subdisks || drives)) { 344130391Sle gctl_ro_param(req, "volumes", sizeof(int), &volumes); 345130391Sle gctl_ro_param(req, "plexes", sizeof(int), &plexes); 346130391Sle gctl_ro_param(req, "subdisks", sizeof(int), &subdisks); 347130391Sle gctl_ro_param(req, "drives", sizeof(int), &drives); 348130391Sle errstr = gctl_issue(req); 349130391Sle if (errstr != NULL) 350130391Sle warnx("create failed: %s", errstr); 351130391Sle } 352130391Sle gctl_free(req); 353130391Sle gvinum_list(0, NULL); 354130391Sle} 355130391Sle 356130391Slevoid 357130391Slegvinum_help(void) 358130391Sle{ 359130391Sle printf("COMMANDS\n" 360130391Sle "attach plex volume [rename]\n" 361130391Sle "attach subdisk plex [offset] [rename]\n" 362130391Sle " Attach a plex to a volume, or a subdisk to a plex.\n" 363130391Sle "checkparity plex [-f] [-v]\n" 364130391Sle " Check the parity blocks of a RAID-4 or RAID-5 plex.\n" 365130391Sle "concat [-f] [-n name] [-v] drives\n" 366130391Sle " Create a concatenated volume from the specified drives.\n" 367130391Sle "create [-f] description-file\n" 368130391Sle " Create a volume as described in description-file.\n" 369130391Sle "detach [-f] [plex | subdisk]\n" 370130391Sle " Detach a plex or subdisk from the volume or plex to" 371130391Sle "which it is\n" 372130391Sle " attached.\n" 373130391Sle "dumpconfig [drive ...]\n" 374130391Sle " List the configuration information stored on the" 375130391Sle " specified\n" 376130391Sle " drives, or all drives in the system if no drive names" 377130391Sle " are speci-\n" 378130391Sle " fied.\n" 379130391Sle "info [-v] [-V]\n" 380130391Sle " List information about volume manager state.\n" 381130391Sle "init [-S size] [-w] plex | subdisk\n" 382130391Sle " Initialize the contents of a subdisk or all the subdisks" 383130391Sle " of a\n" 384130391Sle " plex to all zeros.\n" 385130391Sle "label volume\n" 386130391Sle " Create a volume label.\n" 387130391Sle "l | list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n" 388130391Sle " List information about specified objects.\n" 389130391Sle "ld [-r] [-s] [-v] [-V] [volume]\n" 390130391Sle " List information about drives.\n" 391130391Sle "ls [-r] [-s] [-v] [-V] [subdisk]\n" 392130391Sle " List information about subdisks.\n" 393130391Sle "lp [-r] [-s] [-v] [-V] [plex]\n" 394130391Sle " List information about plexes.\n" 395130391Sle "lv [-r] [-s] [-v] [-V] [volume]\n" 396130391Sle " List information about volumes.\n" 397130391Sle "mirror [-f] [-n name] [-s] [-v] drives\n" 398130391Sle " Create a mirrored volume from the specified drives.\n" 399130391Sle "move | mv -f drive object ...\n" 400130391Sle " Move the object(s) to the specified drive.\n" 401130391Sle "printconfig [file]\n" 402130391Sle " Write a copy of the current configuration to file.\n" 403130391Sle "quit Exit the vinum program when running in interactive mode." 404130391Sle " Nor-\n" 405130391Sle " mally this would be done by entering the EOF character.\n" 406130391Sle "rename [-r] [drive | subdisk | plex | volume] newname\n" 407130391Sle " Change the name of the specified object.\n" 408130391Sle "rebuildparity plex [-f] [-v] [-V]\n" 409130391Sle " Rebuild the parity blocks of a RAID-4 or RAID-5 plex.\n" 410130391Sle "resetconfig\n" 411130391Sle " Reset the complete vinum configuration.\n" 412130391Sle "rm [-f] [-r] volume | plex | subdisk\n" 413130391Sle " Remove an object.\n" 414130391Sle "saveconfig\n" 415130391Sle " Save vinum configuration to disk after configuration" 416130391Sle " failures.\n" 417130391Sle "setstate state [volume | plex | subdisk | drive]\n" 418130391Sle " Set state without influencing other objects, for" 419130391Sle " diagnostic pur-\n" 420130391Sle " poses only.\n" 421130391Sle "start [-i interval] [-S size] [-w] volume | plex | subdisk\n" 422130391Sle " Allow the system to access the objects.\n" 423130391Sle "stop [-f] [volume | plex | subdisk]\n" 424130391Sle " Terminate access to the objects, or stop vinum if no" 425130391Sle " parameters\n" 426130391Sle " are specified.\n" 427130391Sle "stripe [-f] [-n name] [-v] drives\n" 428130391Sle " Create a striped volume from the specified drives.\n" 429130391Sle ); 430130391Sle 431130391Sle return; 432130391Sle} 433130391Sle 434130391Slevoid 435130391Slegvinum_init(int argc, char **argv) 436130391Sle{ 437130391Sle struct gctl_req *req; 438130391Sle int i, initsize, j; 439130391Sle const char *errstr; 440130391Sle char buf[20]; 441130391Sle 442130391Sle initsize = 0; 443130391Sle optreset = 1; 444130391Sle optind = 1; 445130391Sle while ((j = getopt(argc, argv, "S")) != -1) { 446130391Sle switch (j) { 447130391Sle case 'S': 448130391Sle initsize = atoi(optarg); 449130391Sle break; 450130391Sle case '?': 451130391Sle default: 452130391Sle return; 453130391Sle } 454130391Sle } 455130391Sle argc -= optind; 456130391Sle argv += optind; 457130391Sle 458130391Sle if (!initsize) 459130391Sle initsize = 512; 460130391Sle 461130391Sle req = gctl_get_handle(); 462130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 463130391Sle gctl_ro_param(req, "verb", -1, "init"); 464130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 465130391Sle gctl_ro_param(req, "initsize", sizeof(int), &initsize); 466130391Sle if (argc) { 467130391Sle for (i = 0; i < argc; i++) { 468130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 469130391Sle gctl_ro_param(req, buf, -1, argv[i]); 470130391Sle } 471130391Sle } 472130391Sle errstr = gctl_issue(req); 473130391Sle if (errstr != NULL) { 474130391Sle warnx("can't init: %s", errstr); 475130391Sle gctl_free(req); 476130391Sle return; 477130391Sle } 478130391Sle 479130391Sle gctl_free(req); 480130391Sle gvinum_list(0, NULL); 481130391Sle} 482130391Sle 483130391Slevoid 484130391Slegvinum_list(int argc, char **argv) 485130391Sle{ 486130391Sle struct gctl_req *req; 487130391Sle int flags, i, j; 488130391Sle const char *errstr; 489130391Sle char buf[20], *cmd, config[GV_CFG_LEN + 1]; 490130391Sle 491130391Sle flags = 0; 492130391Sle cmd = "list"; 493130391Sle 494130391Sle if (argc) { 495130391Sle optreset = 1; 496130391Sle optind = 1; 497130391Sle cmd = argv[0]; 498130391Sle while ((j = getopt(argc, argv, "rsvV")) != -1) { 499130391Sle switch (j) { 500130391Sle case 'r': 501130391Sle flags |= GV_FLAG_R; 502130391Sle break; 503130391Sle case 's': 504130391Sle flags |= GV_FLAG_S; 505130391Sle break; 506130391Sle case 'v': 507130391Sle flags |= GV_FLAG_V; 508130391Sle break; 509130391Sle case 'V': 510130391Sle flags |= GV_FLAG_V; 511130391Sle flags |= GV_FLAG_VV; 512130391Sle break; 513130391Sle case '?': 514130391Sle default: 515130391Sle return; 516130391Sle } 517130391Sle } 518130391Sle argc -= optind; 519130391Sle argv += optind; 520130391Sle 521130391Sle } 522130391Sle 523130391Sle req = gctl_get_handle(); 524130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 525130391Sle gctl_ro_param(req, "verb", -1, "list"); 526130391Sle gctl_ro_param(req, "cmd", -1, cmd); 527130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 528130391Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 529130391Sle gctl_rw_param(req, "config", sizeof(config), config); 530130391Sle if (argc) { 531130391Sle for (i = 0; i < argc; i++) { 532130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 533130391Sle gctl_ro_param(req, buf, -1, argv[i]); 534130391Sle } 535130391Sle } 536130391Sle errstr = gctl_issue(req); 537130391Sle if (errstr != NULL) { 538130391Sle warnx("can't get configuration: %s", errstr); 539130391Sle gctl_free(req); 540130391Sle return; 541130391Sle } 542130391Sle 543130391Sle printf("%s", config); 544130391Sle gctl_free(req); 545130391Sle return; 546130391Sle} 547130391Sle 548130391Slevoid 549130391Slegvinum_printconfig(int argc, char **argv) 550130391Sle{ 551130391Sle printconfig(stdout, ""); 552130391Sle} 553130391Sle 554130391Slevoid 555130391Slegvinum_rm(int argc, char **argv) 556130391Sle{ 557130391Sle struct gctl_req *req; 558130391Sle int flags, i, j; 559130391Sle const char *errstr; 560130391Sle char buf[20], *cmd; 561130391Sle 562130391Sle cmd = argv[0]; 563130391Sle flags = 0; 564130391Sle optreset = 1; 565130391Sle optind = 1; 566130391Sle while ((j = getopt(argc, argv, "r")) != -1) { 567130391Sle switch (j) { 568130391Sle case 'r': 569130391Sle flags |= GV_FLAG_R; 570130391Sle break; 571130391Sle case '?': 572130391Sle default: 573130391Sle return; 574130391Sle } 575130391Sle } 576130391Sle argc -= optind; 577130391Sle argv += optind; 578130391Sle 579130391Sle req = gctl_get_handle(); 580130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 581130391Sle gctl_ro_param(req, "verb", -1, "remove"); 582130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 583130391Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 584130391Sle if (argc) { 585130391Sle for (i = 0; i < argc; i++) { 586130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 587130391Sle gctl_ro_param(req, buf, -1, argv[i]); 588130391Sle } 589130391Sle } 590130391Sle errstr = gctl_issue(req); 591130391Sle if (errstr != NULL) { 592130391Sle warnx("can't remove: %s", errstr); 593130391Sle gctl_free(req); 594130391Sle return; 595130391Sle } 596130391Sle gctl_free(req); 597130391Sle gvinum_list(0, NULL); 598130391Sle} 599130391Sle 600130391Slevoid 601130391Slegvinum_saveconfig(void) 602130391Sle{ 603130391Sle struct gctl_req *req; 604130391Sle const char *errstr; 605130391Sle 606130391Sle req = gctl_get_handle(); 607130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 608130391Sle gctl_ro_param(req, "verb", -1, "saveconfig"); 609130391Sle errstr = gctl_issue(req); 610130391Sle if (errstr != NULL) 611130391Sle warnx("can't save configuration: %s", errstr); 612130391Sle gctl_free(req); 613130391Sle} 614130391Sle 615130391Slevoid 616130391Slegvinum_start(int argc, char **argv) 617130391Sle{ 618130391Sle struct gctl_req *req; 619130391Sle int i, initsize, j; 620130391Sle const char *errstr; 621130391Sle char buf[20]; 622130391Sle 623130391Sle /* 'start' with no arguments is a no-op. */ 624130391Sle if (argc == 1) 625130391Sle return; 626130391Sle 627130391Sle initsize = 0; 628130391Sle 629130391Sle optreset = 1; 630130391Sle optind = 1; 631130391Sle while ((j = getopt(argc, argv, "S")) != -1) { 632130391Sle switch (j) { 633130391Sle case 'S': 634130391Sle initsize = atoi(optarg); 635130391Sle break; 636130391Sle case '?': 637130391Sle default: 638130391Sle return; 639130391Sle } 640130391Sle } 641130391Sle argc -= optind; 642130391Sle argv += optind; 643130391Sle 644130391Sle if (!initsize) 645130391Sle initsize = 512; 646130391Sle 647130391Sle req = gctl_get_handle(); 648130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 649130391Sle gctl_ro_param(req, "verb", -1, "start"); 650130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 651130391Sle gctl_ro_param(req, "initsize", sizeof(int), &initsize); 652130391Sle if (argc) { 653130391Sle for (i = 0; i < argc; i++) { 654130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 655130391Sle gctl_ro_param(req, buf, -1, argv[i]); 656130391Sle } 657130391Sle } 658130391Sle errstr = gctl_issue(req); 659130391Sle if (errstr != NULL) { 660130391Sle warnx("can't start: %s", errstr); 661130391Sle gctl_free(req); 662130391Sle return; 663130391Sle } 664130391Sle 665130391Sle gctl_free(req); 666130391Sle gvinum_list(0, NULL); 667130391Sle} 668130391Sle 669130391Slevoid 670130391Slegvinum_stop(int argc, char **argv) 671130391Sle{ 672130391Sle int fileid; 673130391Sle 674130391Sle fileid = kldfind(GVINUMMOD); 675130391Sle if (fileid == -1) { 676130391Sle warn("cannot find " GVINUMMOD); 677130391Sle return; 678130391Sle } 679130391Sle if (kldunload(fileid) != 0) { 680130391Sle warn("cannot unload " GVINUMMOD); 681130391Sle return; 682130391Sle } 683130391Sle 684130391Sle warnx(GVINUMMOD " unloaded"); 685130391Sle exit(0); 686130391Sle} 687130391Sle 688130391Slevoid 689130391Sleparseline(int argc, char **argv) 690130391Sle{ 691130391Sle if (argc <= 0) 692130391Sle return; 693130391Sle 694130391Sle if (!strcmp(argv[0], "cancelinit")) 695130391Sle gvinum_cancelinit(argc, argv); 696130391Sle else if (!strcmp(argv[0], "create")) 697130391Sle gvinum_create(argc, argv); 698130391Sle else if (!strcmp(argv[0], "exit") || !strcmp(argv[0], "quit")) 699130391Sle exit(0); 700130391Sle else if (!strcmp(argv[0], "help")) 701130391Sle gvinum_help(); 702130391Sle else if (!strcmp(argv[0], "init")) 703130391Sle gvinum_init(argc, argv); 704130391Sle else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "l")) 705130391Sle gvinum_list(argc, argv); 706130391Sle else if (!strcmp(argv[0], "ld")) 707130391Sle gvinum_list(argc, argv); 708130391Sle else if (!strcmp(argv[0], "lp")) 709130391Sle gvinum_list(argc, argv); 710130391Sle else if (!strcmp(argv[0], "ls")) 711130391Sle gvinum_list(argc, argv); 712130391Sle else if (!strcmp(argv[0], "lv")) 713130391Sle gvinum_list(argc, argv); 714130391Sle else if (!strcmp(argv[0], "printconfig")) 715130391Sle gvinum_printconfig(argc, argv); 716130391Sle else if (!strcmp(argv[0], "rm")) 717130391Sle gvinum_rm(argc, argv); 718130391Sle else if (!strcmp(argv[0], "saveconfig")) 719130391Sle gvinum_saveconfig(); 720130391Sle else if (!strcmp(argv[0], "start")) 721130391Sle gvinum_start(argc, argv); 722130391Sle else if (!strcmp(argv[0], "stop")) 723130391Sle gvinum_stop(argc, argv); 724130391Sle else 725130391Sle printf("unknown command '%s'\n", argv[0]); 726130391Sle 727130391Sle return; 728130391Sle} 729130391Sle 730130391Sle/* 731130391Sle * The guts of printconfig. This is called from gvinum_printconfig and from 732130391Sle * gvinum_create when called without an argument, in order to give the user 733130391Sle * something to edit. 734130391Sle */ 735130391Slevoid 736130391Sleprintconfig(FILE *of, char *comment) 737130391Sle{ 738130391Sle struct gctl_req *req; 739130391Sle struct utsname uname_s; 740130391Sle const char *errstr; 741130391Sle time_t now; 742130391Sle char buf[GV_CFG_LEN + 1]; 743130391Sle 744130391Sle uname(&uname_s); 745130391Sle time(&now); 746130391Sle 747130391Sle req = gctl_get_handle(); 748130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 749130391Sle gctl_ro_param(req, "verb", -1, "getconfig"); 750130391Sle gctl_ro_param(req, "comment", -1, comment); 751130391Sle gctl_rw_param(req, "config", sizeof(buf), buf); 752130391Sle errstr = gctl_issue(req); 753130391Sle if (errstr != NULL) { 754130391Sle warnx("can't get configuration: %s", errstr); 755130391Sle return; 756130391Sle } 757130391Sle gctl_free(req); 758130391Sle 759130391Sle fprintf(of, "# Vinum configuration of %s, saved at %s", 760130391Sle uname_s.nodename, 761130391Sle ctime(&now)); 762130391Sle 763130391Sle if (*comment != '\0') 764130391Sle fprintf(of, "# Current configuration:\n"); 765130391Sle 766130391Sle fprintf(of, buf); 767130391Sle} 768