gvinum.c revision 138112
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 138112 2004-11-26 12:31:36Z 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 **); 58138110Slevoid gvinum_parityop(int, char **, int); 59130391Slevoid gvinum_printconfig(int, char **); 60130391Slevoid gvinum_rm(int, char **); 61130391Slevoid gvinum_saveconfig(void); 62138112Slevoid gvinum_setstate(int, char **); 63130391Slevoid gvinum_start(int, char **); 64130391Slevoid gvinum_stop(int, char **); 65130391Slevoid parseline(int, char **); 66130391Slevoid printconfig(FILE *, char *); 67130391Sle 68130391Sleint 69130391Slemain(int argc, char **argv) 70130391Sle{ 71130391Sle int line, tokens; 72130391Sle char buffer[BUFSIZ], *inputline, *token[GV_MAXARGS]; 73130391Sle 74130391Sle /* Load the module if necessary. */ 75130391Sle if (kldfind(GVINUMMOD) < 0 && kldload(GVINUMMOD) < 0) 76130391Sle err(1, GVINUMMOD ": Kernel module not available"); 77130391Sle 78130391Sle /* Arguments given on the command line. */ 79130391Sle if (argc > 1) { 80130391Sle argc--; 81130391Sle argv++; 82130391Sle parseline(argc, argv); 83130391Sle 84130391Sle /* Interactive mode. */ 85130391Sle } else { 86130391Sle for (;;) { 87130391Sle inputline = readline("gvinum -> "); 88130391Sle if (inputline == NULL) { 89130391Sle if (ferror(stdin)) { 90130391Sle err(1, "can't read input"); 91130391Sle } else { 92130391Sle printf("\n"); 93130391Sle exit(0); 94130391Sle } 95130391Sle } else if (*inputline) { 96130391Sle add_history(inputline); 97130391Sle strcpy(buffer, inputline); 98130391Sle free(inputline); 99130391Sle line++; /* count the lines */ 100130391Sle tokens = gv_tokenize(buffer, token, GV_MAXARGS); 101130391Sle if (tokens) 102130391Sle parseline(tokens, token); 103130391Sle } 104130391Sle } 105130391Sle } 106130391Sle exit(0); 107130391Sle} 108130391Sle 109130391Slevoid 110130391Slegvinum_cancelinit(int argc, char **argv) 111130391Sle{ 112130391Sle struct gctl_req *req; 113130391Sle int i; 114130391Sle const char *errstr; 115130391Sle char buf[20]; 116130391Sle 117130391Sle if (argc == 1) 118130391Sle return; 119130391Sle 120130391Sle argc--; 121130391Sle argv++; 122130391Sle 123130391Sle req = gctl_get_handle(); 124130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 125130391Sle gctl_ro_param(req, "verb", -1, "cancelinit"); 126130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 127130391Sle if (argc) { 128130391Sle for (i = 0; i < argc; i++) { 129130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 130130391Sle gctl_ro_param(req, buf, -1, argv[i]); 131130391Sle } 132130391Sle } 133130391Sle errstr = gctl_issue(req); 134130391Sle if (errstr != NULL) { 135130391Sle warnx("can't init: %s", errstr); 136130391Sle gctl_free(req); 137130391Sle return; 138130391Sle } 139130391Sle 140130391Sle gctl_free(req); 141130391Sle gvinum_list(0, NULL); 142130391Sle} 143130391Sle 144130391Slevoid 145130391Slegvinum_create(int argc, char **argv) 146130391Sle{ 147130391Sle struct gctl_req *req; 148130391Sle struct gv_drive *d; 149130391Sle struct gv_plex *p; 150130391Sle struct gv_sd *s; 151130391Sle struct gv_volume *v; 152130391Sle FILE *tmp; 153130391Sle int drives, errors, fd, line, plexes, plex_in_volume; 154130391Sle int sd_in_plex, status, subdisks, tokens, volumes; 155130391Sle const char *errstr; 156130391Sle char buf[BUFSIZ], buf1[BUFSIZ], commandline[BUFSIZ], *ed; 157130391Sle char original[BUFSIZ], tmpfile[20], *token[GV_MAXARGS]; 158130391Sle char plex[GV_MAXPLEXNAME], volume[GV_MAXVOLNAME]; 159130391Sle 160133097Sle if (argc == 2) { 161133097Sle if ((tmp = fopen(argv[1], "r")) == NULL) { 162133097Sle warn("can't open '%s' for reading", argv[1]); 163133097Sle return; 164133097Sle } 165133097Sle } else { 166133097Sle snprintf(tmpfile, sizeof(tmpfile), "/tmp/gvinum.XXXXXX"); 167133097Sle 168133097Sle if ((fd = mkstemp(tmpfile)) == -1) { 169133097Sle warn("temporary file not accessible"); 170133097Sle return; 171133097Sle } 172133097Sle if ((tmp = fdopen(fd, "w")) == NULL) { 173133097Sle warn("can't open '%s' for writing", tmpfile); 174133097Sle return; 175133097Sle } 176133097Sle printconfig(tmp, "# "); 177133097Sle fclose(tmp); 178133097Sle 179133097Sle ed = getenv("EDITOR"); 180133097Sle if (ed == NULL) 181133097Sle ed = _PATH_VI; 182133097Sle 183133097Sle snprintf(commandline, sizeof(commandline), "%s %s", ed, 184133097Sle tmpfile); 185133097Sle status = system(commandline); 186133097Sle if (status != 0) { 187133097Sle warn("couldn't exec %s; status: %d", ed, status); 188133097Sle return; 189133097Sle } 190133097Sle 191133097Sle if ((tmp = fopen(tmpfile, "r")) == NULL) { 192133097Sle warn("can't open '%s' for reading", tmpfile); 193133097Sle return; 194133097Sle } 195130391Sle } 196130391Sle 197130391Sle req = gctl_get_handle(); 198130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 199130391Sle gctl_ro_param(req, "verb", -1, "create"); 200130391Sle 201130391Sle drives = volumes = plexes = subdisks = 0; 202130391Sle plex_in_volume = sd_in_plex = 0; 203130391Sle errors = 0; 204130391Sle line = 1; 205130391Sle while ((fgets(buf, BUFSIZ, tmp)) != NULL) { 206130391Sle 207130391Sle /* Skip empty lines and comments. */ 208130391Sle if (*buf == '\0' || *buf == '#') { 209130391Sle line++; 210130391Sle continue; 211130391Sle } 212130391Sle 213130391Sle /* Kill off the newline. */ 214130391Sle buf[strlen(buf) - 1] = '\0'; 215130391Sle 216130391Sle /* 217130391Sle * Copy the original input line in case we need it for error 218130391Sle * output. 219130391Sle */ 220130391Sle strncpy(original, buf, sizeof(buf)); 221130391Sle 222130391Sle tokens = gv_tokenize(buf, token, GV_MAXARGS); 223130391Sle 224130391Sle if (tokens > 0) { 225130391Sle /* Volume definition. */ 226130391Sle if (!strcmp(token[0], "volume")) { 227130391Sle v = gv_new_volume(tokens, token); 228130391Sle if (v == NULL) { 229130391Sle warnx("line %d: invalid volume " 230130391Sle "definition", line); 231130391Sle warnx("line %d: '%s'", line, original); 232130391Sle errors++; 233130391Sle } else { 234130391Sle /* Reset plex count for this volume. */ 235130391Sle plex_in_volume = 0; 236130391Sle 237130391Sle /* 238130391Sle * Set default volume name for 239130391Sle * following plex definitions. 240130391Sle */ 241130391Sle strncpy(volume, v->name, 242130391Sle sizeof(volume)); 243130391Sle 244130391Sle snprintf(buf1, sizeof(buf1), "volume%d", 245130391Sle volumes); 246130391Sle gctl_ro_param(req, buf1, sizeof(*v), v); 247130391Sle volumes++; 248130391Sle } 249130391Sle 250130391Sle /* Plex definition. */ 251130391Sle } else if (!strcmp(token[0], "plex")) { 252130391Sle p = gv_new_plex(tokens, token); 253130391Sle if (p == NULL) { 254130391Sle warnx("line %d: invalid plex " 255130391Sle "definition", line); 256130391Sle warnx("line %d: '%s'", line, original); 257130391Sle errors++; 258130391Sle } else { 259130391Sle /* Reset subdisk count for this plex. */ 260130391Sle sd_in_plex = 0; 261130391Sle 262130391Sle /* Default name. */ 263130391Sle if (strlen(p->name) == 0) { 264130391Sle snprintf(p->name, 265130391Sle GV_MAXPLEXNAME, 266130391Sle "%s.p%d", volume, 267130391Sle plex_in_volume++); 268130391Sle } 269130391Sle 270130391Sle /* Default volume. */ 271130391Sle if (strlen(p->volume) == 0) { 272130391Sle snprintf(p->volume, 273130391Sle GV_MAXVOLNAME, "%s", 274130391Sle volume); 275130391Sle } 276130391Sle 277130391Sle /* 278130391Sle * Set default plex name for following 279130391Sle * subdisk definitions. 280130391Sle */ 281130391Sle strncpy(plex, p->name, GV_MAXPLEXNAME); 282130391Sle 283130391Sle snprintf(buf1, sizeof(buf1), "plex%d", 284130391Sle plexes); 285130391Sle gctl_ro_param(req, buf1, sizeof(*p), p); 286130391Sle plexes++; 287130391Sle } 288130391Sle 289130391Sle /* Subdisk definition. */ 290130391Sle } else if (!strcmp(token[0], "sd")) { 291130391Sle s = gv_new_sd(tokens, token); 292130391Sle if (s == NULL) { 293130391Sle warnx("line %d: invalid subdisk " 294130391Sle "definition:", line); 295130391Sle warnx("line %d: '%s'", line, original); 296130391Sle errors++; 297130391Sle } else { 298130391Sle /* Default name. */ 299130391Sle if (strlen(s->name) == 0) { 300130391Sle snprintf(s->name, GV_MAXSDNAME, 301130391Sle "%s.s%d", plex, 302130391Sle sd_in_plex++); 303130391Sle } 304130391Sle 305130391Sle /* Default plex. */ 306130391Sle if (strlen(s->plex) == 0) { 307130391Sle snprintf(s->plex, 308130391Sle GV_MAXPLEXNAME, "%s", plex); 309130391Sle } 310130391Sle 311130391Sle snprintf(buf1, sizeof(buf1), "sd%d", 312130391Sle subdisks); 313130391Sle gctl_ro_param(req, buf1, sizeof(*s), s); 314130391Sle subdisks++; 315130391Sle } 316130391Sle 317130391Sle /* Subdisk definition. */ 318130391Sle } else if (!strcmp(token[0], "drive")) { 319130391Sle d = gv_new_drive(tokens, token); 320130391Sle if (d == NULL) { 321130391Sle warnx("line %d: invalid drive " 322130391Sle "definition:", line); 323130391Sle warnx("line %d: '%s'", line, original); 324130391Sle errors++; 325130391Sle } else { 326130391Sle snprintf(buf1, sizeof(buf1), "drive%d", 327130391Sle drives); 328130391Sle gctl_ro_param(req, buf1, sizeof(*d), d); 329130391Sle drives++; 330130391Sle } 331130391Sle 332130391Sle /* Everything else is bogus. */ 333130391Sle } else { 334130391Sle warnx("line %d: invalid definition:", line); 335130391Sle warnx("line %d: '%s'", line, original); 336130391Sle errors++; 337130391Sle } 338130391Sle } 339130391Sle line++; 340130391Sle } 341130391Sle 342130391Sle fclose(tmp); 343130391Sle unlink(tmpfile); 344130391Sle 345130391Sle if (!errors && (volumes || plexes || subdisks || drives)) { 346130391Sle gctl_ro_param(req, "volumes", sizeof(int), &volumes); 347130391Sle gctl_ro_param(req, "plexes", sizeof(int), &plexes); 348130391Sle gctl_ro_param(req, "subdisks", sizeof(int), &subdisks); 349130391Sle gctl_ro_param(req, "drives", sizeof(int), &drives); 350130391Sle errstr = gctl_issue(req); 351130391Sle if (errstr != NULL) 352130391Sle warnx("create failed: %s", errstr); 353130391Sle } 354130391Sle gctl_free(req); 355130391Sle gvinum_list(0, NULL); 356130391Sle} 357130391Sle 358130391Slevoid 359130391Slegvinum_help(void) 360130391Sle{ 361130391Sle printf("COMMANDS\n" 362130391Sle "attach plex volume [rename]\n" 363130391Sle "attach subdisk plex [offset] [rename]\n" 364130391Sle " Attach a plex to a volume, or a subdisk to a plex.\n" 365130391Sle "checkparity plex [-f] [-v]\n" 366130391Sle " Check the parity blocks of a RAID-4 or RAID-5 plex.\n" 367130391Sle "concat [-f] [-n name] [-v] drives\n" 368130391Sle " Create a concatenated volume from the specified drives.\n" 369130391Sle "create [-f] description-file\n" 370130391Sle " Create a volume as described in description-file.\n" 371130391Sle "detach [-f] [plex | subdisk]\n" 372130391Sle " Detach a plex or subdisk from the volume or plex to" 373130391Sle "which it is\n" 374130391Sle " attached.\n" 375130391Sle "dumpconfig [drive ...]\n" 376130391Sle " List the configuration information stored on the" 377130391Sle " specified\n" 378130391Sle " drives, or all drives in the system if no drive names" 379130391Sle " are speci-\n" 380130391Sle " fied.\n" 381130391Sle "info [-v] [-V]\n" 382130391Sle " List information about volume manager state.\n" 383130391Sle "init [-S size] [-w] plex | subdisk\n" 384130391Sle " Initialize the contents of a subdisk or all the subdisks" 385130391Sle " of a\n" 386130391Sle " plex to all zeros.\n" 387130391Sle "label volume\n" 388130391Sle " Create a volume label.\n" 389130391Sle "l | list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n" 390130391Sle " List information about specified objects.\n" 391130391Sle "ld [-r] [-s] [-v] [-V] [volume]\n" 392130391Sle " List information about drives.\n" 393130391Sle "ls [-r] [-s] [-v] [-V] [subdisk]\n" 394130391Sle " List information about subdisks.\n" 395130391Sle "lp [-r] [-s] [-v] [-V] [plex]\n" 396130391Sle " List information about plexes.\n" 397130391Sle "lv [-r] [-s] [-v] [-V] [volume]\n" 398130391Sle " List information about volumes.\n" 399130391Sle "mirror [-f] [-n name] [-s] [-v] drives\n" 400130391Sle " Create a mirrored volume from the specified drives.\n" 401130391Sle "move | mv -f drive object ...\n" 402130391Sle " Move the object(s) to the specified drive.\n" 403130391Sle "printconfig [file]\n" 404130391Sle " Write a copy of the current configuration to file.\n" 405130391Sle "quit Exit the vinum program when running in interactive mode." 406130391Sle " Nor-\n" 407130391Sle " mally this would be done by entering the EOF character.\n" 408130391Sle "rename [-r] [drive | subdisk | plex | volume] newname\n" 409130391Sle " Change the name of the specified object.\n" 410130391Sle "rebuildparity plex [-f] [-v] [-V]\n" 411130391Sle " Rebuild the parity blocks of a RAID-4 or RAID-5 plex.\n" 412130391Sle "resetconfig\n" 413130391Sle " Reset the complete vinum configuration.\n" 414130391Sle "rm [-f] [-r] volume | plex | subdisk\n" 415130391Sle " Remove an object.\n" 416130391Sle "saveconfig\n" 417130391Sle " Save vinum configuration to disk after configuration" 418130391Sle " failures.\n" 419130391Sle "setstate state [volume | plex | subdisk | drive]\n" 420130391Sle " Set state without influencing other objects, for" 421130391Sle " diagnostic pur-\n" 422130391Sle " poses only.\n" 423130391Sle "start [-i interval] [-S size] [-w] volume | plex | subdisk\n" 424130391Sle " Allow the system to access the objects.\n" 425130391Sle "stop [-f] [volume | plex | subdisk]\n" 426130391Sle " Terminate access to the objects, or stop vinum if no" 427130391Sle " parameters\n" 428130391Sle " are specified.\n" 429130391Sle "stripe [-f] [-n name] [-v] drives\n" 430130391Sle " Create a striped volume from the specified drives.\n" 431130391Sle ); 432130391Sle 433130391Sle return; 434130391Sle} 435130391Sle 436130391Slevoid 437130391Slegvinum_init(int argc, char **argv) 438130391Sle{ 439130391Sle struct gctl_req *req; 440130391Sle int i, initsize, j; 441130391Sle const char *errstr; 442130391Sle char buf[20]; 443130391Sle 444130391Sle initsize = 0; 445130391Sle optreset = 1; 446130391Sle optind = 1; 447130391Sle while ((j = getopt(argc, argv, "S")) != -1) { 448130391Sle switch (j) { 449130391Sle case 'S': 450130391Sle initsize = atoi(optarg); 451130391Sle break; 452130391Sle case '?': 453130391Sle default: 454130391Sle return; 455130391Sle } 456130391Sle } 457130391Sle argc -= optind; 458130391Sle argv += optind; 459130391Sle 460130391Sle if (!initsize) 461130391Sle initsize = 512; 462130391Sle 463130391Sle req = gctl_get_handle(); 464130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 465130391Sle gctl_ro_param(req, "verb", -1, "init"); 466130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 467130391Sle gctl_ro_param(req, "initsize", sizeof(int), &initsize); 468130391Sle if (argc) { 469130391Sle for (i = 0; i < argc; i++) { 470130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 471130391Sle gctl_ro_param(req, buf, -1, argv[i]); 472130391Sle } 473130391Sle } 474130391Sle errstr = gctl_issue(req); 475130391Sle if (errstr != NULL) { 476130391Sle warnx("can't init: %s", errstr); 477130391Sle gctl_free(req); 478130391Sle return; 479130391Sle } 480130391Sle 481130391Sle gctl_free(req); 482130391Sle gvinum_list(0, NULL); 483130391Sle} 484130391Sle 485130391Slevoid 486138112Slegvinum_setstate(int argc, char **argv) 487138112Sle{ 488138112Sle struct gctl_req *req; 489138112Sle int flags, i; 490138112Sle const char *errstr; 491138112Sle 492138112Sle flags = 0; 493138112Sle 494138112Sle optreset = 1; 495138112Sle optind = 1; 496138112Sle 497138112Sle while ((i = getopt(argc, argv, "f")) != -1) { 498138112Sle switch (i) { 499138112Sle case 'f': 500138112Sle flags |= GV_FLAG_F; 501138112Sle break; 502138112Sle case '?': 503138112Sle default: 504138112Sle warn("invalid flag: %c", i); 505138112Sle return; 506138112Sle } 507138112Sle } 508138112Sle 509138112Sle argc -= optind; 510138112Sle argv += optind; 511138112Sle 512138112Sle if (argc != 2) { 513138112Sle warnx("usage: setstate [-f] <state> <obj>"); 514138112Sle return; 515138112Sle } 516138112Sle 517138112Sle /* 518138112Sle * XXX: This hack is needed to avoid tripping over (now) invalid 519138112Sle * 'classic' vinum states and will go away later. 520138112Sle */ 521138112Sle if (strcmp(argv[0], "up") && strcmp(argv[0], "down") && 522138112Sle strcmp(argv[0], "stale")) { 523138112Sle warnx("invalid state '%s'", argv[0]); 524138112Sle return; 525138112Sle } 526138112Sle 527138112Sle req = gctl_get_handle(); 528138112Sle gctl_ro_param(req, "class", -1, "VINUM"); 529138112Sle gctl_ro_param(req, "verb", -1, "setstate"); 530138112Sle gctl_ro_param(req, "state", -1, argv[0]); 531138112Sle gctl_ro_param(req, "object", -1, argv[1]); 532138112Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 533138112Sle 534138112Sle errstr = gctl_issue(req); 535138112Sle if (errstr != NULL) 536138112Sle warnx("%s", errstr); 537138112Sle gctl_free(req); 538138112Sle} 539138112Sle 540138112Slevoid 541130391Slegvinum_list(int argc, char **argv) 542130391Sle{ 543130391Sle struct gctl_req *req; 544130391Sle int flags, i, j; 545130391Sle const char *errstr; 546130391Sle char buf[20], *cmd, config[GV_CFG_LEN + 1]; 547130391Sle 548130391Sle flags = 0; 549130391Sle cmd = "list"; 550130391Sle 551130391Sle if (argc) { 552130391Sle optreset = 1; 553130391Sle optind = 1; 554130391Sle cmd = argv[0]; 555130391Sle while ((j = getopt(argc, argv, "rsvV")) != -1) { 556130391Sle switch (j) { 557130391Sle case 'r': 558130391Sle flags |= GV_FLAG_R; 559130391Sle break; 560130391Sle case 's': 561130391Sle flags |= GV_FLAG_S; 562130391Sle break; 563130391Sle case 'v': 564130391Sle flags |= GV_FLAG_V; 565130391Sle break; 566130391Sle case 'V': 567130391Sle flags |= GV_FLAG_V; 568130391Sle flags |= GV_FLAG_VV; 569130391Sle break; 570130391Sle case '?': 571130391Sle default: 572130391Sle return; 573130391Sle } 574130391Sle } 575130391Sle argc -= optind; 576130391Sle argv += optind; 577130391Sle 578130391Sle } 579130391Sle 580130391Sle req = gctl_get_handle(); 581130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 582130391Sle gctl_ro_param(req, "verb", -1, "list"); 583130391Sle gctl_ro_param(req, "cmd", -1, cmd); 584130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 585130391Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 586130391Sle gctl_rw_param(req, "config", sizeof(config), config); 587130391Sle if (argc) { 588130391Sle for (i = 0; i < argc; i++) { 589130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 590130391Sle gctl_ro_param(req, buf, -1, argv[i]); 591130391Sle } 592130391Sle } 593130391Sle errstr = gctl_issue(req); 594130391Sle if (errstr != NULL) { 595130391Sle warnx("can't get configuration: %s", errstr); 596130391Sle gctl_free(req); 597130391Sle return; 598130391Sle } 599130391Sle 600130391Sle printf("%s", config); 601130391Sle gctl_free(req); 602130391Sle return; 603130391Sle} 604130391Sle 605130391Slevoid 606130391Slegvinum_printconfig(int argc, char **argv) 607130391Sle{ 608130391Sle printconfig(stdout, ""); 609130391Sle} 610130391Sle 611130391Slevoid 612138110Slegvinum_parityop(int argc, char **argv, int rebuild) 613138110Sle{ 614138110Sle struct gctl_req *req; 615138110Sle int flags, i, rv; 616138110Sle off_t offset; 617138110Sle const char *errstr; 618138110Sle char *op, *msg; 619138110Sle 620138110Sle if (rebuild) { 621138110Sle op = "rebuildparity"; 622138110Sle msg = "Rebuilding"; 623138110Sle } else { 624138110Sle op = "checkparity"; 625138110Sle msg = "Checking"; 626138110Sle } 627138110Sle 628138110Sle optreset = 1; 629138110Sle optind = 1; 630138110Sle flags = 0; 631138110Sle while ((i = getopt(argc, argv, "fv")) != -1) { 632138110Sle switch (i) { 633138110Sle case 'f': 634138110Sle flags |= GV_FLAG_F; 635138110Sle break; 636138110Sle case 'v': 637138110Sle flags |= GV_FLAG_V; 638138110Sle break; 639138110Sle case '?': 640138110Sle default: 641138110Sle warnx("invalid flag '%c'", i); 642138110Sle return; 643138110Sle } 644138110Sle } 645138110Sle argc -= optind; 646138110Sle argv += optind; 647138110Sle 648138110Sle if (argc != 1) { 649138110Sle warn("usage: %s [-f] [-v] <plex>", op); 650138110Sle return; 651138110Sle } 652138110Sle 653138110Sle do { 654138110Sle rv = 0; 655138110Sle req = gctl_get_handle(); 656138110Sle gctl_ro_param(req, "class", -1, "VINUM"); 657138110Sle gctl_ro_param(req, "verb", -1, "parityop"); 658138110Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 659138110Sle gctl_ro_param(req, "rebuild", sizeof(int), &rebuild); 660138110Sle gctl_rw_param(req, "rv", sizeof(int), &rv); 661138110Sle gctl_rw_param(req, "offset", sizeof(off_t), &offset); 662138110Sle gctl_ro_param(req, "plex", -1, argv[0]); 663138110Sle errstr = gctl_issue(req); 664138110Sle if (errstr) { 665138110Sle warnx("%s\n", errstr); 666138110Sle gctl_free(req); 667138110Sle break; 668138110Sle } 669138110Sle gctl_free(req); 670138110Sle if (flags & GV_FLAG_V) { 671138110Sle printf("\r%s at %s ... ", msg, 672138110Sle gv_roughlength(offset, 1)); 673138110Sle } 674138110Sle if (rv == 1) { 675138110Sle printf("Parity incorrect at offset 0x%jx\n", 676138110Sle (intmax_t)offset); 677138110Sle if (!rebuild) 678138110Sle break; 679138110Sle } 680138110Sle fflush(stdout); 681138110Sle 682138110Sle /* Clear the -f flag. */ 683138110Sle flags &= ~GV_FLAG_F; 684138110Sle } while (rv >= 0); 685138110Sle 686138110Sle if ((rv == 2) && (flags & GV_FLAG_V)) { 687138110Sle if (rebuild) 688138110Sle printf("Rebuilt parity on %s\n", argv[0]); 689138110Sle else 690138110Sle printf("%s has correct parity\n", argv[0]); 691138110Sle } 692138110Sle} 693138110Sle 694138110Slevoid 695130391Slegvinum_rm(int argc, char **argv) 696130391Sle{ 697130391Sle struct gctl_req *req; 698130391Sle int flags, i, j; 699130391Sle const char *errstr; 700130391Sle char buf[20], *cmd; 701130391Sle 702130391Sle cmd = argv[0]; 703130391Sle flags = 0; 704130391Sle optreset = 1; 705130391Sle optind = 1; 706130391Sle while ((j = getopt(argc, argv, "r")) != -1) { 707130391Sle switch (j) { 708130391Sle case 'r': 709130391Sle flags |= GV_FLAG_R; 710130391Sle break; 711130391Sle case '?': 712130391Sle default: 713130391Sle return; 714130391Sle } 715130391Sle } 716130391Sle argc -= optind; 717130391Sle argv += optind; 718130391Sle 719130391Sle req = gctl_get_handle(); 720130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 721130391Sle gctl_ro_param(req, "verb", -1, "remove"); 722130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 723130391Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 724130391Sle if (argc) { 725130391Sle for (i = 0; i < argc; i++) { 726130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 727130391Sle gctl_ro_param(req, buf, -1, argv[i]); 728130391Sle } 729130391Sle } 730130391Sle errstr = gctl_issue(req); 731130391Sle if (errstr != NULL) { 732130391Sle warnx("can't remove: %s", errstr); 733130391Sle gctl_free(req); 734130391Sle return; 735130391Sle } 736130391Sle gctl_free(req); 737130391Sle gvinum_list(0, NULL); 738130391Sle} 739130391Sle 740130391Slevoid 741130391Slegvinum_saveconfig(void) 742130391Sle{ 743130391Sle struct gctl_req *req; 744130391Sle const char *errstr; 745130391Sle 746130391Sle req = gctl_get_handle(); 747130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 748130391Sle gctl_ro_param(req, "verb", -1, "saveconfig"); 749130391Sle errstr = gctl_issue(req); 750130391Sle if (errstr != NULL) 751130391Sle warnx("can't save configuration: %s", errstr); 752130391Sle gctl_free(req); 753130391Sle} 754130391Sle 755130391Slevoid 756130391Slegvinum_start(int argc, char **argv) 757130391Sle{ 758130391Sle struct gctl_req *req; 759130391Sle int i, initsize, j; 760130391Sle const char *errstr; 761130391Sle char buf[20]; 762130391Sle 763130391Sle /* 'start' with no arguments is a no-op. */ 764130391Sle if (argc == 1) 765130391Sle return; 766130391Sle 767130391Sle initsize = 0; 768130391Sle 769130391Sle optreset = 1; 770130391Sle optind = 1; 771130391Sle while ((j = getopt(argc, argv, "S")) != -1) { 772130391Sle switch (j) { 773130391Sle case 'S': 774130391Sle initsize = atoi(optarg); 775130391Sle break; 776130391Sle case '?': 777130391Sle default: 778130391Sle return; 779130391Sle } 780130391Sle } 781130391Sle argc -= optind; 782130391Sle argv += optind; 783130391Sle 784130391Sle if (!initsize) 785130391Sle initsize = 512; 786130391Sle 787130391Sle req = gctl_get_handle(); 788130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 789130391Sle gctl_ro_param(req, "verb", -1, "start"); 790130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 791130391Sle gctl_ro_param(req, "initsize", sizeof(int), &initsize); 792130391Sle if (argc) { 793130391Sle for (i = 0; i < argc; i++) { 794130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 795130391Sle gctl_ro_param(req, buf, -1, argv[i]); 796130391Sle } 797130391Sle } 798130391Sle errstr = gctl_issue(req); 799130391Sle if (errstr != NULL) { 800130391Sle warnx("can't start: %s", errstr); 801130391Sle gctl_free(req); 802130391Sle return; 803130391Sle } 804130391Sle 805130391Sle gctl_free(req); 806130391Sle gvinum_list(0, NULL); 807130391Sle} 808130391Sle 809130391Slevoid 810130391Slegvinum_stop(int argc, char **argv) 811130391Sle{ 812130391Sle int fileid; 813130391Sle 814130391Sle fileid = kldfind(GVINUMMOD); 815130391Sle if (fileid == -1) { 816130391Sle warn("cannot find " GVINUMMOD); 817130391Sle return; 818130391Sle } 819130391Sle if (kldunload(fileid) != 0) { 820130391Sle warn("cannot unload " GVINUMMOD); 821130391Sle return; 822130391Sle } 823130391Sle 824130391Sle warnx(GVINUMMOD " unloaded"); 825130391Sle exit(0); 826130391Sle} 827130391Sle 828130391Slevoid 829130391Sleparseline(int argc, char **argv) 830130391Sle{ 831130391Sle if (argc <= 0) 832130391Sle return; 833130391Sle 834130391Sle if (!strcmp(argv[0], "cancelinit")) 835130391Sle gvinum_cancelinit(argc, argv); 836130391Sle else if (!strcmp(argv[0], "create")) 837130391Sle gvinum_create(argc, argv); 838130391Sle else if (!strcmp(argv[0], "exit") || !strcmp(argv[0], "quit")) 839130391Sle exit(0); 840130391Sle else if (!strcmp(argv[0], "help")) 841130391Sle gvinum_help(); 842130391Sle else if (!strcmp(argv[0], "init")) 843130391Sle gvinum_init(argc, argv); 844130391Sle else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "l")) 845130391Sle gvinum_list(argc, argv); 846130391Sle else if (!strcmp(argv[0], "ld")) 847130391Sle gvinum_list(argc, argv); 848130391Sle else if (!strcmp(argv[0], "lp")) 849130391Sle gvinum_list(argc, argv); 850130391Sle else if (!strcmp(argv[0], "ls")) 851130391Sle gvinum_list(argc, argv); 852130391Sle else if (!strcmp(argv[0], "lv")) 853130391Sle gvinum_list(argc, argv); 854130391Sle else if (!strcmp(argv[0], "printconfig")) 855130391Sle gvinum_printconfig(argc, argv); 856130391Sle else if (!strcmp(argv[0], "rm")) 857130391Sle gvinum_rm(argc, argv); 858130391Sle else if (!strcmp(argv[0], "saveconfig")) 859130391Sle gvinum_saveconfig(); 860138112Sle else if (!strcmp(argv[0], "setstate")) 861138112Sle gvinum_setstate(argc, argv); 862130391Sle else if (!strcmp(argv[0], "start")) 863130391Sle gvinum_start(argc, argv); 864130391Sle else if (!strcmp(argv[0], "stop")) 865130391Sle gvinum_stop(argc, argv); 866138110Sle else if (!strcmp(argv[0], "checkparity")) 867138110Sle gvinum_parityop(argc, argv, 0); 868138110Sle else if (!strcmp(argv[0], "rebuildparity")) 869138110Sle gvinum_parityop(argc, argv, 1); 870130391Sle else 871130391Sle printf("unknown command '%s'\n", argv[0]); 872130391Sle 873130391Sle return; 874130391Sle} 875130391Sle 876130391Sle/* 877130391Sle * The guts of printconfig. This is called from gvinum_printconfig and from 878130391Sle * gvinum_create when called without an argument, in order to give the user 879130391Sle * something to edit. 880130391Sle */ 881130391Slevoid 882130391Sleprintconfig(FILE *of, char *comment) 883130391Sle{ 884130391Sle struct gctl_req *req; 885130391Sle struct utsname uname_s; 886130391Sle const char *errstr; 887130391Sle time_t now; 888130391Sle char buf[GV_CFG_LEN + 1]; 889130391Sle 890130391Sle uname(&uname_s); 891130391Sle time(&now); 892130391Sle 893130391Sle req = gctl_get_handle(); 894130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 895130391Sle gctl_ro_param(req, "verb", -1, "getconfig"); 896130391Sle gctl_ro_param(req, "comment", -1, comment); 897130391Sle gctl_rw_param(req, "config", sizeof(buf), buf); 898130391Sle errstr = gctl_issue(req); 899130391Sle if (errstr != NULL) { 900130391Sle warnx("can't get configuration: %s", errstr); 901130391Sle return; 902130391Sle } 903130391Sle gctl_free(req); 904130391Sle 905130391Sle fprintf(of, "# Vinum configuration of %s, saved at %s", 906130391Sle uname_s.nodename, 907130391Sle ctime(&now)); 908130391Sle 909130391Sle if (*comment != '\0') 910130391Sle fprintf(of, "# Current configuration:\n"); 911130391Sle 912130391Sle fprintf(of, buf); 913130391Sle} 914