gvinum.c revision 157052
1130391Sle/* 2152616Sle * Copyright (c) 2004 Lukas Ertl, 2005 Chris Jones 3130391Sle * All rights reserved. 4152631Sle * 5152631Sle * Portions of this software were developed for the FreeBSD Project 6152631Sle * by Chris Jones thanks to the support of Google's Summer of Code 7152631Sle * program and mentoring by Lukas Ertl. 8152631Sle * 9130391Sle * Redistribution and use in source and binary forms, with or without 10130391Sle * modification, are permitted provided that the following conditions 11130391Sle * are met: 12130391Sle * 1. Redistributions of source code must retain the above copyright 13130391Sle * notice, this list of conditions and the following disclaimer. 14130391Sle * 2. Redistributions in binary form must reproduce the above copyright 15130391Sle * notice, this list of conditions and the following disclaimer in the 16130391Sle * documentation and/or other materials provided with the distribution. 17152631Sle * 18130391Sle * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19130391Sle * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20130391Sle * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21130391Sle * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 22130391Sle * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23130391Sle * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24130391Sle * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25130391Sle * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26130391Sle * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27130391Sle * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28130391Sle * SUCH DAMAGE. 29130391Sle * 30130391Sle * $FreeBSD: head/sbin/gvinum/gvinum.c 157052 2006-03-23 19:58:43Z le $ 31130391Sle */ 32130391Sle 33130391Sle#include <sys/param.h> 34130391Sle#include <sys/linker.h> 35130391Sle#include <sys/lock.h> 36130391Sle#include <sys/module.h> 37130391Sle#include <sys/mutex.h> 38130391Sle#include <sys/queue.h> 39130391Sle#include <sys/utsname.h> 40130391Sle 41130391Sle#include <geom/vinum/geom_vinum_var.h> 42130391Sle#include <geom/vinum/geom_vinum_share.h> 43130391Sle 44130391Sle#include <ctype.h> 45130391Sle#include <err.h> 46130391Sle#include <libgeom.h> 47130391Sle#include <stdint.h> 48130391Sle#include <stdio.h> 49130391Sle#include <stdlib.h> 50130391Sle#include <paths.h> 51130391Sle#include <readline/readline.h> 52130391Sle#include <readline/history.h> 53130391Sle#include <unistd.h> 54130391Sle 55130391Sle#include "gvinum.h" 56130391Sle 57130391Slevoid gvinum_create(int, char **); 58130391Slevoid gvinum_help(void); 59130391Slevoid gvinum_list(int, char **); 60152616Slevoid gvinum_move(int, char **); 61138110Slevoid gvinum_parityop(int, char **, int); 62130391Slevoid gvinum_printconfig(int, char **); 63152616Slevoid gvinum_rename(int, char **); 64157052Slevoid gvinum_resetconfig(void); 65130391Slevoid gvinum_rm(int, char **); 66130391Slevoid gvinum_saveconfig(void); 67138112Slevoid gvinum_setstate(int, char **); 68130391Slevoid gvinum_start(int, char **); 69130391Slevoid gvinum_stop(int, char **); 70130391Slevoid parseline(int, char **); 71130391Slevoid printconfig(FILE *, char *); 72130391Sle 73130391Sleint 74130391Slemain(int argc, char **argv) 75130391Sle{ 76130391Sle int line, tokens; 77130391Sle char buffer[BUFSIZ], *inputline, *token[GV_MAXARGS]; 78130391Sle 79130391Sle /* Load the module if necessary. */ 80130391Sle if (kldfind(GVINUMMOD) < 0 && kldload(GVINUMMOD) < 0) 81130391Sle err(1, GVINUMMOD ": Kernel module not available"); 82130391Sle 83130391Sle /* Arguments given on the command line. */ 84130391Sle if (argc > 1) { 85130391Sle argc--; 86130391Sle argv++; 87130391Sle parseline(argc, argv); 88130391Sle 89130391Sle /* Interactive mode. */ 90130391Sle } else { 91130391Sle for (;;) { 92130391Sle inputline = readline("gvinum -> "); 93130391Sle if (inputline == NULL) { 94130391Sle if (ferror(stdin)) { 95130391Sle err(1, "can't read input"); 96130391Sle } else { 97130391Sle printf("\n"); 98130391Sle exit(0); 99130391Sle } 100130391Sle } else if (*inputline) { 101130391Sle add_history(inputline); 102130391Sle strcpy(buffer, inputline); 103130391Sle free(inputline); 104130391Sle line++; /* count the lines */ 105130391Sle tokens = gv_tokenize(buffer, token, GV_MAXARGS); 106130391Sle if (tokens) 107130391Sle parseline(tokens, token); 108130391Sle } 109130391Sle } 110130391Sle } 111130391Sle exit(0); 112130391Sle} 113130391Sle 114130391Slevoid 115130391Slegvinum_create(int argc, char **argv) 116130391Sle{ 117130391Sle struct gctl_req *req; 118130391Sle struct gv_drive *d; 119130391Sle struct gv_plex *p; 120130391Sle struct gv_sd *s; 121130391Sle struct gv_volume *v; 122130391Sle FILE *tmp; 123130391Sle int drives, errors, fd, line, plexes, plex_in_volume; 124130391Sle int sd_in_plex, status, subdisks, tokens, volumes; 125130391Sle const char *errstr; 126130391Sle char buf[BUFSIZ], buf1[BUFSIZ], commandline[BUFSIZ], *ed; 127130391Sle char original[BUFSIZ], tmpfile[20], *token[GV_MAXARGS]; 128130391Sle char plex[GV_MAXPLEXNAME], volume[GV_MAXVOLNAME]; 129130391Sle 130133097Sle if (argc == 2) { 131133097Sle if ((tmp = fopen(argv[1], "r")) == NULL) { 132133097Sle warn("can't open '%s' for reading", argv[1]); 133133097Sle return; 134133097Sle } 135133097Sle } else { 136133097Sle snprintf(tmpfile, sizeof(tmpfile), "/tmp/gvinum.XXXXXX"); 137133097Sle 138133097Sle if ((fd = mkstemp(tmpfile)) == -1) { 139133097Sle warn("temporary file not accessible"); 140133097Sle return; 141133097Sle } 142133097Sle if ((tmp = fdopen(fd, "w")) == NULL) { 143133097Sle warn("can't open '%s' for writing", tmpfile); 144133097Sle return; 145133097Sle } 146133097Sle printconfig(tmp, "# "); 147133097Sle fclose(tmp); 148133097Sle 149133097Sle ed = getenv("EDITOR"); 150133097Sle if (ed == NULL) 151133097Sle ed = _PATH_VI; 152133097Sle 153133097Sle snprintf(commandline, sizeof(commandline), "%s %s", ed, 154133097Sle tmpfile); 155133097Sle status = system(commandline); 156133097Sle if (status != 0) { 157133097Sle warn("couldn't exec %s; status: %d", ed, status); 158133097Sle return; 159133097Sle } 160133097Sle 161133097Sle if ((tmp = fopen(tmpfile, "r")) == NULL) { 162133097Sle warn("can't open '%s' for reading", tmpfile); 163133097Sle return; 164133097Sle } 165130391Sle } 166130391Sle 167130391Sle req = gctl_get_handle(); 168130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 169130391Sle gctl_ro_param(req, "verb", -1, "create"); 170130391Sle 171130391Sle drives = volumes = plexes = subdisks = 0; 172130391Sle plex_in_volume = sd_in_plex = 0; 173130391Sle errors = 0; 174130391Sle line = 1; 175130391Sle while ((fgets(buf, BUFSIZ, tmp)) != NULL) { 176130391Sle 177130391Sle /* Skip empty lines and comments. */ 178130391Sle if (*buf == '\0' || *buf == '#') { 179130391Sle line++; 180130391Sle continue; 181130391Sle } 182130391Sle 183130391Sle /* Kill off the newline. */ 184130391Sle buf[strlen(buf) - 1] = '\0'; 185130391Sle 186130391Sle /* 187130391Sle * Copy the original input line in case we need it for error 188130391Sle * output. 189130391Sle */ 190130391Sle strncpy(original, buf, sizeof(buf)); 191130391Sle 192130391Sle tokens = gv_tokenize(buf, token, GV_MAXARGS); 193150044Sle if (tokens <= 0) { 194150044Sle line++; 195150044Sle continue; 196150044Sle } 197130391Sle 198150044Sle /* Volume definition. */ 199150044Sle if (!strcmp(token[0], "volume")) { 200150044Sle v = gv_new_volume(tokens, token); 201150044Sle if (v == NULL) { 202150044Sle warnx("line %d: invalid volume definition", 203150044Sle line); 204150044Sle warnx("line %d: '%s'", line, original); 205150044Sle errors++; 206150044Sle line++; 207150044Sle continue; 208150044Sle } 209130391Sle 210150044Sle /* Reset plex count for this volume. */ 211150044Sle plex_in_volume = 0; 212130391Sle 213150044Sle /* 214150044Sle * Set default volume name for following plex 215150044Sle * definitions. 216150044Sle */ 217150044Sle strncpy(volume, v->name, sizeof(volume)); 218130391Sle 219150044Sle snprintf(buf1, sizeof(buf1), "volume%d", volumes); 220150044Sle gctl_ro_param(req, buf1, sizeof(*v), v); 221150044Sle volumes++; 222130391Sle 223150044Sle /* Plex definition. */ 224150044Sle } else if (!strcmp(token[0], "plex")) { 225150044Sle p = gv_new_plex(tokens, token); 226150044Sle if (p == NULL) { 227150044Sle warnx("line %d: invalid plex definition", line); 228150044Sle warnx("line %d: '%s'", line, original); 229150044Sle errors++; 230150044Sle line++; 231150044Sle continue; 232150044Sle } 233130391Sle 234150044Sle /* Reset subdisk count for this plex. */ 235150044Sle sd_in_plex = 0; 236130391Sle 237150044Sle /* Default name. */ 238150044Sle if (strlen(p->name) == 0) { 239150044Sle snprintf(p->name, GV_MAXPLEXNAME, "%s.p%d", 240150044Sle volume, plex_in_volume++); 241150044Sle } 242130391Sle 243150044Sle /* Default volume. */ 244150044Sle if (strlen(p->volume) == 0) { 245150044Sle snprintf(p->volume, GV_MAXVOLNAME, "%s", 246150044Sle volume); 247150044Sle } 248130391Sle 249150044Sle /* 250150044Sle * Set default plex name for following subdisk 251150044Sle * definitions. 252150044Sle */ 253150044Sle strncpy(plex, p->name, GV_MAXPLEXNAME); 254130391Sle 255150044Sle snprintf(buf1, sizeof(buf1), "plex%d", plexes); 256150044Sle gctl_ro_param(req, buf1, sizeof(*p), p); 257150044Sle plexes++; 258130391Sle 259150044Sle /* Subdisk definition. */ 260150044Sle } else if (!strcmp(token[0], "sd")) { 261150044Sle s = gv_new_sd(tokens, token); 262150044Sle if (s == NULL) { 263150044Sle warnx("line %d: invalid subdisk " 264150044Sle "definition:", line); 265150044Sle warnx("line %d: '%s'", line, original); 266150044Sle errors++; 267150044Sle line++; 268150044Sle continue; 269150044Sle } 270130391Sle 271150044Sle /* Default name. */ 272150044Sle if (strlen(s->name) == 0) { 273150044Sle snprintf(s->name, GV_MAXSDNAME, "%s.s%d", 274150044Sle plex, sd_in_plex++); 275150044Sle } 276150044Sle 277150044Sle /* Default plex. */ 278150044Sle if (strlen(s->plex) == 0) 279150044Sle snprintf(s->plex, GV_MAXPLEXNAME, "%s", plex); 280150044Sle 281150044Sle snprintf(buf1, sizeof(buf1), "sd%d", subdisks); 282150044Sle gctl_ro_param(req, buf1, sizeof(*s), s); 283150044Sle subdisks++; 284150044Sle 285150044Sle /* Subdisk definition. */ 286150044Sle } else if (!strcmp(token[0], "drive")) { 287150044Sle d = gv_new_drive(tokens, token); 288150044Sle if (d == NULL) { 289150044Sle warnx("line %d: invalid drive definition:", 290150044Sle line); 291130391Sle warnx("line %d: '%s'", line, original); 292130391Sle errors++; 293150044Sle line++; 294150044Sle continue; 295130391Sle } 296150044Sle 297150044Sle snprintf(buf1, sizeof(buf1), "drive%d", drives); 298150044Sle gctl_ro_param(req, buf1, sizeof(*d), d); 299150044Sle drives++; 300150044Sle 301150044Sle /* Everything else is bogus. */ 302150044Sle } else { 303150044Sle warnx("line %d: invalid definition:", line); 304150044Sle warnx("line %d: '%s'", line, original); 305150044Sle errors++; 306130391Sle } 307130391Sle line++; 308130391Sle } 309130391Sle 310130391Sle fclose(tmp); 311130391Sle unlink(tmpfile); 312130391Sle 313130391Sle if (!errors && (volumes || plexes || subdisks || drives)) { 314130391Sle gctl_ro_param(req, "volumes", sizeof(int), &volumes); 315130391Sle gctl_ro_param(req, "plexes", sizeof(int), &plexes); 316130391Sle gctl_ro_param(req, "subdisks", sizeof(int), &subdisks); 317130391Sle gctl_ro_param(req, "drives", sizeof(int), &drives); 318130391Sle errstr = gctl_issue(req); 319130391Sle if (errstr != NULL) 320130391Sle warnx("create failed: %s", errstr); 321130391Sle } 322130391Sle gctl_free(req); 323130391Sle gvinum_list(0, NULL); 324130391Sle} 325130391Sle 326130391Slevoid 327130391Slegvinum_help(void) 328130391Sle{ 329130391Sle printf("COMMANDS\n" 330152616Sle "checkparity [-f] plex\n" 331152616Sle " Check the parity blocks of a RAID-5 plex.\n" 332152616Sle "create description-file\n" 333152616Sle " Create as per description-file or open editor.\n" 334152616Sle "l | list [-r] [-v] [-V] [volume | plex | subdisk]\n" 335130391Sle " List information about specified objects.\n" 336152616Sle "ld [-r] [-v] [-V] [volume]\n" 337130391Sle " List information about drives.\n" 338152616Sle "ls [-r] [-v] [-V] [subdisk]\n" 339130391Sle " List information about subdisks.\n" 340152616Sle "lp [-r] [-v] [-V] [plex]\n" 341130391Sle " List information about plexes.\n" 342152616Sle "lv [-r] [-v] [-V] [volume]\n" 343130391Sle " List information about volumes.\n" 344130391Sle "move | mv -f drive object ...\n" 345130391Sle " Move the object(s) to the specified drive.\n" 346130391Sle "quit Exit the vinum program when running in interactive mode." 347130391Sle " Nor-\n" 348130391Sle " mally this would be done by entering the EOF character.\n" 349130391Sle "rename [-r] [drive | subdisk | plex | volume] newname\n" 350130391Sle " Change the name of the specified object.\n" 351152616Sle "rebuildparity plex [-f]\n" 352152616Sle " Rebuild the parity blocks of a RAID-5 plex.\n" 353157052Sle "resetconfig\n" 354157052Sle " Reset the complete gvinum configuration\n" 355152616Sle "rm [-r] volume | plex | subdisk | drive\n" 356130391Sle " Remove an object.\n" 357130391Sle "saveconfig\n" 358130391Sle " Save vinum configuration to disk after configuration" 359130391Sle " failures.\n" 360152616Sle "setstate [-f] state [volume | plex | subdisk | drive]\n" 361130391Sle " Set state without influencing other objects, for" 362130391Sle " diagnostic pur-\n" 363130391Sle " poses only.\n" 364152616Sle "start [-S size] volume | plex | subdisk\n" 365130391Sle " Allow the system to access the objects.\n" 366130391Sle ); 367130391Sle 368130391Sle return; 369130391Sle} 370130391Sle 371130391Slevoid 372138112Slegvinum_setstate(int argc, char **argv) 373138112Sle{ 374138112Sle struct gctl_req *req; 375138112Sle int flags, i; 376138112Sle const char *errstr; 377138112Sle 378138112Sle flags = 0; 379138112Sle 380138112Sle optreset = 1; 381138112Sle optind = 1; 382138112Sle 383138112Sle while ((i = getopt(argc, argv, "f")) != -1) { 384138112Sle switch (i) { 385138112Sle case 'f': 386138112Sle flags |= GV_FLAG_F; 387138112Sle break; 388138112Sle case '?': 389138112Sle default: 390138112Sle warn("invalid flag: %c", i); 391138112Sle return; 392138112Sle } 393138112Sle } 394138112Sle 395138112Sle argc -= optind; 396138112Sle argv += optind; 397138112Sle 398138112Sle if (argc != 2) { 399138112Sle warnx("usage: setstate [-f] <state> <obj>"); 400138112Sle return; 401138112Sle } 402138112Sle 403138112Sle /* 404138112Sle * XXX: This hack is needed to avoid tripping over (now) invalid 405138112Sle * 'classic' vinum states and will go away later. 406138112Sle */ 407138112Sle if (strcmp(argv[0], "up") && strcmp(argv[0], "down") && 408138112Sle strcmp(argv[0], "stale")) { 409138112Sle warnx("invalid state '%s'", argv[0]); 410138112Sle return; 411138112Sle } 412138112Sle 413138112Sle req = gctl_get_handle(); 414138112Sle gctl_ro_param(req, "class", -1, "VINUM"); 415138112Sle gctl_ro_param(req, "verb", -1, "setstate"); 416138112Sle gctl_ro_param(req, "state", -1, argv[0]); 417138112Sle gctl_ro_param(req, "object", -1, argv[1]); 418138112Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 419138112Sle 420138112Sle errstr = gctl_issue(req); 421138112Sle if (errstr != NULL) 422138112Sle warnx("%s", errstr); 423138112Sle gctl_free(req); 424138112Sle} 425138112Sle 426138112Slevoid 427130391Slegvinum_list(int argc, char **argv) 428130391Sle{ 429130391Sle struct gctl_req *req; 430130391Sle int flags, i, j; 431130391Sle const char *errstr; 432130391Sle char buf[20], *cmd, config[GV_CFG_LEN + 1]; 433130391Sle 434130391Sle flags = 0; 435130391Sle cmd = "list"; 436130391Sle 437130391Sle if (argc) { 438130391Sle optreset = 1; 439130391Sle optind = 1; 440130391Sle cmd = argv[0]; 441130391Sle while ((j = getopt(argc, argv, "rsvV")) != -1) { 442130391Sle switch (j) { 443130391Sle case 'r': 444130391Sle flags |= GV_FLAG_R; 445130391Sle break; 446130391Sle case 's': 447130391Sle flags |= GV_FLAG_S; 448130391Sle break; 449130391Sle case 'v': 450130391Sle flags |= GV_FLAG_V; 451130391Sle break; 452130391Sle case 'V': 453130391Sle flags |= GV_FLAG_V; 454130391Sle flags |= GV_FLAG_VV; 455130391Sle break; 456130391Sle case '?': 457130391Sle default: 458130391Sle return; 459130391Sle } 460130391Sle } 461130391Sle argc -= optind; 462130391Sle argv += optind; 463130391Sle 464130391Sle } 465130391Sle 466130391Sle req = gctl_get_handle(); 467130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 468130391Sle gctl_ro_param(req, "verb", -1, "list"); 469130391Sle gctl_ro_param(req, "cmd", -1, cmd); 470130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 471130391Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 472130391Sle gctl_rw_param(req, "config", sizeof(config), config); 473130391Sle if (argc) { 474130391Sle for (i = 0; i < argc; i++) { 475130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 476130391Sle gctl_ro_param(req, buf, -1, argv[i]); 477130391Sle } 478130391Sle } 479130391Sle errstr = gctl_issue(req); 480130391Sle if (errstr != NULL) { 481130391Sle warnx("can't get configuration: %s", errstr); 482130391Sle gctl_free(req); 483130391Sle return; 484130391Sle } 485130391Sle 486130391Sle printf("%s", config); 487130391Sle gctl_free(req); 488130391Sle return; 489130391Sle} 490130391Sle 491152616Sle/* Note that move is currently of form '[-r] target object [...]' */ 492130391Slevoid 493152616Slegvinum_move(int argc, char **argv) 494152616Sle{ 495152616Sle struct gctl_req *req; 496152616Sle const char *errstr; 497152616Sle char buf[20]; 498152616Sle int flags, i, j; 499152616Sle 500152616Sle flags = 0; 501152616Sle if (argc) { 502152616Sle optreset = 1; 503152616Sle optind = 1; 504152616Sle while ((j = getopt(argc, argv, "f")) != -1) { 505152616Sle switch (j) { 506152616Sle case 'f': 507152616Sle flags |= GV_FLAG_F; 508152616Sle break; 509152616Sle case '?': 510152616Sle default: 511152616Sle return; 512152616Sle } 513152616Sle } 514152616Sle argc -= optind; 515152616Sle argv += optind; 516152616Sle } 517152616Sle 518152616Sle switch (argc) { 519152616Sle case 0: 520152616Sle warnx("no destination or object(s) to move specified"); 521152616Sle return; 522152616Sle case 1: 523152616Sle warnx("no object(s) to move specified"); 524152616Sle return; 525152616Sle default: 526152616Sle break; 527152616Sle } 528152616Sle 529152616Sle req = gctl_get_handle(); 530152616Sle gctl_ro_param(req, "class", -1, "VINUM"); 531152616Sle gctl_ro_param(req, "verb", -1, "move"); 532152616Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 533152616Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 534152616Sle gctl_ro_param(req, "destination", -1, argv[0]); 535152616Sle for (i = 1; i < argc; i++) { 536152616Sle snprintf(buf, sizeof(buf), "argv%d", i); 537152616Sle gctl_ro_param(req, buf, -1, argv[i]); 538152616Sle } 539152631Sle errstr = gctl_issue(req); 540152616Sle if (errstr != NULL) 541152616Sle warnx("can't move object(s): %s", errstr); 542152616Sle gctl_free(req); 543152616Sle return; 544152616Sle} 545152616Sle 546152616Slevoid 547130391Slegvinum_printconfig(int argc, char **argv) 548130391Sle{ 549130391Sle printconfig(stdout, ""); 550130391Sle} 551130391Sle 552130391Slevoid 553138110Slegvinum_parityop(int argc, char **argv, int rebuild) 554138110Sle{ 555138110Sle struct gctl_req *req; 556138110Sle int flags, i, rv; 557138110Sle off_t offset; 558138110Sle const char *errstr; 559138110Sle char *op, *msg; 560138110Sle 561138110Sle if (rebuild) { 562138110Sle op = "rebuildparity"; 563138110Sle msg = "Rebuilding"; 564138110Sle } else { 565138110Sle op = "checkparity"; 566138110Sle msg = "Checking"; 567138110Sle } 568138110Sle 569138110Sle optreset = 1; 570138110Sle optind = 1; 571138110Sle flags = 0; 572138110Sle while ((i = getopt(argc, argv, "fv")) != -1) { 573138110Sle switch (i) { 574138110Sle case 'f': 575138110Sle flags |= GV_FLAG_F; 576138110Sle break; 577138110Sle case 'v': 578138110Sle flags |= GV_FLAG_V; 579138110Sle break; 580138110Sle case '?': 581138110Sle default: 582138110Sle warnx("invalid flag '%c'", i); 583138110Sle return; 584138110Sle } 585138110Sle } 586138110Sle argc -= optind; 587138110Sle argv += optind; 588138110Sle 589138110Sle if (argc != 1) { 590138110Sle warn("usage: %s [-f] [-v] <plex>", op); 591138110Sle return; 592138110Sle } 593138110Sle 594138110Sle do { 595138110Sle rv = 0; 596138110Sle req = gctl_get_handle(); 597138110Sle gctl_ro_param(req, "class", -1, "VINUM"); 598138110Sle gctl_ro_param(req, "verb", -1, "parityop"); 599138110Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 600138110Sle gctl_ro_param(req, "rebuild", sizeof(int), &rebuild); 601138110Sle gctl_rw_param(req, "rv", sizeof(int), &rv); 602138110Sle gctl_rw_param(req, "offset", sizeof(off_t), &offset); 603138110Sle gctl_ro_param(req, "plex", -1, argv[0]); 604138110Sle errstr = gctl_issue(req); 605138110Sle if (errstr) { 606138110Sle warnx("%s\n", errstr); 607138110Sle gctl_free(req); 608138110Sle break; 609138110Sle } 610138110Sle gctl_free(req); 611138110Sle if (flags & GV_FLAG_V) { 612138110Sle printf("\r%s at %s ... ", msg, 613138110Sle gv_roughlength(offset, 1)); 614138110Sle } 615138110Sle if (rv == 1) { 616138110Sle printf("Parity incorrect at offset 0x%jx\n", 617138110Sle (intmax_t)offset); 618138110Sle if (!rebuild) 619138110Sle break; 620138110Sle } 621138110Sle fflush(stdout); 622138110Sle 623138110Sle /* Clear the -f flag. */ 624138110Sle flags &= ~GV_FLAG_F; 625138110Sle } while (rv >= 0); 626138110Sle 627138110Sle if ((rv == 2) && (flags & GV_FLAG_V)) { 628138110Sle if (rebuild) 629138110Sle printf("Rebuilt parity on %s\n", argv[0]); 630138110Sle else 631138110Sle printf("%s has correct parity\n", argv[0]); 632138110Sle } 633138110Sle} 634138110Sle 635138110Slevoid 636152616Slegvinum_rename(int argc, char **argv) 637152616Sle{ 638152616Sle struct gctl_req *req; 639152616Sle const char *errstr; 640152616Sle int flags, j; 641152616Sle 642152616Sle flags = 0; 643152616Sle 644152616Sle if (argc) { 645152616Sle optreset = 1; 646152616Sle optind = 1; 647152616Sle while ((j = getopt(argc, argv, "r")) != -1) { 648152616Sle switch (j) { 649152616Sle case 'r': 650152616Sle flags |= GV_FLAG_R; 651152616Sle break; 652152616Sle case '?': 653152616Sle default: 654152616Sle return; 655152616Sle } 656152616Sle } 657152616Sle argc -= optind; 658152616Sle argv += optind; 659152616Sle } 660152616Sle 661152616Sle switch (argc) { 662152616Sle case 0: 663152616Sle warnx("no object to rename specified"); 664152616Sle return; 665152616Sle case 1: 666152616Sle warnx("no new name specified"); 667152616Sle return; 668152616Sle case 2: 669152616Sle break; 670152616Sle default: 671152616Sle warnx("more than one new name specified"); 672152616Sle return; 673152616Sle } 674152616Sle 675152616Sle req = gctl_get_handle(); 676152616Sle gctl_ro_param(req, "class", -1, "VINUM"); 677152616Sle gctl_ro_param(req, "verb", -1, "rename"); 678152616Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 679152616Sle gctl_ro_param(req, "object", -1, argv[0]); 680152616Sle gctl_ro_param(req, "newname", -1, argv[1]); 681152631Sle errstr = gctl_issue(req); 682152616Sle if (errstr != NULL) 683152616Sle warnx("can't rename object: %s", errstr); 684152616Sle gctl_free(req); 685152616Sle return; 686152616Sle} 687152616Sle 688152616Slevoid 689130391Slegvinum_rm(int argc, char **argv) 690130391Sle{ 691130391Sle struct gctl_req *req; 692130391Sle int flags, i, j; 693130391Sle const char *errstr; 694130391Sle char buf[20], *cmd; 695130391Sle 696130391Sle cmd = argv[0]; 697130391Sle flags = 0; 698130391Sle optreset = 1; 699130391Sle optind = 1; 700130391Sle while ((j = getopt(argc, argv, "r")) != -1) { 701130391Sle switch (j) { 702130391Sle case 'r': 703130391Sle flags |= GV_FLAG_R; 704130391Sle break; 705130391Sle case '?': 706130391Sle default: 707130391Sle return; 708130391Sle } 709130391Sle } 710130391Sle argc -= optind; 711130391Sle argv += optind; 712130391Sle 713130391Sle req = gctl_get_handle(); 714130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 715130391Sle gctl_ro_param(req, "verb", -1, "remove"); 716130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 717130391Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 718130391Sle if (argc) { 719130391Sle for (i = 0; i < argc; i++) { 720130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 721130391Sle gctl_ro_param(req, buf, -1, argv[i]); 722130391Sle } 723130391Sle } 724130391Sle errstr = gctl_issue(req); 725130391Sle if (errstr != NULL) { 726130391Sle warnx("can't remove: %s", errstr); 727130391Sle gctl_free(req); 728130391Sle return; 729130391Sle } 730130391Sle gctl_free(req); 731130391Sle gvinum_list(0, NULL); 732130391Sle} 733130391Sle 734130391Slevoid 735157052Slegvinum_resetconfig(void) 736157052Sle{ 737157052Sle struct gctl_req *req; 738157052Sle const char *errstr; 739157052Sle char reply[32]; 740157052Sle 741157052Sle if (!isatty(STDIN_FILENO)) { 742157052Sle warn("Please enter this command from a tty device\n"); 743157052Sle return; 744157052Sle } 745157052Sle printf(" WARNING! This command will completely wipe out your gvinum" 746157052Sle "configuration.\n" 747157052Sle " All data will be lost. If you really want to do this," 748157052Sle " enter the text\n\n" 749157052Sle " NO FUTURE\n" 750157052Sle " Enter text -> "); 751157052Sle fgets(reply, sizeof(reply), stdin); 752157052Sle if (strcmp(reply, "NO FUTURE\n")) { 753157052Sle printf("\n No change\n"); 754157052Sle return; 755157052Sle } 756157052Sle req = gctl_get_handle(); 757157052Sle gctl_ro_param(req, "class", -1, "VINUM"); 758157052Sle gctl_ro_param(req, "verb", -1, "resetconfig"); 759157052Sle errstr = gctl_issue(req); 760157052Sle if (errstr != NULL) { 761157052Sle warnx("can't reset config: %s", errstr); 762157052Sle gctl_free(req); 763157052Sle return; 764157052Sle } 765157052Sle gctl_free(req); 766157052Sle gvinum_list(0, NULL); 767157052Sle printf("gvinum configuration obliterated\n"); 768157052Sle} 769157052Sle 770157052Slevoid 771130391Slegvinum_saveconfig(void) 772130391Sle{ 773130391Sle struct gctl_req *req; 774130391Sle const char *errstr; 775130391Sle 776130391Sle req = gctl_get_handle(); 777130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 778130391Sle gctl_ro_param(req, "verb", -1, "saveconfig"); 779130391Sle errstr = gctl_issue(req); 780130391Sle if (errstr != NULL) 781130391Sle warnx("can't save configuration: %s", errstr); 782130391Sle gctl_free(req); 783130391Sle} 784130391Sle 785130391Slevoid 786130391Slegvinum_start(int argc, char **argv) 787130391Sle{ 788130391Sle struct gctl_req *req; 789130391Sle int i, initsize, j; 790130391Sle const char *errstr; 791130391Sle char buf[20]; 792130391Sle 793130391Sle /* 'start' with no arguments is a no-op. */ 794130391Sle if (argc == 1) 795130391Sle return; 796130391Sle 797130391Sle initsize = 0; 798130391Sle 799130391Sle optreset = 1; 800130391Sle optind = 1; 801130391Sle while ((j = getopt(argc, argv, "S")) != -1) { 802130391Sle switch (j) { 803130391Sle case 'S': 804130391Sle initsize = atoi(optarg); 805130391Sle break; 806130391Sle case '?': 807130391Sle default: 808130391Sle return; 809130391Sle } 810130391Sle } 811130391Sle argc -= optind; 812130391Sle argv += optind; 813130391Sle 814130391Sle if (!initsize) 815130391Sle initsize = 512; 816130391Sle 817130391Sle req = gctl_get_handle(); 818130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 819130391Sle gctl_ro_param(req, "verb", -1, "start"); 820130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 821130391Sle gctl_ro_param(req, "initsize", sizeof(int), &initsize); 822130391Sle if (argc) { 823130391Sle for (i = 0; i < argc; i++) { 824130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 825130391Sle gctl_ro_param(req, buf, -1, argv[i]); 826130391Sle } 827130391Sle } 828130391Sle errstr = gctl_issue(req); 829130391Sle if (errstr != NULL) { 830130391Sle warnx("can't start: %s", errstr); 831130391Sle gctl_free(req); 832130391Sle return; 833130391Sle } 834130391Sle 835130391Sle gctl_free(req); 836130391Sle gvinum_list(0, NULL); 837130391Sle} 838130391Sle 839130391Slevoid 840130391Slegvinum_stop(int argc, char **argv) 841130391Sle{ 842130391Sle int fileid; 843130391Sle 844130391Sle fileid = kldfind(GVINUMMOD); 845130391Sle if (fileid == -1) { 846130391Sle warn("cannot find " GVINUMMOD); 847130391Sle return; 848130391Sle } 849130391Sle if (kldunload(fileid) != 0) { 850130391Sle warn("cannot unload " GVINUMMOD); 851130391Sle return; 852130391Sle } 853130391Sle 854130391Sle warnx(GVINUMMOD " unloaded"); 855130391Sle exit(0); 856130391Sle} 857130391Sle 858130391Slevoid 859130391Sleparseline(int argc, char **argv) 860130391Sle{ 861130391Sle if (argc <= 0) 862130391Sle return; 863130391Sle 864150044Sle if (!strcmp(argv[0], "create")) 865130391Sle gvinum_create(argc, argv); 866130391Sle else if (!strcmp(argv[0], "exit") || !strcmp(argv[0], "quit")) 867130391Sle exit(0); 868130391Sle else if (!strcmp(argv[0], "help")) 869130391Sle gvinum_help(); 870130391Sle else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "l")) 871130391Sle gvinum_list(argc, argv); 872130391Sle else if (!strcmp(argv[0], "ld")) 873130391Sle gvinum_list(argc, argv); 874130391Sle else if (!strcmp(argv[0], "lp")) 875130391Sle gvinum_list(argc, argv); 876130391Sle else if (!strcmp(argv[0], "ls")) 877130391Sle gvinum_list(argc, argv); 878130391Sle else if (!strcmp(argv[0], "lv")) 879130391Sle gvinum_list(argc, argv); 880152616Sle else if (!strcmp(argv[0], "move")) 881152616Sle gvinum_move(argc, argv); 882152616Sle else if (!strcmp(argv[0], "mv")) 883152616Sle gvinum_move(argc, argv); 884130391Sle else if (!strcmp(argv[0], "printconfig")) 885130391Sle gvinum_printconfig(argc, argv); 886152616Sle else if (!strcmp(argv[0], "rename")) 887152616Sle gvinum_rename(argc, argv); 888157052Sle else if (!strcmp(argv[0], "resetconfig")) 889157052Sle gvinum_resetconfig(); 890130391Sle else if (!strcmp(argv[0], "rm")) 891130391Sle gvinum_rm(argc, argv); 892130391Sle else if (!strcmp(argv[0], "saveconfig")) 893130391Sle gvinum_saveconfig(); 894138112Sle else if (!strcmp(argv[0], "setstate")) 895138112Sle gvinum_setstate(argc, argv); 896130391Sle else if (!strcmp(argv[0], "start")) 897130391Sle gvinum_start(argc, argv); 898130391Sle else if (!strcmp(argv[0], "stop")) 899130391Sle gvinum_stop(argc, argv); 900138110Sle else if (!strcmp(argv[0], "checkparity")) 901138110Sle gvinum_parityop(argc, argv, 0); 902138110Sle else if (!strcmp(argv[0], "rebuildparity")) 903138110Sle gvinum_parityop(argc, argv, 1); 904130391Sle else 905130391Sle printf("unknown command '%s'\n", argv[0]); 906130391Sle 907130391Sle return; 908130391Sle} 909130391Sle 910130391Sle/* 911130391Sle * The guts of printconfig. This is called from gvinum_printconfig and from 912130391Sle * gvinum_create when called without an argument, in order to give the user 913130391Sle * something to edit. 914130391Sle */ 915130391Slevoid 916130391Sleprintconfig(FILE *of, char *comment) 917130391Sle{ 918130391Sle struct gctl_req *req; 919130391Sle struct utsname uname_s; 920130391Sle const char *errstr; 921130391Sle time_t now; 922130391Sle char buf[GV_CFG_LEN + 1]; 923130391Sle 924130391Sle uname(&uname_s); 925130391Sle time(&now); 926130391Sle 927130391Sle req = gctl_get_handle(); 928130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 929130391Sle gctl_ro_param(req, "verb", -1, "getconfig"); 930130391Sle gctl_ro_param(req, "comment", -1, comment); 931130391Sle gctl_rw_param(req, "config", sizeof(buf), buf); 932130391Sle errstr = gctl_issue(req); 933130391Sle if (errstr != NULL) { 934130391Sle warnx("can't get configuration: %s", errstr); 935130391Sle return; 936130391Sle } 937130391Sle gctl_free(req); 938130391Sle 939130391Sle fprintf(of, "# Vinum configuration of %s, saved at %s", 940130391Sle uname_s.nodename, 941130391Sle ctime(&now)); 942130391Sle 943130391Sle if (*comment != '\0') 944130391Sle fprintf(of, "# Current configuration:\n"); 945130391Sle 946130391Sle fprintf(of, buf); 947130391Sle} 948