Add gvinum, the geom_vinum userland tool.
This commit is contained in:
parent
dc91f66bc8
commit
74769ce0e6
14
sbin/gvinum/Makefile
Normal file
14
sbin/gvinum/Makefile
Normal file
@ -0,0 +1,14 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= gvinum
|
||||
SRCS= gvinum.c gvinum.h geom_vinum_share.c
|
||||
NOMAN= notyet
|
||||
|
||||
CFLAGS+= -I${.CURDIR}/../../sys
|
||||
|
||||
DPADD= ${LIBREADLINE} ${LIBTERMCAP} ${LIBDEVSTAT} ${LIBKVM} ${LIBGEOM}
|
||||
LDADD= -lreadline -ltermcap -ldevstat -lkvm -lgeom
|
||||
|
||||
.PATH: ${.CURDIR}/../../sys/geom/vinum
|
||||
|
||||
.include <bsd.prog.mk>
|
758
sbin/gvinum/gvinum.c
Normal file
758
sbin/gvinum/gvinum.c
Normal file
@ -0,0 +1,758 @@
|
||||
/*
|
||||
* Copyright (c) 2004 Lukas Ertl
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/linker.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#include <geom/vinum/geom_vinum_var.h>
|
||||
#include <geom/vinum/geom_vinum_share.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <libgeom.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <paths.h>
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "gvinum.h"
|
||||
|
||||
void gvinum_cancelinit(int, char **);
|
||||
void gvinum_create(int, char **);
|
||||
void gvinum_help(void);
|
||||
void gvinum_init(int, char **);
|
||||
void gvinum_list(int, char **);
|
||||
void gvinum_printconfig(int, char **);
|
||||
void gvinum_rm(int, char **);
|
||||
void gvinum_saveconfig(void);
|
||||
void gvinum_start(int, char **);
|
||||
void gvinum_stop(int, char **);
|
||||
void parseline(int, char **);
|
||||
void printconfig(FILE *, char *);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int line, tokens;
|
||||
char buffer[BUFSIZ], *inputline, *token[GV_MAXARGS];
|
||||
|
||||
/* Load the module if necessary. */
|
||||
if (kldfind(GVINUMMOD) < 0 && kldload(GVINUMMOD) < 0)
|
||||
err(1, GVINUMMOD ": Kernel module not available");
|
||||
|
||||
/* Arguments given on the command line. */
|
||||
if (argc > 1) {
|
||||
argc--;
|
||||
argv++;
|
||||
parseline(argc, argv);
|
||||
|
||||
/* Interactive mode. */
|
||||
} else {
|
||||
for (;;) {
|
||||
inputline = readline("gvinum -> ");
|
||||
if (inputline == NULL) {
|
||||
if (ferror(stdin)) {
|
||||
err(1, "can't read input");
|
||||
} else {
|
||||
printf("\n");
|
||||
exit(0);
|
||||
}
|
||||
} else if (*inputline) {
|
||||
add_history(inputline);
|
||||
strcpy(buffer, inputline);
|
||||
free(inputline);
|
||||
line++; /* count the lines */
|
||||
tokens = gv_tokenize(buffer, token, GV_MAXARGS);
|
||||
if (tokens)
|
||||
parseline(tokens, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
gvinum_cancelinit(int argc, char **argv)
|
||||
{
|
||||
struct gctl_req *req;
|
||||
int i;
|
||||
const char *errstr;
|
||||
char buf[20];
|
||||
|
||||
if (argc == 1)
|
||||
return;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
req = gctl_get_handle();
|
||||
gctl_ro_param(req, "class", -1, "VINUM");
|
||||
gctl_ro_param(req, "verb", -1, "cancelinit");
|
||||
gctl_ro_param(req, "argc", sizeof(int), &argc);
|
||||
if (argc) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
snprintf(buf, sizeof(buf), "argv%d", i);
|
||||
gctl_ro_param(req, buf, -1, argv[i]);
|
||||
}
|
||||
}
|
||||
errstr = gctl_issue(req);
|
||||
if (errstr != NULL) {
|
||||
warnx("can't init: %s", errstr);
|
||||
gctl_free(req);
|
||||
return;
|
||||
}
|
||||
|
||||
gctl_free(req);
|
||||
gvinum_list(0, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gvinum_create(int argc, char **argv)
|
||||
{
|
||||
struct gctl_req *req;
|
||||
struct gv_drive *d;
|
||||
struct gv_plex *p;
|
||||
struct gv_sd *s;
|
||||
struct gv_volume *v;
|
||||
FILE *tmp;
|
||||
int drives, errors, fd, line, plexes, plex_in_volume;
|
||||
int sd_in_plex, status, subdisks, tokens, volumes;
|
||||
const char *errstr;
|
||||
char buf[BUFSIZ], buf1[BUFSIZ], commandline[BUFSIZ], *ed;
|
||||
char original[BUFSIZ], tmpfile[20], *token[GV_MAXARGS];
|
||||
char plex[GV_MAXPLEXNAME], volume[GV_MAXVOLNAME];
|
||||
|
||||
snprintf(tmpfile, sizeof(tmpfile), "/tmp/gvinum.XXXXXX");
|
||||
|
||||
if ((fd = mkstemp(tmpfile)) == -1) {
|
||||
warn("temporary file not accessible");
|
||||
return;
|
||||
}
|
||||
if ((tmp = fdopen(fd, "w")) == NULL) {
|
||||
warn("can't open '%s' for writing", tmpfile);
|
||||
return;
|
||||
}
|
||||
printconfig(tmp, "# ");
|
||||
fclose(tmp);
|
||||
|
||||
ed = getenv("EDITOR");
|
||||
if (ed == NULL)
|
||||
ed = _PATH_VI;
|
||||
|
||||
snprintf(commandline, sizeof(commandline), "%s %s", ed, tmpfile);
|
||||
status = system(commandline);
|
||||
if (status != 0) {
|
||||
warn("couldn't exec %s; status: %d", ed, status);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((tmp = fopen(tmpfile, "r")) == NULL) {
|
||||
warn("can't open '%s' for reading", tmpfile);
|
||||
}
|
||||
|
||||
req = gctl_get_handle();
|
||||
gctl_ro_param(req, "class", -1, "VINUM");
|
||||
gctl_ro_param(req, "verb", -1, "create");
|
||||
|
||||
drives = volumes = plexes = subdisks = 0;
|
||||
plex_in_volume = sd_in_plex = 0;
|
||||
errors = 0;
|
||||
line = 1;
|
||||
while ((fgets(buf, BUFSIZ, tmp)) != NULL) {
|
||||
|
||||
/* Skip empty lines and comments. */
|
||||
if (*buf == '\0' || *buf == '#') {
|
||||
line++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Kill off the newline. */
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
|
||||
/*
|
||||
* Copy the original input line in case we need it for error
|
||||
* output.
|
||||
*/
|
||||
strncpy(original, buf, sizeof(buf));
|
||||
|
||||
tokens = gv_tokenize(buf, token, GV_MAXARGS);
|
||||
|
||||
if (tokens > 0) {
|
||||
/* Volume definition. */
|
||||
if (!strcmp(token[0], "volume")) {
|
||||
v = gv_new_volume(tokens, token);
|
||||
if (v == NULL) {
|
||||
warnx("line %d: invalid volume "
|
||||
"definition", line);
|
||||
warnx("line %d: '%s'", line, original);
|
||||
errors++;
|
||||
} else {
|
||||
/* Reset plex count for this volume. */
|
||||
plex_in_volume = 0;
|
||||
|
||||
/*
|
||||
* Set default volume name for
|
||||
* following plex definitions.
|
||||
*/
|
||||
strncpy(volume, v->name,
|
||||
sizeof(volume));
|
||||
|
||||
snprintf(buf1, sizeof(buf1), "volume%d",
|
||||
volumes);
|
||||
gctl_ro_param(req, buf1, sizeof(*v), v);
|
||||
volumes++;
|
||||
}
|
||||
|
||||
/* Plex definition. */
|
||||
} else if (!strcmp(token[0], "plex")) {
|
||||
p = gv_new_plex(tokens, token);
|
||||
if (p == NULL) {
|
||||
warnx("line %d: invalid plex "
|
||||
"definition", line);
|
||||
warnx("line %d: '%s'", line, original);
|
||||
errors++;
|
||||
} else {
|
||||
/* Reset subdisk count for this plex. */
|
||||
sd_in_plex = 0;
|
||||
|
||||
/* Default name. */
|
||||
if (strlen(p->name) == 0) {
|
||||
snprintf(p->name,
|
||||
GV_MAXPLEXNAME,
|
||||
"%s.p%d", volume,
|
||||
plex_in_volume++);
|
||||
}
|
||||
|
||||
/* Default volume. */
|
||||
if (strlen(p->volume) == 0) {
|
||||
snprintf(p->volume,
|
||||
GV_MAXVOLNAME, "%s",
|
||||
volume);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set default plex name for following
|
||||
* subdisk definitions.
|
||||
*/
|
||||
strncpy(plex, p->name, GV_MAXPLEXNAME);
|
||||
|
||||
snprintf(buf1, sizeof(buf1), "plex%d",
|
||||
plexes);
|
||||
gctl_ro_param(req, buf1, sizeof(*p), p);
|
||||
plexes++;
|
||||
}
|
||||
|
||||
/* Subdisk definition. */
|
||||
} else if (!strcmp(token[0], "sd")) {
|
||||
s = gv_new_sd(tokens, token);
|
||||
if (s == NULL) {
|
||||
warnx("line %d: invalid subdisk "
|
||||
"definition:", line);
|
||||
warnx("line %d: '%s'", line, original);
|
||||
errors++;
|
||||
} else {
|
||||
/* Default name. */
|
||||
if (strlen(s->name) == 0) {
|
||||
snprintf(s->name, GV_MAXSDNAME,
|
||||
"%s.s%d", plex,
|
||||
sd_in_plex++);
|
||||
}
|
||||
|
||||
/* Default plex. */
|
||||
if (strlen(s->plex) == 0) {
|
||||
snprintf(s->plex,
|
||||
GV_MAXPLEXNAME, "%s", plex);
|
||||
}
|
||||
|
||||
snprintf(buf1, sizeof(buf1), "sd%d",
|
||||
subdisks);
|
||||
gctl_ro_param(req, buf1, sizeof(*s), s);
|
||||
subdisks++;
|
||||
}
|
||||
|
||||
/* Subdisk definition. */
|
||||
} else if (!strcmp(token[0], "drive")) {
|
||||
d = gv_new_drive(tokens, token);
|
||||
if (d == NULL) {
|
||||
warnx("line %d: invalid drive "
|
||||
"definition:", line);
|
||||
warnx("line %d: '%s'", line, original);
|
||||
errors++;
|
||||
} else {
|
||||
snprintf(buf1, sizeof(buf1), "drive%d",
|
||||
drives);
|
||||
gctl_ro_param(req, buf1, sizeof(*d), d);
|
||||
drives++;
|
||||
}
|
||||
|
||||
/* Everything else is bogus. */
|
||||
} else {
|
||||
warnx("line %d: invalid definition:", line);
|
||||
warnx("line %d: '%s'", line, original);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
line++;
|
||||
}
|
||||
|
||||
fclose(tmp);
|
||||
unlink(tmpfile);
|
||||
|
||||
if (!errors && (volumes || plexes || subdisks || drives)) {
|
||||
gctl_ro_param(req, "volumes", sizeof(int), &volumes);
|
||||
gctl_ro_param(req, "plexes", sizeof(int), &plexes);
|
||||
gctl_ro_param(req, "subdisks", sizeof(int), &subdisks);
|
||||
gctl_ro_param(req, "drives", sizeof(int), &drives);
|
||||
errstr = gctl_issue(req);
|
||||
if (errstr != NULL)
|
||||
warnx("create failed: %s", errstr);
|
||||
}
|
||||
gctl_free(req);
|
||||
gvinum_list(0, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gvinum_help(void)
|
||||
{
|
||||
printf("COMMANDS\n"
|
||||
"attach plex volume [rename]\n"
|
||||
"attach subdisk plex [offset] [rename]\n"
|
||||
" Attach a plex to a volume, or a subdisk to a plex.\n"
|
||||
"checkparity plex [-f] [-v]\n"
|
||||
" Check the parity blocks of a RAID-4 or RAID-5 plex.\n"
|
||||
"concat [-f] [-n name] [-v] drives\n"
|
||||
" Create a concatenated volume from the specified drives.\n"
|
||||
"create [-f] description-file\n"
|
||||
" Create a volume as described in description-file.\n"
|
||||
"detach [-f] [plex | subdisk]\n"
|
||||
" Detach a plex or subdisk from the volume or plex to"
|
||||
"which it is\n"
|
||||
" attached.\n"
|
||||
"dumpconfig [drive ...]\n"
|
||||
" List the configuration information stored on the"
|
||||
" specified\n"
|
||||
" drives, or all drives in the system if no drive names"
|
||||
" are speci-\n"
|
||||
" fied.\n"
|
||||
"info [-v] [-V]\n"
|
||||
" List information about volume manager state.\n"
|
||||
"init [-S size] [-w] plex | subdisk\n"
|
||||
" Initialize the contents of a subdisk or all the subdisks"
|
||||
" of a\n"
|
||||
" plex to all zeros.\n"
|
||||
"label volume\n"
|
||||
" Create a volume label.\n"
|
||||
"l | list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
|
||||
" List information about specified objects.\n"
|
||||
"ld [-r] [-s] [-v] [-V] [volume]\n"
|
||||
" List information about drives.\n"
|
||||
"ls [-r] [-s] [-v] [-V] [subdisk]\n"
|
||||
" List information about subdisks.\n"
|
||||
"lp [-r] [-s] [-v] [-V] [plex]\n"
|
||||
" List information about plexes.\n"
|
||||
"lv [-r] [-s] [-v] [-V] [volume]\n"
|
||||
" List information about volumes.\n"
|
||||
"mirror [-f] [-n name] [-s] [-v] drives\n"
|
||||
" Create a mirrored volume from the specified drives.\n"
|
||||
"move | mv -f drive object ...\n"
|
||||
" Move the object(s) to the specified drive.\n"
|
||||
"printconfig [file]\n"
|
||||
" Write a copy of the current configuration to file.\n"
|
||||
"quit Exit the vinum program when running in interactive mode."
|
||||
" Nor-\n"
|
||||
" mally this would be done by entering the EOF character.\n"
|
||||
"rename [-r] [drive | subdisk | plex | volume] newname\n"
|
||||
" Change the name of the specified object.\n"
|
||||
"rebuildparity plex [-f] [-v] [-V]\n"
|
||||
" Rebuild the parity blocks of a RAID-4 or RAID-5 plex.\n"
|
||||
"resetconfig\n"
|
||||
" Reset the complete vinum configuration.\n"
|
||||
"rm [-f] [-r] volume | plex | subdisk\n"
|
||||
" Remove an object.\n"
|
||||
"saveconfig\n"
|
||||
" Save vinum configuration to disk after configuration"
|
||||
" failures.\n"
|
||||
"setstate state [volume | plex | subdisk | drive]\n"
|
||||
" Set state without influencing other objects, for"
|
||||
" diagnostic pur-\n"
|
||||
" poses only.\n"
|
||||
"start [-i interval] [-S size] [-w] volume | plex | subdisk\n"
|
||||
" Allow the system to access the objects.\n"
|
||||
"stop [-f] [volume | plex | subdisk]\n"
|
||||
" Terminate access to the objects, or stop vinum if no"
|
||||
" parameters\n"
|
||||
" are specified.\n"
|
||||
"stripe [-f] [-n name] [-v] drives\n"
|
||||
" Create a striped volume from the specified drives.\n"
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
gvinum_init(int argc, char **argv)
|
||||
{
|
||||
struct gctl_req *req;
|
||||
int i, initsize, j;
|
||||
const char *errstr;
|
||||
char buf[20];
|
||||
|
||||
initsize = 0;
|
||||
optreset = 1;
|
||||
optind = 1;
|
||||
while ((j = getopt(argc, argv, "S")) != -1) {
|
||||
switch (j) {
|
||||
case 'S':
|
||||
initsize = atoi(optarg);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!initsize)
|
||||
initsize = 512;
|
||||
|
||||
req = gctl_get_handle();
|
||||
gctl_ro_param(req, "class", -1, "VINUM");
|
||||
gctl_ro_param(req, "verb", -1, "init");
|
||||
gctl_ro_param(req, "argc", sizeof(int), &argc);
|
||||
gctl_ro_param(req, "initsize", sizeof(int), &initsize);
|
||||
if (argc) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
snprintf(buf, sizeof(buf), "argv%d", i);
|
||||
gctl_ro_param(req, buf, -1, argv[i]);
|
||||
}
|
||||
}
|
||||
errstr = gctl_issue(req);
|
||||
if (errstr != NULL) {
|
||||
warnx("can't init: %s", errstr);
|
||||
gctl_free(req);
|
||||
return;
|
||||
}
|
||||
|
||||
gctl_free(req);
|
||||
gvinum_list(0, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gvinum_list(int argc, char **argv)
|
||||
{
|
||||
struct gctl_req *req;
|
||||
int flags, i, j;
|
||||
const char *errstr;
|
||||
char buf[20], *cmd, config[GV_CFG_LEN + 1];
|
||||
|
||||
flags = 0;
|
||||
cmd = "list";
|
||||
|
||||
if (argc) {
|
||||
optreset = 1;
|
||||
optind = 1;
|
||||
cmd = argv[0];
|
||||
while ((j = getopt(argc, argv, "rsvV")) != -1) {
|
||||
switch (j) {
|
||||
case 'r':
|
||||
flags |= GV_FLAG_R;
|
||||
break;
|
||||
case 's':
|
||||
flags |= GV_FLAG_S;
|
||||
break;
|
||||
case 'v':
|
||||
flags |= GV_FLAG_V;
|
||||
break;
|
||||
case 'V':
|
||||
flags |= GV_FLAG_V;
|
||||
flags |= GV_FLAG_VV;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
}
|
||||
|
||||
req = gctl_get_handle();
|
||||
gctl_ro_param(req, "class", -1, "VINUM");
|
||||
gctl_ro_param(req, "verb", -1, "list");
|
||||
gctl_ro_param(req, "cmd", -1, cmd);
|
||||
gctl_ro_param(req, "argc", sizeof(int), &argc);
|
||||
gctl_ro_param(req, "flags", sizeof(int), &flags);
|
||||
gctl_rw_param(req, "config", sizeof(config), config);
|
||||
if (argc) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
snprintf(buf, sizeof(buf), "argv%d", i);
|
||||
gctl_ro_param(req, buf, -1, argv[i]);
|
||||
}
|
||||
}
|
||||
errstr = gctl_issue(req);
|
||||
if (errstr != NULL) {
|
||||
warnx("can't get configuration: %s", errstr);
|
||||
gctl_free(req);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("%s", config);
|
||||
gctl_free(req);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
gvinum_printconfig(int argc, char **argv)
|
||||
{
|
||||
printconfig(stdout, "");
|
||||
}
|
||||
|
||||
void
|
||||
gvinum_rm(int argc, char **argv)
|
||||
{
|
||||
struct gctl_req *req;
|
||||
int flags, i, j;
|
||||
const char *errstr;
|
||||
char buf[20], *cmd;
|
||||
|
||||
cmd = argv[0];
|
||||
flags = 0;
|
||||
optreset = 1;
|
||||
optind = 1;
|
||||
while ((j = getopt(argc, argv, "r")) != -1) {
|
||||
switch (j) {
|
||||
case 'r':
|
||||
flags |= GV_FLAG_R;
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
req = gctl_get_handle();
|
||||
gctl_ro_param(req, "class", -1, "VINUM");
|
||||
gctl_ro_param(req, "verb", -1, "remove");
|
||||
gctl_ro_param(req, "argc", sizeof(int), &argc);
|
||||
gctl_ro_param(req, "flags", sizeof(int), &flags);
|
||||
if (argc) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
snprintf(buf, sizeof(buf), "argv%d", i);
|
||||
gctl_ro_param(req, buf, -1, argv[i]);
|
||||
}
|
||||
}
|
||||
errstr = gctl_issue(req);
|
||||
if (errstr != NULL) {
|
||||
warnx("can't remove: %s", errstr);
|
||||
gctl_free(req);
|
||||
return;
|
||||
}
|
||||
gctl_free(req);
|
||||
gvinum_list(0, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gvinum_saveconfig(void)
|
||||
{
|
||||
struct gctl_req *req;
|
||||
const char *errstr;
|
||||
|
||||
req = gctl_get_handle();
|
||||
gctl_ro_param(req, "class", -1, "VINUM");
|
||||
gctl_ro_param(req, "verb", -1, "saveconfig");
|
||||
errstr = gctl_issue(req);
|
||||
if (errstr != NULL)
|
||||
warnx("can't save configuration: %s", errstr);
|
||||
gctl_free(req);
|
||||
}
|
||||
|
||||
void
|
||||
gvinum_start(int argc, char **argv)
|
||||
{
|
||||
struct gctl_req *req;
|
||||
int i, initsize, j;
|
||||
const char *errstr;
|
||||
char buf[20];
|
||||
|
||||
/* 'start' with no arguments is a no-op. */
|
||||
if (argc == 1)
|
||||
return;
|
||||
|
||||
initsize = 0;
|
||||
|
||||
optreset = 1;
|
||||
optind = 1;
|
||||
while ((j = getopt(argc, argv, "S")) != -1) {
|
||||
switch (j) {
|
||||
case 'S':
|
||||
initsize = atoi(optarg);
|
||||
break;
|
||||
case '?':
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (!initsize)
|
||||
initsize = 512;
|
||||
|
||||
req = gctl_get_handle();
|
||||
gctl_ro_param(req, "class", -1, "VINUM");
|
||||
gctl_ro_param(req, "verb", -1, "start");
|
||||
gctl_ro_param(req, "argc", sizeof(int), &argc);
|
||||
gctl_ro_param(req, "initsize", sizeof(int), &initsize);
|
||||
if (argc) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
snprintf(buf, sizeof(buf), "argv%d", i);
|
||||
gctl_ro_param(req, buf, -1, argv[i]);
|
||||
}
|
||||
}
|
||||
errstr = gctl_issue(req);
|
||||
if (errstr != NULL) {
|
||||
warnx("can't start: %s", errstr);
|
||||
gctl_free(req);
|
||||
return;
|
||||
}
|
||||
|
||||
gctl_free(req);
|
||||
gvinum_list(0, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
gvinum_stop(int argc, char **argv)
|
||||
{
|
||||
int fileid;
|
||||
|
||||
fileid = kldfind(GVINUMMOD);
|
||||
if (fileid == -1) {
|
||||
warn("cannot find " GVINUMMOD);
|
||||
return;
|
||||
}
|
||||
if (kldunload(fileid) != 0) {
|
||||
warn("cannot unload " GVINUMMOD);
|
||||
return;
|
||||
}
|
||||
|
||||
warnx(GVINUMMOD " unloaded");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
parseline(int argc, char **argv)
|
||||
{
|
||||
if (argc <= 0)
|
||||
return;
|
||||
|
||||
if (!strcmp(argv[0], "cancelinit"))
|
||||
gvinum_cancelinit(argc, argv);
|
||||
else if (!strcmp(argv[0], "create"))
|
||||
gvinum_create(argc, argv);
|
||||
else if (!strcmp(argv[0], "exit") || !strcmp(argv[0], "quit"))
|
||||
exit(0);
|
||||
else if (!strcmp(argv[0], "help"))
|
||||
gvinum_help();
|
||||
else if (!strcmp(argv[0], "init"))
|
||||
gvinum_init(argc, argv);
|
||||
else if (!strcmp(argv[0], "list") || !strcmp(argv[0], "l"))
|
||||
gvinum_list(argc, argv);
|
||||
else if (!strcmp(argv[0], "ld"))
|
||||
gvinum_list(argc, argv);
|
||||
else if (!strcmp(argv[0], "lp"))
|
||||
gvinum_list(argc, argv);
|
||||
else if (!strcmp(argv[0], "ls"))
|
||||
gvinum_list(argc, argv);
|
||||
else if (!strcmp(argv[0], "lv"))
|
||||
gvinum_list(argc, argv);
|
||||
else if (!strcmp(argv[0], "printconfig"))
|
||||
gvinum_printconfig(argc, argv);
|
||||
else if (!strcmp(argv[0], "rm"))
|
||||
gvinum_rm(argc, argv);
|
||||
else if (!strcmp(argv[0], "saveconfig"))
|
||||
gvinum_saveconfig();
|
||||
else if (!strcmp(argv[0], "start"))
|
||||
gvinum_start(argc, argv);
|
||||
else if (!strcmp(argv[0], "stop"))
|
||||
gvinum_stop(argc, argv);
|
||||
else
|
||||
printf("unknown command '%s'\n", argv[0]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The guts of printconfig. This is called from gvinum_printconfig and from
|
||||
* gvinum_create when called without an argument, in order to give the user
|
||||
* something to edit.
|
||||
*/
|
||||
void
|
||||
printconfig(FILE *of, char *comment)
|
||||
{
|
||||
struct gctl_req *req;
|
||||
struct utsname uname_s;
|
||||
const char *errstr;
|
||||
time_t now;
|
||||
char buf[GV_CFG_LEN + 1];
|
||||
|
||||
uname(&uname_s);
|
||||
time(&now);
|
||||
|
||||
req = gctl_get_handle();
|
||||
gctl_ro_param(req, "class", -1, "VINUM");
|
||||
gctl_ro_param(req, "verb", -1, "getconfig");
|
||||
gctl_ro_param(req, "comment", -1, comment);
|
||||
gctl_rw_param(req, "config", sizeof(buf), buf);
|
||||
errstr = gctl_issue(req);
|
||||
if (errstr != NULL) {
|
||||
warnx("can't get configuration: %s", errstr);
|
||||
return;
|
||||
}
|
||||
gctl_free(req);
|
||||
|
||||
fprintf(of, "# Vinum configuration of %s, saved at %s",
|
||||
uname_s.nodename,
|
||||
ctime(&now));
|
||||
|
||||
if (*comment != '\0')
|
||||
fprintf(of, "# Current configuration:\n");
|
||||
|
||||
fprintf(of, buf);
|
||||
}
|
39
sbin/gvinum/gvinum.h
Normal file
39
sbin/gvinum/gvinum.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*-
|
||||
* Copyright (c) 1997, 1998
|
||||
* Nan Yang Computer Services Limited. All rights reserved.
|
||||
*
|
||||
* This software is distributed under the so-called ``Berkeley
|
||||
* License'':
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by Nan Yang Computer
|
||||
* Services Limited.
|
||||
* 4. Neither the name of the Company nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* This software is provided ``as is'', and any express or implied
|
||||
* warranties, including, but not limited to, the implied warranties of
|
||||
* merchantability and fitness for a particular purpose are disclaimed.
|
||||
* In no event shall the company or contributors be liable for any
|
||||
* direct, indirect, incidental, special, exemplary, or consequential
|
||||
* damages (including, but not limited to, procurement of substitute
|
||||
* goods or services; loss of use, data, or profits; or business
|
||||
* interruption) however caused and on any theory of liability, whether
|
||||
* in contract, strict liability, or tort (including negligence or
|
||||
* otherwise) arising in any way out of the use of this software, even if
|
||||
* advised of the possibility of such damage.
|
||||
*/
|
||||
|
||||
/* $FreeBSD$ */
|
||||
|
||||
#define GVINUMMOD "geom_vinum"
|
Loading…
Reference in New Issue
Block a user