Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / sbin / vinum / commands.c
blob6dd7ad9470cece6ae0ad1817d7834d0cf82115fe
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.10 2008/06/05 18:06:31 swildner 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/readline.h>
63 #include <devstat.h>
65 static void dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen);
67 void
68 vinum_create(int argc, char *argv[], char *arg0[])
70 int error;
71 FILE *dfd; /* file descriptor for the config file */
72 char buffer[BUFSIZE]; /* read config file in here */
73 char commandline[BUFSIZE]; /* issue command from here */
74 struct _ioctl_reply *reply;
75 int ioctltype; /* for ioctl call */
76 char tempfile[PATH_MAX]; /* name of temp file for direct editing */
77 char *file; /* file to read */
78 FILE *tf; /* temp file */
80 if (argc == 0) { /* no args, */
81 char *editor; /* editor to start */
82 int status;
84 editor = getenv("EDITOR");
85 if (editor == NULL)
86 editor = "/usr/bin/vi";
87 sprintf(tempfile, "/var/tmp/" VINUMMOD ".create.%d", getpid()); /* create a temp file */
88 tf = fopen(tempfile, "w"); /* open it */
89 if (tf == NULL) {
90 fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno));
91 return;
93 printconfig(tf, "# "); /* and put the current config it */
94 fclose(tf);
95 sprintf(commandline, "%s %s", editor, tempfile); /* create an edit command */
96 status = system(commandline); /* do it */
97 if (status != 0) {
98 fprintf(stderr, "Can't edit config: status %d\n", status);
99 return;
101 file = tempfile;
102 } else if (argc == 1)
103 file = argv[0];
104 else {
105 fprintf(stderr, "Expecting 1 parameter, not %d\n", argc);
106 return;
108 reply = (struct _ioctl_reply *) &buffer;
109 dfd = fopen(file, "r");
110 if (dfd == NULL) { /* no go */
111 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
112 return;
114 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
115 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
116 return;
118 file_line = 0; /* start with line 1 */
119 /* Parse the configuration, and add it to the global configuration */
120 for (;;) { /* love this style(9) */
121 char *configline;
123 configline = fgets(buffer, BUFSIZE, dfd);
125 if (configline == NULL) {
126 if (ferror(dfd))
127 perror("Can't read config file");
128 break;
130 if (hist)
131 fprintf(hist, "%s", buffer);
132 file_line++; /* count the lines */
133 if (vflag)
134 printf("%4d: %s", file_line, buffer);
135 strcpy(commandline, buffer); /* make a copy */
136 ioctl(superdev, VINUM_CREATE, buffer);
137 if (reply->error != 0) { /* error in config */
138 if (!vflag) /* print this line anyway */
139 printf("%4d: %s", file_line, commandline);
140 fprintf(stdout, "** %d %s: %s\n",
141 file_line,
142 reply->msg,
143 strerror(reply->error));
146 * XXX at the moment, we reset the config
147 * lock on error, so try to get it again.
148 * If we fail, don't cry again.
150 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) /* can't get config? */
151 return;
154 fclose(dfd); /* done with the config file */
155 ioctltype = 0; /* saveconfig after update */
156 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
157 if (error != 0)
158 perror("Can't save Vinum config");
159 make_devices();
160 listconfig();
161 checkupdates(); /* make sure we're updating */
164 /* Read vinum config from a disk */
165 void
166 vinum_read(int argc, char *argv[], char *arg0[])
168 int error;
169 char buffer[BUFSIZE]; /* read config file in here */
170 struct _ioctl_reply *reply;
171 int i;
173 reply = (struct _ioctl_reply *) &buffer;
174 if (argc < 1) { /* wrong arg count */
175 fprintf(stderr, "Usage: read drive [drive ...]\n");
176 return;
178 strcpy(buffer, "read ");
179 for (i = 0; i < argc; i++) { /* each drive name */
180 strcat(buffer, argv[i]);
181 strcat(buffer, " ");
184 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
185 fprintf(stderr, "Can't configure: %s (%d)\n", strerror(errno), errno);
186 return;
188 ioctl(superdev, VINUM_CREATE, &buffer);
189 if (reply->error != 0) { /* error in config */
190 fprintf(stdout, "** %s: %s\n", reply->msg, strerror(reply->error));
191 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
192 if (error != 0)
193 perror("Can't save Vinum config");
194 } else {
195 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
196 if (error != 0)
197 perror("Can't save Vinum config");
198 make_devices();
200 checkupdates(); /* make sure we're updating */
203 #ifdef VINUMDEBUG
204 void
205 vinum_debug(int argc, char *argv[], char *arg0[])
207 struct debuginfo info;
209 if (argc > 0) {
210 info.param = atoi(argv[0]);
211 info.changeit = 1;
212 } else {
213 info.changeit = 0;
214 sleep(2); /* give a chance to leave the window */
216 ioctl(superdev, VINUM_DEBUG, (caddr_t) & info);
218 #endif
220 void
221 vinum_modify(int argc, char *argv[], char *arg0[])
223 fprintf(stderr, "Modify command is currently not implemented\n");
224 checkupdates(); /* make sure we're updating */
227 void
228 vinum_set(int argc, char *argv[], char *arg0[])
230 fprintf(stderr, "set is not implemented yet\n");
233 void
234 vinum_rm(int argc, char *argv[], char *arg0[])
236 int object;
237 struct _ioctl_reply reply;
238 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
240 if (argc == 0) /* start everything */
241 fprintf(stderr, "Usage: rm object [object...]\n");
242 else { /* start specified objects */
243 int index;
244 enum objecttype type;
246 for (index = 0; index < argc; index++) {
247 object = find_object(argv[index], &type); /* look for it */
248 if (type == invalid_object)
249 fprintf(stderr, "Can't find object: %s\n", argv[index]);
250 else {
251 message->index = object; /* pass object number */
252 message->type = type; /* and type of object */
253 message->force = force; /* do we want to force the operation? */
254 message->recurse = recurse; /* do we want to remove subordinates? */
255 ioctl(superdev, VINUM_REMOVE, message);
256 if (reply.error != 0) {
257 fprintf(stderr,
258 "Can't remove %s: %s (%d)\n",
259 argv[index],
260 reply.msg[0] ? reply.msg : strerror(reply.error),
261 reply.error);
262 } else if (vflag)
263 fprintf(stderr, "%s removed\n", argv[index]);
266 checkupdates(); /* make sure we're updating */
270 void
271 vinum_resetconfig(int argc, char *argv[], char *arg0[])
273 char reply[32];
274 int error;
276 if (! isatty (STDIN_FILENO)) {
277 fprintf (stderr, "Please enter this command from a tty device\n");
278 return;
280 printf(" WARNING! This command will completely wipe out your vinum configuration.\n"
281 " All data will be lost. If you really want to do this, enter the text\n\n"
282 " NO FUTURE\n"
283 " Enter text -> ");
284 fgets(reply, sizeof(reply), stdin);
285 if (strcmp(reply, "NO FUTURE\n")) /* changed his mind */
286 printf("\n No change\n");
287 else {
288 error = ioctl(superdev, VINUM_RESETCONFIG, NULL); /* trash config on disk */
289 if (error) {
290 if (errno == EBUSY)
291 fprintf(stderr, "Can't reset configuration: objects are in use\n");
292 else
293 perror("Can't find vinum config");
294 } else {
295 make_devices(); /* recreate the /dev/vinum hierarchy */
296 printf("\b Vinum configuration obliterated\n");
297 start_daemon(); /* then restart the daemon */
300 checkupdates(); /* make sure we're updating */
303 /* Initialize subdisks */
304 void
305 vinum_init(int argc, char *argv[], char *arg0[])
307 if (argc > 0) { /* initialize plexes */
308 int objindex;
309 int objno;
310 enum objecttype type; /* type returned */
312 if (hist)
313 fflush(hist); /* don't let all the kids do it. */
314 for (objindex = 0; objindex < argc; objindex++) {
315 objno = find_object(argv[objindex], &type); /* find the object */
316 if (objno < 0)
317 printf("Can't find %s\n", argv[objindex]);
318 else {
319 switch (type) {
320 case volume_object:
321 initvol(objno);
322 break;
324 case plex_object:
325 initplex(objno, argv[objindex]);
326 break;
328 case sd_object:
329 initsd(objno, dowait);
330 break;
332 default:
333 printf("Can't initialize %s: wrong object type\n", argv[objindex]);
334 break;
339 checkupdates(); /* make sure we're updating */
342 void
343 initvol(int volno)
345 printf("Initializing volumes is not implemented yet\n");
348 void
349 initplex(int plexno, char *name)
351 int sdno;
352 int plexfh = 0; /* file handle for plex */
353 pid_t pid;
354 char filename[MAXPATHLEN]; /* create a file name here */
356 /* Variables for use by children */
357 int failed = 0; /* set if a child dies badly */
359 sprintf(filename, VINUM_DIR "/plex/%s", name);
360 if ((plexfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* got a plex, open it */
362 * We don't actually write anything to the
363 * plex. We open it to ensure that nobody
364 * else tries to open it while we initialize
365 * its subdisks.
367 fprintf(stderr, "can't open plex %s: %s\n", filename, strerror(errno));
368 return;
370 if (dowait == 0) {
371 pid = fork(); /* into the background with you */
372 if (pid != 0) { /* I'm the parent, or we failed */
373 if (pid < 0) /* failure */
374 printf("Couldn't fork: %s", strerror(errno));
375 close(plexfh); /* we don't need this any more */
376 return;
380 * If we get here, we're either the first-level
381 * child (if we're not waiting) or we're going
382 * to wait.
384 for (sdno = 0; sdno < plex.subdisks; sdno++) { /* initialize each subdisk */
385 get_plex_sd_info(&sd, plexno, sdno);
386 initsd(sd.sdno, 0);
388 /* Now wait for them to complete */
389 while (1) {
390 int status;
391 pid = wait(&status);
392 if (((int) pid == -1)
393 && (errno == ECHILD)) /* all gone */
394 break;
395 if (WEXITSTATUS(status) != 0) { /* oh, oh */
396 printf("child %d exited with status 0x%x\n", pid, WEXITSTATUS(status));
397 failed++;
400 if (failed == 0) {
401 #if 0
402 message->index = plexno; /* pass object number */
403 message->type = plex_object; /* and type of object */
404 message->state = object_up;
405 message->force = 1; /* insist */
406 ioctl(superdev, VINUM_SETSTATE, message);
407 #endif
408 syslog(LOG_INFO | LOG_KERN, "plex %s initialized", plex.name);
409 } else
410 syslog(LOG_ERR | LOG_KERN, "couldn't initialize plex %s, %d processes died",
411 plex.name,
412 failed);
413 if (dowait == 0) /* we're the waiting child, */
414 exit(0); /* we've done our dash */
417 /* Initialize a subdisk. */
418 void
419 initsd(int sdno, int dowait)
421 pid_t pid;
422 struct _ioctl_reply reply;
423 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
424 char filename[MAXPATHLEN]; /* create a file name here */
426 /* Variables for use by children */
427 int sdfh; /* and for subdisk */
428 int initsize; /* actual size to write */
429 int64_t sdsize; /* size of subdisk */
431 if (dowait == 0) {
432 pid = fork(); /* into the background with you */
433 if (pid > 0) /* I'm the parent */
434 return;
435 else if (pid < 0) { /* failure */
436 printf("couldn't fork for subdisk %d: %s", sdno, strerror(errno));
437 return;
440 if (SSize != 0) { /* specified a size for init */
441 if (SSize < 512)
442 SSize <<= DEV_BSHIFT;
443 initsize = min(SSize, MAXPLEXINITSIZE);
444 } else
445 initsize = PLEXINITSIZE;
446 openlog("vinum", LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
447 get_sd_info(&sd, sdno);
448 sdsize = sd.sectors * DEV_BSIZE; /* size of subdisk in bytes */
449 sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
450 setproctitle("initializing %s", filename); /* show what we're doing */
451 syslog(LOG_INFO | LOG_KERN, "initializing subdisk %s", filename);
452 if ((sdfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* no go */
453 syslog(LOG_ERR | LOG_KERN,
454 "can't open subdisk %s: %s",
455 filename,
456 strerror(errno));
457 exit(1);
459 /* Set the subdisk in initializing state */
460 message->index = sd.sdno; /* pass object number */
461 message->type = sd_object; /* and type of object */
462 message->state = object_initializing;
463 message->verify = vflag; /* verify what we write? */
464 message->force = 1; /* insist */
465 ioctl(superdev, VINUM_SETSTATE, message);
466 if ((SSize > 0) /* specified a size for init */
467 &&(SSize < 512))
468 SSize <<= DEV_BSHIFT;
469 if (reply.error) {
470 fprintf(stderr,
471 "Can't initialize %s: %s (%d)\n",
472 filename,
473 strerror(reply.error),
474 reply.error);
475 exit(1);
476 } else {
477 do {
478 if (interval) /* pause between copies */
479 usleep(interval * 1000);
480 message->index = sd.sdno; /* pass object number */
481 message->type = sd_object; /* and type of object */
482 message->state = object_up;
483 message->verify = vflag; /* verify what we write? */
484 message->blocksize = SSize;
485 ioctl(superdev, VINUM_SETSTATE, message);
487 while (reply.error == EAGAIN); /* until we're done */
488 if (reply.error) {
489 fprintf(stderr,
490 "Can't initialize %s: %s (%d)\n",
491 filename,
492 strerror(reply.error),
493 reply.error);
494 get_sd_info(&sd, sdno);
495 if (sd.state != sd_up)
496 /* Set the subdisk down */
497 message->index = sd.sdno; /* pass object number */
498 message->type = sd_object; /* and type of object */
499 message->state = object_down;
500 message->verify = vflag; /* verify what we write? */
501 message->force = 1; /* insist */
502 ioctl(superdev, VINUM_SETSTATE, message);
505 printf("subdisk %s initialized\n", filename);
506 if (!dowait)
507 exit(0);
510 void
511 vinum_start(int argc, char *argv[], char *arg0[])
513 int object;
514 struct _ioctl_reply reply;
515 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
517 if (argc == 0) { /* start everything */
518 int devs = getnumdevs();
519 struct statinfo statinfo;
520 char *namelist;
521 char *enamelist; /* end of name list */
522 int i;
523 char **token; /* list of tokens */
524 int tokens; /* and their number */
526 bzero(&statinfo, sizeof(struct statinfo));
527 statinfo.dinfo = malloc(devs * sizeof(struct statinfo));
528 namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8));
529 token = malloc((devs + 1) * sizeof(char *));
530 if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) {
531 fprintf(stderr, "Can't allocate memory for drive list\n");
532 return;
534 bzero(statinfo.dinfo, sizeof(struct devinfo));
536 tokens = 0; /* no tokens yet */
537 if (getdevs(&statinfo) < 0) { /* find out what devices we have */
538 perror("Can't get device list");
539 return;
541 namelist[0] = '\0'; /* start with empty namelist */
542 enamelist = namelist; /* point to the end of the list */
544 for (i = 0; i < devs; i++) {
545 struct devstat *stat = &statinfo.dinfo->devices[i];
547 if ((((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */
548 || ((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) /* storage array */
549 &&((stat->device_type & DEVSTAT_TYPE_IF_MASK) != DEVSTAT_TYPE_IF_OTHER) /* and not md */
550 &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */
551 &&((stat->device_name[0] != '\0'))) { /* and it has a name */
552 sprintf(enamelist, "%s%s%d", _PATH_DEV, stat->device_name, stat->unit_number);
553 token[tokens] = enamelist; /* point to it */
554 tokens++; /* one more token */
555 enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */
558 free(statinfo.dinfo); /* don't need the list any more */
559 vinum_read(tokens, token, &token[0]); /* start the system */
560 free(namelist);
561 free(token);
562 list_defective_objects(); /* and list anything that's down */
563 } else { /* start specified objects */
564 int index;
565 enum objecttype type;
567 for (index = 0; index < argc; index++) {
568 object = find_object(argv[index], &type); /* look for it */
569 if (type == invalid_object)
570 fprintf(stderr, "Can't find object: %s\n", argv[index]);
571 else {
572 int doit = 0; /* set to 1 if we pass our tests */
573 switch (type) {
574 case drive_object:
575 if (drive.state == drive_up) /* already up */
576 fprintf(stderr, "%s is already up\n", drive.label.name);
577 else
578 doit = 1;
579 break;
581 case sd_object:
582 if (sd.state == sd_up) /* already up */
583 fprintf(stderr, "%s is already up\n", sd.name);
584 else
585 doit = 1;
586 break;
588 case plex_object:
589 if (plex.state == plex_up) /* already up */
590 fprintf(stderr, "%s is already up\n", plex.name);
591 else {
592 int sdno;
595 * First, see if we can bring it up
596 * just by asking. This might happen
597 * if somebody has used setupstate on
598 * the subdisks. If we don't do this,
599 * we'll return success, but the plex
600 * won't have changed state. Note
601 * that we don't check for errors
602 * here.
604 message->index = plex.plexno; /* pass object number */
605 message->type = plex_object; /* it's a plex */
606 message->state = object_up;
607 message->force = 0; /* don't force it */
608 ioctl(superdev, VINUM_SETSTATE, message);
609 for (sdno = 0; sdno < plex.subdisks; sdno++) {
610 get_plex_sd_info(&sd, object, sdno);
611 if ((sd.state >= sd_empty)
612 && (sd.state <= sd_reviving)) { /* candidate for start */
613 message->index = sd.sdno; /* pass object number */
614 message->type = sd_object; /* it's a subdisk */
615 message->state = object_up;
616 message->force = force; /* don't force it, use a larger hammer */
619 * We don't do any checking here.
620 * The kernel module has a better
621 * understanding of these things,
622 * let it do it.
624 if (SSize != 0) { /* specified a size for init */
625 if (SSize < 512)
626 SSize <<= DEV_BSHIFT;
627 message->blocksize = SSize;
628 } else
629 message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
630 ioctl(superdev, VINUM_SETSTATE, message);
631 if (reply.error != 0) {
632 if (reply.error == EAGAIN) /* we're reviving */
633 continue_revive(sd.sdno);
634 else
635 fprintf(stderr,
636 "Can't start %s: %s (%d)\n",
637 sd.name,
638 reply.msg[0] ? reply.msg : strerror(reply.error),
639 reply.error);
641 if (Verbose)
642 vinum_lsi(sd.sdno, 0);
646 break;
648 case volume_object:
649 if (vol.state == volume_up) /* already up */
650 fprintf(stderr, "%s is already up\n", vol.name);
651 else
652 doit = 1;
653 break;
655 default:
656 break;
659 if (doit) {
660 message->index = object; /* pass object number */
661 message->type = type; /* and type of object */
662 message->state = object_up;
663 message->force = force; /* don't force it, use a larger hammer */
666 * We don't do any checking here.
667 * The kernel module has a better
668 * understanding of these things,
669 * let it do it.
671 if (SSize != 0) { /* specified a size for init or revive */
672 if (SSize < 512)
673 SSize <<= DEV_BSHIFT;
674 message->blocksize = SSize;
675 } else
676 message->blocksize = 0;
677 ioctl(superdev, VINUM_SETSTATE, message);
678 if (reply.error != 0) {
679 if ((reply.error == EAGAIN) /* we're reviving */
680 &&(type == sd_object))
681 continue_revive(object);
682 else
683 fprintf(stderr,
684 "Can't start %s: %s (%d)\n",
685 argv[index],
686 reply.msg[0] ? reply.msg : strerror(reply.error),
687 reply.error);
689 if (Verbose)
690 vinum_li(object, type);
695 checkupdates(); /* make sure we're updating */
698 void
699 vinum_stop(int argc, char *argv[], char *arg0[])
701 int object;
702 struct _ioctl_reply reply;
703 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
705 if (checkupdates() && (!force)) /* not updating? */
706 return;
707 message->force = force; /* should we force the transition? */
708 if (argc == 0) { /* stop vinum */
709 int fileid = 0; /* ID of Vinum kld */
711 close(superdev); /* we can't stop if we have vinum open */
712 sleep(1); /* wait for the daemon to let go */
713 fileid = kldfind(VINUMMOD);
714 if ((fileid < 0) /* no go */
715 ||(kldunload(fileid) < 0))
716 perror("Can't unload " VINUMMOD);
717 else {
718 fprintf(stderr, VINUMMOD " unloaded\n");
719 exit(0);
722 /* If we got here, the stop failed. Reopen the superdevice. */
723 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */
724 if (superdev < 0) {
725 perror("Can't reopen Vinum superdevice");
726 exit(1);
728 } else { /* stop specified objects */
729 int i;
730 enum objecttype type;
732 for (i = 0; i < argc; i++) {
733 object = find_object(argv[i], &type); /* look for it */
734 if (type == invalid_object)
735 fprintf(stderr, "Can't find object: %s\n", argv[i]);
736 else {
737 message->index = object; /* pass object number */
738 message->type = type; /* and type of object */
739 message->state = object_down;
740 ioctl(superdev, VINUM_SETSTATE, message);
741 if (reply.error != 0)
742 fprintf(stderr,
743 "Can't stop %s: %s (%d)\n",
744 argv[i],
745 reply.msg[0] ? reply.msg : strerror(reply.error),
746 reply.error);
747 if (Verbose)
748 vinum_li(object, type);
754 void
755 vinum_label(int argc, char *argv[], char *arg0[])
757 int object;
758 struct _ioctl_reply reply;
759 int *message = (int *) &reply;
761 if (argc == 0) /* start everything */
762 fprintf(stderr, "label: please specify one or more volume names\n");
763 else { /* start specified objects */
764 int i;
765 enum objecttype type;
767 for (i = 0; i < argc; i++) {
768 object = find_object(argv[i], &type); /* look for it */
769 if (type == invalid_object)
770 fprintf(stderr, "Can't find object: %s\n", argv[i]);
771 else if (type != volume_object) /* it exists, but it isn't a volume */
772 fprintf(stderr, "%s is not a volume\n", argv[i]);
773 else {
774 message[0] = object; /* pass object number */
775 ioctl(superdev, VINUM_LABEL, message);
776 if (reply.error != 0)
777 fprintf(stderr,
778 "Can't label %s: %s (%d)\n",
779 argv[i],
780 reply.msg[0] ? reply.msg : strerror(reply.error),
781 reply.error);
782 if (Verbose)
783 vinum_li(object, type);
787 checkupdates(); /* not updating? */
790 void
791 reset_volume_stats(int volno, int recurse)
793 struct vinum_ioctl_msg msg;
794 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
796 msg.index = volno;
797 msg.type = volume_object;
798 /* XXX get these numbers right if we ever
799 * actually return errors */
800 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
801 fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg);
802 longjmp(command_fail, -1);
803 } else if (recurse) {
804 struct volume vol;
805 int plexno;
807 get_volume_info(&vol, volno);
808 for (plexno = 0; plexno < vol.plexes; plexno++)
809 reset_plex_stats(vol.plex[plexno], recurse);
813 void
814 reset_plex_stats(int plexno, int recurse)
816 struct vinum_ioctl_msg msg;
817 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
819 msg.index = plexno;
820 msg.type = plex_object;
821 /* XXX get these numbers right if we ever
822 * actually return errors */
823 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
824 fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg);
825 longjmp(command_fail, -1);
826 } else if (recurse) {
827 struct plex plex;
828 struct sd sd;
829 int sdno;
831 get_plex_info(&plex, plexno);
832 for (sdno = 0; sdno < plex.subdisks; sdno++) {
833 get_plex_sd_info(&sd, plex.plexno, sdno);
834 reset_sd_stats(sd.sdno, recurse);
839 void
840 reset_sd_stats(int sdno, int recurse)
842 struct vinum_ioctl_msg msg;
843 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
845 msg.index = sdno;
846 msg.type = sd_object;
847 /* XXX get these numbers right if we ever
848 * actually return errors */
849 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
850 fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg);
851 longjmp(command_fail, -1);
852 } else if (recurse) {
853 get_sd_info(&sd, sdno); /* get the info */
854 reset_drive_stats(sd.driveno); /* and clear the drive */
858 void
859 reset_drive_stats(int driveno)
861 struct vinum_ioctl_msg msg;
862 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
864 msg.index = driveno;
865 msg.type = drive_object;
866 /* XXX get these numbers right if we ever
867 * actually return errors */
868 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
869 fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg);
870 longjmp(command_fail, -1);
874 void
875 vinum_resetstats(int argc, char *argv[], char *argv0[])
877 int i;
878 int objno;
879 enum objecttype type;
881 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
882 perror("Can't get vinum config");
883 return;
885 if (argc == 0) {
886 for (objno = 0; objno < vinum_conf.volumes_allocated; objno++)
887 reset_volume_stats(objno, 1); /* clear everything recursively */
888 } else {
889 for (i = 0; i < argc; i++) {
890 objno = find_object(argv[i], &type);
891 if (objno >= 0) { /* not invalid */
892 switch (type) {
893 case drive_object:
894 reset_drive_stats(objno);
895 break;
897 case sd_object:
898 reset_sd_stats(objno, recurse);
899 break;
901 case plex_object:
902 reset_plex_stats(objno, recurse);
903 break;
905 case volume_object:
906 reset_volume_stats(objno, recurse);
907 break;
909 case invalid_object: /* can't get this */
910 break;
917 /* Attach a subdisk to a plex, or a plex to a volume.
918 * attach subdisk plex [offset] [rename]
919 * attach plex volume [rename]
921 void
922 vinum_attach(int argc, char *argv[], char *argv0[])
924 int i;
925 enum objecttype supertype;
926 struct vinum_ioctl_msg msg;
927 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
928 const char *objname = argv[0];
929 const char *supername = argv[1];
930 int sdno = -1;
931 int plexno = -1;
932 char oldname[MAXNAME + 8];
933 char newname[MAXNAME + 8];
934 int rename = 0; /* set if we want to rename the object */
936 if ((argc < 2)
937 || (argc > 4)) {
938 fprintf(stderr,
939 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
940 "\tattach <plex> <volume> [rename]\n");
941 return;
943 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
944 perror("Can't get vinum config");
945 return;
947 msg.index = find_object(objname, &msg.type); /* find the object to attach */
948 msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */
949 msg.force = force; /* did we specify the use of force? */
950 msg.recurse = recurse;
951 msg.offset = -1; /* and no offset */
953 for (i = 2; i < argc; i++) {
954 if (!strcmp(argv[i], "rename")) {
955 rename = 1;
956 msg.rename = 1; /* do renaming */
957 } else if (!isdigit(argv[i][0])) { /* not an offset */
958 fprintf(stderr, "Unknown attribute: %s\n", supername);
959 return;
960 } else
961 msg.offset = sizespec(argv[i]);
964 switch (msg.type) {
965 case sd_object:
966 find_object(argv[1], &supertype);
967 if (supertype != plex_object) { /* huh? */
968 fprintf(stderr, "%s can only be attached to a plex\n", objname);
969 return;
971 if ((plex.organization != plex_concat) /* not a cat plex, */
972 &&(!force)) {
973 fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization));
974 return;
976 sdno = msg.index; /* note the subdisk number for later */
977 break;
979 case plex_object:
980 find_object(argv[1], &supertype);
981 if (supertype != volume_object) { /* huh? */
982 fprintf(stderr, "%s can only be attached to a volume\n", objname);
983 return;
985 break;
987 case volume_object:
988 case drive_object:
989 fprintf(stderr, "Can only attach subdisks and plexes\n");
990 return;
992 default:
993 fprintf(stderr, "%s is not a Vinum object\n", objname);
994 return;
997 ioctl(superdev, VINUM_ATTACH, &msg);
998 if (reply->error != 0) {
999 if (reply->error == EAGAIN) /* reviving */
1000 continue_revive(sdno); /* continue the revive */
1001 else
1002 fprintf(stderr,
1003 "Can't attach %s to %s: %s (%d)\n",
1004 objname,
1005 supername,
1006 reply->msg[0] ? reply->msg : strerror(reply->error),
1007 reply->error);
1009 if (rename) {
1010 struct sd;
1011 struct plex;
1012 struct volume;
1014 /* we've overwritten msg with the
1015 * ioctl reply, start again */
1016 msg.index = find_object(objname, &msg.type); /* find the object to rename */
1017 switch (msg.type) {
1018 case sd_object:
1019 get_sd_info(&sd, msg.index);
1020 get_plex_info(&plex, sd.plexno);
1021 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1022 if (plex.sdnos[sdno] == msg.index) /* found our subdisk */
1023 break;
1025 sprintf(newname, "%s.s%d", plex.name, sdno);
1026 sprintf(oldname, "%s", sd.name);
1027 vinum_rename_2(oldname, newname);
1028 break;
1030 case plex_object:
1031 get_plex_info(&plex, msg.index);
1032 get_volume_info(&vol, plex.volno);
1033 for (plexno = 0; plexno < vol.plexes; plexno++) {
1034 if (vol.plex[plexno] == msg.index) /* found our subdisk */
1035 break;
1037 sprintf(newname, "%s.p%d", vol.name, plexno);
1038 sprintf(oldname, "%s", plex.name);
1039 vinum_rename_2(oldname, newname); /* this may recurse */
1040 break;
1042 default: /* can't get here */
1043 break;
1046 checkupdates(); /* make sure we're updating */
1049 /* Detach a subdisk from a plex, or a plex from a volume.
1050 * detach subdisk plex [rename]
1051 * detach plex volume [rename]
1053 void
1054 vinum_detach(int argc, char *argv[], char *argv0[])
1056 struct vinum_ioctl_msg msg;
1057 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
1059 if ((argc < 1)
1060 || (argc > 2)) {
1061 fprintf(stderr,
1062 "Usage: \tdetach <subdisk> [rename]\n"
1063 "\tdetach <plex> [rename]\n");
1064 return;
1066 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1067 perror("Can't get vinum config");
1068 return;
1070 msg.index = find_object(argv[0], &msg.type); /* find the object to detach */
1071 msg.force = force; /* did we specify the use of force? */
1072 msg.rename = 0; /* don't specify new name */
1073 msg.recurse = recurse; /* but recurse if we have to */
1075 /* XXX are we going to keep this?
1076 * Don't document it yet, since the
1077 * kernel side of things doesn't
1078 * implement it */
1079 if (argc == 2) {
1080 if (!strcmp(argv[1], "rename"))
1081 msg.rename = 1; /* do renaming */
1082 else {
1083 fprintf(stderr, "Unknown attribute: %s\n", argv[1]);
1084 return;
1087 if ((msg.type != sd_object)
1088 && (msg.type != plex_object)) {
1089 fprintf(stderr, "Can only detach subdisks and plexes\n");
1090 return;
1092 ioctl(superdev, VINUM_DETACH, &msg);
1093 if (reply->error != 0)
1094 fprintf(stderr,
1095 "Can't detach %s: %s (%d)\n",
1096 argv[0],
1097 reply->msg[0] ? reply->msg : strerror(reply->error),
1098 reply->error);
1099 checkupdates(); /* make sure we're updating */
1102 static void
1103 dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen)
1105 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
1107 if (strlen(name) > maxlen) {
1108 fprintf(stderr, "%s is too long\n", name);
1109 return;
1111 strcpy(msg->newname, name);
1112 ioctl(superdev, VINUM_RENAME, msg);
1113 if (reply->error != 0)
1114 fprintf(stderr,
1115 "Can't rename %s to %s: %s (%d)\n",
1116 oldname,
1117 name,
1118 reply->msg[0] ? reply->msg : strerror(reply->error),
1119 reply->error);
1122 /* Rename an object:
1123 * rename <object> "newname"
1125 void
1126 vinum_rename_2(char *oldname, char *newname)
1128 struct vinum_rename_msg msg;
1129 int volno;
1130 int plexno;
1132 msg.index = find_object(oldname, &msg.type); /* find the object to rename */
1133 msg.recurse = recurse;
1135 /* Ugh. Determine how long the name may be */
1136 switch (msg.type) {
1137 case drive_object:
1138 dorename(&msg, oldname, newname, MAXDRIVENAME);
1139 break;
1141 case sd_object:
1142 dorename(&msg, oldname, newname, MAXSDNAME);
1143 break;
1145 case plex_object:
1146 plexno = msg.index;
1147 dorename(&msg, oldname, newname, MAXPLEXNAME);
1148 if (recurse) {
1149 int sdno;
1151 get_plex_info(&plex, plexno); /* find out who we are */
1152 msg.type = sd_object;
1153 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1154 char sdname[MAXPLEXNAME + 8];
1156 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1157 sprintf(sdname, "%s.s%d", newname, sdno);
1158 msg.index = sd.sdno; /* number of the subdisk */
1159 dorename(&msg, sd.name, sdname, MAXSDNAME);
1162 break;
1164 case volume_object:
1165 volno = msg.index;
1166 dorename(&msg, oldname, newname, MAXVOLNAME);
1167 if (recurse) {
1168 int sdno;
1169 int plexno;
1171 get_volume_info(&vol, volno); /* find out who we are */
1172 for (plexno = 0; plexno < vol.plexes; plexno++) {
1173 char plexname[MAXVOLNAME + 8];
1175 msg.type = plex_object;
1176 sprintf(plexname, "%s.p%d", newname, plexno);
1177 msg.index = vol.plex[plexno]; /* number of the plex */
1178 dorename(&msg, plex.name, plexname, MAXPLEXNAME);
1179 get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */
1180 msg.type = sd_object;
1181 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1182 char sdname[MAXPLEXNAME + 8];
1184 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1185 sprintf(sdname, "%s.s%d", plexname, sdno);
1186 msg.index = sd.sdno; /* number of the subdisk */
1187 dorename(&msg, sd.name, sdname, MAXSDNAME);
1191 break;
1193 default:
1194 fprintf(stderr, "%s is not a Vinum object\n", oldname);
1195 return;
1199 void
1200 vinum_rename(int argc, char *argv[], char *argv0[])
1202 if (argc != 2) {
1203 fprintf(stderr, "Usage: \trename <object> <new name>\n");
1204 return;
1206 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1207 perror("Can't get vinum config");
1208 return;
1210 vinum_rename_2(argv[0], argv[1]);
1211 checkupdates(); /* make sure we're updating */
1215 * Move objects:
1217 * mv <dest> <src> ...
1219 void
1220 vinum_mv(int argc, char *argv[], char *argv0[])
1222 int i; /* loop index */
1223 int srcobj;
1224 int destobj;
1225 enum objecttype srct;
1226 enum objecttype destt;
1227 int sdno;
1228 struct _ioctl_reply reply;
1229 struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply;
1231 if (argc < 2) {
1232 fprintf(stderr, "Usage: \tmove <dest> <src> ...\n");
1233 return;
1235 /* Get current config */
1236 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1237 perror("Cannot get vinum config\n");
1238 return;
1240 /* Get our destination */
1241 destobj = find_object(argv[0], &destt);
1242 if (destobj == -1) {
1243 fprintf(stderr, "Can't find %s\n", argv[0]);
1244 return;
1246 /* Verify that the target is a drive */
1247 if (destt != drive_object) {
1248 fprintf(stderr, "%s is not a drive\n", argv[0]);
1249 return;
1251 for (i = 1; i < argc; i++) { /* for all the sources */
1252 srcobj = find_object(argv[i], &srct);
1253 if (srcobj == -1) {
1254 fprintf(stderr, "Can't find %s\n", argv[i]);
1255 continue;
1257 msg->index = destobj;
1258 switch (srct) { /* Handle the source object */
1259 case drive_object: /* Move all subdisks on the drive to dst. */
1260 get_drive_info(&drive, srcobj); /* get info on drive */
1261 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) {
1262 get_sd_info(&sd, sdno);
1263 if (sd.driveno == srcobj) {
1264 msg->index = destobj;
1265 msg->otherobject = sd.sdno;
1266 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1267 fprintf(stderr,
1268 "Can't move %s (part of %s) to %s: %s (%d)\n",
1269 sd.name,
1270 drive.label.name,
1271 argv[0],
1272 strerror(reply.error),
1273 reply.error);
1276 break;
1278 case sd_object:
1279 msg->otherobject = srcobj;
1280 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1281 fprintf(stderr,
1282 "Can't move %s to %s: %s (%d)\n",
1283 sd.name,
1284 argv[0],
1285 strerror(reply.error),
1286 reply.error);
1287 break;
1289 case plex_object:
1290 get_plex_info(&plex, srcobj);
1291 for (sdno = 0; sdno < plex.subdisks; ++sdno) {
1292 get_plex_sd_info(&sd, plex.plexno, sdno);
1293 msg->index = destobj;
1294 msg->otherobject = sd.sdno;
1295 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1296 fprintf(stderr,
1297 "Can't move %s (part of %s) to %s: %s (%d)\n",
1298 sd.name,
1299 plex.name,
1300 argv[0],
1301 strerror(reply.error),
1302 reply.error);
1304 break;
1306 case volume_object:
1307 case invalid_object:
1308 default:
1309 fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]);
1310 break;
1312 if (reply.error)
1313 fprintf(stderr,
1314 "Can't move %s to %s: %s (%d)\n",
1315 argv[i],
1316 argv[0],
1317 strerror(reply.error),
1318 reply.error);
1320 checkupdates(); /* make sure we're updating */
1324 * Replace objects. Not implemented, may never be.
1326 void
1327 vinum_replace(int argc, char *argv[], char *argv0[])
1329 fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n");
1332 /* Primitive help function */
1333 void
1334 vinum_help(int argc, char *argv[], char *argv0[])
1336 char commands[] =
1338 "COMMANDS\n"
1339 "create [-f description-file]\n"
1340 " Create a volume as described in description-file\n"
1341 "attach plex volume [rename]\n"
1342 "attach subdisk plex [offset] [rename]\n"
1343 " Attach a plex to a volume, or a subdisk to a plex.\n"
1344 "debug\n"
1345 " Cause the volume manager to enter the kernel debugger.\n"
1346 "debug flags\n"
1347 " Set debugging flags.\n"
1348 "detach [plex | subdisk]\n"
1349 " Detach a plex or subdisk from the volume or plex to which it is\n"
1350 " attached.\n"
1351 "info [-v]\n"
1352 " List information about volume manager state.\n"
1353 "init [-v] [-w] plex\n"
1354 " Initialize a plex by writing zeroes to all its subdisks.\n"
1355 "label volume\n"
1356 " Create a volume label\n"
1357 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1358 " List information about specified objects\n"
1359 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1360 " List information about specified objects (alternative to\n"
1361 " list command)\n"
1362 "ld [-r] [-s] [-v] [-V] [volume]\n"
1363 " List information about drives\n"
1364 "ls [-r] [-s] [-v] [-V] [subdisk]\n"
1365 " List information about subdisks\n"
1366 "lp [-r] [-s] [-v] [-V] [plex]\n"
1367 " List information about plexes\n"
1368 "lv [-r] [-s] [-v] [-V] [volume]\n"
1369 " List information about volumes\n"
1370 "printconfig [file]\n"
1371 " Write a copy of the current configuration to file.\n"
1372 "makedev\n"
1373 " Remake the device nodes in " _PATH_DEV "vinum.\n"
1374 "move drive [subdisk | plex | drive]\n"
1375 " Move the subdisks of the specified object(s) to drive.\n"
1376 "quit\n"
1377 " Exit the vinum program when running in interactive mode. Nor-\n"
1378 " mally this would be done by entering the EOF character.\n"
1379 "read disk [disk...]\n"
1380 " Read the vinum configuration from the specified disks.\n"
1381 "rename [-r] [drive | subdisk | plex | volume] newname\n"
1382 " Change the name of the specified object.\n"
1383 "resetconfig\n"
1384 " Reset the complete vinum configuration.\n"
1385 "resetstats [-r] [volume | plex | subdisk]\n"
1386 " Reset statistisc counters for the specified objects, or for all\n"
1387 " objects if none are specified.\n"
1388 "rm [-f] [-r] volume | plex | subdisk\n"
1389 " Remove an object\n"
1390 "saveconfig\n"
1391 " Save vinum configuration to disk.\n"
1392 "setdaemon [value]\n"
1393 " Set daemon configuration.\n"
1394 "start\n"
1395 " Read configuration from all vinum drives.\n"
1396 "start [volume | plex | subdisk]\n"
1397 " Allow the system to access the objects\n"
1398 "stop [-f] [volume | plex | subdisk]\n"
1399 " Terminate access to the objects, or stop vinum if no parameters\n"
1400 " are specified.\n"
1402 puts(commands);
1405 /* Set daemon options.
1406 * XXX quick and dirty: use a bitmap, which requires
1407 * knowing which bit does what. FIXME */
1408 void
1409 vinum_setdaemon(int argc, char *argv[], char *argv0[])
1411 int options;
1413 switch (argc) {
1414 case 0:
1415 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1416 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1417 else
1418 printf("Options mask: %d\n", options);
1419 break;
1421 case 1:
1422 options = atoi(argv[0]);
1423 if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0)
1424 fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno);
1425 break;
1427 default:
1428 fprintf(stderr, "Usage: \tsetdaemon [<bitmask>]\n");
1430 checkupdates(); /* make sure we're updating */
1434 checkupdates(void)
1436 int options;
1438 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1439 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1440 if (options & daemon_noupdate) {
1441 fprintf(stderr, "*** Warning: configuration updates are disabled. ***\n");
1442 return 1;
1443 } else
1444 return 0;
1447 /* Save config info */
1448 void
1449 vinum_saveconfig(int argc, char *argv[], char *argv0[])
1451 int ioctltype;
1453 if (argc != 0) {
1454 printf("Usage: saveconfig\n");
1455 return;
1457 ioctltype = 1; /* user saveconfig */
1458 if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0)
1459 fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno);
1460 checkupdates(); /* make sure we're updating */
1464 * Create a volume name for the quick and dirty
1465 * commands. It will be of the form "vinum#",
1466 * where # is a small positive number.
1468 void
1469 genvolname(void)
1471 int v; /* volume number */
1472 static char volumename[MAXVOLNAME]; /* name to create */
1473 enum objecttype type;
1475 objectname = volumename; /* point to it */
1476 for (v = 0;; v++) {
1477 sprintf(objectname, "vinum%d", v); /* create the name */
1478 if (find_object(objectname, &type) == -1) /* does it exist? */
1479 return; /* no, it's ours */
1484 * Create a drive for the quick and dirty
1485 * commands. The name will be of the form
1486 * vinumdrive#, where # is a small positive
1487 * number. Return the name of the drive.
1489 struct drive *
1490 create_drive(char *devicename)
1492 int d; /* volume number */
1493 static char drivename[MAXDRIVENAME]; /* name to create */
1494 enum objecttype type;
1495 struct _ioctl_reply *reply;
1498 * We're never likely to get anything
1499 * like 10000 drives. The only reason for
1500 * this limit is to stop the thing
1501 * looping if we have a bug somewhere.
1503 for (d = 0; d < 100000; d++) { /* look for a free drive number */
1504 sprintf(drivename, "vinumdrive%d", d); /* create the name */
1505 if (find_object(drivename, &type) == -1) { /* does it exist? */
1506 char command[MAXDRIVENAME * 2];
1508 sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */
1509 if (vflag)
1510 printf("drive %s device %s\n", drivename, devicename); /* create a create command */
1511 ioctl(superdev, VINUM_CREATE, command);
1512 reply = (struct _ioctl_reply *) &command;
1513 if (reply->error != 0) { /* error in config */
1514 if (reply->msg[0])
1515 fprintf(stderr,
1516 "Can't create drive %s, device %s: %s\n",
1517 drivename,
1518 devicename,
1519 reply->msg);
1520 else
1521 fprintf(stderr,
1522 "Can't create drive %s, device %s: %s (%d)\n",
1523 drivename,
1524 devicename,
1525 strerror(reply->error),
1526 reply->error);
1527 longjmp(command_fail, -1); /* give up */
1529 find_object(drivename, &type);
1530 return &drive; /* return the name of the drive */
1533 fprintf(stderr, "Can't generate a drive name\n");
1534 /* NOTREACHED */
1535 return NULL;
1539 * Create a volume with a single concatenated plex from
1540 * as much space as we can get on the specified drives.
1541 * If the drives aren't Vinum drives, make them so.
1543 void
1544 vinum_concat(int argc, char *argv[], char *argv0[])
1546 int o; /* object number */
1547 char buffer[BUFSIZE];
1548 struct drive *drive; /* drive we're currently looking at */
1549 struct _ioctl_reply *reply;
1550 int ioctltype;
1551 int error;
1552 enum objecttype type;
1554 reply = (struct _ioctl_reply *) &buffer;
1555 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1556 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1557 return;
1559 if (!objectname) /* we need a name for our object */
1560 genvolname();
1561 sprintf(buffer, "volume %s", objectname);
1562 if (vflag)
1563 printf("volume %s\n", objectname);
1564 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1565 if (reply->error != 0) { /* error in config */
1566 if (reply->msg[0])
1567 fprintf(stderr,
1568 "Can't create volume %s: %s\n",
1569 objectname,
1570 reply->msg);
1571 else
1572 fprintf(stderr,
1573 "Can't create volume %s: %s (%d)\n",
1574 objectname,
1575 strerror(reply->error),
1576 reply->error);
1577 longjmp(command_fail, -1); /* give up */
1579 sprintf(buffer, "plex name %s.p0 org concat", objectname);
1580 if (vflag)
1581 printf(" plex name %s.p0 org concat\n", objectname);
1582 ioctl(superdev, VINUM_CREATE, buffer);
1583 if (reply->error != 0) { /* error in config */
1584 if (reply->msg[0])
1585 fprintf(stderr,
1586 "Can't create plex %s.p0: %s\n",
1587 objectname,
1588 reply->msg);
1589 else
1590 fprintf(stderr,
1591 "Can't create plex %s.p0: %s (%d)\n",
1592 objectname,
1593 strerror(reply->error),
1594 reply->error);
1595 longjmp(command_fail, -1); /* give up */
1597 for (o = 0; o < argc; o++) {
1598 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1599 drive = create_drive(argv[o]); /* create it */
1600 sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name);
1601 if (vflag)
1602 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name);
1603 ioctl(superdev, VINUM_CREATE, buffer);
1604 if (reply->error != 0) { /* error in config */
1605 if (reply->msg[0])
1606 fprintf(stderr,
1607 "Can't create subdisk %s.p0.s%d: %s\n",
1608 objectname,
1610 reply->msg);
1611 else
1612 fprintf(stderr,
1613 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1614 objectname,
1616 strerror(reply->error),
1617 reply->error);
1618 longjmp(command_fail, -1); /* give up */
1622 /* done, save the config */
1623 ioctltype = 0; /* saveconfig after update */
1624 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1625 if (error != 0)
1626 perror("Can't save Vinum config");
1627 find_object(objectname, &type); /* find the index of the volume */
1628 make_vol_dev(vol.volno, 1); /* and create the devices */
1629 if (vflag) {
1630 vflag--; /* XXX don't give too much detail */
1631 find_object(objectname, &type); /* point to the volume */
1632 vinum_lvi(vol.volno, 1); /* and print info about it */
1638 * Create a volume with a single striped plex from
1639 * as much space as we can get on the specified drives.
1640 * If the drives aren't Vinum drives, make them so.
1642 void
1643 vinum_stripe(int argc, char *argv[], char *argv0[])
1645 int o; /* object number */
1646 char buffer[BUFSIZE];
1647 struct drive *drive; /* drive we're currently looking at */
1648 struct _ioctl_reply *reply;
1649 int ioctltype;
1650 int error;
1651 enum objecttype type;
1652 off_t maxsize;
1653 int fe; /* freelist entry index */
1654 union freeunion {
1655 struct drive_freelist freelist;
1656 struct ferq { /* request to pass to ioctl */
1657 int driveno;
1658 int fe;
1659 } ferq;
1660 } freeunion;
1661 u_int64_t bigchunk; /* biggest chunk in freelist */
1663 maxsize = QUAD_MAX;
1664 reply = (struct _ioctl_reply *) &buffer;
1667 * First, check our drives.
1669 if (argc < 2) {
1670 fprintf(stderr, "You need at least two drives to create a striped plex\n");
1671 return;
1673 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1674 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1675 return;
1677 if (!objectname) /* we need a name for our object */
1678 genvolname();
1679 for (o = 0; o < argc; o++) {
1680 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1681 drive = create_drive(argv[o]); /* create it */
1682 /* Now find the largest chunk available on the drive */
1683 bigchunk = 0; /* ain't found nothin' yet */
1684 for (fe = 0; fe < drive->freelist_entries; fe++) {
1685 freeunion.ferq.driveno = drive->driveno;
1686 freeunion.ferq.fe = fe;
1687 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
1688 fprintf(stderr,
1689 "Can't get free list element %d: %s\n",
1691 strerror(errno));
1692 longjmp(command_fail, -1);
1694 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
1696 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1699 /* Now create the volume */
1700 sprintf(buffer, "volume %s", objectname);
1701 if (vflag)
1702 printf("volume %s\n", objectname);
1703 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1704 if (reply->error != 0) { /* error in config */
1705 if (reply->msg[0])
1706 fprintf(stderr,
1707 "Can't create volume %s: %s\n",
1708 objectname,
1709 reply->msg);
1710 else
1711 fprintf(stderr,
1712 "Can't create volume %s: %s (%d)\n",
1713 objectname,
1714 strerror(reply->error),
1715 reply->error);
1716 longjmp(command_fail, -1); /* give up */
1718 sprintf(buffer, "plex name %s.p0 org striped 256k", objectname);
1719 if (vflag)
1720 printf(" plex name %s.p0 org striped 256k\n", objectname);
1721 ioctl(superdev, VINUM_CREATE, buffer);
1722 if (reply->error != 0) { /* error in config */
1723 if (reply->msg[0])
1724 fprintf(stderr,
1725 "Can't create plex %s.p0: %s\n",
1726 objectname,
1727 reply->msg);
1728 else
1729 fprintf(stderr,
1730 "Can't create plex %s.p0: %s (%d)\n",
1731 objectname,
1732 strerror(reply->error),
1733 reply->error);
1734 longjmp(command_fail, -1); /* give up */
1736 for (o = 0; o < argc; o++) {
1737 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1738 sprintf(buffer,
1739 "sd name %s.p0.s%d drive %s size %lldb",
1740 objectname,
1742 drive->label.name,
1743 (long long) maxsize);
1744 if (vflag)
1745 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1746 objectname,
1748 drive->label.name,
1749 (long long) maxsize);
1750 ioctl(superdev, VINUM_CREATE, buffer);
1751 if (reply->error != 0) { /* error in config */
1752 if (reply->msg[0])
1753 fprintf(stderr,
1754 "Can't create subdisk %s.p0.s%d: %s\n",
1755 objectname,
1757 reply->msg);
1758 else
1759 fprintf(stderr,
1760 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1761 objectname,
1763 strerror(reply->error),
1764 reply->error);
1765 longjmp(command_fail, -1); /* give up */
1769 /* done, save the config */
1770 ioctltype = 0; /* saveconfig after update */
1771 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1772 if (error != 0)
1773 perror("Can't save Vinum config");
1774 find_object(objectname, &type); /* find the index of the volume */
1775 make_vol_dev(vol.volno, 1); /* and create the devices */
1776 if (vflag) {
1777 vflag--; /* XXX don't give too much detail */
1778 find_object(objectname, &type); /* point to the volume */
1779 vinum_lvi(vol.volno, 1); /* and print info about it */
1784 * Create a volume with a single RAID-4 plex from
1785 * as much space as we can get on the specified drives.
1786 * If the drives aren't Vinum drives, make them so.
1788 void
1789 vinum_raid4(int argc, char *argv[], char *argv0[])
1791 int o; /* object number */
1792 char buffer[BUFSIZE];
1793 struct drive *drive; /* drive we're currently looking at */
1794 struct _ioctl_reply *reply;
1795 int ioctltype;
1796 int error;
1797 enum objecttype type;
1798 off_t maxsize;
1799 int fe; /* freelist entry index */
1800 union freeunion {
1801 struct drive_freelist freelist;
1802 struct ferq { /* request to pass to ioctl */
1803 int driveno;
1804 int fe;
1805 } ferq;
1806 } freeunion;
1807 u_int64_t bigchunk; /* biggest chunk in freelist */
1809 maxsize = QUAD_MAX;
1810 reply = (struct _ioctl_reply *) &buffer;
1813 * First, check our drives.
1815 if (argc < 3) {
1816 fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n");
1817 return;
1819 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1820 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1821 return;
1823 if (!objectname) /* we need a name for our object */
1824 genvolname();
1825 for (o = 0; o < argc; o++) {
1826 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1827 drive = create_drive(argv[o]); /* create it */
1828 /* Now find the largest chunk available on the drive */
1829 bigchunk = 0; /* ain't found nothin' yet */
1830 for (fe = 0; fe < drive->freelist_entries; fe++) {
1831 freeunion.ferq.driveno = drive->driveno;
1832 freeunion.ferq.fe = fe;
1833 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
1834 fprintf(stderr,
1835 "Can't get free list element %d: %s\n",
1837 strerror(errno));
1838 longjmp(command_fail, -1);
1840 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
1842 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1845 /* Now create the volume */
1846 sprintf(buffer, "volume %s", objectname);
1847 if (vflag)
1848 printf("volume %s\n", objectname);
1849 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1850 if (reply->error != 0) { /* error in config */
1851 if (reply->msg[0])
1852 fprintf(stderr,
1853 "Can't create volume %s: %s\n",
1854 objectname,
1855 reply->msg);
1856 else
1857 fprintf(stderr,
1858 "Can't create volume %s: %s (%d)\n",
1859 objectname,
1860 strerror(reply->error),
1861 reply->error);
1862 longjmp(command_fail, -1); /* give up */
1864 sprintf(buffer, "plex name %s.p0 org raid4 256k", objectname);
1865 if (vflag)
1866 printf(" plex name %s.p0 org raid4 256k\n", objectname);
1867 ioctl(superdev, VINUM_CREATE, buffer);
1868 if (reply->error != 0) { /* error in config */
1869 if (reply->msg[0])
1870 fprintf(stderr,
1871 "Can't create plex %s.p0: %s\n",
1872 objectname,
1873 reply->msg);
1874 else
1875 fprintf(stderr,
1876 "Can't create plex %s.p0: %s (%d)\n",
1877 objectname,
1878 strerror(reply->error),
1879 reply->error);
1880 longjmp(command_fail, -1); /* give up */
1882 for (o = 0; o < argc; o++) {
1883 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1884 sprintf(buffer,
1885 "sd name %s.p0.s%d drive %s size %lldb",
1886 objectname,
1888 drive->label.name,
1889 (long long) maxsize);
1890 if (vflag)
1891 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1892 objectname,
1894 drive->label.name,
1895 (long long) maxsize);
1896 ioctl(superdev, VINUM_CREATE, buffer);
1897 if (reply->error != 0) { /* error in config */
1898 if (reply->msg[0])
1899 fprintf(stderr,
1900 "Can't create subdisk %s.p0.s%d: %s\n",
1901 objectname,
1903 reply->msg);
1904 else
1905 fprintf(stderr,
1906 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1907 objectname,
1909 strerror(reply->error),
1910 reply->error);
1911 longjmp(command_fail, -1); /* give up */
1915 /* done, save the config */
1916 ioctltype = 0; /* saveconfig after update */
1917 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1918 if (error != 0)
1919 perror("Can't save Vinum config");
1920 find_object(objectname, &type); /* find the index of the volume */
1921 make_vol_dev(vol.volno, 1); /* and create the devices */
1922 if (vflag) {
1923 vflag--; /* XXX don't give too much detail */
1924 find_object(objectname, &type); /* point to the volume */
1925 vinum_lvi(vol.volno, 1); /* and print info about it */
1930 * Create a volume with a single RAID-4 plex from
1931 * as much space as we can get on the specified drives.
1932 * If the drives aren't Vinum drives, make them so.
1934 void
1935 vinum_raid5(int argc, char *argv[], char *argv0[])
1937 int o; /* object number */
1938 char buffer[BUFSIZE];
1939 struct drive *drive; /* drive we're currently looking at */
1940 struct _ioctl_reply *reply;
1941 int ioctltype;
1942 int error;
1943 enum objecttype type;
1944 off_t maxsize;
1945 int fe; /* freelist entry index */
1946 union freeunion {
1947 struct drive_freelist freelist;
1948 struct ferq { /* request to pass to ioctl */
1949 int driveno;
1950 int fe;
1951 } ferq;
1952 } freeunion;
1953 u_int64_t bigchunk; /* biggest chunk in freelist */
1955 maxsize = QUAD_MAX;
1956 reply = (struct _ioctl_reply *) &buffer;
1959 * First, check our drives.
1961 if (argc < 3) {
1962 fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n");
1963 return;
1965 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1966 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1967 return;
1969 if (!objectname) /* we need a name for our object */
1970 genvolname();
1971 for (o = 0; o < argc; o++) {
1972 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1973 drive = create_drive(argv[o]); /* create it */
1974 /* Now find the largest chunk available on the drive */
1975 bigchunk = 0; /* ain't found nothin' yet */
1976 for (fe = 0; fe < drive->freelist_entries; fe++) {
1977 freeunion.ferq.driveno = drive->driveno;
1978 freeunion.ferq.fe = fe;
1979 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
1980 fprintf(stderr,
1981 "Can't get free list element %d: %s\n",
1983 strerror(errno));
1984 longjmp(command_fail, -1);
1986 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
1988 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1991 /* Now create the volume */
1992 sprintf(buffer, "volume %s", objectname);
1993 if (vflag)
1994 printf("volume %s\n", objectname);
1995 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1996 if (reply->error != 0) { /* error in config */
1997 if (reply->msg[0])
1998 fprintf(stderr,
1999 "Can't create volume %s: %s\n",
2000 objectname,
2001 reply->msg);
2002 else
2003 fprintf(stderr,
2004 "Can't create volume %s: %s (%d)\n",
2005 objectname,
2006 strerror(reply->error),
2007 reply->error);
2008 longjmp(command_fail, -1); /* give up */
2010 sprintf(buffer, "plex name %s.p0 org raid5 256k", objectname);
2011 if (vflag)
2012 printf(" plex name %s.p0 org raid5 256k\n", objectname);
2013 ioctl(superdev, VINUM_CREATE, buffer);
2014 if (reply->error != 0) { /* error in config */
2015 if (reply->msg[0])
2016 fprintf(stderr,
2017 "Can't create plex %s.p0: %s\n",
2018 objectname,
2019 reply->msg);
2020 else
2021 fprintf(stderr,
2022 "Can't create plex %s.p0: %s (%d)\n",
2023 objectname,
2024 strerror(reply->error),
2025 reply->error);
2026 longjmp(command_fail, -1); /* give up */
2028 for (o = 0; o < argc; o++) {
2029 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2030 sprintf(buffer,
2031 "sd name %s.p0.s%d drive %s size %lldb",
2032 objectname,
2034 drive->label.name,
2035 (long long) maxsize);
2036 if (vflag)
2037 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
2038 objectname,
2040 drive->label.name,
2041 (long long) maxsize);
2042 ioctl(superdev, VINUM_CREATE, buffer);
2043 if (reply->error != 0) { /* error in config */
2044 if (reply->msg[0])
2045 fprintf(stderr,
2046 "Can't create subdisk %s.p0.s%d: %s\n",
2047 objectname,
2049 reply->msg);
2050 else
2051 fprintf(stderr,
2052 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2053 objectname,
2055 strerror(reply->error),
2056 reply->error);
2057 longjmp(command_fail, -1); /* give up */
2061 /* done, save the config */
2062 ioctltype = 0; /* saveconfig after update */
2063 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2064 if (error != 0)
2065 perror("Can't save Vinum config");
2066 find_object(objectname, &type); /* find the index of the volume */
2067 make_vol_dev(vol.volno, 1); /* and create the devices */
2068 if (vflag) {
2069 vflag--; /* XXX don't give too much detail */
2070 find_object(objectname, &type); /* point to the volume */
2071 vinum_lvi(vol.volno, 1); /* and print info about it */
2076 * Create a volume with a two plexes from as much space
2077 * as we can get on the specified drives. If the
2078 * drives aren't Vinum drives, make them so.
2080 * The number of drives must be even, and at least 4
2081 * for a striped plex. Specify striped plexes with the
2082 * -s flag; otherwise they will be concatenated. It's
2083 * possible that the two plexes may differ in length.
2085 void
2086 vinum_mirror(int argc, char *argv[], char *argv0[])
2088 int o; /* object number */
2089 int p; /* plex number */
2090 char buffer[BUFSIZE];
2091 struct drive *drive; /* drive we're currently looking at */
2092 struct _ioctl_reply *reply;
2093 int ioctltype;
2094 int error;
2095 enum objecttype type;
2096 off_t maxsize[2]; /* maximum subdisk size for striped plexes */
2097 int fe; /* freelist entry index */
2098 union freeunion {
2099 struct drive_freelist freelist;
2100 struct ferq { /* request to pass to ioctl */
2101 int driveno;
2102 int fe;
2103 } ferq;
2104 } freeunion;
2105 u_int64_t bigchunk; /* biggest chunk in freelist */
2107 if (sflag) /* striped, */
2108 maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */
2109 else
2110 maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */
2112 reply = (struct _ioctl_reply *) &buffer;
2115 * First, check our drives.
2117 if (argc & 1) {
2118 fprintf(stderr, "You need an even number of drives to create a mirrored volume\n");
2119 return;
2121 if (sflag && (argc < 4)) {
2122 fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n");
2123 return;
2125 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
2126 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
2127 return;
2129 if (!objectname) /* we need a name for our object */
2130 genvolname();
2131 for (o = 0; o < argc; o++) {
2132 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
2133 drive = create_drive(argv[o]); /* create it */
2134 if (sflag) { /* striping, */
2135 /* Find the largest chunk available on the drive */
2136 bigchunk = 0; /* ain't found nothin' yet */
2137 for (fe = 0; fe < drive->freelist_entries; fe++) {
2138 freeunion.ferq.driveno = drive->driveno;
2139 freeunion.ferq.fe = fe;
2140 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
2141 fprintf(stderr,
2142 "Can't get free list element %d: %s\n",
2144 strerror(errno));
2145 longjmp(command_fail, -1);
2147 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
2149 maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */
2153 /* Now create the volume */
2154 sprintf(buffer, "volume %s setupstate", objectname);
2155 if (vflag)
2156 printf("volume %s setupstate\n", objectname);
2157 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
2158 if (reply->error != 0) { /* error in config */
2159 if (reply->msg[0])
2160 fprintf(stderr,
2161 "Can't create volume %s: %s\n",
2162 objectname,
2163 reply->msg);
2164 else
2165 fprintf(stderr,
2166 "Can't create volume %s: %s (%d)\n",
2167 objectname,
2168 strerror(reply->error),
2169 reply->error);
2170 longjmp(command_fail, -1); /* give up */
2172 for (p = 0; p < 2; p++) { /* create each plex */
2173 if (sflag) {
2174 sprintf(buffer, "plex name %s.p%d org striped 256k", objectname, p);
2175 if (vflag)
2176 printf(" plex name %s.p%d org striped 256k\n", objectname, p);
2177 } else { /* concat */
2178 sprintf(buffer, "plex name %s.p%d org concat", objectname, p);
2179 if (vflag)
2180 printf(" plex name %s.p%d org concat\n", objectname, p);
2182 ioctl(superdev, VINUM_CREATE, buffer);
2183 if (reply->error != 0) { /* error in config */
2184 if (reply->msg[0])
2185 fprintf(stderr,
2186 "Can't create plex %s.p%d: %s\n",
2187 objectname,
2189 reply->msg);
2190 else
2191 fprintf(stderr,
2192 "Can't create plex %s.p%d: %s (%d)\n",
2193 objectname,
2195 strerror(reply->error),
2196 reply->error);
2197 longjmp(command_fail, -1); /* give up */
2199 /* Now look at the subdisks */
2200 for (o = p; o < argc; o += 2) { /* every second one */
2201 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2202 sprintf(buffer,
2203 "sd name %s.p%d.s%d drive %s size %lldb",
2204 objectname,
2206 o >> 1,
2207 drive->label.name,
2208 (long long) maxsize[p]);
2209 if (vflag)
2210 printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
2211 objectname,
2213 o >> 1,
2214 drive->label.name,
2215 (long long) maxsize[p]);
2216 ioctl(superdev, VINUM_CREATE, buffer);
2217 if (reply->error != 0) { /* error in config */
2218 if (reply->msg[0])
2219 fprintf(stderr,
2220 "Can't create subdisk %s.p%d.s%d: %s\n",
2221 objectname,
2223 o >> 1,
2224 reply->msg);
2225 else
2226 fprintf(stderr,
2227 "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2228 objectname,
2230 o >> 1,
2231 strerror(reply->error),
2232 reply->error);
2233 longjmp(command_fail, -1); /* give up */
2238 /* done, save the config */
2239 ioctltype = 0; /* saveconfig after update */
2240 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2241 if (error != 0)
2242 perror("Can't save Vinum config");
2243 find_object(objectname, &type); /* find the index of the volume */
2244 make_vol_dev(vol.volno, 1); /* and create the devices */
2245 if (vflag) {
2246 vflag--; /* XXX don't give too much detail */
2247 sflag = 0; /* no stats, please */
2248 find_object(objectname, &type); /* point to the volume */
2249 vinum_lvi(vol.volno, 1); /* and print info about it */
2253 void
2254 vinum_readpol(int argc, char *argv[], char *argv0[])
2256 int object;
2257 struct _ioctl_reply reply;
2258 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2259 enum objecttype type;
2260 struct plex plex;
2261 struct volume vol;
2262 int plexno;
2264 if (argc == 0) { /* start everything */
2265 fprintf(stderr, "Usage: readpol <volume> <plex>|round\n");
2266 return;
2268 object = find_object(argv[1], &type); /* look for it */
2269 if (type != volume_object) {
2270 fprintf(stderr, "%s is not a volume\n", argv[1]);
2271 return;
2273 get_volume_info(&vol, object);
2274 if (strcmp(argv[2], "round")) { /* not 'round' */
2275 object = find_object(argv[2], &type); /* look for it */
2276 if (type != plex_object) {
2277 fprintf(stderr, "%s is not a plex\n", argv[2]);
2278 return;
2280 get_plex_info(&plex, object);
2281 plexno = plex.plexno;
2282 } else /* round */
2283 plexno = -1;
2285 /* Set the value */
2286 message->index = vol.volno;
2287 message->otherobject = plexno;
2288 if (ioctl(superdev, VINUM_READPOL, message) < 0)
2289 fprintf(stderr, "Can't set read policy: %s (%d)\n", strerror(errno), errno);
2290 if (vflag)
2291 vinum_lpi(plexno, recurse);
2295 * Brute force set state function. Don't look at
2296 * any dependencies, just do it.
2298 void
2299 vinum_setstate(int argc, char *argv[], char *argv0[])
2301 int object;
2302 struct _ioctl_reply reply;
2303 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2304 int index;
2305 enum objecttype type;
2306 int state;
2308 for (index = 1; index < argc; index++) {
2309 object = find_object(argv[index], &type); /* look for it */
2310 if (type == invalid_object)
2311 fprintf(stderr, "Can't find object: %s\n", argv[index]);
2312 else {
2313 int doit = 0; /* set to 1 if we pass our tests */
2314 switch (type) {
2315 case drive_object:
2316 state = DriveState(argv[0]); /* get the state */
2317 if (drive.state == state) /* already in that state */
2318 fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]);
2319 else
2320 doit = 1;
2321 break;
2323 case sd_object:
2324 state = SdState(argv[0]); /* get the state */
2325 if (sd.state == state) /* already in that state */
2326 fprintf(stderr, "%s is already %s\n", sd.name, argv[0]);
2327 else
2328 doit = 1;
2329 break;
2331 case plex_object:
2332 state = PlexState(argv[0]); /* get the state */
2333 if (plex.state == state) /* already in that state */
2334 fprintf(stderr, "%s is already %s\n", plex.name, argv[0]);
2335 else
2336 doit = 1;
2337 break;
2339 case volume_object:
2340 state = VolState(argv[0]); /* get the state */
2341 if (vol.state == state) /* already in that state */
2342 fprintf(stderr, "%s is already %s\n", vol.name, argv[0]);
2343 else
2344 doit = 1;
2345 break;
2347 default:
2348 state = 0; /* to keep the compiler happy */
2351 if (state == -1)
2352 fprintf(stderr, "Invalid state for object: %s\n", argv[0]);
2353 else if (doit) {
2354 message->index = object; /* pass object number */
2355 message->type = type; /* and type of object */
2356 message->state = state;
2357 message->force = force; /* don't force it, use a larger hammer */
2358 ioctl(superdev, VINUM_SETSTATE_FORCE, message);
2359 if (reply.error != 0)
2360 fprintf(stderr,
2361 "Can't start %s: %s (%d)\n",
2362 argv[index],
2363 reply.msg[0] ? reply.msg : strerror(reply.error),
2364 reply.error);
2365 if (Verbose)
2366 vinum_li(object, type);
2372 void
2373 vinum_checkparity(int argc, char *argv[], char *argv0[])
2375 Verbose = vflag; /* accept -v for verbose */
2376 if (argc == 0) /* no parameters? */
2377 fprintf(stderr, "Usage: checkparity object [object...]\n");
2378 else
2379 parityops(argc, argv, checkparity);
2382 void
2383 vinum_rebuildparity(int argc, char *argv[], char *argv0[])
2385 if (argc == 0) /* no parameters? */
2386 fprintf(stderr, "Usage: rebuildparity object [object...]\n");
2387 else
2388 parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity);
2392 * Common code for rebuildparity and checkparity.
2393 * We bend the meanings of some flags here:
2395 * -v: Report incorrect parity on rebuild.
2396 * -V: Show running count of position being checked.
2397 * -f: Start from beginning of the plex.
2399 void
2400 parityops(int argc, char *argv[], enum parityop op)
2402 int object;
2403 struct plex plex;
2404 struct _ioctl_reply reply;
2405 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2406 int index;
2407 enum objecttype type;
2408 char *msg;
2409 off_t block;
2411 if (op == checkparity)
2412 msg = "Checking";
2413 else
2414 msg = "Rebuilding";
2415 for (index = 0; index < argc; index++) {
2416 object = find_object(argv[index], &type); /* look for it */
2417 if (type != plex_object)
2418 fprintf(stderr, "%s is not a plex\n", argv[index]);
2419 else {
2420 get_plex_info(&plex, object);
2421 if (!isparity((&plex)))
2422 fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]);
2423 else {
2424 do {
2425 message->index = object; /* pass object number */
2426 message->type = type; /* and type of object */
2427 message->op = op; /* what to do */
2428 if (force)
2429 message->offset = 0; /* start at the beginning */
2430 else
2431 message->offset = plex.checkblock; /* continue where we left off */
2432 force = 0; /* don't reset after the first time */
2433 ioctl(superdev, VINUM_PARITYOP, message);
2434 get_plex_info(&plex, object);
2435 if (Verbose) {
2436 block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1);
2437 if (block != 0)
2438 printf("\r%s at %s (%d%%) ",
2439 msg,
2440 roughlength(block, 1),
2441 ((int) (block * 100 / plex.length) >> DEV_BSHIFT));
2442 if ((reply.error == EAGAIN)
2443 && (reply.msg[0])) /* got a comment back */
2444 fputs(reply.msg, stderr); /* show it */
2445 fflush(stdout);
2448 while (reply.error == EAGAIN);
2449 if (reply.error != 0) {
2450 if (reply.msg[0])
2451 fputs(reply.msg, stderr);
2452 else
2453 fprintf(stderr,
2454 "%s failed: %s\n",
2455 msg,
2456 strerror(reply.error));
2457 } else if (Verbose) {
2458 if (op == checkparity)
2459 fprintf(stderr, "%s has correct parity\n", argv[index]);
2460 else
2461 fprintf(stderr, "Rebuilt parity on %s\n", argv[index]);
2468 /* Local Variables: */
2469 /* fill-column: 50 */
2470 /* End: */