diff options
Diffstat (limited to 'sbin/vinum/commands.c')
-rw-r--r-- | sbin/vinum/commands.c | 2329 |
1 files changed, 0 insertions, 2329 deletions
diff --git a/sbin/vinum/commands.c b/sbin/vinum/commands.c deleted file mode 100644 index c0038e4..0000000 --- a/sbin/vinum/commands.c +++ /dev/null @@ -1,2329 +0,0 @@ -/* commands.c: vinum interface program, main commands */ -/*- - * Copyright (c) 1997, 1998 - * Nan Yang Computer Services Limited. All rights reserved. - * - * Written by Greg Lehey - * - * 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. - * - * $Id: commands.c,v 1.52 2003/05/08 00:33:57 grog Exp $ - * $FreeBSD$ - */ - -#include "vext.h" -#include <devstat.h> - -static void dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen); - -void -vinum_create(int argc, char *argv[], char *arg0[]) -{ - int error; - FILE *dfd; /* file descriptor for the config file */ - char buffer[BUFSIZE]; /* read config file in here */ - char commandline[BUFSIZE]; /* issue command from here */ - struct _ioctl_reply *reply; - int ioctltype; /* for ioctl call */ - char tempfile[PATH_MAX]; /* name of temp file for direct editing */ - char *file; /* file to read */ - FILE *tf; /* temp file */ - - if (argc == 0) { /* no args, */ - char *editor; /* editor to start */ - int status; - - editor = getenv("EDITOR"); - if (editor == NULL) - editor = _PATH_VI; - sprintf(tempfile, "/var/tmp/" VINUMMOD ".create.%d", getpid()); /* create a temp file */ - tf = fopen(tempfile, "w"); /* open it */ - if (tf == NULL) { - fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno)); - return; - } - printconfig(tf, "# "); /* and put the current config it */ - fclose(tf); - sprintf(commandline, "%s %s", editor, tempfile); /* create an edit command */ - status = system(commandline); /* do it */ - if (status != 0) { - fprintf(stderr, "Can't edit config: status %d\n", status); - return; - } - file = tempfile; - } else if (argc == 1) - file = argv[0]; - else { - fprintf(stderr, "Expecting 1 parameter, not %d\n", argc); - return; - } - reply = (struct _ioctl_reply *) &buffer; - dfd = fopen(file, "r"); - if (dfd == NULL) { /* no go */ - fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno)); - return; - } - if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ - printf("Can't configure: %s (%d)\n", strerror(errno), errno); - return; - } - file_line = 0; /* start with line 1 */ - /* Parse the configuration, and add it to the global configuration */ - for (;;) { /* love this style(9) */ - char *configline; - - configline = fgets(buffer, BUFSIZE, dfd); - if (History) - fprintf(History, "%s", buffer); - - if (configline == NULL) { - if (ferror(dfd)) - perror("Can't read config file"); - break; - } - file_line++; /* count the lines */ - if (vflag) - printf("%4d: %s", file_line, buffer); - strcpy(commandline, buffer); /* make a copy */ - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (!vflag) /* print this line anyway */ - printf("%4d: %s", file_line, commandline); - fprintf(stdout, "** %d %s: %s\n", - file_line, - reply->msg, - strerror(reply->error)); - - /* - * XXX at the moment, we reset the config - * lock on error, so try to get it again. - * If we fail, don't cry again. - */ - if (ioctl(superdev, VINUM_STARTCONFIG, &force)) /* can't get config? */ - return; - } - } - fclose(dfd); /* done with the config file */ - ioctltype = 0; /* saveconfig after update */ - error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ - if (error != 0) - perror("Can't save Vinum config"); - listconfig(); - checkupdates(); /* make sure we're updating */ -} - -/* Read vinum config from a disk */ -void -vinum_read(int argc, char *argv[], char *arg0[]) -{ - char buffer[BUFSIZE]; /* read config file in here */ - struct _ioctl_reply *reply; - int i; - - reply = (struct _ioctl_reply *) &buffer; - buffer[0] = '\0'; /* make sure we don't pass anything */ - if (argc > 0) { /* args specified, */ - for (i = 0; i < argc; i++) { /* each drive name */ - strlcat(buffer, argv[i], sizeof(buffer)); - strlcat(buffer, " ", sizeof(buffer)); - } - } - ioctl(superdev, VINUM_READCONFIG, &buffer); - if (reply->error != 0) /* error in config */ - fprintf(stdout, "** %s: %s\n", reply->msg, strerror(reply->error)); - checkupdates(); /* make sure we're updating */ -} - -void -vinum_debug(int argc, char *argv[], char *arg0[]) -{ - struct debuginfo info; - - if (vinum_conf.flags & VF_HASDEBUG) { - if (argc > 0) { - info.param = atoi(argv[0]); - info.changeit = 1; - } else { - info.changeit = 0; - sleep(2); /* give a chance to leave the window */ - } - ioctl(superdev, VINUM_DEBUG, (caddr_t) & info); - } else /* no debug in kernel module */ - fprintf(stderr, "Kernel module does not have debug support\n"); -} - -void -vinum_modify(int argc, char *argv[], char *arg0[]) -{ - fprintf(stderr, "Modify command is currently not implemented\n"); - checkupdates(); /* make sure we're updating */ -} - -void -vinum_set(int argc, char *argv[], char *arg0[]) -{ - fprintf(stderr, "set is not implemented yet\n"); -} - -void -vinum_rm(int argc, char *argv[], char *arg0[]) -{ - int object; - struct _ioctl_reply reply; - struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; - - if (argc == 0) /* start everything */ - fprintf(stderr, "usage: rm object [object...]\n"); - else { /* start specified objects */ - int index; - enum objecttype type; - - for (index = 0; index < argc; index++) { - object = find_object(argv[index], &type); /* look for it */ - if (type == invalid_object) - fprintf(stderr, "Can't find object: %s\n", argv[index]); - else { - message->index = object; /* pass object number */ - message->type = type; /* and type of object */ - message->force = force; /* do we want to force the operation? */ - message->recurse = recurse; /* do we want to remove subordinates? */ - ioctl(superdev, VINUM_REMOVE, message); - if (reply.error != 0) { - fprintf(stderr, - "Can't remove %s: %s (%d)\n", - argv[index], - reply.msg[0] ? reply.msg : strerror(reply.error), - reply.error); - } else if (vflag) - fprintf(stderr, "%s removed\n", argv[index]); - } - } - checkupdates(); /* make sure we're updating */ - /* Arguably we should be cleverer about this. */ - } -} - -void -vinum_resetconfig(int argc, char *argv[], char *arg0[]) -{ - char reply[32]; - int error; - - if (isatty(STDIN_FILENO)) { - printf(" WARNING! This command will completely wipe out your vinum configuration.\n" - " All data will be lost. If you really want to do this, enter the text\n\n" - " NO FUTURE\n" - " Enter text -> "); - fgets(reply, sizeof(reply), stdin); - if (strcmp(reply, "NO FUTURE\n")) /* changed his mind */ - printf("\n No change\n"); - else { - error = ioctl(superdev, VINUM_RESETCONFIG, NULL); /* trash config on disk */ - if (error) { - if (errno == EBUSY) - fprintf(stderr, "Can't reset configuration: objects are in use\n"); - else - perror("Can't find vinum config"); - } else { - printf("\b Vinum configuration obliterated\n"); - start_daemon(); /* then restart the daemon */ - } - } - checkupdates(); /* make sure we're updating */ - } else - fprintf(stderr, "Please enter this command from a terminal\n"); -} - -/* Initialize subdisks */ -void -vinum_init(int argc, char *argv[], char *arg0[]) -{ - if (argc > 0) { /* initialize plexes */ - int objindex; - int objno; - enum objecttype type; /* type returned */ - - if (History) - fflush(History); /* don't let all the kids do it. */ - for (objindex = 0; objindex < argc; objindex++) { - objno = find_object(argv[objindex], &type); /* find the object */ - if (objno < 0) - printf("Can't find %s\n", argv[objindex]); - else { - switch (type) { - case volume_object: - initvol(objno); - break; - - case plex_object: - initplex(objno, argv[objindex]); - break; - - case sd_object: - initsd(objno, dowait); - break; - - default: - printf("Can't initialize %s: wrong object type\n", argv[objindex]); - break; - } - } - } - } - checkupdates(); /* make sure we're updating */ -} - -void -initvol(int volno) -{ - printf("Initializing volumes is not implemented yet\n"); -} - -void -initplex(int plexno, char *name) -{ - int sdno; - int plexfh = 0; /* file handle for plex */ - pid_t pid; - char filename[MAXPATHLEN]; /* create a file name here */ - - /* Variables for use by children */ - int failed = 0; /* set if a child dies badly */ - - sprintf(filename, VINUM_DIR "/plex/%s", name); - if ((plexfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* got a plex, open it */ - /* - * We don't actually write anything to the - * plex. We open it to ensure that nobody - * else tries to open it while we initialize - * its subdisks. - */ - fprintf(stderr, "can't open plex %s: %s\n", filename, strerror(errno)); - return; - } - if (dowait == 0) { - pid = fork(); /* into the background with you */ - if (pid != 0) { /* I'm the parent, or we failed */ - if (pid < 0) /* failure */ - printf("Couldn't fork: %s", strerror(errno)); - close(plexfh); /* we don't need this any more */ - return; - } - } - /* - * If we get here, we're either the first-level - * child (if we're not waiting) or we're going - * to wait. - */ - for (sdno = 0; sdno < plex.subdisks; sdno++) { /* initialize each subdisk */ - get_plex_sd_info(&sd, plexno, sdno); - initsd(sd.sdno, 0); - } - /* Now wait for them to complete */ - while (1) { - int status; - pid = wait(&status); - if (((int) pid == -1) - && (errno == ECHILD)) /* all gone */ - break; - if (WEXITSTATUS(status) != 0) { /* oh, oh */ - printf("child %d exited with status 0x%x\n", pid, WEXITSTATUS(status)); - failed++; - } - } - if (failed == 0) { - syslog(LOG_INFO | LOG_KERN, "plex %s initialized", plex.name); - } else - syslog(LOG_ERR | LOG_KERN, "couldn't initialize plex %s, %d processes died", - plex.name, - failed); - if (dowait == 0) /* we're the waiting child, */ - exit(0); /* we've done our dash */ -} - -/* Initialize a subdisk. */ -void -initsd(int sdno, int dowait) -{ - pid_t pid; - struct _ioctl_reply reply; - struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; - char filename[MAXPATHLEN]; /* create a file name here */ - - /* Variables for use by children */ - int sdfh; /* and for subdisk */ - int initsize; /* actual size to write */ - int64_t sdsize; /* size of subdisk */ - - if (dowait == 0) { - pid = fork(); /* into the background with you */ - if (pid > 0) /* I'm the parent */ - return; - else if (pid < 0) { /* failure */ - printf("couldn't fork for subdisk %d: %s", sdno, strerror(errno)); - return; - } - } - if (SSize != 0) { /* specified a size for init */ - if (SSize < 512) - SSize <<= DEV_BSHIFT; - initsize = min(SSize, MAXPLEXINITSIZE); - } else - initsize = PLEXINITSIZE; - openlog("vinum", LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN); - get_sd_info(&sd, sdno); - sdsize = sd.sectors * DEV_BSIZE; /* size of subdisk in bytes */ - sprintf(filename, VINUM_DIR "/sd/%s", sd.name); - setproctitle("initializing %s", filename); /* show what we're doing */ - syslog(LOG_INFO | LOG_KERN, "initializing subdisk %s", filename); - if ((sdfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* no go */ - syslog(LOG_ERR | LOG_KERN, - "can't open subdisk %s: %s", - filename, - strerror(errno)); - exit(1); - } - /* Set the subdisk in initializing state */ - message->index = sd.sdno; /* pass object number */ - message->type = sd_object; /* and type of object */ - message->state = object_initializing; - message->verify = vflag; /* verify what we write? */ - message->force = 1; /* insist */ - ioctl(superdev, VINUM_SETSTATE, message); - if ((SSize > 0) /* specified a size for init */ - &&(SSize < 512)) - SSize <<= DEV_BSHIFT; - if (reply.error) { - fprintf(stderr, - "Can't initialize %s: %s (%d)\n", - filename, - strerror(reply.error), - reply.error); - exit(1); - } else { - do { - if (interval) /* pause between copies */ - usleep(interval * 1000); - message->index = sd.sdno; /* pass object number */ - message->type = sd_object; /* and type of object */ - message->state = object_up; - message->verify = vflag; /* verify what we write? */ - message->blocksize = SSize; - ioctl(superdev, VINUM_SETSTATE, message); - } - while (reply.error == EAGAIN); /* until we're done */ - if (reply.error) { - fprintf(stderr, - "Can't initialize %s: %s (%d)\n", - filename, - strerror(reply.error), - reply.error); - get_sd_info(&sd, sdno); - if (sd.state != sd_up) - /* Set the subdisk down */ - message->index = sd.sdno; /* pass object number */ - message->type = sd_object; /* and type of object */ - message->state = object_down; - message->verify = vflag; /* verify what we write? */ - message->force = 1; /* insist */ - ioctl(superdev, VINUM_SETSTATE, message); - } - } - printf("subdisk %s initialized\n", filename); - if (!dowait) - exit(0); -} - -void -vinum_start(int argc, char *argv[], char *arg0[]) -{ - int object; - struct _ioctl_reply reply; - struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; - - if (argc == 0) /* start everything */ - /* XXX how should we do this right? */ - vinum_read(0, NULL, NULL); /* that's what vinum_read does now */ - else { /* start specified objects */ - int index; - enum objecttype type; - - for (index = 0; index < argc; index++) { - object = find_object(argv[index], &type); /* look for it */ - if (type == invalid_object) - fprintf(stderr, "Can't find object: %s\n", argv[index]); - else { - int doit = 0; /* set to 1 if we pass our tests */ - switch (type) { - case drive_object: - if (drive.state == drive_up) /* already up */ - fprintf(stderr, "%s is already up\n", drive.label.name); - else - doit = 1; - break; - - case sd_object: - if (sd.state == sd_up) /* already up */ - fprintf(stderr, "%s is already up\n", sd.name); - else - doit = 1; - break; - - case plex_object: - if (plex.state == plex_up) /* already up */ - fprintf(stderr, "%s is already up\n", plex.name); - else { - int sdno; - - /* - * First, see if we can bring it up - * just by asking. This might happen - * if somebody has used setupstate on - * the subdisks. If we don't do this, - * we'll return success, but the plex - * won't have changed state. Note - * that we don't check for errors - * here. - */ - message->index = plex.plexno; /* pass object number */ - message->type = plex_object; /* it's a plex */ - message->state = object_up; - message->force = 0; /* don't force it */ - ioctl(superdev, VINUM_SETSTATE, message); - for (sdno = 0; sdno < plex.subdisks; sdno++) { - get_plex_sd_info(&sd, object, sdno); - if ((sd.state >= sd_empty) - && (sd.state <= sd_reviving)) { /* candidate for start */ - message->index = sd.sdno; /* pass object number */ - message->type = sd_object; /* it's a subdisk */ - message->state = object_up; - message->force = force; /* don't force it, use a larger hammer */ - - /* - * We don't do any checking here. - * The kernel module has a better - * understanding of these things, - * let it do it. - */ - if (SSize != 0) { /* specified a size for init */ - if (SSize < 512) - SSize <<= DEV_BSHIFT; - message->blocksize = SSize; - } else - message->blocksize = DEFAULT_REVIVE_BLOCKSIZE; - ioctl(superdev, VINUM_SETSTATE, message); - if (reply.error != 0) { - if (reply.error == EAGAIN) /* we're reviving */ - continue_revive(sd.sdno); - else - fprintf(stderr, - "Can't start %s: %s (%d)\n", - sd.name, - reply.msg[0] ? reply.msg : strerror(reply.error), - reply.error); - } - if (Verbose) - vinum_lsi(sd.sdno, 0); - } - } - } - break; - - case volume_object: - if (vol.state == volume_up) /* already up */ - fprintf(stderr, "%s is already up\n", vol.name); - else - doit = 1; - break; - } - - if (doit) { - message->index = object; /* pass object number */ - message->type = type; /* and type of object */ - message->state = object_up; - message->force = force; /* don't force it, use a larger hammer */ - - /* - * We don't do any checking here. - * The kernel module has a better - * understanding of these things, - * let it do it. - */ - if (SSize != 0) { /* specified a size for init or revive */ - if (SSize < 512) - SSize <<= DEV_BSHIFT; - message->blocksize = SSize; - } else - message->blocksize = 0; - ioctl(superdev, VINUM_SETSTATE, message); - if (reply.error != 0) { - if ((reply.error == EAGAIN) /* we're reviving */ - &&(type == sd_object)) - continue_revive(object); - else - fprintf(stderr, - "Can't start %s: %s (%d)\n", - argv[index], - reply.msg[0] ? reply.msg : strerror(reply.error), - reply.error); - } - if (Verbose) - vinum_li(object, type); - } - } - } - } - checkupdates(); /* make sure we're updating */ -} - -void -vinum_stop(int argc, char *argv[], char *arg0[]) -{ - int object; - struct _ioctl_reply reply; - struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; - - if (checkupdates() && (!force)) /* not updating? */ - return; - message->force = force; /* should we force the transition? */ - if (argc == 0) { /* stop vinum */ - int fileid = 0; /* ID of Vinum kld */ - - close(superdev); /* we can't stop if we have vinum open */ - sleep(1); /* wait for the daemon to let go */ - fileid = kldfind(VINUMMOD); - if ((fileid < 0) /* no go */ - ||(kldunload(fileid) < 0)) - perror("Can't unload " VINUMMOD); - else { - fprintf(stderr, VINUMMOD " unloaded\n"); - exit(0); - } - - /* If we got here, the stop failed. Reopen the superdevice. */ - superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */ - if (superdev < 0) { - perror("Can't reopen Vinum superdevice"); - exit(1); - } - } else { /* stop specified objects */ - int i; - enum objecttype type; - - for (i = 0; i < argc; i++) { - object = find_object(argv[i], &type); /* look for it */ - if (type == invalid_object) - fprintf(stderr, "Can't find object: %s\n", argv[i]); - else { - message->index = object; /* pass object number */ - message->type = type; /* and type of object */ - message->state = object_down; - ioctl(superdev, VINUM_SETSTATE, message); - if (reply.error != 0) - fprintf(stderr, - "Can't stop %s: %s (%d)\n", - argv[i], - reply.msg[0] ? reply.msg : strerror(reply.error), - reply.error); - if (Verbose) - vinum_li(object, type); - } - } - } -} - -void -reset_volume_stats(int volno, int recurse) -{ - struct vinum_ioctl_msg msg; - struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; - - msg.index = volno; - msg.type = volume_object; - /* XXX get these numbers right if we ever - * actually return errors */ - if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { - fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg); - longjmp(command_fail, -1); - } else if (recurse) { - struct _volume vol; - int plexno; - - get_volume_info(&vol, volno); - for (plexno = 0; plexno < vol.plexes; plexno++) - reset_plex_stats(vol.plex[plexno], recurse); - } -} - -void -reset_plex_stats(int plexno, int recurse) -{ - struct vinum_ioctl_msg msg; - struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; - - msg.index = plexno; - msg.type = plex_object; - /* XXX get these numbers right if we ever - * actually return errors */ - if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { - fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg); - longjmp(command_fail, -1); - } else if (recurse) { - struct _plex plex; - struct _sd sd; - int sdno; - - get_plex_info(&plex, plexno); - for (sdno = 0; sdno < plex.subdisks; sdno++) { - get_plex_sd_info(&sd, plex.plexno, sdno); - reset_sd_stats(sd.sdno, recurse); - } - } -} - -void -reset_sd_stats(int sdno, int recurse) -{ - struct vinum_ioctl_msg msg; - struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; - - msg.index = sdno; - msg.type = sd_object; - /* XXX get these numbers right if we ever - * actually return errors */ - if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { - fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg); - longjmp(command_fail, -1); - } else if (recurse) { - get_sd_info(&sd, sdno); /* get the info */ - reset_drive_stats(sd.driveno); /* and clear the drive */ - } -} - -void -reset_drive_stats(int driveno) -{ - struct vinum_ioctl_msg msg; - struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; - - msg.index = driveno; - msg.type = drive_object; - /* XXX get these numbers right if we ever - * actually return errors */ - if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { - fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg); - longjmp(command_fail, -1); - } -} - -void -vinum_resetstats(int argc, char *argv[], char *argv0[]) -{ - int i; - int objno; - enum objecttype type; - - if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { - perror("Can't get vinum config"); - return; - } - if (argc == 0) { - for (objno = 0; objno < vinum_conf.volumes_allocated; objno++) - reset_volume_stats(objno, 1); /* clear everything recursively */ - } else { - for (i = 0; i < argc; i++) { - objno = find_object(argv[i], &type); - if (objno >= 0) { /* not invalid */ - switch (type) { - case drive_object: - reset_drive_stats(objno); - break; - - case sd_object: - reset_sd_stats(objno, recurse); - break; - - case plex_object: - reset_plex_stats(objno, recurse); - break; - - case volume_object: - reset_volume_stats(objno, recurse); - break; - - case invalid_object: /* can't get this */ - break; - } - } - } - } -} - -/* Attach a subdisk to a plex, or a plex to a volume. - * attach subdisk plex [offset] [rename] - * attach plex volume [rename] - */ -void -vinum_attach(int argc, char *argv[], char *argv0[]) -{ - int i; - enum objecttype supertype; - struct vinum_ioctl_msg msg; - struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; - const char *objname = argv[0]; - const char *supername = argv[1]; - int sdno = -1; - int plexno = -1; - char oldname[MAXNAME + 8]; - char newname[MAXNAME + 8]; - int rename = 0; /* set if we want to rename the object */ - - if ((argc < 2) - || (argc > 4)) { - fprintf(stderr, - "usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n" - "\tattach <plex> <volume> [rename]\n"); - return; - } - if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { - perror("Can't get vinum config"); - return; - } - msg.index = find_object(objname, &msg.type); /* find the object to attach */ - msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */ - msg.force = force; /* did we specify the use of force? */ - msg.recurse = recurse; - msg.offset = -1; /* and no offset */ - - for (i = 2; i < argc; i++) { - if (!strcmp(argv[i], "rename")) { - rename = 1; - msg.rename = 1; /* do renaming */ - } else if (!isdigit(argv[i][0])) { /* not an offset */ - fprintf(stderr, "Unknown attribute: %s\n", supername); - return; - } else - msg.offset = sizespec(argv[i]); - } - - switch (msg.type) { - case sd_object: - find_object(argv[1], &supertype); - if (supertype != plex_object) { /* huh? */ - fprintf(stderr, "%s can only be attached to a plex\n", objname); - return; - } - if ((plex.organization != plex_concat) /* not a cat plex, */ - &&(!force)) { - fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization)); - return; - } - sdno = msg.index; /* note the subdisk number for later */ - break; - - case plex_object: - find_object(argv[1], &supertype); - if (supertype != volume_object) { /* huh? */ - fprintf(stderr, "%s can only be attached to a volume\n", objname); - return; - } - break; - - case volume_object: - case drive_object: - fprintf(stderr, "Can only attach subdisks and plexes\n"); - return; - - default: - fprintf(stderr, "%s is not a Vinum object\n", objname); - return; - } - - ioctl(superdev, VINUM_ATTACH, &msg); - if (reply->error != 0) { - if (reply->error == EAGAIN) /* reviving */ - continue_revive(sdno); /* continue the revive */ - else - fprintf(stderr, - "Can't attach %s to %s: %s (%d)\n", - objname, - supername, - reply->msg[0] ? reply->msg : strerror(reply->error), - reply->error); - } - if (rename) { - struct sd; - struct _plex; - struct _volume; - - /* we've overwritten msg with the - * ioctl reply, start again */ - msg.index = find_object(objname, &msg.type); /* find the object to rename */ - switch (msg.type) { - case sd_object: - get_sd_info(&sd, msg.index); - get_plex_info(&plex, sd.plexno); - for (sdno = 0; sdno < plex.subdisks; sdno++) { - if (plex.sdnos[sdno] == msg.index) /* found our subdisk */ - break; - } - sprintf(newname, "%s.s%d", plex.name, sdno); - sprintf(oldname, "%s", sd.name); - vinum_rename_2(oldname, newname); - break; - - case plex_object: - get_plex_info(&plex, msg.index); - get_volume_info(&vol, plex.volno); - for (plexno = 0; plexno < vol.plexes; plexno++) { - if (vol.plex[plexno] == msg.index) /* found our subdisk */ - break; - } - sprintf(newname, "%s.p%d", vol.name, plexno); - sprintf(oldname, "%s", plex.name); - vinum_rename_2(oldname, newname); /* this may recurse */ - break; - } - } - checkupdates(); /* make sure we're updating */ -} - -/* Detach a subdisk from a plex, or a plex from a volume. - * detach subdisk plex [rename] - * detach plex volume [rename] - */ -void -vinum_detach(int argc, char *argv[], char *argv0[]) -{ - struct vinum_ioctl_msg msg; - struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; - - if ((argc < 1) - || (argc > 2)) { - fprintf(stderr, - "usage: \tdetach <subdisk> [rename]\n" - "\tdetach <plex> [rename]\n"); - return; - } - if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { - perror("Can't get vinum config"); - return; - } - msg.index = find_object(argv[0], &msg.type); /* find the object to detach */ - msg.force = force; /* did we specify the use of force? */ - msg.rename = 0; /* don't specify new name */ - msg.recurse = recurse; /* but recurse if we have to */ - - /* XXX are we going to keep this? - * Don't document it yet, since the - * kernel side of things doesn't - * implement it */ - if (argc == 2) { - if (!strcmp(argv[1], "rename")) - msg.rename = 1; /* do renaming */ - else { - fprintf(stderr, "Unknown attribute: %s\n", argv[1]); - return; - } - } - if ((msg.type != sd_object) - && (msg.type != plex_object)) { - fprintf(stderr, "Can only detach subdisks and plexes\n"); - return; - } - ioctl(superdev, VINUM_DETACH, &msg); - if (reply->error != 0) - fprintf(stderr, - "Can't detach %s: %s (%d)\n", - argv[0], - reply->msg[0] ? reply->msg : strerror(reply->error), - reply->error); - checkupdates(); /* make sure we're updating */ -} - -static void -dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen) -{ - struct _ioctl_reply *reply = (struct _ioctl_reply *) msg; - - if (strlen(name) > maxlen) { - fprintf(stderr, "%s is too long\n", name); - return; - } - strcpy(msg->newname, name); - ioctl(superdev, VINUM_RENAME, msg); - if (reply->error != 0) - fprintf(stderr, - "Can't rename %s to %s: %s (%d)\n", - oldname, - name, - reply->msg[0] ? reply->msg : strerror(reply->error), - reply->error); -} - -/* Rename an object: - * rename <object> "newname" - */ -void -vinum_rename_2(char *oldname, char *newname) -{ - struct vinum_rename_msg msg; - int volno; - int plexno; - - msg.index = find_object(oldname, &msg.type); /* find the object to rename */ - msg.recurse = recurse; - - /* Ugh. Determine how long the name may be */ - switch (msg.type) { - case drive_object: - dorename(&msg, oldname, newname, MAXDRIVENAME); - break; - - case sd_object: - dorename(&msg, oldname, newname, MAXSDNAME); - break; - - case plex_object: - plexno = msg.index; - dorename(&msg, oldname, newname, MAXPLEXNAME); - if (recurse) { - int sdno; - - get_plex_info(&plex, plexno); /* find out who we are */ - msg.type = sd_object; - for (sdno = 0; sdno < plex.subdisks; sdno++) { - char sdname[MAXPLEXNAME + 8]; - - get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */ - sprintf(sdname, "%s.s%d", newname, sdno); - msg.index = sd.sdno; /* number of the subdisk */ - dorename(&msg, sd.name, sdname, MAXSDNAME); - } - } - break; - - case volume_object: - volno = msg.index; - dorename(&msg, oldname, newname, MAXVOLNAME); - if (recurse) { - int sdno; - int plexno; - - get_volume_info(&vol, volno); /* find out who we are */ - for (plexno = 0; plexno < vol.plexes; plexno++) { - char plexname[MAXVOLNAME + 8]; - - msg.type = plex_object; - sprintf(plexname, "%s.p%d", newname, plexno); - msg.index = vol.plex[plexno]; /* number of the plex */ - dorename(&msg, plex.name, plexname, MAXPLEXNAME); - get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */ - msg.type = sd_object; - for (sdno = 0; sdno < plex.subdisks; sdno++) { - char sdname[MAXPLEXNAME + 8]; - - get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */ - sprintf(sdname, "%s.s%d", plexname, sdno); - msg.index = sd.sdno; /* number of the subdisk */ - dorename(&msg, sd.name, sdname, MAXSDNAME); - } - } - } - break; - - default: - fprintf(stderr, "%s is not a Vinum object\n", oldname); - return; - } -} - -void -vinum_rename(int argc, char *argv[], char *argv0[]) -{ - if (argc != 2) { - fprintf(stderr, "usage: \trename <object> <new name>\n"); - return; - } - if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { - perror("Can't get vinum config"); - return; - } - vinum_rename_2(argv[0], argv[1]); - checkupdates(); /* make sure we're updating */ -} - -/* - * Move objects: - * - * mv <dest> <src> ... - */ -void -vinum_mv(int argc, char *argv[], char *argv0[]) -{ - int i; /* loop index */ - int srcobj; - int destobj; - enum objecttype srct; - enum objecttype destt; - int sdno; - struct _ioctl_reply reply; - struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply; - - if (argc < 2) { - fprintf(stderr, "usage: \tmove <dest> <src> ...\n"); - return; - } - /* Get current config */ - if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { - perror("Cannot get vinum config\n"); - return; - } - /* Get our destination */ - destobj = find_object(argv[0], &destt); - if (destobj == -1) { - fprintf(stderr, "Can't find %s\n", argv[0]); - return; - } - /* Verify that the target is a drive */ - if (destt != drive_object) { - fprintf(stderr, "%s is not a drive\n", argv[0]); - return; - } - for (i = 1; i < argc; i++) { /* for all the sources */ - srcobj = find_object(argv[i], &srct); - if (srcobj == -1) { - fprintf(stderr, "Can't find %s\n", argv[i]); - continue; - } - msg->index = destobj; - switch (srct) { /* Handle the source object */ - case drive_object: /* Move all subdisks on the drive to dst. */ - get_drive_info(&drive, srcobj); /* get info on drive */ - for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) { - get_sd_info(&sd, sdno); - if (sd.driveno == srcobj) { - msg->index = destobj; - msg->otherobject = sd.sdno; - if (ioctl(superdev, VINUM_MOVE, msg) < 0) - fprintf(stderr, - "Can't move %s (part of %s) to %s: %s (%d)\n", - sd.name, - drive.label.name, - argv[0], - strerror(reply.error), - reply.error); - } - } - break; - - case sd_object: - msg->otherobject = srcobj; - if (ioctl(superdev, VINUM_MOVE, msg) < 0) - fprintf(stderr, - "Can't move %s to %s: %s (%d)\n", - sd.name, - argv[0], - strerror(reply.error), - reply.error); - break; - - case plex_object: - get_plex_info(&plex, srcobj); - for (sdno = 0; sdno < plex.subdisks; ++sdno) { - get_plex_sd_info(&sd, plex.plexno, sdno); - msg->index = destobj; - msg->otherobject = sd.sdno; - if (ioctl(superdev, VINUM_MOVE, msg) < 0) - fprintf(stderr, - "Can't move %s (part of %s) to %s: %s (%d)\n", - sd.name, - plex.name, - argv[0], - strerror(reply.error), - reply.error); - } - break; - - case volume_object: - case invalid_object: - default: - fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]); - break; - } - if (reply.error) - fprintf(stderr, - "Can't move %s to %s: %s (%d)\n", - argv[i], - argv[0], - strerror(reply.error), - reply.error); - } - checkupdates(); /* make sure we're updating */ -} - -/* - * Replace objects. Not implemented, may never be. - */ -void -vinum_replace(int argc, char *argv[], char *argv0[]) -{ - fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n"); -} - -/* Primitive help function */ -void -vinum_help(int argc, char *argv[], char *argv0[]) -{ - char commands[] = - { - "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" - "debug Cause the volume manager to enter the kernel debugger.\n" - "debug flags\n" - " Set debugging flags.\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] [drive]\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" - "read disk ...\n" - " Read the vinum configuration from the specified disks.\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" - "resetstats [-r] [volume | plex | subdisk]\n" - " Reset statistics counters for the specified objects, or for all\n" - " objects if none are specified.\n" - "rm [-f] [-r] volume | plex | subdisk\n" - " Remove an object.\n" - "saveconfig\n" - " Save vinum configuration to disk after configuration failures.\n" - "setdaemon [value]\n" - " Set daemon configuration.\n" - "setstate state [volume | plex | subdisk | drive]\n" - " Set state without influencing other objects, for diagnostic pur-\n" - " poses only.\n" - "start Read configuration from all vinum drives.\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" - }; - puts(commands); -} - -/* Set daemon options. - * XXX quick and dirty: use a bitmap, which requires - * knowing which bit does what. FIXME */ -void -vinum_setdaemon(int argc, char *argv[], char *argv0[]) -{ - int options; - - switch (argc) { - case 0: - if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0) - fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno); - else - printf("Options mask: %d\n", options); - break; - - case 1: - options = atoi(argv[0]); - if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0) - fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno); - break; - - default: - fprintf(stderr, "usage: \tsetdaemon [<bitmask>]\n"); - } - checkupdates(); /* make sure we're updating */ -} - -/* Save config info */ -void -vinum_saveconfig(int argc, char *argv[], char *argv0[]) -{ - int ioctltype; - - if (argc != 0) { - printf("usage: saveconfig\n"); - return; - } - ioctltype = 1; /* user saveconfig */ - if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0) - fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno); - checkupdates(); /* make sure we're updating */ -} - -/* - * Create a volume name for the quick and dirty - * commands. It will be of the form "vinum#", - * where # is a small positive number. - */ -void -genvolname() -{ - int v; /* volume number */ - static char volumename[MAXVOLNAME]; /* name to create */ - enum objecttype type; - - objectname = volumename; /* point to it */ - for (v = 0;; v++) { - sprintf(objectname, "vinum%d", v); /* create the name */ - if (find_object(objectname, &type) == -1) /* does it exist? */ - return; /* no, it's ours */ - } -} - -/* - * Create a drive for the quick and dirty - * commands. The name will be of the form - * vinumdrive#, where # is a small positive - * number. Return the name of the drive. - */ -struct _drive * -create_drive(char *devicename) -{ - int d; /* volume number */ - static char drivename[MAXDRIVENAME]; /* name to create */ - enum objecttype type; - struct _ioctl_reply *reply; - - /* - * We're never likely to get anything - * like 10000 drives. The only reason for - * this limit is to stop the thing - * looping if we have a bug somewhere. - */ - for (d = 0; d < 100000; d++) { /* look for a free drive number */ - sprintf(drivename, "vinumdrive%d", d); /* create the name */ - if (find_object(drivename, &type) == -1) { /* does it exist? */ - char command[MAXDRIVENAME * 2]; - - sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */ - if (vflag) - printf("drive %s device %s\n", drivename, devicename); /* create a create command */ - ioctl(superdev, VINUM_CREATE, command); - reply = (struct _ioctl_reply *) &command; - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create drive %s, device %s: %s\n", - drivename, - devicename, - reply->msg); - else - fprintf(stderr, - "Can't create drive %s, device %s: %s (%d)\n", - drivename, - devicename, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - find_object(drivename, &type); - return &drive; /* return the name of the drive */ - } - } - fprintf(stderr, "Can't generate a drive name\n"); - /* NOTREACHED */ - return NULL; -} - -/* - * Create a volume with a single concatenated plex from - * as much space as we can get on the specified drives. - * If the drives aren't Vinum drives, make them so. - */ -void -vinum_concat(int argc, char *argv[], char *argv0[]) -{ - int o; /* object number */ - char buffer[BUFSIZE]; - struct _drive *drive; /* drive we're currently looking at */ - struct _ioctl_reply *reply; - int ioctltype; - int error; - enum objecttype type; - - reply = (struct _ioctl_reply *) &buffer; - if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ - printf("Can't configure: %s (%d)\n", strerror(errno), errno); - return; - } - if (!objectname) /* we need a name for our object */ - genvolname(); - sprintf(buffer, "volume %s", objectname); - if (vflag) - printf("volume %s\n", objectname); - ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create volume %s: %s\n", - objectname, - reply->msg); - else - fprintf(stderr, - "Can't create volume %s: %s (%d)\n", - objectname, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - sprintf(buffer, "plex name %s.p0 org concat", objectname); - if (vflag) - printf(" plex name %s.p0 org concat\n", objectname); - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create plex %s.p0: %s\n", - objectname, - reply->msg); - else - fprintf(stderr, - "Can't create plex %s.p0: %s (%d)\n", - objectname, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - for (o = 0; o < argc; o++) { - if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ - drive = create_drive(argv[o]); /* create it */ - sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name); - if (vflag) - printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name); - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create subdisk %s.p0.s%d: %s\n", - objectname, - o, - reply->msg); - else - fprintf(stderr, - "Can't create subdisk %s.p0.s%d: %s (%d)\n", - objectname, - o, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - } - - /* done, save the config */ - ioctltype = 0; /* saveconfig after update */ - error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ - if (error != 0) - perror("Can't save Vinum config"); - find_object(objectname, &type); /* find the index of the volume */ - if (vflag) { - vflag--; /* XXX don't give too much detail */ - find_object(objectname, &type); /* point to the volume */ - vinum_lvi(vol.volno, 1); /* and print info about it */ - } -} - - -/* - * Create a volume with a single striped plex from - * as much space as we can get on the specified drives. - * If the drives aren't Vinum drives, make them so. - */ -void -vinum_stripe(int argc, char *argv[], char *argv0[]) -{ - int o; /* object number */ - char buffer[BUFSIZE]; - struct _drive *drive; /* drive we're currently looking at */ - struct _ioctl_reply *reply; - int ioctltype; - int error; - enum objecttype type; - off_t maxsize; - int fe; /* freelist entry index */ - struct drive_freelist freelist; - struct ferq { /* request to pass to ioctl */ - int driveno; - int fe; - } *ferq = (struct ferq *) &freelist; - u_int64_t bigchunk; /* biggest chunk in freelist */ - - maxsize = QUAD_MAX; - reply = (struct _ioctl_reply *) &buffer; - - /* - * First, check our drives. - */ - if (argc < 2) { - fprintf(stderr, "You need at least two drives to create a striped plex\n"); - return; - } - if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ - printf("Can't configure: %s (%d)\n", strerror(errno), errno); - return; - } - if (!objectname) /* we need a name for our object */ - genvolname(); - for (o = 0; o < argc; o++) { - if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ - drive = create_drive(argv[o]); /* create it */ - /* Now find the largest chunk available on the drive */ - bigchunk = 0; /* ain't found nothin' yet */ - for (fe = 0; fe < drive->freelist_entries; fe++) { - ferq->driveno = drive->driveno; - ferq->fe = fe; - if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) { - fprintf(stderr, - "Can't get free list element %d: %s\n", - fe, - strerror(errno)); - longjmp(command_fail, -1); - } - bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */ - } - maxsize = min(maxsize, bigchunk); /* this is as much as we can do */ - } - - /* Now create the volume */ - sprintf(buffer, "volume %s", objectname); - if (vflag) - printf("volume %s\n", objectname); - ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create volume %s: %s\n", - objectname, - reply->msg); - else - fprintf(stderr, - "Can't create volume %s: %s (%d)\n", - objectname, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - sprintf(buffer, "plex name %s.p0 org striped 279k", objectname); - if (vflag) - printf(" plex name %s.p0 org striped 279k\n", objectname); - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create plex %s.p0: %s\n", - objectname, - reply->msg); - else - fprintf(stderr, - "Can't create plex %s.p0: %s (%d)\n", - objectname, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - for (o = 0; o < argc; o++) { - drive = find_drive_by_devname(argv[o]); /* we know it exists... */ - sprintf(buffer, - "sd name %s.p0.s%d drive %s size %lldb", - objectname, - o, - drive->label.name, - (long long) maxsize); - if (vflag) - printf(" sd name %s.p0.s%d drive %s size %lldb\n", - objectname, - o, - drive->label.name, - (long long) maxsize); - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create subdisk %s.p0.s%d: %s\n", - objectname, - o, - reply->msg); - else - fprintf(stderr, - "Can't create subdisk %s.p0.s%d: %s (%d)\n", - objectname, - o, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - } - - /* done, save the config */ - ioctltype = 0; /* saveconfig after update */ - error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ - if (error != 0) - perror("Can't save Vinum config"); - find_object(objectname, &type); /* find the index of the volume */ - if (vflag) { - vflag--; /* XXX don't give too much detail */ - find_object(objectname, &type); /* point to the volume */ - vinum_lvi(vol.volno, 1); /* and print info about it */ - } -} - -/* - * Create a volume with a single RAID-4 plex from - * as much space as we can get on the specified drives. - * If the drives aren't Vinum drives, make them so. - */ -void -vinum_raid4(int argc, char *argv[], char *argv0[]) -{ - int o; /* object number */ - char buffer[BUFSIZE]; - struct _drive *drive; /* drive we're currently looking at */ - struct _ioctl_reply *reply; - int ioctltype; - int error; - enum objecttype type; - off_t maxsize; - int fe; /* freelist entry index */ - struct drive_freelist freelist; - struct ferq { /* request to pass to ioctl */ - int driveno; - int fe; - } *ferq = (struct ferq *) &freelist; - u_int64_t bigchunk; /* biggest chunk in freelist */ - - maxsize = QUAD_MAX; - reply = (struct _ioctl_reply *) &buffer; - - /* - * First, check our drives. - */ - if (argc < 3) { - fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n"); - return; - } - if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ - printf("Can't configure: %s (%d)\n", strerror(errno), errno); - return; - } - if (!objectname) /* we need a name for our object */ - genvolname(); - for (o = 0; o < argc; o++) { - if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ - drive = create_drive(argv[o]); /* create it */ - /* Now find the largest chunk available on the drive */ - bigchunk = 0; /* ain't found nothin' yet */ - for (fe = 0; fe < drive->freelist_entries; fe++) { - ferq->driveno = drive->driveno; - ferq->fe = fe; - if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) { - fprintf(stderr, - "Can't get free list element %d: %s\n", - fe, - strerror(errno)); - longjmp(command_fail, -1); - } - bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */ - } - maxsize = min(maxsize, bigchunk); /* this is as much as we can do */ - } - - /* Now create the volume */ - sprintf(buffer, "volume %s", objectname); - if (vflag) - printf("volume %s\n", objectname); - ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create volume %s: %s\n", - objectname, - reply->msg); - else - fprintf(stderr, - "Can't create volume %s: %s (%d)\n", - objectname, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - sprintf(buffer, "plex name %s.p0 org raid4 279k", objectname); - if (vflag) - printf(" plex name %s.p0 org raid4 279k\n", objectname); - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create plex %s.p0: %s\n", - objectname, - reply->msg); - else - fprintf(stderr, - "Can't create plex %s.p0: %s (%d)\n", - objectname, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - for (o = 0; o < argc; o++) { - drive = find_drive_by_devname(argv[o]); /* we know it exists... */ - sprintf(buffer, - "sd name %s.p0.s%d drive %s size %lldb", - objectname, - o, - drive->label.name, - (long long) maxsize); - if (vflag) - printf(" sd name %s.p0.s%d drive %s size %lldb\n", - objectname, - o, - drive->label.name, - (long long) maxsize); - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create subdisk %s.p0.s%d: %s\n", - objectname, - o, - reply->msg); - else - fprintf(stderr, - "Can't create subdisk %s.p0.s%d: %s (%d)\n", - objectname, - o, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - } - - /* done, save the config */ - ioctltype = 0; /* saveconfig after update */ - error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ - if (error != 0) - perror("Can't save Vinum config"); - find_object(objectname, &type); /* find the index of the volume */ - if (vflag) { - vflag--; /* XXX don't give too much detail */ - find_object(objectname, &type); /* point to the volume */ - vinum_lvi(vol.volno, 1); /* and print info about it */ - } -} - -/* - * Create a volume with a single RAID-4 plex from - * as much space as we can get on the specified drives. - * If the drives aren't Vinum drives, make them so. - */ -void -vinum_raid5(int argc, char *argv[], char *argv0[]) -{ - int o; /* object number */ - char buffer[BUFSIZE]; - struct _drive *drive; /* drive we're currently looking at */ - struct _ioctl_reply *reply; - int ioctltype; - int error; - enum objecttype type; - off_t maxsize; - int fe; /* freelist entry index */ - struct drive_freelist freelist; - struct ferq { /* request to pass to ioctl */ - int driveno; - int fe; - } *ferq = (struct ferq *) &freelist; - u_int64_t bigchunk; /* biggest chunk in freelist */ - - maxsize = QUAD_MAX; - reply = (struct _ioctl_reply *) &buffer; - - /* - * First, check our drives. - */ - if (argc < 3) { - fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n"); - return; - } - if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ - printf("Can't configure: %s (%d)\n", strerror(errno), errno); - return; - } - if (!objectname) /* we need a name for our object */ - genvolname(); - for (o = 0; o < argc; o++) { - if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ - drive = create_drive(argv[o]); /* create it */ - /* Now find the largest chunk available on the drive */ - bigchunk = 0; /* ain't found nothin' yet */ - for (fe = 0; fe < drive->freelist_entries; fe++) { - ferq->driveno = drive->driveno; - ferq->fe = fe; - if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) { - fprintf(stderr, - "Can't get free list element %d: %s\n", - fe, - strerror(errno)); - longjmp(command_fail, -1); - } - bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */ - } - maxsize = min(maxsize, bigchunk); /* this is as much as we can do */ - } - - /* Now create the volume */ - sprintf(buffer, "volume %s", objectname); - if (vflag) - printf("volume %s\n", objectname); - ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create volume %s: %s\n", - objectname, - reply->msg); - else - fprintf(stderr, - "Can't create volume %s: %s (%d)\n", - objectname, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - sprintf(buffer, "plex name %s.p0 org raid5 279k", objectname); - if (vflag) - printf(" plex name %s.p0 org raid5 279k\n", objectname); - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create plex %s.p0: %s\n", - objectname, - reply->msg); - else - fprintf(stderr, - "Can't create plex %s.p0: %s (%d)\n", - objectname, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - for (o = 0; o < argc; o++) { - drive = find_drive_by_devname(argv[o]); /* we know it exists... */ - sprintf(buffer, - "sd name %s.p0.s%d drive %s size %lldb", - objectname, - o, - drive->label.name, - (long long) maxsize); - if (vflag) - printf(" sd name %s.p0.s%d drive %s size %lldb\n", - objectname, - o, - drive->label.name, - (long long) maxsize); - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create subdisk %s.p0.s%d: %s\n", - objectname, - o, - reply->msg); - else - fprintf(stderr, - "Can't create subdisk %s.p0.s%d: %s (%d)\n", - objectname, - o, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - } - - /* done, save the config */ - ioctltype = 0; /* saveconfig after update */ - error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ - if (error != 0) - perror("Can't save Vinum config"); - find_object(objectname, &type); /* find the index of the volume */ - if (vflag) { - vflag--; /* XXX don't give too much detail */ - find_object(objectname, &type); /* point to the volume */ - vinum_lvi(vol.volno, 1); /* and print info about it */ - } -} - -/* - * Create a volume with a two plexes from as much space - * as we can get on the specified drives. If the - * drives aren't Vinum drives, make them so. - * - * The number of drives must be even, and at least 4 - * for a striped plex. Specify striped plexes with the - * -s flag; otherwise they will be concatenated. It's - * possible that the two plexes may differ in length. - */ -void -vinum_mirror(int argc, char *argv[], char *argv0[]) -{ - int o; /* object number */ - int p; /* plex number */ - char buffer[BUFSIZE]; - struct _drive *drive; /* drive we're currently looking at */ - struct _ioctl_reply *reply; - int ioctltype; - int error; - enum objecttype type; - off_t maxsize[2]; /* maximum subdisk size for striped plexes */ - int fe; /* freelist entry index */ - struct drive_freelist freelist; - struct ferq { /* request to pass to ioctl */ - int driveno; - int fe; - } *ferq = (struct ferq *) &freelist; - u_int64_t bigchunk; /* biggest chunk in freelist */ - - if (sflag) /* striped, */ - maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */ - else - maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */ - - reply = (struct _ioctl_reply *) &buffer; - - /* - * First, check our drives. - */ - if ((argc < 2) - || (argc & 1)) { - fprintf(stderr, "You need an even number of drives to create a mirrored volume\n"); - return; - } - if (sflag && (argc < 4)) { - fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n"); - return; - } - if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ - printf("Can't configure: %s (%d)\n", strerror(errno), errno); - return; - } - if (!objectname) /* we need a name for our object */ - genvolname(); - for (o = 0; o < argc; o++) { - if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ - drive = create_drive(argv[o]); /* create it */ - if (sflag) { /* striping, */ - /* Find the largest chunk available on the drive */ - bigchunk = 0; /* ain't found nothin' yet */ - for (fe = 0; fe < drive->freelist_entries; fe++) { - ferq->driveno = drive->driveno; - ferq->fe = fe; - if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) { - fprintf(stderr, - "Can't get free list element %d: %s\n", - fe, - strerror(errno)); - longjmp(command_fail, -1); - } - bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */ - } - maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */ - } - } - - /* Now create the volume */ - sprintf(buffer, "volume %s setupstate", objectname); - if (vflag) - printf("volume %s setupstate\n", objectname); - ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create volume %s: %s\n", - objectname, - reply->msg); - else - fprintf(stderr, - "Can't create volume %s: %s (%d)\n", - objectname, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - for (p = 0; p < 2; p++) { /* create each plex */ - if (sflag) { - sprintf(buffer, "plex name %s.p%d org striped 279k", objectname, p); - if (vflag) - printf(" plex name %s.p%d org striped 279k\n", objectname, p); - } else { /* concat */ - sprintf(buffer, "plex name %s.p%d org concat", objectname, p); - if (vflag) - printf(" plex name %s.p%d org concat\n", objectname, p); - } - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create plex %s.p%d: %s\n", - objectname, - p, - reply->msg); - else - fprintf(stderr, - "Can't create plex %s.p%d: %s (%d)\n", - objectname, - p, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - /* Now look at the subdisks */ - for (o = p; o < argc; o += 2) { /* every second one */ - drive = find_drive_by_devname(argv[o]); /* we know it exists... */ - sprintf(buffer, - "sd name %s.p%d.s%d drive %s size %lldb", - objectname, - p, - o >> 1, - drive->label.name, - (long long) maxsize[p]); - if (vflag) - printf(" sd name %s.p%d.s%d drive %s size %lldb\n", - objectname, - p, - o >> 1, - drive->label.name, - (long long) maxsize[p]); - ioctl(superdev, VINUM_CREATE, buffer); - if (reply->error != 0) { /* error in config */ - if (reply->msg[0]) - fprintf(stderr, - "Can't create subdisk %s.p%d.s%d: %s\n", - objectname, - p, - o >> 1, - reply->msg); - else - fprintf(stderr, - "Can't create subdisk %s.p%d.s%d: %s (%d)\n", - objectname, - p, - o >> 1, - strerror(reply->error), - reply->error); - longjmp(command_fail, -1); /* give up */ - } - } - } - - /* done, save the config */ - ioctltype = 0; /* saveconfig after update */ - error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ - if (error != 0) - perror("Can't save Vinum config"); - find_object(objectname, &type); /* find the index of the volume */ - if (vflag) { - vflag--; /* XXX don't give too much detail */ - sflag = 0; /* no stats, please */ - find_object(objectname, &type); /* point to the volume */ - vinum_lvi(vol.volno, 1); /* and print info about it */ - } -} - -void -vinum_readpol(int argc, char *argv[], char *argv0[]) -{ - int object; - struct _ioctl_reply reply; - struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; - enum objecttype type; - struct _plex plex; - struct _volume vol; - int plexno; - - if (argc != 2) { - fprintf(stderr, "usage: readpol <volume> <plex> | round\n"); - return; - } - object = find_object(argv[0], &type); /* look for it */ - if (type != volume_object) { - fprintf(stderr, "%s is not a volume\n", argv[0]); - return; - } - get_volume_info(&vol, object); - if (strcmp(argv[1], "round")) { /* not 'round' */ - object = find_object(argv[1], &type); /* look for it */ - if (type != plex_object) { - fprintf(stderr, "%s is not a plex\n", argv[1]); - return; - } - get_plex_info(&plex, object); - plexno = plex.plexno; - } else /* round */ - plexno = -1; - - /* Set the value */ - message->index = vol.volno; - message->otherobject = plexno; - ioctl(superdev, VINUM_READPOL, message); - if (reply.error) - fprintf(stderr, - "Can't set read policy: %s (%d)\n", - reply.msg[0] ? reply.msg : strerror(reply.error), - reply.error); - if (vflag) - vinum_lpi(plexno, recurse); -} - -/* - * Brute force set state function. Don't look at - * any dependencies, just do it. - */ -void -vinum_setstate(int argc, char *argv[], char *argv0[]) -{ - int object; - struct _ioctl_reply reply; - struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; - int index; - enum objecttype type; - int state; - - for (index = 1; index < argc; index++) { - object = find_object(argv[index], &type); /* look for it */ - if (type == invalid_object) - fprintf(stderr, "Can't find object: %s\n", argv[index]); - else { - int doit = 0; /* set to 1 if we pass our tests */ - switch (type) { - case drive_object: - state = DriveState(argv[0]); /* get the state */ - if (drive.state == state) /* already in that state */ - fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]); - else - doit = 1; - break; - - case sd_object: - state = SdState(argv[0]); /* get the state */ - if (sd.state == state) /* already in that state */ - fprintf(stderr, "%s is already %s\n", sd.name, argv[0]); - else - doit = 1; - break; - - case plex_object: - state = PlexState(argv[0]); /* get the state */ - if (plex.state == state) /* already in that state */ - fprintf(stderr, "%s is already %s\n", plex.name, argv[0]); - else - doit = 1; - break; - - case volume_object: - state = VolState(argv[0]); /* get the state */ - if (vol.state == state) /* already in that state */ - fprintf(stderr, "%s is already %s\n", vol.name, argv[0]); - else - doit = 1; - break; - - default: - state = 0; /* to keep the compiler happy */ - } - - if (state == -1) - fprintf(stderr, "Invalid state for object: %s\n", argv[0]); - else if (doit) { - message->index = object; /* pass object number */ - message->type = type; /* and type of object */ - message->state = state; - message->force = force; /* don't force it, use a larger hammer */ - ioctl(superdev, VINUM_SETSTATE_FORCE, message); - if (reply.error != 0) - fprintf(stderr, - "Can't start %s: %s (%d)\n", - argv[index], - reply.msg[0] ? reply.msg : strerror(reply.error), - reply.error); - if (Verbose) - vinum_li(object, type); - } - } - } -} - -void -vinum_checkparity(int argc, char *argv[], char *argv0[]) -{ - Verbose = vflag; /* accept -v for verbose */ - if (argc == 0) /* no parameters? */ - fprintf(stderr, "usage: checkparity object [object...]\n"); - else - parityops(argc, argv, checkparity); -} - -void -vinum_rebuildparity(int argc, char *argv[], char *argv0[]) -{ - if (argc == 0) /* no parameters? */ - fprintf(stderr, "usage: rebuildparity object [object...]\n"); - else - parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity); -} - -/* - * Common code for rebuildparity and checkparity. - * We bend the meanings of some flags here: - * - * -v: Report incorrect parity on rebuild. - * -V: Show running count of position being checked. - * -f: Start from beginning of the plex. - */ -void -parityops(int argc, char *argv[], enum parityop op) -{ - int object; - struct _plex plex; - struct _ioctl_reply reply; - struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; - int index; - enum objecttype type; - char *msg; - off_t block; - - if (op == checkparity) - msg = "Checking"; - else - msg = "Rebuilding"; - for (index = 0; index < argc; index++) { - object = find_object(argv[index], &type); /* look for it */ - if (type != plex_object) - fprintf(stderr, "%s is not a plex\n", argv[index]); - else { - get_plex_info(&plex, object); - if (!isparity((&plex))) - fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]); - else { - do { - message->index = object; /* pass object number */ - message->type = type; /* and type of object */ - message->op = op; /* what to do */ - if (force) - message->offset = 0; /* start at the beginning */ - else - message->offset = plex.checkblock; /* continue where we left off */ - force = 0; /* don't reset after the first time */ - ioctl(superdev, VINUM_PARITYOP, message); - get_plex_info(&plex, object); - if (Verbose) { - block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1); - if (block != 0) - printf("\r%s at %s (%d%%) ", - msg, - roughlength(block, 1), - ((int) (block * 100 / plex.length) >> DEV_BSHIFT)); - if ((reply.error == EAGAIN) - && (reply.msg[0])) /* got a comment back */ - fputs(reply.msg, stderr); /* show it */ - fflush(stdout); - } - } - while (reply.error == EAGAIN); - if (reply.error != 0) { - if (reply.msg[0]) - fputs(reply.msg, stderr); - else - fprintf(stderr, - "%s failed: %s\n", - msg, - strerror(reply.error)); - } else if (Verbose) { - if (op == checkparity) - fprintf(stderr, "%s has correct parity\n", argv[index]); - else - fprintf(stderr, "Rebuilt parity on %s\n", argv[index]); - } - } - } - } -} - -/* Local Variables: */ -/* fill-column: 50 */ -/* End: */ |