gvinum.c revision 152631
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 152631 2005-11-20 10:35:46Z 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 **); 64130391Slevoid gvinum_rm(int, char **); 65130391Slevoid gvinum_saveconfig(void); 66138112Slevoid gvinum_setstate(int, char **); 67130391Slevoid gvinum_start(int, char **); 68130391Slevoid gvinum_stop(int, char **); 69130391Slevoid parseline(int, char **); 70130391Slevoid printconfig(FILE *, char *); 71130391Sle 72130391Sleint 73130391Slemain(int argc, char **argv) 74130391Sle{ 75130391Sle int line, tokens; 76130391Sle char buffer[BUFSIZ], *inputline, *token[GV_MAXARGS]; 77130391Sle 78130391Sle /* Load the module if necessary. */ 79130391Sle if (kldfind(GVINUMMOD) < 0 && kldload(GVINUMMOD) < 0) 80130391Sle err(1, GVINUMMOD ": Kernel module not available"); 81130391Sle 82130391Sle /* Arguments given on the command line. */ 83130391Sle if (argc > 1) { 84130391Sle argc--; 85130391Sle argv++; 86130391Sle parseline(argc, argv); 87130391Sle 88130391Sle /* Interactive mode. */ 89130391Sle } else { 90130391Sle for (;;) { 91130391Sle inputline = readline("gvinum -> "); 92130391Sle if (inputline == NULL) { 93130391Sle if (ferror(stdin)) { 94130391Sle err(1, "can't read input"); 95130391Sle } else { 96130391Sle printf("\n"); 97130391Sle exit(0); 98130391Sle } 99130391Sle } else if (*inputline) { 100130391Sle add_history(inputline); 101130391Sle strcpy(buffer, inputline); 102130391Sle free(inputline); 103130391Sle line++; /* count the lines */ 104130391Sle tokens = gv_tokenize(buffer, token, GV_MAXARGS); 105130391Sle if (tokens) 106130391Sle parseline(tokens, token); 107130391Sle } 108130391Sle } 109130391Sle } 110130391Sle exit(0); 111130391Sle} 112130391Sle 113130391Slevoid 114130391Slegvinum_create(int argc, char **argv) 115130391Sle{ 116130391Sle struct gctl_req *req; 117130391Sle struct gv_drive *d; 118130391Sle struct gv_plex *p; 119130391Sle struct gv_sd *s; 120130391Sle struct gv_volume *v; 121130391Sle FILE *tmp; 122130391Sle int drives, errors, fd, line, plexes, plex_in_volume; 123130391Sle int sd_in_plex, status, subdisks, tokens, volumes; 124130391Sle const char *errstr; 125130391Sle char buf[BUFSIZ], buf1[BUFSIZ], commandline[BUFSIZ], *ed; 126130391Sle char original[BUFSIZ], tmpfile[20], *token[GV_MAXARGS]; 127130391Sle char plex[GV_MAXPLEXNAME], volume[GV_MAXVOLNAME]; 128130391Sle 129133097Sle if (argc == 2) { 130133097Sle if ((tmp = fopen(argv[1], "r")) == NULL) { 131133097Sle warn("can't open '%s' for reading", argv[1]); 132133097Sle return; 133133097Sle } 134133097Sle } else { 135133097Sle snprintf(tmpfile, sizeof(tmpfile), "/tmp/gvinum.XXXXXX"); 136133097Sle 137133097Sle if ((fd = mkstemp(tmpfile)) == -1) { 138133097Sle warn("temporary file not accessible"); 139133097Sle return; 140133097Sle } 141133097Sle if ((tmp = fdopen(fd, "w")) == NULL) { 142133097Sle warn("can't open '%s' for writing", tmpfile); 143133097Sle return; 144133097Sle } 145133097Sle printconfig(tmp, "# "); 146133097Sle fclose(tmp); 147133097Sle 148133097Sle ed = getenv("EDITOR"); 149133097Sle if (ed == NULL) 150133097Sle ed = _PATH_VI; 151133097Sle 152133097Sle snprintf(commandline, sizeof(commandline), "%s %s", ed, 153133097Sle tmpfile); 154133097Sle status = system(commandline); 155133097Sle if (status != 0) { 156133097Sle warn("couldn't exec %s; status: %d", ed, status); 157133097Sle return; 158133097Sle } 159133097Sle 160133097Sle if ((tmp = fopen(tmpfile, "r")) == NULL) { 161133097Sle warn("can't open '%s' for reading", tmpfile); 162133097Sle return; 163133097Sle } 164130391Sle } 165130391Sle 166130391Sle req = gctl_get_handle(); 167130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 168130391Sle gctl_ro_param(req, "verb", -1, "create"); 169130391Sle 170130391Sle drives = volumes = plexes = subdisks = 0; 171130391Sle plex_in_volume = sd_in_plex = 0; 172130391Sle errors = 0; 173130391Sle line = 1; 174130391Sle while ((fgets(buf, BUFSIZ, tmp)) != NULL) { 175130391Sle 176130391Sle /* Skip empty lines and comments. */ 177130391Sle if (*buf == '\0' || *buf == '#') { 178130391Sle line++; 179130391Sle continue; 180130391Sle } 181130391Sle 182130391Sle /* Kill off the newline. */ 183130391Sle buf[strlen(buf) - 1] = '\0'; 184130391Sle 185130391Sle /* 186130391Sle * Copy the original input line in case we need it for error 187130391Sle * output. 188130391Sle */ 189130391Sle strncpy(original, buf, sizeof(buf)); 190130391Sle 191130391Sle tokens = gv_tokenize(buf, token, GV_MAXARGS); 192150044Sle if (tokens <= 0) { 193150044Sle line++; 194150044Sle continue; 195150044Sle } 196130391Sle 197150044Sle /* Volume definition. */ 198150044Sle if (!strcmp(token[0], "volume")) { 199150044Sle v = gv_new_volume(tokens, token); 200150044Sle if (v == NULL) { 201150044Sle warnx("line %d: invalid volume definition", 202150044Sle line); 203150044Sle warnx("line %d: '%s'", line, original); 204150044Sle errors++; 205150044Sle line++; 206150044Sle continue; 207150044Sle } 208130391Sle 209150044Sle /* Reset plex count for this volume. */ 210150044Sle plex_in_volume = 0; 211130391Sle 212150044Sle /* 213150044Sle * Set default volume name for following plex 214150044Sle * definitions. 215150044Sle */ 216150044Sle strncpy(volume, v->name, sizeof(volume)); 217130391Sle 218150044Sle snprintf(buf1, sizeof(buf1), "volume%d", volumes); 219150044Sle gctl_ro_param(req, buf1, sizeof(*v), v); 220150044Sle volumes++; 221130391Sle 222150044Sle /* Plex definition. */ 223150044Sle } else if (!strcmp(token[0], "plex")) { 224150044Sle p = gv_new_plex(tokens, token); 225150044Sle if (p == NULL) { 226150044Sle warnx("line %d: invalid plex definition", line); 227150044Sle warnx("line %d: '%s'", line, original); 228150044Sle errors++; 229150044Sle line++; 230150044Sle continue; 231150044Sle } 232130391Sle 233150044Sle /* Reset subdisk count for this plex. */ 234150044Sle sd_in_plex = 0; 235130391Sle 236150044Sle /* Default name. */ 237150044Sle if (strlen(p->name) == 0) { 238150044Sle snprintf(p->name, GV_MAXPLEXNAME, "%s.p%d", 239150044Sle volume, plex_in_volume++); 240150044Sle } 241130391Sle 242150044Sle /* Default volume. */ 243150044Sle if (strlen(p->volume) == 0) { 244150044Sle snprintf(p->volume, GV_MAXVOLNAME, "%s", 245150044Sle volume); 246150044Sle } 247130391Sle 248150044Sle /* 249150044Sle * Set default plex name for following subdisk 250150044Sle * definitions. 251150044Sle */ 252150044Sle strncpy(plex, p->name, GV_MAXPLEXNAME); 253130391Sle 254150044Sle snprintf(buf1, sizeof(buf1), "plex%d", plexes); 255150044Sle gctl_ro_param(req, buf1, sizeof(*p), p); 256150044Sle plexes++; 257130391Sle 258150044Sle /* Subdisk definition. */ 259150044Sle } else if (!strcmp(token[0], "sd")) { 260150044Sle s = gv_new_sd(tokens, token); 261150044Sle if (s == NULL) { 262150044Sle warnx("line %d: invalid subdisk " 263150044Sle "definition:", line); 264150044Sle warnx("line %d: '%s'", line, original); 265150044Sle errors++; 266150044Sle line++; 267150044Sle continue; 268150044Sle } 269130391Sle 270150044Sle /* Default name. */ 271150044Sle if (strlen(s->name) == 0) { 272150044Sle snprintf(s->name, GV_MAXSDNAME, "%s.s%d", 273150044Sle plex, sd_in_plex++); 274150044Sle } 275150044Sle 276150044Sle /* Default plex. */ 277150044Sle if (strlen(s->plex) == 0) 278150044Sle snprintf(s->plex, GV_MAXPLEXNAME, "%s", plex); 279150044Sle 280150044Sle snprintf(buf1, sizeof(buf1), "sd%d", subdisks); 281150044Sle gctl_ro_param(req, buf1, sizeof(*s), s); 282150044Sle subdisks++; 283150044Sle 284150044Sle /* Subdisk definition. */ 285150044Sle } else if (!strcmp(token[0], "drive")) { 286150044Sle d = gv_new_drive(tokens, token); 287150044Sle if (d == NULL) { 288150044Sle warnx("line %d: invalid drive definition:", 289150044Sle line); 290130391Sle warnx("line %d: '%s'", line, original); 291130391Sle errors++; 292150044Sle line++; 293150044Sle continue; 294130391Sle } 295150044Sle 296150044Sle snprintf(buf1, sizeof(buf1), "drive%d", drives); 297150044Sle gctl_ro_param(req, buf1, sizeof(*d), d); 298150044Sle drives++; 299150044Sle 300150044Sle /* Everything else is bogus. */ 301150044Sle } else { 302150044Sle warnx("line %d: invalid definition:", line); 303150044Sle warnx("line %d: '%s'", line, original); 304150044Sle errors++; 305130391Sle } 306130391Sle line++; 307130391Sle } 308130391Sle 309130391Sle fclose(tmp); 310130391Sle unlink(tmpfile); 311130391Sle 312130391Sle if (!errors && (volumes || plexes || subdisks || drives)) { 313130391Sle gctl_ro_param(req, "volumes", sizeof(int), &volumes); 314130391Sle gctl_ro_param(req, "plexes", sizeof(int), &plexes); 315130391Sle gctl_ro_param(req, "subdisks", sizeof(int), &subdisks); 316130391Sle gctl_ro_param(req, "drives", sizeof(int), &drives); 317130391Sle errstr = gctl_issue(req); 318130391Sle if (errstr != NULL) 319130391Sle warnx("create failed: %s", errstr); 320130391Sle } 321130391Sle gctl_free(req); 322130391Sle gvinum_list(0, NULL); 323130391Sle} 324130391Sle 325130391Slevoid 326130391Slegvinum_help(void) 327130391Sle{ 328130391Sle printf("COMMANDS\n" 329152616Sle "checkparity [-f] plex\n" 330152616Sle " Check the parity blocks of a RAID-5 plex.\n" 331152616Sle "create description-file\n" 332152616Sle " Create as per description-file or open editor.\n" 333152616Sle "l | list [-r] [-v] [-V] [volume | plex | subdisk]\n" 334130391Sle " List information about specified objects.\n" 335152616Sle "ld [-r] [-v] [-V] [volume]\n" 336130391Sle " List information about drives.\n" 337152616Sle "ls [-r] [-v] [-V] [subdisk]\n" 338130391Sle " List information about subdisks.\n" 339152616Sle "lp [-r] [-v] [-V] [plex]\n" 340130391Sle " List information about plexes.\n" 341152616Sle "lv [-r] [-v] [-V] [volume]\n" 342130391Sle " List information about volumes.\n" 343130391Sle "move | mv -f drive object ...\n" 344130391Sle " Move the object(s) to the specified drive.\n" 345130391Sle "quit Exit the vinum program when running in interactive mode." 346130391Sle " Nor-\n" 347130391Sle " mally this would be done by entering the EOF character.\n" 348130391Sle "rename [-r] [drive | subdisk | plex | volume] newname\n" 349130391Sle " Change the name of the specified object.\n" 350152616Sle "rebuildparity plex [-f]\n" 351152616Sle " Rebuild the parity blocks of a RAID-5 plex.\n" 352152616Sle "rm [-r] volume | plex | subdisk | drive\n" 353130391Sle " Remove an object.\n" 354130391Sle "saveconfig\n" 355130391Sle " Save vinum configuration to disk after configuration" 356130391Sle " failures.\n" 357152616Sle "setstate [-f] state [volume | plex | subdisk | drive]\n" 358130391Sle " Set state without influencing other objects, for" 359130391Sle " diagnostic pur-\n" 360130391Sle " poses only.\n" 361152616Sle "start [-S size] volume | plex | subdisk\n" 362130391Sle " Allow the system to access the objects.\n" 363130391Sle ); 364130391Sle 365130391Sle return; 366130391Sle} 367130391Sle 368130391Slevoid 369138112Slegvinum_setstate(int argc, char **argv) 370138112Sle{ 371138112Sle struct gctl_req *req; 372138112Sle int flags, i; 373138112Sle const char *errstr; 374138112Sle 375138112Sle flags = 0; 376138112Sle 377138112Sle optreset = 1; 378138112Sle optind = 1; 379138112Sle 380138112Sle while ((i = getopt(argc, argv, "f")) != -1) { 381138112Sle switch (i) { 382138112Sle case 'f': 383138112Sle flags |= GV_FLAG_F; 384138112Sle break; 385138112Sle case '?': 386138112Sle default: 387138112Sle warn("invalid flag: %c", i); 388138112Sle return; 389138112Sle } 390138112Sle } 391138112Sle 392138112Sle argc -= optind; 393138112Sle argv += optind; 394138112Sle 395138112Sle if (argc != 2) { 396138112Sle warnx("usage: setstate [-f] <state> <obj>"); 397138112Sle return; 398138112Sle } 399138112Sle 400138112Sle /* 401138112Sle * XXX: This hack is needed to avoid tripping over (now) invalid 402138112Sle * 'classic' vinum states and will go away later. 403138112Sle */ 404138112Sle if (strcmp(argv[0], "up") && strcmp(argv[0], "down") && 405138112Sle strcmp(argv[0], "stale")) { 406138112Sle warnx("invalid state '%s'", argv[0]); 407138112Sle return; 408138112Sle } 409138112Sle 410138112Sle req = gctl_get_handle(); 411138112Sle gctl_ro_param(req, "class", -1, "VINUM"); 412138112Sle gctl_ro_param(req, "verb", -1, "setstate"); 413138112Sle gctl_ro_param(req, "state", -1, argv[0]); 414138112Sle gctl_ro_param(req, "object", -1, argv[1]); 415138112Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 416138112Sle 417138112Sle errstr = gctl_issue(req); 418138112Sle if (errstr != NULL) 419138112Sle warnx("%s", errstr); 420138112Sle gctl_free(req); 421138112Sle} 422138112Sle 423138112Slevoid 424130391Slegvinum_list(int argc, char **argv) 425130391Sle{ 426130391Sle struct gctl_req *req; 427130391Sle int flags, i, j; 428130391Sle const char *errstr; 429130391Sle char buf[20], *cmd, config[GV_CFG_LEN + 1]; 430130391Sle 431130391Sle flags = 0; 432130391Sle cmd = "list"; 433130391Sle 434130391Sle if (argc) { 435130391Sle optreset = 1; 436130391Sle optind = 1; 437130391Sle cmd = argv[0]; 438130391Sle while ((j = getopt(argc, argv, "rsvV")) != -1) { 439130391Sle switch (j) { 440130391Sle case 'r': 441130391Sle flags |= GV_FLAG_R; 442130391Sle break; 443130391Sle case 's': 444130391Sle flags |= GV_FLAG_S; 445130391Sle break; 446130391Sle case 'v': 447130391Sle flags |= GV_FLAG_V; 448130391Sle break; 449130391Sle case 'V': 450130391Sle flags |= GV_FLAG_V; 451130391Sle flags |= GV_FLAG_VV; 452130391Sle break; 453130391Sle case '?': 454130391Sle default: 455130391Sle return; 456130391Sle } 457130391Sle } 458130391Sle argc -= optind; 459130391Sle argv += optind; 460130391Sle 461130391Sle } 462130391Sle 463130391Sle req = gctl_get_handle(); 464130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 465130391Sle gctl_ro_param(req, "verb", -1, "list"); 466130391Sle gctl_ro_param(req, "cmd", -1, cmd); 467130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 468130391Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 469130391Sle gctl_rw_param(req, "config", sizeof(config), config); 470130391Sle if (argc) { 471130391Sle for (i = 0; i < argc; i++) { 472130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 473130391Sle gctl_ro_param(req, buf, -1, argv[i]); 474130391Sle } 475130391Sle } 476130391Sle errstr = gctl_issue(req); 477130391Sle if (errstr != NULL) { 478130391Sle warnx("can't get configuration: %s", errstr); 479130391Sle gctl_free(req); 480130391Sle return; 481130391Sle } 482130391Sle 483130391Sle printf("%s", config); 484130391Sle gctl_free(req); 485130391Sle return; 486130391Sle} 487130391Sle 488152616Sle/* Note that move is currently of form '[-r] target object [...]' */ 489130391Slevoid 490152616Slegvinum_move(int argc, char **argv) 491152616Sle{ 492152616Sle struct gctl_req *req; 493152616Sle const char *errstr; 494152616Sle char buf[20]; 495152616Sle int flags, i, j; 496152616Sle 497152616Sle flags = 0; 498152616Sle if (argc) { 499152616Sle optreset = 1; 500152616Sle optind = 1; 501152616Sle while ((j = getopt(argc, argv, "f")) != -1) { 502152616Sle switch (j) { 503152616Sle case 'f': 504152616Sle flags |= GV_FLAG_F; 505152616Sle break; 506152616Sle case '?': 507152616Sle default: 508152616Sle return; 509152616Sle } 510152616Sle } 511152616Sle argc -= optind; 512152616Sle argv += optind; 513152616Sle } 514152616Sle 515152616Sle switch (argc) { 516152616Sle case 0: 517152616Sle warnx("no destination or object(s) to move specified"); 518152616Sle return; 519152616Sle case 1: 520152616Sle warnx("no object(s) to move specified"); 521152616Sle return; 522152616Sle default: 523152616Sle break; 524152616Sle } 525152616Sle 526152616Sle req = gctl_get_handle(); 527152616Sle gctl_ro_param(req, "class", -1, "VINUM"); 528152616Sle gctl_ro_param(req, "verb", -1, "move"); 529152616Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 530152616Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 531152616Sle gctl_ro_param(req, "destination", -1, argv[0]); 532152616Sle for (i = 1; i < argc; i++) { 533152616Sle snprintf(buf, sizeof(buf), "argv%d", i); 534152616Sle gctl_ro_param(req, buf, -1, argv[i]); 535152616Sle } 536152631Sle errstr = gctl_issue(req); 537152616Sle if (errstr != NULL) 538152616Sle warnx("can't move object(s): %s", errstr); 539152616Sle gctl_free(req); 540152616Sle return; 541152616Sle} 542152616Sle 543152616Slevoid 544130391Slegvinum_printconfig(int argc, char **argv) 545130391Sle{ 546130391Sle printconfig(stdout, ""); 547130391Sle} 548130391Sle 549130391Slevoid 550138110Slegvinum_parityop(int argc, char **argv, int rebuild) 551138110Sle{ 552138110Sle struct gctl_req *req; 553138110Sle int flags, i, rv; 554138110Sle off_t offset; 555138110Sle const char *errstr; 556138110Sle char *op, *msg; 557138110Sle 558138110Sle if (rebuild) { 559138110Sle op = "rebuildparity"; 560138110Sle msg = "Rebuilding"; 561138110Sle } else { 562138110Sle op = "checkparity"; 563138110Sle msg = "Checking"; 564138110Sle } 565138110Sle 566138110Sle optreset = 1; 567138110Sle optind = 1; 568138110Sle flags = 0; 569138110Sle while ((i = getopt(argc, argv, "fv")) != -1) { 570138110Sle switch (i) { 571138110Sle case 'f': 572138110Sle flags |= GV_FLAG_F; 573138110Sle break; 574138110Sle case 'v': 575138110Sle flags |= GV_FLAG_V; 576138110Sle break; 577138110Sle case '?': 578138110Sle default: 579138110Sle warnx("invalid flag '%c'", i); 580138110Sle return; 581138110Sle } 582138110Sle } 583138110Sle argc -= optind; 584138110Sle argv += optind; 585138110Sle 586138110Sle if (argc != 1) { 587138110Sle warn("usage: %s [-f] [-v] <plex>", op); 588138110Sle return; 589138110Sle } 590138110Sle 591138110Sle do { 592138110Sle rv = 0; 593138110Sle req = gctl_get_handle(); 594138110Sle gctl_ro_param(req, "class", -1, "VINUM"); 595138110Sle gctl_ro_param(req, "verb", -1, "parityop"); 596138110Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 597138110Sle gctl_ro_param(req, "rebuild", sizeof(int), &rebuild); 598138110Sle gctl_rw_param(req, "rv", sizeof(int), &rv); 599138110Sle gctl_rw_param(req, "offset", sizeof(off_t), &offset); 600138110Sle gctl_ro_param(req, "plex", -1, argv[0]); 601138110Sle errstr = gctl_issue(req); 602138110Sle if (errstr) { 603138110Sle warnx("%s\n", errstr); 604138110Sle gctl_free(req); 605138110Sle break; 606138110Sle } 607138110Sle gctl_free(req); 608138110Sle if (flags & GV_FLAG_V) { 609138110Sle printf("\r%s at %s ... ", msg, 610138110Sle gv_roughlength(offset, 1)); 611138110Sle } 612138110Sle if (rv == 1) { 613138110Sle printf("Parity incorrect at offset 0x%jx\n", 614138110Sle (intmax_t)offset); 615138110Sle if (!rebuild) 616138110Sle break; 617138110Sle } 618138110Sle fflush(stdout); 619138110Sle 620138110Sle /* Clear the -f flag. */ 621138110Sle flags &= ~GV_FLAG_F; 622138110Sle } while (rv >= 0); 623138110Sle 624138110Sle if ((rv == 2) && (flags & GV_FLAG_V)) { 625138110Sle if (rebuild) 626138110Sle printf("Rebuilt parity on %s\n", argv[0]); 627138110Sle else 628138110Sle printf("%s has correct parity\n", argv[0]); 629138110Sle } 630138110Sle} 631138110Sle 632138110Slevoid 633152616Slegvinum_rename(int argc, char **argv) 634152616Sle{ 635152616Sle struct gctl_req *req; 636152616Sle const char *errstr; 637152616Sle int flags, j; 638152616Sle 639152616Sle flags = 0; 640152616Sle 641152616Sle if (argc) { 642152616Sle optreset = 1; 643152616Sle optind = 1; 644152616Sle while ((j = getopt(argc, argv, "r")) != -1) { 645152616Sle switch (j) { 646152616Sle case 'r': 647152616Sle flags |= GV_FLAG_R; 648152616Sle break; 649152616Sle case '?': 650152616Sle default: 651152616Sle return; 652152616Sle } 653152616Sle } 654152616Sle argc -= optind; 655152616Sle argv += optind; 656152616Sle } 657152616Sle 658152616Sle switch (argc) { 659152616Sle case 0: 660152616Sle warnx("no object to rename specified"); 661152616Sle return; 662152616Sle case 1: 663152616Sle warnx("no new name specified"); 664152616Sle return; 665152616Sle case 2: 666152616Sle break; 667152616Sle default: 668152616Sle warnx("more than one new name specified"); 669152616Sle return; 670152616Sle } 671152616Sle 672152616Sle req = gctl_get_handle(); 673152616Sle gctl_ro_param(req, "class", -1, "VINUM"); 674152616Sle gctl_ro_param(req, "verb", -1, "rename"); 675152616Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 676152616Sle gctl_ro_param(req, "object", -1, argv[0]); 677152616Sle gctl_ro_param(req, "newname", -1, argv[1]); 678152631Sle errstr = gctl_issue(req); 679152616Sle if (errstr != NULL) 680152616Sle warnx("can't rename object: %s", errstr); 681152616Sle gctl_free(req); 682152616Sle return; 683152616Sle} 684152616Sle 685152616Slevoid 686130391Slegvinum_rm(int argc, char **argv) 687130391Sle{ 688130391Sle struct gctl_req *req; 689130391Sle int flags, i, j; 690130391Sle const char *errstr; 691130391Sle char buf[20], *cmd; 692130391Sle 693130391Sle cmd = argv[0]; 694130391Sle flags = 0; 695130391Sle optreset = 1; 696130391Sle optind = 1; 697130391Sle while ((j = getopt(argc, argv, "r")) != -1) { 698130391Sle switch (j) { 699130391Sle case 'r': 700130391Sle flags |= GV_FLAG_R; 701130391Sle break; 702130391Sle case '?': 703130391Sle default: 704130391Sle return; 705130391Sle } 706130391Sle } 707130391Sle argc -= optind; 708130391Sle argv += optind; 709130391Sle 710130391Sle req = gctl_get_handle(); 711130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 712130391Sle gctl_ro_param(req, "verb", -1, "remove"); 713130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 714130391Sle gctl_ro_param(req, "flags", sizeof(int), &flags); 715130391Sle if (argc) { 716130391Sle for (i = 0; i < argc; i++) { 717130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 718130391Sle gctl_ro_param(req, buf, -1, argv[i]); 719130391Sle } 720130391Sle } 721130391Sle errstr = gctl_issue(req); 722130391Sle if (errstr != NULL) { 723130391Sle warnx("can't remove: %s", errstr); 724130391Sle gctl_free(req); 725130391Sle return; 726130391Sle } 727130391Sle gctl_free(req); 728130391Sle gvinum_list(0, NULL); 729130391Sle} 730130391Sle 731130391Slevoid 732130391Slegvinum_saveconfig(void) 733130391Sle{ 734130391Sle struct gctl_req *req; 735130391Sle const char *errstr; 736130391Sle 737130391Sle req = gctl_get_handle(); 738130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 739130391Sle gctl_ro_param(req, "verb", -1, "saveconfig"); 740130391Sle errstr = gctl_issue(req); 741130391Sle if (errstr != NULL) 742130391Sle warnx("can't save configuration: %s", errstr); 743130391Sle gctl_free(req); 744130391Sle} 745130391Sle 746130391Slevoid 747130391Slegvinum_start(int argc, char **argv) 748130391Sle{ 749130391Sle struct gctl_req *req; 750130391Sle int i, initsize, j; 751130391Sle const char *errstr; 752130391Sle char buf[20]; 753130391Sle 754130391Sle /* 'start' with no arguments is a no-op. */ 755130391Sle if (argc == 1) 756130391Sle return; 757130391Sle 758130391Sle initsize = 0; 759130391Sle 760130391Sle optreset = 1; 761130391Sle optind = 1; 762130391Sle while ((j = getopt(argc, argv, "S")) != -1) { 763130391Sle switch (j) { 764130391Sle case 'S': 765130391Sle initsize = atoi(optarg); 766130391Sle break; 767130391Sle case '?': 768130391Sle default: 769130391Sle return; 770130391Sle } 771130391Sle } 772130391Sle argc -= optind; 773130391Sle argv += optind; 774130391Sle 775130391Sle if (!initsize) 776130391Sle initsize = 512; 777130391Sle 778130391Sle req = gctl_get_handle(); 779130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 780130391Sle gctl_ro_param(req, "verb", -1, "start"); 781130391Sle gctl_ro_param(req, "argc", sizeof(int), &argc); 782130391Sle gctl_ro_param(req, "initsize", sizeof(int), &initsize); 783130391Sle if (argc) { 784130391Sle for (i = 0; i < argc; i++) { 785130391Sle snprintf(buf, sizeof(buf), "argv%d", i); 786130391Sle gctl_ro_param(req, buf, -1, argv[i]); 787130391Sle } 788130391Sle } 789130391Sle errstr = gctl_issue(req); 790130391Sle if (errstr != NULL) { 791130391Sle warnx("can't start: %s", errstr); 792130391Sle gctl_free(req); 793130391Sle return; 794130391Sle } 795130391Sle 796130391Sle gctl_free(req); 797130391Sle gvinum_list(0, NULL); 798130391Sle} 799130391Sle 800130391Slevoid 801130391Slegvinum_stop(int argc, char **argv) 802130391Sle{ 803130391Sle int fileid; 804130391Sle 805130391Sle fileid = kldfind(GVINUMMOD); 806130391Sle if (fileid == -1) { 807130391Sle warn("cannot find " GVINUMMOD); 808130391Sle return; 809130391Sle } 810130391Sle if (kldunload(fileid) != 0) { 811130391Sle warn("cannot unload " GVINUMMOD); 812130391Sle return; 813130391Sle } 814130391Sle 815130391Sle warnx(GVINUMMOD " unloaded"); 816130391Sle exit(0); 817130391Sle} 818130391Sle 819130391Slevoid 820130391Sleparseline(int argc, char **argv) 821130391Sle{ 822130391Sle if (argc <= 0) 823130391Sle return; 824130391Sle 825150044Sle if (!strcmp(argv[0], "create")) 826130391Sle gvinum_create(argc, argv); 827130391Sle else if (!strcmp(argv[0], "exit") || !strcmp(argv[0], "quit")) 828130391Sle exit(0); 829130391Sle else if (!strcmp(argv[0], "help")) 830130391Sle gvinum_help(); 831130391Sle else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "l")) 832130391Sle gvinum_list(argc, argv); 833130391Sle else if (!strcmp(argv[0], "ld")) 834130391Sle gvinum_list(argc, argv); 835130391Sle else if (!strcmp(argv[0], "lp")) 836130391Sle gvinum_list(argc, argv); 837130391Sle else if (!strcmp(argv[0], "ls")) 838130391Sle gvinum_list(argc, argv); 839130391Sle else if (!strcmp(argv[0], "lv")) 840130391Sle gvinum_list(argc, argv); 841152616Sle else if (!strcmp(argv[0], "move")) 842152616Sle gvinum_move(argc, argv); 843152616Sle else if (!strcmp(argv[0], "mv")) 844152616Sle gvinum_move(argc, argv); 845130391Sle else if (!strcmp(argv[0], "printconfig")) 846130391Sle gvinum_printconfig(argc, argv); 847152616Sle else if (!strcmp(argv[0], "rename")) 848152616Sle gvinum_rename(argc, argv); 849130391Sle else if (!strcmp(argv[0], "rm")) 850130391Sle gvinum_rm(argc, argv); 851130391Sle else if (!strcmp(argv[0], "saveconfig")) 852130391Sle gvinum_saveconfig(); 853138112Sle else if (!strcmp(argv[0], "setstate")) 854138112Sle gvinum_setstate(argc, argv); 855130391Sle else if (!strcmp(argv[0], "start")) 856130391Sle gvinum_start(argc, argv); 857130391Sle else if (!strcmp(argv[0], "stop")) 858130391Sle gvinum_stop(argc, argv); 859138110Sle else if (!strcmp(argv[0], "checkparity")) 860138110Sle gvinum_parityop(argc, argv, 0); 861138110Sle else if (!strcmp(argv[0], "rebuildparity")) 862138110Sle gvinum_parityop(argc, argv, 1); 863130391Sle else 864130391Sle printf("unknown command '%s'\n", argv[0]); 865130391Sle 866130391Sle return; 867130391Sle} 868130391Sle 869130391Sle/* 870130391Sle * The guts of printconfig. This is called from gvinum_printconfig and from 871130391Sle * gvinum_create when called without an argument, in order to give the user 872130391Sle * something to edit. 873130391Sle */ 874130391Slevoid 875130391Sleprintconfig(FILE *of, char *comment) 876130391Sle{ 877130391Sle struct gctl_req *req; 878130391Sle struct utsname uname_s; 879130391Sle const char *errstr; 880130391Sle time_t now; 881130391Sle char buf[GV_CFG_LEN + 1]; 882130391Sle 883130391Sle uname(&uname_s); 884130391Sle time(&now); 885130391Sle 886130391Sle req = gctl_get_handle(); 887130391Sle gctl_ro_param(req, "class", -1, "VINUM"); 888130391Sle gctl_ro_param(req, "verb", -1, "getconfig"); 889130391Sle gctl_ro_param(req, "comment", -1, comment); 890130391Sle gctl_rw_param(req, "config", sizeof(buf), buf); 891130391Sle errstr = gctl_issue(req); 892130391Sle if (errstr != NULL) { 893130391Sle warnx("can't get configuration: %s", errstr); 894130391Sle return; 895130391Sle } 896130391Sle gctl_free(req); 897130391Sle 898130391Sle fprintf(of, "# Vinum configuration of %s, saved at %s", 899130391Sle uname_s.nodename, 900130391Sle ctime(&now)); 901130391Sle 902130391Sle if (*comment != '\0') 903130391Sle fprintf(of, "# Current configuration:\n"); 904130391Sle 905130391Sle fprintf(of, buf); 906130391Sle} 907