More minor IPI work.
[dragonfly/vkernel-mp.git] / sbin / vinum / commands.c
blobe0d37402644bd0ae577213ff448265c0700912e8
1 /* commands.c: vinum interface program, main commands */
2 /*-
3 * Copyright (c) 1997, 1998
4 * Nan Yang Computer Services Limited. All rights reserved.
6 * Written by Greg Lehey
8 * This software is distributed under the so-called ``Berkeley
9 * License'':
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Company nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * This software is provided ``as is'', and any express or implied
24 * warranties, including, but not limited to, the implied warranties of
25 * merchantability and fitness for a particular purpose are disclaimed.
26 * In no event shall the company or contributors be liable for any
27 * direct, indirect, incidental, special, exemplary, or consequential
28 * damages (including, but not limited to, procurement of substitute
29 * goods or services; loss of use, data, or profits; or business
30 * interruption) however caused and on any theory of liability, whether
31 * in contract, strict liability, or tort (including negligence or
32 * otherwise) arising in any way out of the use of this software, even if
33 * advised of the possibility of such damage.
35 * $Id: commands.c,v 1.14 2000/11/14 20:01:23 grog Exp grog $
36 * $FreeBSD: src/sbin/vinum/commands.c,v 1.31.2.6 2003/06/06 05:13:29 grog Exp $
37 * $DragonFly: src/sbin/vinum/commands.c,v 1.7 2007/01/20 20:20:39 dillon Exp $
40 #define _KERNEL_STRUCTURES
42 #include <ctype.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <sys/mman.h>
46 #include <netdb.h>
47 #include <paths.h>
48 #include <setjmp.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <syslog.h>
53 #include <unistd.h>
54 #include <sys/ioctl.h>
55 #include <dev/raid/vinum/vinumhdr.h>
56 #include <dev/raid/vinum/request.h>
57 #include "vext.h"
58 #include <sys/types.h>
59 #include <sys/linker.h>
60 #include <sys/module.h>
61 #include <sys/wait.h>
62 #include <readline/history.h>
63 #include <readline/readline.h>
64 #include <devstat.h>
66 static void dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen);
68 void
69 vinum_create(int argc, char *argv[], char *arg0[])
71 int error;
72 FILE *dfd; /* file descriptor for the config file */
73 char buffer[BUFSIZE]; /* read config file in here */
74 char commandline[BUFSIZE]; /* issue command from here */
75 struct _ioctl_reply *reply;
76 int ioctltype; /* for ioctl call */
77 char tempfile[PATH_MAX]; /* name of temp file for direct editing */
78 char *file; /* file to read */
79 FILE *tf; /* temp file */
81 if (argc == 0) { /* no args, */
82 char *editor; /* editor to start */
83 int status;
85 editor = getenv("EDITOR");
86 if (editor == NULL)
87 editor = "/usr/bin/vi";
88 sprintf(tempfile, "/var/tmp/" VINUMMOD ".create.%d", getpid()); /* create a temp file */
89 tf = fopen(tempfile, "w"); /* open it */
90 if (tf == NULL) {
91 fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno));
92 return;
94 printconfig(tf, "# "); /* and put the current config it */
95 fclose(tf);
96 sprintf(commandline, "%s %s", editor, tempfile); /* create an edit command */
97 status = system(commandline); /* do it */
98 if (status != 0) {
99 fprintf(stderr, "Can't edit config: status %d\n", status);
100 return;
102 file = tempfile;
103 } else if (argc == 1)
104 file = argv[0];
105 else {
106 fprintf(stderr, "Expecting 1 parameter, not %d\n", argc);
107 return;
109 reply = (struct _ioctl_reply *) &buffer;
110 dfd = fopen(file, "r");
111 if (dfd == NULL) { /* no go */
112 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
113 return;
115 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
116 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
117 return;
119 file_line = 0; /* start with line 1 */
120 /* Parse the configuration, and add it to the global configuration */
121 for (;;) { /* love this style(9) */
122 char *configline;
124 configline = fgets(buffer, BUFSIZE, dfd);
125 if (history)
126 fprintf(history, "%s", buffer);
128 if (configline == NULL) {
129 if (ferror(dfd))
130 perror("Can't read config file");
131 break;
133 file_line++; /* count the lines */
134 if (vflag)
135 printf("%4d: %s", file_line, buffer);
136 strcpy(commandline, buffer); /* make a copy */
137 ioctl(superdev, VINUM_CREATE, buffer);
138 if (reply->error != 0) { /* error in config */
139 if (!vflag) /* print this line anyway */
140 printf("%4d: %s", file_line, commandline);
141 fprintf(stdout, "** %d %s: %s\n",
142 file_line,
143 reply->msg,
144 strerror(reply->error));
147 * XXX at the moment, we reset the config
148 * lock on error, so try to get it again.
149 * If we fail, don't cry again.
151 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) /* can't get config? */
152 return;
155 fclose(dfd); /* done with the config file */
156 ioctltype = 0; /* saveconfig after update */
157 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
158 if (error != 0)
159 perror("Can't save Vinum config");
160 make_devices();
161 listconfig();
162 checkupdates(); /* make sure we're updating */
165 /* Read vinum config from a disk */
166 void
167 vinum_read(int argc, char *argv[], char *arg0[])
169 int error;
170 char buffer[BUFSIZE]; /* read config file in here */
171 struct _ioctl_reply *reply;
172 int i;
174 reply = (struct _ioctl_reply *) &buffer;
175 if (argc < 1) { /* wrong arg count */
176 fprintf(stderr, "Usage: read drive [drive ...]\n");
177 return;
179 strcpy(buffer, "read ");
180 for (i = 0; i < argc; i++) { /* each drive name */
181 strcat(buffer, argv[i]);
182 strcat(buffer, " ");
185 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
186 fprintf(stderr, "Can't configure: %s (%d)\n", strerror(errno), errno);
187 return;
189 ioctl(superdev, VINUM_CREATE, &buffer);
190 if (reply->error != 0) { /* error in config */
191 fprintf(stdout, "** %s: %s\n", reply->msg, strerror(reply->error));
192 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
193 if (error != 0)
194 perror("Can't save Vinum config");
195 } else {
196 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
197 if (error != 0)
198 perror("Can't save Vinum config");
199 make_devices();
201 checkupdates(); /* make sure we're updating */
204 #ifdef VINUMDEBUG
205 void
206 vinum_debug(int argc, char *argv[], char *arg0[])
208 struct debuginfo info;
210 if (argc > 0) {
211 info.param = atoi(argv[0]);
212 info.changeit = 1;
213 } else {
214 info.changeit = 0;
215 sleep(2); /* give a chance to leave the window */
217 ioctl(superdev, VINUM_DEBUG, (caddr_t) & info);
219 #endif
221 void
222 vinum_modify(int argc, char *argv[], char *arg0[])
224 fprintf(stderr, "Modify command is currently not implemented\n");
225 checkupdates(); /* make sure we're updating */
228 void
229 vinum_set(int argc, char *argv[], char *arg0[])
231 fprintf(stderr, "set is not implemented yet\n");
234 void
235 vinum_rm(int argc, char *argv[], char *arg0[])
237 int object;
238 struct _ioctl_reply reply;
239 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
241 if (argc == 0) /* start everything */
242 fprintf(stderr, "Usage: rm object [object...]\n");
243 else { /* start specified objects */
244 int index;
245 enum objecttype type;
247 for (index = 0; index < argc; index++) {
248 object = find_object(argv[index], &type); /* look for it */
249 if (type == invalid_object)
250 fprintf(stderr, "Can't find object: %s\n", argv[index]);
251 else {
252 message->index = object; /* pass object number */
253 message->type = type; /* and type of object */
254 message->force = force; /* do we want to force the operation? */
255 message->recurse = recurse; /* do we want to remove subordinates? */
256 ioctl(superdev, VINUM_REMOVE, message);
257 if (reply.error != 0) {
258 fprintf(stderr,
259 "Can't remove %s: %s (%d)\n",
260 argv[index],
261 reply.msg[0] ? reply.msg : strerror(reply.error),
262 reply.error);
263 } else if (vflag)
264 fprintf(stderr, "%s removed\n", argv[index]);
267 checkupdates(); /* make sure we're updating */
271 void
272 vinum_resetconfig(int argc, char *argv[], char *arg0[])
274 char reply[32];
275 int error;
277 if (! isatty (STDIN_FILENO)) {
278 fprintf (stderr, "Please enter this command from a tty device\n");
279 return;
281 printf(" WARNING! This command will completely wipe out your vinum configuration.\n"
282 " All data will be lost. If you really want to do this, enter the text\n\n"
283 " NO FUTURE\n"
284 " Enter text -> ");
285 fgets(reply, sizeof(reply), stdin);
286 if (strcmp(reply, "NO FUTURE\n")) /* changed his mind */
287 printf("\n No change\n");
288 else {
289 error = ioctl(superdev, VINUM_RESETCONFIG, NULL); /* trash config on disk */
290 if (error) {
291 if (errno == EBUSY)
292 fprintf(stderr, "Can't reset configuration: objects are in use\n");
293 else
294 perror("Can't find vinum config");
295 } else {
296 make_devices(); /* recreate the /dev/vinum hierarchy */
297 printf("\b Vinum configuration obliterated\n");
298 start_daemon(); /* then restart the daemon */
301 checkupdates(); /* make sure we're updating */
304 /* Initialize subdisks */
305 void
306 vinum_init(int argc, char *argv[], char *arg0[])
308 if (argc > 0) { /* initialize plexes */
309 int objindex;
310 int objno;
311 enum objecttype type; /* type returned */
313 if (history)
314 fflush(history); /* don't let all the kids do it. */
315 for (objindex = 0; objindex < argc; objindex++) {
316 objno = find_object(argv[objindex], &type); /* find the object */
317 if (objno < 0)
318 printf("Can't find %s\n", argv[objindex]);
319 else {
320 switch (type) {
321 case volume_object:
322 initvol(objno);
323 break;
325 case plex_object:
326 initplex(objno, argv[objindex]);
327 break;
329 case sd_object:
330 initsd(objno, dowait);
331 break;
333 default:
334 printf("Can't initialize %s: wrong object type\n", argv[objindex]);
335 break;
340 checkupdates(); /* make sure we're updating */
343 void
344 initvol(int volno)
346 printf("Initializing volumes is not implemented yet\n");
349 void
350 initplex(int plexno, char *name)
352 int sdno;
353 int plexfh = NULL; /* file handle for plex */
354 pid_t pid;
355 char filename[MAXPATHLEN]; /* create a file name here */
357 /* Variables for use by children */
358 int failed = 0; /* set if a child dies badly */
360 sprintf(filename, VINUM_DIR "/plex/%s", name);
361 if ((plexfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* got a plex, open it */
363 * We don't actually write anything to the
364 * plex. We open it to ensure that nobody
365 * else tries to open it while we initialize
366 * its subdisks.
368 fprintf(stderr, "can't open plex %s: %s\n", filename, strerror(errno));
369 return;
371 if (dowait == 0) {
372 pid = fork(); /* into the background with you */
373 if (pid != 0) { /* I'm the parent, or we failed */
374 if (pid < 0) /* failure */
375 printf("Couldn't fork: %s", strerror(errno));
376 close(plexfh); /* we don't need this any more */
377 return;
381 * If we get here, we're either the first-level
382 * child (if we're not waiting) or we're going
383 * to wait.
385 for (sdno = 0; sdno < plex.subdisks; sdno++) { /* initialize each subdisk */
386 get_plex_sd_info(&sd, plexno, sdno);
387 initsd(sd.sdno, 0);
389 /* Now wait for them to complete */
390 while (1) {
391 int status;
392 pid = wait(&status);
393 if (((int) pid == -1)
394 && (errno == ECHILD)) /* all gone */
395 break;
396 if (WEXITSTATUS(status) != 0) { /* oh, oh */
397 printf("child %d exited with status 0x%x\n", pid, WEXITSTATUS(status));
398 failed++;
401 if (failed == 0) {
402 #if 0
403 message->index = plexno; /* pass object number */
404 message->type = plex_object; /* and type of object */
405 message->state = object_up;
406 message->force = 1; /* insist */
407 ioctl(superdev, VINUM_SETSTATE, message);
408 #endif
409 syslog(LOG_INFO | LOG_KERN, "plex %s initialized", plex.name);
410 } else
411 syslog(LOG_ERR | LOG_KERN, "couldn't initialize plex %s, %d processes died",
412 plex.name,
413 failed);
414 if (dowait == 0) /* we're the waiting child, */
415 exit(0); /* we've done our dash */
418 /* Initialize a subdisk. */
419 void
420 initsd(int sdno, int dowait)
422 pid_t pid;
423 struct _ioctl_reply reply;
424 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
425 char filename[MAXPATHLEN]; /* create a file name here */
427 /* Variables for use by children */
428 int sdfh; /* and for subdisk */
429 int initsize; /* actual size to write */
430 int64_t sdsize; /* size of subdisk */
432 if (dowait == 0) {
433 pid = fork(); /* into the background with you */
434 if (pid > 0) /* I'm the parent */
435 return;
436 else if (pid < 0) { /* failure */
437 printf("couldn't fork for subdisk %d: %s", sdno, strerror(errno));
438 return;
441 if (SSize != 0) { /* specified a size for init */
442 if (SSize < 512)
443 SSize <<= DEV_BSHIFT;
444 initsize = min(SSize, MAXPLEXINITSIZE);
445 } else
446 initsize = PLEXINITSIZE;
447 openlog("vinum", LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
448 get_sd_info(&sd, sdno);
449 sdsize = sd.sectors * DEV_BSIZE; /* size of subdisk in bytes */
450 sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
451 setproctitle("initializing %s", filename); /* show what we're doing */
452 syslog(LOG_INFO | LOG_KERN, "initializing subdisk %s", filename);
453 if ((sdfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* no go */
454 syslog(LOG_ERR | LOG_KERN,
455 "can't open subdisk %s: %s",
456 filename,
457 strerror(errno));
458 exit(1);
460 /* Set the subdisk in initializing state */
461 message->index = sd.sdno; /* pass object number */
462 message->type = sd_object; /* and type of object */
463 message->state = object_initializing;
464 message->verify = vflag; /* verify what we write? */
465 message->force = 1; /* insist */
466 ioctl(superdev, VINUM_SETSTATE, message);
467 if ((SSize > 0) /* specified a size for init */
468 &&(SSize < 512))
469 SSize <<= DEV_BSHIFT;
470 if (reply.error) {
471 fprintf(stderr,
472 "Can't initialize %s: %s (%d)\n",
473 filename,
474 strerror(reply.error),
475 reply.error);
476 exit(1);
477 } else {
478 do {
479 if (interval) /* pause between copies */
480 usleep(interval * 1000);
481 message->index = sd.sdno; /* pass object number */
482 message->type = sd_object; /* and type of object */
483 message->state = object_up;
484 message->verify = vflag; /* verify what we write? */
485 message->blocksize = SSize;
486 ioctl(superdev, VINUM_SETSTATE, message);
488 while (reply.error == EAGAIN); /* until we're done */
489 if (reply.error) {
490 fprintf(stderr,
491 "Can't initialize %s: %s (%d)\n",
492 filename,
493 strerror(reply.error),
494 reply.error);
495 get_sd_info(&sd, sdno);
496 if (sd.state != sd_up)
497 /* Set the subdisk down */
498 message->index = sd.sdno; /* pass object number */
499 message->type = sd_object; /* and type of object */
500 message->state = object_down;
501 message->verify = vflag; /* verify what we write? */
502 message->force = 1; /* insist */
503 ioctl(superdev, VINUM_SETSTATE, message);
506 printf("subdisk %s initialized\n", filename);
507 if (!dowait)
508 exit(0);
511 void
512 vinum_start(int argc, char *argv[], char *arg0[])
514 int object;
515 struct _ioctl_reply reply;
516 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
518 if (argc == 0) { /* start everything */
519 int devs = getnumdevs();
520 struct statinfo statinfo;
521 char *namelist;
522 char *enamelist; /* end of name list */
523 int i;
524 char **token; /* list of tokens */
525 int tokens; /* and their number */
527 bzero(&statinfo, sizeof(struct statinfo));
528 statinfo.dinfo = malloc(devs * sizeof(struct statinfo));
529 namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8));
530 token = malloc((devs + 1) * sizeof(char *));
531 if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) {
532 fprintf(stderr, "Can't allocate memory for drive list\n");
533 return;
535 bzero(statinfo.dinfo, sizeof(struct devinfo));
537 tokens = 0; /* no tokens yet */
538 if (getdevs(&statinfo) < 0) { /* find out what devices we have */
539 perror("Can't get device list");
540 return;
542 namelist[0] = '\0'; /* start with empty namelist */
543 enamelist = namelist; /* point to the end of the list */
545 for (i = 0; i < devs; i++) {
546 struct devstat *stat = &statinfo.dinfo->devices[i];
548 if ((((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */
549 || ((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) /* storage array */
550 &&((stat->device_type & DEVSTAT_TYPE_IF_MASK) != DEVSTAT_TYPE_IF_OTHER) /* and not md */
551 &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */
552 &&((stat->device_name[0] != '\0'))) { /* and it has a name */
553 sprintf(enamelist, "%s%s%d", _PATH_DEV, stat->device_name, stat->unit_number);
554 token[tokens] = enamelist; /* point to it */
555 tokens++; /* one more token */
556 enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */
559 free(statinfo.dinfo); /* don't need the list any more */
560 vinum_read(tokens, token, &token[0]); /* start the system */
561 free(namelist);
562 free(token);
563 list_defective_objects(); /* and list anything that's down */
564 } else { /* start specified objects */
565 int index;
566 enum objecttype type;
568 for (index = 0; index < argc; index++) {
569 object = find_object(argv[index], &type); /* look for it */
570 if (type == invalid_object)
571 fprintf(stderr, "Can't find object: %s\n", argv[index]);
572 else {
573 int doit = 0; /* set to 1 if we pass our tests */
574 switch (type) {
575 case drive_object:
576 if (drive.state == drive_up) /* already up */
577 fprintf(stderr, "%s is already up\n", drive.label.name);
578 else
579 doit = 1;
580 break;
582 case sd_object:
583 if (sd.state == sd_up) /* already up */
584 fprintf(stderr, "%s is already up\n", sd.name);
585 else
586 doit = 1;
587 break;
589 case plex_object:
590 if (plex.state == plex_up) /* already up */
591 fprintf(stderr, "%s is already up\n", plex.name);
592 else {
593 int sdno;
596 * First, see if we can bring it up
597 * just by asking. This might happen
598 * if somebody has used setupstate on
599 * the subdisks. If we don't do this,
600 * we'll return success, but the plex
601 * won't have changed state. Note
602 * that we don't check for errors
603 * here.
605 message->index = plex.plexno; /* pass object number */
606 message->type = plex_object; /* it's a plex */
607 message->state = object_up;
608 message->force = 0; /* don't force it */
609 ioctl(superdev, VINUM_SETSTATE, message);
610 for (sdno = 0; sdno < plex.subdisks; sdno++) {
611 get_plex_sd_info(&sd, object, sdno);
612 if ((sd.state >= sd_empty)
613 && (sd.state <= sd_reviving)) { /* candidate for start */
614 message->index = sd.sdno; /* pass object number */
615 message->type = sd_object; /* it's a subdisk */
616 message->state = object_up;
617 message->force = force; /* don't force it, use a larger hammer */
620 * We don't do any checking here.
621 * The kernel module has a better
622 * understanding of these things,
623 * let it do it.
625 if (SSize != 0) { /* specified a size for init */
626 if (SSize < 512)
627 SSize <<= DEV_BSHIFT;
628 message->blocksize = SSize;
629 } else
630 message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
631 ioctl(superdev, VINUM_SETSTATE, message);
632 if (reply.error != 0) {
633 if (reply.error == EAGAIN) /* we're reviving */
634 continue_revive(sd.sdno);
635 else
636 fprintf(stderr,
637 "Can't start %s: %s (%d)\n",
638 sd.name,
639 reply.msg[0] ? reply.msg : strerror(reply.error),
640 reply.error);
642 if (Verbose)
643 vinum_lsi(sd.sdno, 0);
647 break;
649 case volume_object:
650 if (vol.state == volume_up) /* already up */
651 fprintf(stderr, "%s is already up\n", vol.name);
652 else
653 doit = 1;
654 break;
656 default:
657 break;
660 if (doit) {
661 message->index = object; /* pass object number */
662 message->type = type; /* and type of object */
663 message->state = object_up;
664 message->force = force; /* don't force it, use a larger hammer */
667 * We don't do any checking here.
668 * The kernel module has a better
669 * understanding of these things,
670 * let it do it.
672 if (SSize != 0) { /* specified a size for init or revive */
673 if (SSize < 512)
674 SSize <<= DEV_BSHIFT;
675 message->blocksize = SSize;
676 } else
677 message->blocksize = 0;
678 ioctl(superdev, VINUM_SETSTATE, message);
679 if (reply.error != 0) {
680 if ((reply.error == EAGAIN) /* we're reviving */
681 &&(type == sd_object))
682 continue_revive(object);
683 else
684 fprintf(stderr,
685 "Can't start %s: %s (%d)\n",
686 argv[index],
687 reply.msg[0] ? reply.msg : strerror(reply.error),
688 reply.error);
690 if (Verbose)
691 vinum_li(object, type);
696 checkupdates(); /* make sure we're updating */
699 void
700 vinum_stop(int argc, char *argv[], char *arg0[])
702 int object;
703 struct _ioctl_reply reply;
704 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
706 if (checkupdates() && (!force)) /* not updating? */
707 return;
708 message->force = force; /* should we force the transition? */
709 if (argc == 0) { /* stop vinum */
710 int fileid = 0; /* ID of Vinum kld */
712 close(superdev); /* we can't stop if we have vinum open */
713 sleep(1); /* wait for the daemon to let go */
714 fileid = kldfind(VINUMMOD);
715 if ((fileid < 0) /* no go */
716 ||(kldunload(fileid) < 0))
717 perror("Can't unload " VINUMMOD);
718 else {
719 fprintf(stderr, VINUMMOD " unloaded\n");
720 exit(0);
723 /* If we got here, the stop failed. Reopen the superdevice. */
724 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */
725 if (superdev < 0) {
726 perror("Can't reopen Vinum superdevice");
727 exit(1);
729 } else { /* stop specified objects */
730 int i;
731 enum objecttype type;
733 for (i = 0; i < argc; i++) {
734 object = find_object(argv[i], &type); /* look for it */
735 if (type == invalid_object)
736 fprintf(stderr, "Can't find object: %s\n", argv[i]);
737 else {
738 message->index = object; /* pass object number */
739 message->type = type; /* and type of object */
740 message->state = object_down;
741 ioctl(superdev, VINUM_SETSTATE, message);
742 if (reply.error != 0)
743 fprintf(stderr,
744 "Can't stop %s: %s (%d)\n",
745 argv[i],
746 reply.msg[0] ? reply.msg : strerror(reply.error),
747 reply.error);
748 if (Verbose)
749 vinum_li(object, type);
755 void
756 vinum_label(int argc, char *argv[], char *arg0[])
758 int object;
759 struct _ioctl_reply reply;
760 int *message = (int *) &reply;
762 if (argc == 0) /* start everything */
763 fprintf(stderr, "label: please specify one or more volume names\n");
764 else { /* start specified objects */
765 int i;
766 enum objecttype type;
768 for (i = 0; i < argc; i++) {
769 object = find_object(argv[i], &type); /* look for it */
770 if (type == invalid_object)
771 fprintf(stderr, "Can't find object: %s\n", argv[i]);
772 else if (type != volume_object) /* it exists, but it isn't a volume */
773 fprintf(stderr, "%s is not a volume\n", argv[i]);
774 else {
775 message[0] = object; /* pass object number */
776 ioctl(superdev, VINUM_LABEL, message);
777 if (reply.error != 0)
778 fprintf(stderr,
779 "Can't label %s: %s (%d)\n",
780 argv[i],
781 reply.msg[0] ? reply.msg : strerror(reply.error),
782 reply.error);
783 if (Verbose)
784 vinum_li(object, type);
788 checkupdates(); /* not updating? */
791 void
792 reset_volume_stats(int volno, int recurse)
794 struct vinum_ioctl_msg msg;
795 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
797 msg.index = volno;
798 msg.type = volume_object;
799 /* XXX get these numbers right if we ever
800 * actually return errors */
801 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
802 fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg);
803 longjmp(command_fail, -1);
804 } else if (recurse) {
805 struct volume vol;
806 int plexno;
808 get_volume_info(&vol, volno);
809 for (plexno = 0; plexno < vol.plexes; plexno++)
810 reset_plex_stats(vol.plex[plexno], recurse);
814 void
815 reset_plex_stats(int plexno, int recurse)
817 struct vinum_ioctl_msg msg;
818 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
820 msg.index = plexno;
821 msg.type = plex_object;
822 /* XXX get these numbers right if we ever
823 * actually return errors */
824 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
825 fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg);
826 longjmp(command_fail, -1);
827 } else if (recurse) {
828 struct plex plex;
829 struct sd sd;
830 int sdno;
832 get_plex_info(&plex, plexno);
833 for (sdno = 0; sdno < plex.subdisks; sdno++) {
834 get_plex_sd_info(&sd, plex.plexno, sdno);
835 reset_sd_stats(sd.sdno, recurse);
840 void
841 reset_sd_stats(int sdno, int recurse)
843 struct vinum_ioctl_msg msg;
844 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
846 msg.index = sdno;
847 msg.type = sd_object;
848 /* XXX get these numbers right if we ever
849 * actually return errors */
850 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
851 fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg);
852 longjmp(command_fail, -1);
853 } else if (recurse) {
854 get_sd_info(&sd, sdno); /* get the info */
855 reset_drive_stats(sd.driveno); /* and clear the drive */
859 void
860 reset_drive_stats(int driveno)
862 struct vinum_ioctl_msg msg;
863 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
865 msg.index = driveno;
866 msg.type = drive_object;
867 /* XXX get these numbers right if we ever
868 * actually return errors */
869 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
870 fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg);
871 longjmp(command_fail, -1);
875 void
876 vinum_resetstats(int argc, char *argv[], char *argv0[])
878 int i;
879 int objno;
880 enum objecttype type;
882 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
883 perror("Can't get vinum config");
884 return;
886 if (argc == 0) {
887 for (objno = 0; objno < vinum_conf.volumes_allocated; objno++)
888 reset_volume_stats(objno, 1); /* clear everything recursively */
889 } else {
890 for (i = 0; i < argc; i++) {
891 objno = find_object(argv[i], &type);
892 if (objno >= 0) { /* not invalid */
893 switch (type) {
894 case drive_object:
895 reset_drive_stats(objno);
896 break;
898 case sd_object:
899 reset_sd_stats(objno, recurse);
900 break;
902 case plex_object:
903 reset_plex_stats(objno, recurse);
904 break;
906 case volume_object:
907 reset_volume_stats(objno, recurse);
908 break;
910 case invalid_object: /* can't get this */
911 break;
918 /* Attach a subdisk to a plex, or a plex to a volume.
919 * attach subdisk plex [offset] [rename]
920 * attach plex volume [rename]
922 void
923 vinum_attach(int argc, char *argv[], char *argv0[])
925 int i;
926 enum objecttype supertype;
927 struct vinum_ioctl_msg msg;
928 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
929 const char *objname = argv[0];
930 const char *supername = argv[1];
931 int sdno = -1;
932 int plexno = -1;
933 char oldname[MAXNAME + 8];
934 char newname[MAXNAME + 8];
935 int rename = 0; /* set if we want to rename the object */
937 if ((argc < 2)
938 || (argc > 4)) {
939 fprintf(stderr,
940 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
941 "\tattach <plex> <volume> [rename]\n");
942 return;
944 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
945 perror("Can't get vinum config");
946 return;
948 msg.index = find_object(objname, &msg.type); /* find the object to attach */
949 msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */
950 msg.force = force; /* did we specify the use of force? */
951 msg.recurse = recurse;
952 msg.offset = -1; /* and no offset */
954 for (i = 2; i < argc; i++) {
955 if (!strcmp(argv[i], "rename")) {
956 rename = 1;
957 msg.rename = 1; /* do renaming */
958 } else if (!isdigit(argv[i][0])) { /* not an offset */
959 fprintf(stderr, "Unknown attribute: %s\n", supername);
960 return;
961 } else
962 msg.offset = sizespec(argv[i]);
965 switch (msg.type) {
966 case sd_object:
967 find_object(argv[1], &supertype);
968 if (supertype != plex_object) { /* huh? */
969 fprintf(stderr, "%s can only be attached to a plex\n", objname);
970 return;
972 if ((plex.organization != plex_concat) /* not a cat plex, */
973 &&(!force)) {
974 fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization));
975 return;
977 sdno = msg.index; /* note the subdisk number for later */
978 break;
980 case plex_object:
981 find_object(argv[1], &supertype);
982 if (supertype != volume_object) { /* huh? */
983 fprintf(stderr, "%s can only be attached to a volume\n", objname);
984 return;
986 break;
988 case volume_object:
989 case drive_object:
990 fprintf(stderr, "Can only attach subdisks and plexes\n");
991 return;
993 default:
994 fprintf(stderr, "%s is not a Vinum object\n", objname);
995 return;
998 ioctl(superdev, VINUM_ATTACH, &msg);
999 if (reply->error != 0) {
1000 if (reply->error == EAGAIN) /* reviving */
1001 continue_revive(sdno); /* continue the revive */
1002 else
1003 fprintf(stderr,
1004 "Can't attach %s to %s: %s (%d)\n",
1005 objname,
1006 supername,
1007 reply->msg[0] ? reply->msg : strerror(reply->error),
1008 reply->error);
1010 if (rename) {
1011 struct sd;
1012 struct plex;
1013 struct volume;
1015 /* we've overwritten msg with the
1016 * ioctl reply, start again */
1017 msg.index = find_object(objname, &msg.type); /* find the object to rename */
1018 switch (msg.type) {
1019 case sd_object:
1020 get_sd_info(&sd, msg.index);
1021 get_plex_info(&plex, sd.plexno);
1022 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1023 if (plex.sdnos[sdno] == msg.index) /* found our subdisk */
1024 break;
1026 sprintf(newname, "%s.s%d", plex.name, sdno);
1027 sprintf(oldname, "%s", sd.name);
1028 vinum_rename_2(oldname, newname);
1029 break;
1031 case plex_object:
1032 get_plex_info(&plex, msg.index);
1033 get_volume_info(&vol, plex.volno);
1034 for (plexno = 0; plexno < vol.plexes; plexno++) {
1035 if (vol.plex[plexno] == msg.index) /* found our subdisk */
1036 break;
1038 sprintf(newname, "%s.p%d", vol.name, plexno);
1039 sprintf(oldname, "%s", plex.name);
1040 vinum_rename_2(oldname, newname); /* this may recurse */
1041 break;
1043 default: /* can't get here */
1044 break;
1047 checkupdates(); /* make sure we're updating */
1050 /* Detach a subdisk from a plex, or a plex from a volume.
1051 * detach subdisk plex [rename]
1052 * detach plex volume [rename]
1054 void
1055 vinum_detach(int argc, char *argv[], char *argv0[])
1057 struct vinum_ioctl_msg msg;
1058 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
1060 if ((argc < 1)
1061 || (argc > 2)) {
1062 fprintf(stderr,
1063 "Usage: \tdetach <subdisk> [rename]\n"
1064 "\tdetach <plex> [rename]\n");
1065 return;
1067 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1068 perror("Can't get vinum config");
1069 return;
1071 msg.index = find_object(argv[0], &msg.type); /* find the object to detach */
1072 msg.force = force; /* did we specify the use of force? */
1073 msg.rename = 0; /* don't specify new name */
1074 msg.recurse = recurse; /* but recurse if we have to */
1076 /* XXX are we going to keep this?
1077 * Don't document it yet, since the
1078 * kernel side of things doesn't
1079 * implement it */
1080 if (argc == 2) {
1081 if (!strcmp(argv[1], "rename"))
1082 msg.rename = 1; /* do renaming */
1083 else {
1084 fprintf(stderr, "Unknown attribute: %s\n", argv[1]);
1085 return;
1088 if ((msg.type != sd_object)
1089 && (msg.type != plex_object)) {
1090 fprintf(stderr, "Can only detach subdisks and plexes\n");
1091 return;
1093 ioctl(superdev, VINUM_DETACH, &msg);
1094 if (reply->error != 0)
1095 fprintf(stderr,
1096 "Can't detach %s: %s (%d)\n",
1097 argv[0],
1098 reply->msg[0] ? reply->msg : strerror(reply->error),
1099 reply->error);
1100 checkupdates(); /* make sure we're updating */
1103 static void
1104 dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen)
1106 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
1108 if (strlen(name) > maxlen) {
1109 fprintf(stderr, "%s is too long\n", name);
1110 return;
1112 strcpy(msg->newname, name);
1113 ioctl(superdev, VINUM_RENAME, msg);
1114 if (reply->error != 0)
1115 fprintf(stderr,
1116 "Can't rename %s to %s: %s (%d)\n",
1117 oldname,
1118 name,
1119 reply->msg[0] ? reply->msg : strerror(reply->error),
1120 reply->error);
1123 /* Rename an object:
1124 * rename <object> "newname"
1126 void
1127 vinum_rename_2(char *oldname, char *newname)
1129 struct vinum_rename_msg msg;
1130 int volno;
1131 int plexno;
1133 msg.index = find_object(oldname, &msg.type); /* find the object to rename */
1134 msg.recurse = recurse;
1136 /* Ugh. Determine how long the name may be */
1137 switch (msg.type) {
1138 case drive_object:
1139 dorename(&msg, oldname, newname, MAXDRIVENAME);
1140 break;
1142 case sd_object:
1143 dorename(&msg, oldname, newname, MAXSDNAME);
1144 break;
1146 case plex_object:
1147 plexno = msg.index;
1148 dorename(&msg, oldname, newname, MAXPLEXNAME);
1149 if (recurse) {
1150 int sdno;
1152 get_plex_info(&plex, plexno); /* find out who we are */
1153 msg.type = sd_object;
1154 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1155 char sdname[MAXPLEXNAME + 8];
1157 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1158 sprintf(sdname, "%s.s%d", newname, sdno);
1159 msg.index = sd.sdno; /* number of the subdisk */
1160 dorename(&msg, sd.name, sdname, MAXSDNAME);
1163 break;
1165 case volume_object:
1166 volno = msg.index;
1167 dorename(&msg, oldname, newname, MAXVOLNAME);
1168 if (recurse) {
1169 int sdno;
1170 int plexno;
1172 get_volume_info(&vol, volno); /* find out who we are */
1173 for (plexno = 0; plexno < vol.plexes; plexno++) {
1174 char plexname[MAXVOLNAME + 8];
1176 msg.type = plex_object;
1177 sprintf(plexname, "%s.p%d", newname, plexno);
1178 msg.index = vol.plex[plexno]; /* number of the plex */
1179 dorename(&msg, plex.name, plexname, MAXPLEXNAME);
1180 get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */
1181 msg.type = sd_object;
1182 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1183 char sdname[MAXPLEXNAME + 8];
1185 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1186 sprintf(sdname, "%s.s%d", plexname, sdno);
1187 msg.index = sd.sdno; /* number of the subdisk */
1188 dorename(&msg, sd.name, sdname, MAXSDNAME);
1192 break;
1194 default:
1195 fprintf(stderr, "%s is not a Vinum object\n", oldname);
1196 return;
1200 void
1201 vinum_rename(int argc, char *argv[], char *argv0[])
1203 if (argc != 2) {
1204 fprintf(stderr, "Usage: \trename <object> <new name>\n");
1205 return;
1207 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1208 perror("Can't get vinum config");
1209 return;
1211 vinum_rename_2(argv[0], argv[1]);
1212 checkupdates(); /* make sure we're updating */
1216 * Move objects:
1218 * mv <dest> <src> ...
1220 void
1221 vinum_mv(int argc, char *argv[], char *argv0[])
1223 int i; /* loop index */
1224 int srcobj;
1225 int destobj;
1226 enum objecttype srct;
1227 enum objecttype destt;
1228 int sdno;
1229 struct _ioctl_reply reply;
1230 struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply;
1232 if (argc < 2) {
1233 fprintf(stderr, "Usage: \tmove <dest> <src> ...\n");
1234 return;
1236 /* Get current config */
1237 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1238 perror("Cannot get vinum config\n");
1239 return;
1241 /* Get our destination */
1242 destobj = find_object(argv[0], &destt);
1243 if (destobj == -1) {
1244 fprintf(stderr, "Can't find %s\n", argv[0]);
1245 return;
1247 /* Verify that the target is a drive */
1248 if (destt != drive_object) {
1249 fprintf(stderr, "%s is not a drive\n", argv[0]);
1250 return;
1252 for (i = 1; i < argc; i++) { /* for all the sources */
1253 srcobj = find_object(argv[i], &srct);
1254 if (srcobj == -1) {
1255 fprintf(stderr, "Can't find %s\n", argv[i]);
1256 continue;
1258 msg->index = destobj;
1259 switch (srct) { /* Handle the source object */
1260 case drive_object: /* Move all subdisks on the drive to dst. */
1261 get_drive_info(&drive, srcobj); /* get info on drive */
1262 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) {
1263 get_sd_info(&sd, sdno);
1264 if (sd.driveno == srcobj) {
1265 msg->index = destobj;
1266 msg->otherobject = sd.sdno;
1267 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1268 fprintf(stderr,
1269 "Can't move %s (part of %s) to %s: %s (%d)\n",
1270 sd.name,
1271 drive.label.name,
1272 argv[0],
1273 strerror(reply.error),
1274 reply.error);
1277 break;
1279 case sd_object:
1280 msg->otherobject = srcobj;
1281 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1282 fprintf(stderr,
1283 "Can't move %s to %s: %s (%d)\n",
1284 sd.name,
1285 argv[0],
1286 strerror(reply.error),
1287 reply.error);
1288 break;
1290 case plex_object:
1291 get_plex_info(&plex, srcobj);
1292 for (sdno = 0; sdno < plex.subdisks; ++sdno) {
1293 get_plex_sd_info(&sd, plex.plexno, sdno);
1294 msg->index = destobj;
1295 msg->otherobject = sd.sdno;
1296 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1297 fprintf(stderr,
1298 "Can't move %s (part of %s) to %s: %s (%d)\n",
1299 sd.name,
1300 plex.name,
1301 argv[0],
1302 strerror(reply.error),
1303 reply.error);
1305 break;
1307 case volume_object:
1308 case invalid_object:
1309 default:
1310 fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]);
1311 break;
1313 if (reply.error)
1314 fprintf(stderr,
1315 "Can't move %s to %s: %s (%d)\n",
1316 argv[i],
1317 argv[0],
1318 strerror(reply.error),
1319 reply.error);
1321 checkupdates(); /* make sure we're updating */
1325 * Replace objects. Not implemented, may never be.
1327 void
1328 vinum_replace(int argc, char *argv[], char *argv0[])
1330 fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n");
1333 /* Primitive help function */
1334 void
1335 vinum_help(int argc, char *argv[], char *argv0[])
1337 char commands[] =
1339 "COMMANDS\n"
1340 "create [-f description-file]\n"
1341 " Create a volume as described in description-file\n"
1342 "attach plex volume [rename]\n"
1343 "attach subdisk plex [offset] [rename]\n"
1344 " Attach a plex to a volume, or a subdisk to a plex.\n"
1345 "debug\n"
1346 " Cause the volume manager to enter the kernel debugger.\n"
1347 "debug flags\n"
1348 " Set debugging flags.\n"
1349 "detach [plex | subdisk]\n"
1350 " Detach a plex or subdisk from the volume or plex to which it is\n"
1351 " attached.\n"
1352 "info [-v]\n"
1353 " List information about volume manager state.\n"
1354 "init [-v] [-w] plex\n"
1355 " Initialize a plex by writing zeroes to all its subdisks.\n"
1356 "label volume\n"
1357 " Create a volume label\n"
1358 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1359 " List information about specified objects\n"
1360 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1361 " List information about specified objects (alternative to\n"
1362 " list command)\n"
1363 "ld [-r] [-s] [-v] [-V] [volume]\n"
1364 " List information about drives\n"
1365 "ls [-r] [-s] [-v] [-V] [subdisk]\n"
1366 " List information about subdisks\n"
1367 "lp [-r] [-s] [-v] [-V] [plex]\n"
1368 " List information about plexes\n"
1369 "lv [-r] [-s] [-v] [-V] [volume]\n"
1370 " List information about volumes\n"
1371 "printconfig [file]\n"
1372 " Write a copy of the current configuration to file.\n"
1373 "makedev\n"
1374 " Remake the device nodes in " _PATH_DEV "vinum.\n"
1375 "move drive [subdisk | plex | drive]\n"
1376 " Move the subdisks of the specified object(s) to drive.\n"
1377 "quit\n"
1378 " Exit the vinum program when running in interactive mode. Nor-\n"
1379 " mally this would be done by entering the EOF character.\n"
1380 "read disk [disk...]\n"
1381 " Read the vinum configuration from the specified disks.\n"
1382 "rename [-r] [drive | subdisk | plex | volume] newname\n"
1383 " Change the name of the specified object.\n"
1384 "resetconfig\n"
1385 " Reset the complete vinum configuration.\n"
1386 "resetstats [-r] [volume | plex | subdisk]\n"
1387 " Reset statistisc counters for the specified objects, or for all\n"
1388 " objects if none are specified.\n"
1389 "rm [-f] [-r] volume | plex | subdisk\n"
1390 " Remove an object\n"
1391 "saveconfig\n"
1392 " Save vinum configuration to disk.\n"
1393 "setdaemon [value]\n"
1394 " Set daemon configuration.\n"
1395 "start\n"
1396 " Read configuration from all vinum drives.\n"
1397 "start [volume | plex | subdisk]\n"
1398 " Allow the system to access the objects\n"
1399 "stop [-f] [volume | plex | subdisk]\n"
1400 " Terminate access to the objects, or stop vinum if no parameters\n"
1401 " are specified.\n"
1403 puts(commands);
1406 /* Set daemon options.
1407 * XXX quick and dirty: use a bitmap, which requires
1408 * knowing which bit does what. FIXME */
1409 void
1410 vinum_setdaemon(int argc, char *argv[], char *argv0[])
1412 int options;
1414 switch (argc) {
1415 case 0:
1416 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1417 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1418 else
1419 printf("Options mask: %d\n", options);
1420 break;
1422 case 1:
1423 options = atoi(argv[0]);
1424 if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0)
1425 fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno);
1426 break;
1428 default:
1429 fprintf(stderr, "Usage: \tsetdaemon [<bitmask>]\n");
1431 checkupdates(); /* make sure we're updating */
1435 checkupdates(void)
1437 int options;
1439 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1440 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1441 if (options & daemon_noupdate) {
1442 fprintf(stderr, "*** Warning: configuration updates are disabled. ***\n");
1443 return 1;
1444 } else
1445 return 0;
1448 /* Save config info */
1449 void
1450 vinum_saveconfig(int argc, char *argv[], char *argv0[])
1452 int ioctltype;
1454 if (argc != 0) {
1455 printf("Usage: saveconfig\n");
1456 return;
1458 ioctltype = 1; /* user saveconfig */
1459 if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0)
1460 fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno);
1461 checkupdates(); /* make sure we're updating */
1465 * Create a volume name for the quick and dirty
1466 * commands. It will be of the form "vinum#",
1467 * where # is a small positive number.
1469 void
1470 genvolname(void)
1472 int v; /* volume number */
1473 static char volumename[MAXVOLNAME]; /* name to create */
1474 enum objecttype type;
1476 objectname = volumename; /* point to it */
1477 for (v = 0;; v++) {
1478 sprintf(objectname, "vinum%d", v); /* create the name */
1479 if (find_object(objectname, &type) == -1) /* does it exist? */
1480 return; /* no, it's ours */
1485 * Create a drive for the quick and dirty
1486 * commands. The name will be of the form
1487 * vinumdrive#, where # is a small positive
1488 * number. Return the name of the drive.
1490 struct drive *
1491 create_drive(char *devicename)
1493 int d; /* volume number */
1494 static char drivename[MAXDRIVENAME]; /* name to create */
1495 enum objecttype type;
1496 struct _ioctl_reply *reply;
1499 * We're never likely to get anything
1500 * like 10000 drives. The only reason for
1501 * this limit is to stop the thing
1502 * looping if we have a bug somewhere.
1504 for (d = 0; d < 100000; d++) { /* look for a free drive number */
1505 sprintf(drivename, "vinumdrive%d", d); /* create the name */
1506 if (find_object(drivename, &type) == -1) { /* does it exist? */
1507 char command[MAXDRIVENAME * 2];
1509 sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */
1510 if (vflag)
1511 printf("drive %s device %s\n", drivename, devicename); /* create a create command */
1512 ioctl(superdev, VINUM_CREATE, command);
1513 reply = (struct _ioctl_reply *) &command;
1514 if (reply->error != 0) { /* error in config */
1515 if (reply->msg[0])
1516 fprintf(stderr,
1517 "Can't create drive %s, device %s: %s\n",
1518 drivename,
1519 devicename,
1520 reply->msg);
1521 else
1522 fprintf(stderr,
1523 "Can't create drive %s, device %s: %s (%d)\n",
1524 drivename,
1525 devicename,
1526 strerror(reply->error),
1527 reply->error);
1528 longjmp(command_fail, -1); /* give up */
1530 find_object(drivename, &type);
1531 return &drive; /* return the name of the drive */
1534 fprintf(stderr, "Can't generate a drive name\n");
1535 /* NOTREACHED */
1536 return NULL;
1540 * Create a volume with a single concatenated plex from
1541 * as much space as we can get on the specified drives.
1542 * If the drives aren't Vinum drives, make them so.
1544 void
1545 vinum_concat(int argc, char *argv[], char *argv0[])
1547 int o; /* object number */
1548 char buffer[BUFSIZE];
1549 struct drive *drive; /* drive we're currently looking at */
1550 struct _ioctl_reply *reply;
1551 int ioctltype;
1552 int error;
1553 enum objecttype type;
1555 reply = (struct _ioctl_reply *) &buffer;
1556 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1557 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1558 return;
1560 if (!objectname) /* we need a name for our object */
1561 genvolname();
1562 sprintf(buffer, "volume %s", objectname);
1563 if (vflag)
1564 printf("volume %s\n", objectname);
1565 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1566 if (reply->error != 0) { /* error in config */
1567 if (reply->msg[0])
1568 fprintf(stderr,
1569 "Can't create volume %s: %s\n",
1570 objectname,
1571 reply->msg);
1572 else
1573 fprintf(stderr,
1574 "Can't create volume %s: %s (%d)\n",
1575 objectname,
1576 strerror(reply->error),
1577 reply->error);
1578 longjmp(command_fail, -1); /* give up */
1580 sprintf(buffer, "plex name %s.p0 org concat", objectname);
1581 if (vflag)
1582 printf(" plex name %s.p0 org concat\n", objectname);
1583 ioctl(superdev, VINUM_CREATE, buffer);
1584 if (reply->error != 0) { /* error in config */
1585 if (reply->msg[0])
1586 fprintf(stderr,
1587 "Can't create plex %s.p0: %s\n",
1588 objectname,
1589 reply->msg);
1590 else
1591 fprintf(stderr,
1592 "Can't create plex %s.p0: %s (%d)\n",
1593 objectname,
1594 strerror(reply->error),
1595 reply->error);
1596 longjmp(command_fail, -1); /* give up */
1598 for (o = 0; o < argc; o++) {
1599 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1600 drive = create_drive(argv[o]); /* create it */
1601 sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name);
1602 if (vflag)
1603 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name);
1604 ioctl(superdev, VINUM_CREATE, buffer);
1605 if (reply->error != 0) { /* error in config */
1606 if (reply->msg[0])
1607 fprintf(stderr,
1608 "Can't create subdisk %s.p0.s%d: %s\n",
1609 objectname,
1611 reply->msg);
1612 else
1613 fprintf(stderr,
1614 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1615 objectname,
1617 strerror(reply->error),
1618 reply->error);
1619 longjmp(command_fail, -1); /* give up */
1623 /* done, save the config */
1624 ioctltype = 0; /* saveconfig after update */
1625 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1626 if (error != 0)
1627 perror("Can't save Vinum config");
1628 find_object(objectname, &type); /* find the index of the volume */
1629 make_vol_dev(vol.volno, 1); /* and create the devices */
1630 if (vflag) {
1631 vflag--; /* XXX don't give too much detail */
1632 find_object(objectname, &type); /* point to the volume */
1633 vinum_lvi(vol.volno, 1); /* and print info about it */
1639 * Create a volume with a single striped plex from
1640 * as much space as we can get on the specified drives.
1641 * If the drives aren't Vinum drives, make them so.
1643 void
1644 vinum_stripe(int argc, char *argv[], char *argv0[])
1646 int o; /* object number */
1647 char buffer[BUFSIZE];
1648 struct drive *drive; /* drive we're currently looking at */
1649 struct _ioctl_reply *reply;
1650 int ioctltype;
1651 int error;
1652 enum objecttype type;
1653 off_t maxsize;
1654 int fe; /* freelist entry index */
1655 union freeunion {
1656 struct drive_freelist freelist;
1657 struct ferq { /* request to pass to ioctl */
1658 int driveno;
1659 int fe;
1660 } ferq;
1661 } freeunion;
1662 u_int64_t bigchunk; /* biggest chunk in freelist */
1664 maxsize = QUAD_MAX;
1665 reply = (struct _ioctl_reply *) &buffer;
1668 * First, check our drives.
1670 if (argc < 2) {
1671 fprintf(stderr, "You need at least two drives to create a striped plex\n");
1672 return;
1674 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1675 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1676 return;
1678 if (!objectname) /* we need a name for our object */
1679 genvolname();
1680 for (o = 0; o < argc; o++) {
1681 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1682 drive = create_drive(argv[o]); /* create it */
1683 /* Now find the largest chunk available on the drive */
1684 bigchunk = 0; /* ain't found nothin' yet */
1685 for (fe = 0; fe < drive->freelist_entries; fe++) {
1686 freeunion.ferq.driveno = drive->driveno;
1687 freeunion.ferq.fe = fe;
1688 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
1689 fprintf(stderr,
1690 "Can't get free list element %d: %s\n",
1692 strerror(errno));
1693 longjmp(command_fail, -1);
1695 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
1697 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1700 /* Now create the volume */
1701 sprintf(buffer, "volume %s", objectname);
1702 if (vflag)
1703 printf("volume %s\n", objectname);
1704 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1705 if (reply->error != 0) { /* error in config */
1706 if (reply->msg[0])
1707 fprintf(stderr,
1708 "Can't create volume %s: %s\n",
1709 objectname,
1710 reply->msg);
1711 else
1712 fprintf(stderr,
1713 "Can't create volume %s: %s (%d)\n",
1714 objectname,
1715 strerror(reply->error),
1716 reply->error);
1717 longjmp(command_fail, -1); /* give up */
1719 sprintf(buffer, "plex name %s.p0 org striped 256k", objectname);
1720 if (vflag)
1721 printf(" plex name %s.p0 org striped 256k\n", objectname);
1722 ioctl(superdev, VINUM_CREATE, buffer);
1723 if (reply->error != 0) { /* error in config */
1724 if (reply->msg[0])
1725 fprintf(stderr,
1726 "Can't create plex %s.p0: %s\n",
1727 objectname,
1728 reply->msg);
1729 else
1730 fprintf(stderr,
1731 "Can't create plex %s.p0: %s (%d)\n",
1732 objectname,
1733 strerror(reply->error),
1734 reply->error);
1735 longjmp(command_fail, -1); /* give up */
1737 for (o = 0; o < argc; o++) {
1738 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1739 sprintf(buffer,
1740 "sd name %s.p0.s%d drive %s size %lldb",
1741 objectname,
1743 drive->label.name,
1744 (long long) maxsize);
1745 if (vflag)
1746 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1747 objectname,
1749 drive->label.name,
1750 (long long) maxsize);
1751 ioctl(superdev, VINUM_CREATE, buffer);
1752 if (reply->error != 0) { /* error in config */
1753 if (reply->msg[0])
1754 fprintf(stderr,
1755 "Can't create subdisk %s.p0.s%d: %s\n",
1756 objectname,
1758 reply->msg);
1759 else
1760 fprintf(stderr,
1761 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1762 objectname,
1764 strerror(reply->error),
1765 reply->error);
1766 longjmp(command_fail, -1); /* give up */
1770 /* done, save the config */
1771 ioctltype = 0; /* saveconfig after update */
1772 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1773 if (error != 0)
1774 perror("Can't save Vinum config");
1775 find_object(objectname, &type); /* find the index of the volume */
1776 make_vol_dev(vol.volno, 1); /* and create the devices */
1777 if (vflag) {
1778 vflag--; /* XXX don't give too much detail */
1779 find_object(objectname, &type); /* point to the volume */
1780 vinum_lvi(vol.volno, 1); /* and print info about it */
1785 * Create a volume with a single RAID-4 plex from
1786 * as much space as we can get on the specified drives.
1787 * If the drives aren't Vinum drives, make them so.
1789 void
1790 vinum_raid4(int argc, char *argv[], char *argv0[])
1792 int o; /* object number */
1793 char buffer[BUFSIZE];
1794 struct drive *drive; /* drive we're currently looking at */
1795 struct _ioctl_reply *reply;
1796 int ioctltype;
1797 int error;
1798 enum objecttype type;
1799 off_t maxsize;
1800 int fe; /* freelist entry index */
1801 union freeunion {
1802 struct drive_freelist freelist;
1803 struct ferq { /* request to pass to ioctl */
1804 int driveno;
1805 int fe;
1806 } ferq;
1807 } freeunion;
1808 u_int64_t bigchunk; /* biggest chunk in freelist */
1810 maxsize = QUAD_MAX;
1811 reply = (struct _ioctl_reply *) &buffer;
1814 * First, check our drives.
1816 if (argc < 3) {
1817 fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n");
1818 return;
1820 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1821 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1822 return;
1824 if (!objectname) /* we need a name for our object */
1825 genvolname();
1826 for (o = 0; o < argc; o++) {
1827 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1828 drive = create_drive(argv[o]); /* create it */
1829 /* Now find the largest chunk available on the drive */
1830 bigchunk = 0; /* ain't found nothin' yet */
1831 for (fe = 0; fe < drive->freelist_entries; fe++) {
1832 freeunion.ferq.driveno = drive->driveno;
1833 freeunion.ferq.fe = fe;
1834 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
1835 fprintf(stderr,
1836 "Can't get free list element %d: %s\n",
1838 strerror(errno));
1839 longjmp(command_fail, -1);
1841 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
1843 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1846 /* Now create the volume */
1847 sprintf(buffer, "volume %s", objectname);
1848 if (vflag)
1849 printf("volume %s\n", objectname);
1850 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1851 if (reply->error != 0) { /* error in config */
1852 if (reply->msg[0])
1853 fprintf(stderr,
1854 "Can't create volume %s: %s\n",
1855 objectname,
1856 reply->msg);
1857 else
1858 fprintf(stderr,
1859 "Can't create volume %s: %s (%d)\n",
1860 objectname,
1861 strerror(reply->error),
1862 reply->error);
1863 longjmp(command_fail, -1); /* give up */
1865 sprintf(buffer, "plex name %s.p0 org raid4 256k", objectname);
1866 if (vflag)
1867 printf(" plex name %s.p0 org raid4 256k\n", objectname);
1868 ioctl(superdev, VINUM_CREATE, buffer);
1869 if (reply->error != 0) { /* error in config */
1870 if (reply->msg[0])
1871 fprintf(stderr,
1872 "Can't create plex %s.p0: %s\n",
1873 objectname,
1874 reply->msg);
1875 else
1876 fprintf(stderr,
1877 "Can't create plex %s.p0: %s (%d)\n",
1878 objectname,
1879 strerror(reply->error),
1880 reply->error);
1881 longjmp(command_fail, -1); /* give up */
1883 for (o = 0; o < argc; o++) {
1884 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1885 sprintf(buffer,
1886 "sd name %s.p0.s%d drive %s size %lldb",
1887 objectname,
1889 drive->label.name,
1890 (long long) maxsize);
1891 if (vflag)
1892 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1893 objectname,
1895 drive->label.name,
1896 (long long) maxsize);
1897 ioctl(superdev, VINUM_CREATE, buffer);
1898 if (reply->error != 0) { /* error in config */
1899 if (reply->msg[0])
1900 fprintf(stderr,
1901 "Can't create subdisk %s.p0.s%d: %s\n",
1902 objectname,
1904 reply->msg);
1905 else
1906 fprintf(stderr,
1907 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1908 objectname,
1910 strerror(reply->error),
1911 reply->error);
1912 longjmp(command_fail, -1); /* give up */
1916 /* done, save the config */
1917 ioctltype = 0; /* saveconfig after update */
1918 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1919 if (error != 0)
1920 perror("Can't save Vinum config");
1921 find_object(objectname, &type); /* find the index of the volume */
1922 make_vol_dev(vol.volno, 1); /* and create the devices */
1923 if (vflag) {
1924 vflag--; /* XXX don't give too much detail */
1925 find_object(objectname, &type); /* point to the volume */
1926 vinum_lvi(vol.volno, 1); /* and print info about it */
1931 * Create a volume with a single RAID-4 plex from
1932 * as much space as we can get on the specified drives.
1933 * If the drives aren't Vinum drives, make them so.
1935 void
1936 vinum_raid5(int argc, char *argv[], char *argv0[])
1938 int o; /* object number */
1939 char buffer[BUFSIZE];
1940 struct drive *drive; /* drive we're currently looking at */
1941 struct _ioctl_reply *reply;
1942 int ioctltype;
1943 int error;
1944 enum objecttype type;
1945 off_t maxsize;
1946 int fe; /* freelist entry index */
1947 union freeunion {
1948 struct drive_freelist freelist;
1949 struct ferq { /* request to pass to ioctl */
1950 int driveno;
1951 int fe;
1952 } ferq;
1953 } freeunion;
1954 u_int64_t bigchunk; /* biggest chunk in freelist */
1956 maxsize = QUAD_MAX;
1957 reply = (struct _ioctl_reply *) &buffer;
1960 * First, check our drives.
1962 if (argc < 3) {
1963 fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n");
1964 return;
1966 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1967 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1968 return;
1970 if (!objectname) /* we need a name for our object */
1971 genvolname();
1972 for (o = 0; o < argc; o++) {
1973 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1974 drive = create_drive(argv[o]); /* create it */
1975 /* Now find the largest chunk available on the drive */
1976 bigchunk = 0; /* ain't found nothin' yet */
1977 for (fe = 0; fe < drive->freelist_entries; fe++) {
1978 freeunion.ferq.driveno = drive->driveno;
1979 freeunion.ferq.fe = fe;
1980 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
1981 fprintf(stderr,
1982 "Can't get free list element %d: %s\n",
1984 strerror(errno));
1985 longjmp(command_fail, -1);
1987 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
1989 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1992 /* Now create the volume */
1993 sprintf(buffer, "volume %s", objectname);
1994 if (vflag)
1995 printf("volume %s\n", objectname);
1996 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1997 if (reply->error != 0) { /* error in config */
1998 if (reply->msg[0])
1999 fprintf(stderr,
2000 "Can't create volume %s: %s\n",
2001 objectname,
2002 reply->msg);
2003 else
2004 fprintf(stderr,
2005 "Can't create volume %s: %s (%d)\n",
2006 objectname,
2007 strerror(reply->error),
2008 reply->error);
2009 longjmp(command_fail, -1); /* give up */
2011 sprintf(buffer, "plex name %s.p0 org raid5 256k", objectname);
2012 if (vflag)
2013 printf(" plex name %s.p0 org raid5 256k\n", objectname);
2014 ioctl(superdev, VINUM_CREATE, buffer);
2015 if (reply->error != 0) { /* error in config */
2016 if (reply->msg[0])
2017 fprintf(stderr,
2018 "Can't create plex %s.p0: %s\n",
2019 objectname,
2020 reply->msg);
2021 else
2022 fprintf(stderr,
2023 "Can't create plex %s.p0: %s (%d)\n",
2024 objectname,
2025 strerror(reply->error),
2026 reply->error);
2027 longjmp(command_fail, -1); /* give up */
2029 for (o = 0; o < argc; o++) {
2030 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2031 sprintf(buffer,
2032 "sd name %s.p0.s%d drive %s size %lldb",
2033 objectname,
2035 drive->label.name,
2036 (long long) maxsize);
2037 if (vflag)
2038 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
2039 objectname,
2041 drive->label.name,
2042 (long long) maxsize);
2043 ioctl(superdev, VINUM_CREATE, buffer);
2044 if (reply->error != 0) { /* error in config */
2045 if (reply->msg[0])
2046 fprintf(stderr,
2047 "Can't create subdisk %s.p0.s%d: %s\n",
2048 objectname,
2050 reply->msg);
2051 else
2052 fprintf(stderr,
2053 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2054 objectname,
2056 strerror(reply->error),
2057 reply->error);
2058 longjmp(command_fail, -1); /* give up */
2062 /* done, save the config */
2063 ioctltype = 0; /* saveconfig after update */
2064 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2065 if (error != 0)
2066 perror("Can't save Vinum config");
2067 find_object(objectname, &type); /* find the index of the volume */
2068 make_vol_dev(vol.volno, 1); /* and create the devices */
2069 if (vflag) {
2070 vflag--; /* XXX don't give too much detail */
2071 find_object(objectname, &type); /* point to the volume */
2072 vinum_lvi(vol.volno, 1); /* and print info about it */
2077 * Create a volume with a two plexes from as much space
2078 * as we can get on the specified drives. If the
2079 * drives aren't Vinum drives, make them so.
2081 * The number of drives must be even, and at least 4
2082 * for a striped plex. Specify striped plexes with the
2083 * -s flag; otherwise they will be concatenated. It's
2084 * possible that the two plexes may differ in length.
2086 void
2087 vinum_mirror(int argc, char *argv[], char *argv0[])
2089 int o; /* object number */
2090 int p; /* plex number */
2091 char buffer[BUFSIZE];
2092 struct drive *drive; /* drive we're currently looking at */
2093 struct _ioctl_reply *reply;
2094 int ioctltype;
2095 int error;
2096 enum objecttype type;
2097 off_t maxsize[2]; /* maximum subdisk size for striped plexes */
2098 int fe; /* freelist entry index */
2099 union freeunion {
2100 struct drive_freelist freelist;
2101 struct ferq { /* request to pass to ioctl */
2102 int driveno;
2103 int fe;
2104 } ferq;
2105 } freeunion;
2106 u_int64_t bigchunk; /* biggest chunk in freelist */
2108 if (sflag) /* striped, */
2109 maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */
2110 else
2111 maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */
2113 reply = (struct _ioctl_reply *) &buffer;
2116 * First, check our drives.
2118 if (argc & 1) {
2119 fprintf(stderr, "You need an even number of drives to create a mirrored volume\n");
2120 return;
2122 if (sflag && (argc < 4)) {
2123 fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n");
2124 return;
2126 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
2127 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
2128 return;
2130 if (!objectname) /* we need a name for our object */
2131 genvolname();
2132 for (o = 0; o < argc; o++) {
2133 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
2134 drive = create_drive(argv[o]); /* create it */
2135 if (sflag) { /* striping, */
2136 /* Find the largest chunk available on the drive */
2137 bigchunk = 0; /* ain't found nothin' yet */
2138 for (fe = 0; fe < drive->freelist_entries; fe++) {
2139 freeunion.ferq.driveno = drive->driveno;
2140 freeunion.ferq.fe = fe;
2141 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
2142 fprintf(stderr,
2143 "Can't get free list element %d: %s\n",
2145 strerror(errno));
2146 longjmp(command_fail, -1);
2148 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
2150 maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */
2154 /* Now create the volume */
2155 sprintf(buffer, "volume %s setupstate", objectname);
2156 if (vflag)
2157 printf("volume %s setupstate\n", objectname);
2158 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
2159 if (reply->error != 0) { /* error in config */
2160 if (reply->msg[0])
2161 fprintf(stderr,
2162 "Can't create volume %s: %s\n",
2163 objectname,
2164 reply->msg);
2165 else
2166 fprintf(stderr,
2167 "Can't create volume %s: %s (%d)\n",
2168 objectname,
2169 strerror(reply->error),
2170 reply->error);
2171 longjmp(command_fail, -1); /* give up */
2173 for (p = 0; p < 2; p++) { /* create each plex */
2174 if (sflag) {
2175 sprintf(buffer, "plex name %s.p%d org striped 256k", objectname, p);
2176 if (vflag)
2177 printf(" plex name %s.p%d org striped 256k\n", objectname, p);
2178 } else { /* concat */
2179 sprintf(buffer, "plex name %s.p%d org concat", objectname, p);
2180 if (vflag)
2181 printf(" plex name %s.p%d org concat\n", objectname, p);
2183 ioctl(superdev, VINUM_CREATE, buffer);
2184 if (reply->error != 0) { /* error in config */
2185 if (reply->msg[0])
2186 fprintf(stderr,
2187 "Can't create plex %s.p%d: %s\n",
2188 objectname,
2190 reply->msg);
2191 else
2192 fprintf(stderr,
2193 "Can't create plex %s.p%d: %s (%d)\n",
2194 objectname,
2196 strerror(reply->error),
2197 reply->error);
2198 longjmp(command_fail, -1); /* give up */
2200 /* Now look at the subdisks */
2201 for (o = p; o < argc; o += 2) { /* every second one */
2202 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2203 sprintf(buffer,
2204 "sd name %s.p%d.s%d drive %s size %lldb",
2205 objectname,
2207 o >> 1,
2208 drive->label.name,
2209 (long long) maxsize[p]);
2210 if (vflag)
2211 printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
2212 objectname,
2214 o >> 1,
2215 drive->label.name,
2216 (long long) maxsize[p]);
2217 ioctl(superdev, VINUM_CREATE, buffer);
2218 if (reply->error != 0) { /* error in config */
2219 if (reply->msg[0])
2220 fprintf(stderr,
2221 "Can't create subdisk %s.p%d.s%d: %s\n",
2222 objectname,
2224 o >> 1,
2225 reply->msg);
2226 else
2227 fprintf(stderr,
2228 "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2229 objectname,
2231 o >> 1,
2232 strerror(reply->error),
2233 reply->error);
2234 longjmp(command_fail, -1); /* give up */
2239 /* done, save the config */
2240 ioctltype = 0; /* saveconfig after update */
2241 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2242 if (error != 0)
2243 perror("Can't save Vinum config");
2244 find_object(objectname, &type); /* find the index of the volume */
2245 make_vol_dev(vol.volno, 1); /* and create the devices */
2246 if (vflag) {
2247 vflag--; /* XXX don't give too much detail */
2248 sflag = 0; /* no stats, please */
2249 find_object(objectname, &type); /* point to the volume */
2250 vinum_lvi(vol.volno, 1); /* and print info about it */
2254 void
2255 vinum_readpol(int argc, char *argv[], char *argv0[])
2257 int object;
2258 struct _ioctl_reply reply;
2259 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2260 enum objecttype type;
2261 struct plex plex;
2262 struct volume vol;
2263 int plexno;
2265 if (argc == 0) { /* start everything */
2266 fprintf(stderr, "Usage: readpol <volume> <plex>|round\n");
2267 return;
2269 object = find_object(argv[1], &type); /* look for it */
2270 if (type != volume_object) {
2271 fprintf(stderr, "%s is not a volume\n", argv[1]);
2272 return;
2274 get_volume_info(&vol, object);
2275 if (strcmp(argv[2], "round")) { /* not 'round' */
2276 object = find_object(argv[2], &type); /* look for it */
2277 if (type != plex_object) {
2278 fprintf(stderr, "%s is not a plex\n", argv[2]);
2279 return;
2281 get_plex_info(&plex, object);
2282 plexno = plex.plexno;
2283 } else /* round */
2284 plexno = -1;
2286 /* Set the value */
2287 message->index = vol.volno;
2288 message->otherobject = plexno;
2289 if (ioctl(superdev, VINUM_READPOL, message) < 0)
2290 fprintf(stderr, "Can't set read policy: %s (%d)\n", strerror(errno), errno);
2291 if (vflag)
2292 vinum_lpi(plexno, recurse);
2296 * Brute force set state function. Don't look at
2297 * any dependencies, just do it.
2299 void
2300 vinum_setstate(int argc, char *argv[], char *argv0[])
2302 int object;
2303 struct _ioctl_reply reply;
2304 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2305 int index;
2306 enum objecttype type;
2307 int state;
2309 for (index = 1; index < argc; index++) {
2310 object = find_object(argv[index], &type); /* look for it */
2311 if (type == invalid_object)
2312 fprintf(stderr, "Can't find object: %s\n", argv[index]);
2313 else {
2314 int doit = 0; /* set to 1 if we pass our tests */
2315 switch (type) {
2316 case drive_object:
2317 state = DriveState(argv[0]); /* get the state */
2318 if (drive.state == state) /* already in that state */
2319 fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]);
2320 else
2321 doit = 1;
2322 break;
2324 case sd_object:
2325 state = SdState(argv[0]); /* get the state */
2326 if (sd.state == state) /* already in that state */
2327 fprintf(stderr, "%s is already %s\n", sd.name, argv[0]);
2328 else
2329 doit = 1;
2330 break;
2332 case plex_object:
2333 state = PlexState(argv[0]); /* get the state */
2334 if (plex.state == state) /* already in that state */
2335 fprintf(stderr, "%s is already %s\n", plex.name, argv[0]);
2336 else
2337 doit = 1;
2338 break;
2340 case volume_object:
2341 state = VolState(argv[0]); /* get the state */
2342 if (vol.state == state) /* already in that state */
2343 fprintf(stderr, "%s is already %s\n", vol.name, argv[0]);
2344 else
2345 doit = 1;
2346 break;
2348 default:
2349 state = 0; /* to keep the compiler happy */
2352 if (state == -1)
2353 fprintf(stderr, "Invalid state for object: %s\n", argv[0]);
2354 else if (doit) {
2355 message->index = object; /* pass object number */
2356 message->type = type; /* and type of object */
2357 message->state = state;
2358 message->force = force; /* don't force it, use a larger hammer */
2359 ioctl(superdev, VINUM_SETSTATE_FORCE, message);
2360 if (reply.error != 0)
2361 fprintf(stderr,
2362 "Can't start %s: %s (%d)\n",
2363 argv[index],
2364 reply.msg[0] ? reply.msg : strerror(reply.error),
2365 reply.error);
2366 if (Verbose)
2367 vinum_li(object, type);
2373 void
2374 vinum_checkparity(int argc, char *argv[], char *argv0[])
2376 Verbose = vflag; /* accept -v for verbose */
2377 if (argc == 0) /* no parameters? */
2378 fprintf(stderr, "Usage: checkparity object [object...]\n");
2379 else
2380 parityops(argc, argv, checkparity);
2383 void
2384 vinum_rebuildparity(int argc, char *argv[], char *argv0[])
2386 if (argc == 0) /* no parameters? */
2387 fprintf(stderr, "Usage: rebuildparity object [object...]\n");
2388 else
2389 parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity);
2393 * Common code for rebuildparity and checkparity.
2394 * We bend the meanings of some flags here:
2396 * -v: Report incorrect parity on rebuild.
2397 * -V: Show running count of position being checked.
2398 * -f: Start from beginning of the plex.
2400 void
2401 parityops(int argc, char *argv[], enum parityop op)
2403 int object;
2404 struct plex plex;
2405 struct _ioctl_reply reply;
2406 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2407 int index;
2408 enum objecttype type;
2409 char *msg;
2410 off_t block;
2412 if (op == checkparity)
2413 msg = "Checking";
2414 else
2415 msg = "Rebuilding";
2416 for (index = 0; index < argc; index++) {
2417 object = find_object(argv[index], &type); /* look for it */
2418 if (type != plex_object)
2419 fprintf(stderr, "%s is not a plex\n", argv[index]);
2420 else {
2421 get_plex_info(&plex, object);
2422 if (!isparity((&plex)))
2423 fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]);
2424 else {
2425 do {
2426 message->index = object; /* pass object number */
2427 message->type = type; /* and type of object */
2428 message->op = op; /* what to do */
2429 if (force)
2430 message->offset = 0; /* start at the beginning */
2431 else
2432 message->offset = plex.checkblock; /* continue where we left off */
2433 force = 0; /* don't reset after the first time */
2434 ioctl(superdev, VINUM_PARITYOP, message);
2435 get_plex_info(&plex, object);
2436 if (Verbose) {
2437 block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1);
2438 if (block != 0)
2439 printf("\r%s at %s (%d%%) ",
2440 msg,
2441 roughlength(block, 1),
2442 ((int) (block * 100 / plex.length) >> DEV_BSHIFT));
2443 if ((reply.error == EAGAIN)
2444 && (reply.msg[0])) /* got a comment back */
2445 fputs(reply.msg, stderr); /* show it */
2446 fflush(stdout);
2449 while (reply.error == EAGAIN);
2450 if (reply.error != 0) {
2451 if (reply.msg[0])
2452 fputs(reply.msg, stderr);
2453 else
2454 fprintf(stderr,
2455 "%s failed: %s\n",
2456 msg,
2457 strerror(reply.error));
2458 } else if (Verbose) {
2459 if (op == checkparity)
2460 fprintf(stderr, "%s has correct parity\n", argv[index]);
2461 else
2462 fprintf(stderr, "Rebuilt parity on %s\n", argv[index]);
2469 /* Local Variables: */
2470 /* fill-column: 50 */
2471 /* End: */