HAMMER Util - Bulk transfer, SIGPIPE, more features.
[dragonfly.git] / sbin / vinum / commands.c
blob615a09a0f611163fff9a362af0eb9b9796e23a26
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 <fstab.h>
47 #include <netdb.h>
48 #include <paths.h>
49 #include <setjmp.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <syslog.h>
54 #include <unistd.h>
55 #include <sys/ioctl.h>
56 #include <dev/raid/vinum/vinumhdr.h>
57 #include <dev/raid/vinum/request.h>
58 #include "vext.h"
59 #include <sys/types.h>
60 #include <sys/linker.h>
61 #include <sys/module.h>
62 #include <sys/wait.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);
67 static void reparse(char *buf, char *tmp);
69 void
70 vinum_create(int argc, char *argv[], char *arg0[])
72 int error;
73 FILE *dfd; /* file descriptor for the config file */
74 char buffer[BUFSIZE]; /* read config file in here */
75 char commandline[BUFSIZE]; /* issue command from here */
76 struct _ioctl_reply *reply;
77 int ioctltype; /* for ioctl call */
78 char tempfile[PATH_MAX]; /* name of temp file for direct editing */
79 char *file; /* file to read */
80 FILE *tf; /* temp file */
82 if (argc == 0) { /* no args, */
83 char *editor; /* editor to start */
84 int status;
86 editor = getenv("EDITOR");
87 if (editor == NULL)
88 editor = "/usr/bin/vi";
89 sprintf(tempfile, "/var/tmp/" VINUMMOD ".create.%d", getpid()); /* create a temp file */
90 tf = fopen(tempfile, "w"); /* open it */
91 if (tf == NULL) {
92 fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno));
93 return;
95 printconfig(tf, "# "); /* and put the current config it */
96 fclose(tf);
97 sprintf(commandline, "%s %s", editor, tempfile); /* create an edit command */
98 status = system(commandline); /* do it */
99 if (status != 0) {
100 fprintf(stderr, "Can't edit config: status %d\n", status);
101 return;
103 file = tempfile;
104 } else if (argc == 1)
105 file = argv[0];
106 else {
107 fprintf(stderr, "Expecting 1 parameter, not %d\n", argc);
108 return;
110 reply = (struct _ioctl_reply *) &buffer;
111 dfd = fopen(file, "r");
112 if (dfd == NULL) { /* no go */
113 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
114 return;
116 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
117 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
118 return;
120 file_line = 0; /* start with line 1 */
121 /* Parse the configuration, and add it to the global configuration */
122 for (;;) { /* love this style(9) */
123 char *configline;
125 configline = fgets(buffer, BUFSIZE, dfd);
127 if (configline == NULL) {
128 if (ferror(dfd))
129 perror("Can't read config file");
130 break;
132 if (hist)
133 fprintf(hist, "%s", buffer);
134 file_line++; /* count the lines */
136 reparse(buffer, commandline);
138 if (vflag)
139 printf("%4d: %s", file_line, buffer);
140 strcpy(commandline, buffer); /* make a copy */
141 ioctl(superdev, VINUM_CREATE, buffer);
142 if (reply->error != 0) { /* error in config */
143 if (!vflag) /* print this line anyway */
144 printf("%4d: %s", file_line, commandline);
145 fprintf(stdout, "** %d %s: %s\n",
146 file_line,
147 reply->msg,
148 strerror(reply->error));
151 * XXX at the moment, we reset the config
152 * lock on error, so try to get it again.
153 * If we fail, don't cry again.
155 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) /* can't get config? */
156 return;
159 fclose(dfd); /* done with the config file */
160 ioctltype = 0; /* saveconfig after update */
161 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
162 if (error != 0)
163 perror("Can't save Vinum config");
164 make_devices();
165 listconfig();
166 checkupdates(); /* make sure we're updating */
169 /* Read vinum config from a disk */
170 void
171 vinum_read(int argc, char *argv[], char *arg0[])
173 int error;
174 char buffer[BUFSIZE]; /* read config file in here */
175 struct _ioctl_reply *reply;
176 int i;
178 reply = (struct _ioctl_reply *) &buffer;
179 if (argc < 1) { /* wrong arg count */
180 fprintf(stderr, "Usage: read drive [drive ...]\n");
181 return;
183 strcpy(buffer, "read ");
184 for (i = 0; i < argc; i++) { /* each drive name */
185 strcat(buffer, argv[i]);
186 strcat(buffer, " ");
189 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
190 fprintf(stderr, "Can't configure: %s (%d)\n", strerror(errno), errno);
191 return;
193 ioctl(superdev, VINUM_CREATE, &buffer);
194 if (reply->error != 0) { /* error in config */
195 fprintf(stdout, "** %s: %s\n", reply->msg, strerror(reply->error));
196 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
197 if (error != 0)
198 perror("Can't save Vinum config");
199 } else {
200 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
201 if (error != 0)
202 perror("Can't save Vinum config");
203 make_devices();
205 checkupdates(); /* make sure we're updating */
208 #ifdef VINUMDEBUG
209 void
210 vinum_debug(int argc, char *argv[], char *arg0[])
212 struct debuginfo info;
214 if (argc > 0) {
215 info.param = atoi(argv[0]);
216 info.changeit = 1;
217 } else {
218 info.changeit = 0;
219 sleep(2); /* give a chance to leave the window */
221 ioctl(superdev, VINUM_DEBUG, (caddr_t) & info);
223 #endif
225 void
226 vinum_modify(int argc, char *argv[], char *arg0[])
228 fprintf(stderr, "Modify command is currently not implemented\n");
229 checkupdates(); /* make sure we're updating */
232 void
233 vinum_set(int argc, char *argv[], char *arg0[])
235 fprintf(stderr, "set is not implemented yet\n");
238 void
239 vinum_rm(int argc, char *argv[], char *arg0[])
241 int object;
242 struct _ioctl_reply reply;
243 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
245 if (argc == 0) /* start everything */
246 fprintf(stderr, "Usage: rm object [object...]\n");
247 else { /* start specified objects */
248 int index;
249 enum objecttype type;
251 for (index = 0; index < argc; index++) {
252 object = find_object(argv[index], &type); /* look for it */
253 if (type == invalid_object)
254 fprintf(stderr, "Can't find object: %s\n", argv[index]);
255 else {
256 message->index = object; /* pass object number */
257 message->type = type; /* and type of object */
258 message->force = force; /* do we want to force the operation? */
259 message->recurse = recurse; /* do we want to remove subordinates? */
260 ioctl(superdev, VINUM_REMOVE, message);
261 if (reply.error != 0) {
262 fprintf(stderr,
263 "Can't remove %s: %s (%d)\n",
264 argv[index],
265 reply.msg[0] ? reply.msg : strerror(reply.error),
266 reply.error);
267 } else if (vflag)
268 fprintf(stderr, "%s removed\n", argv[index]);
271 checkupdates(); /* make sure we're updating */
275 void
276 vinum_resetconfig(int argc, char *argv[], char *arg0[])
278 char reply[32];
279 int error;
281 if (! isatty (STDIN_FILENO)) {
282 fprintf (stderr, "Please enter this command from a tty device\n");
283 return;
285 printf(" WARNING! This command will completely wipe out your vinum configuration.\n"
286 " All data will be lost. If you really want to do this, enter the text\n\n"
287 " NO FUTURE\n"
288 " Enter text -> ");
289 fgets(reply, sizeof(reply), stdin);
290 if (strcmp(reply, "NO FUTURE\n")) /* changed his mind */
291 printf("\n No change\n");
292 else {
293 error = ioctl(superdev, VINUM_RESETCONFIG, NULL); /* trash config on disk */
294 if (error) {
295 if (errno == EBUSY)
296 fprintf(stderr, "Can't reset configuration: objects are in use\n");
297 else
298 perror("Can't find vinum config");
299 } else {
300 make_devices(); /* recreate the /dev/vinum hierarchy */
301 printf("\b Vinum configuration obliterated\n");
302 start_daemon(); /* then restart the daemon */
305 checkupdates(); /* make sure we're updating */
308 /* Initialize subdisks */
309 void
310 vinum_init(int argc, char *argv[], char *arg0[])
312 if (argc > 0) { /* initialize plexes */
313 int objindex;
314 int objno;
315 enum objecttype type; /* type returned */
317 if (hist)
318 fflush(hist); /* don't let all the kids do it. */
319 for (objindex = 0; objindex < argc; objindex++) {
320 objno = find_object(argv[objindex], &type); /* find the object */
321 if (objno < 0)
322 printf("Can't find %s\n", argv[objindex]);
323 else {
324 switch (type) {
325 case volume_object:
326 initvol(objno);
327 break;
329 case plex_object:
330 initplex(objno, argv[objindex]);
331 break;
333 case sd_object:
334 initsd(objno, dowait);
335 break;
337 default:
338 printf("Can't initialize %s: wrong object type\n", argv[objindex]);
339 break;
344 checkupdates(); /* make sure we're updating */
347 void
348 initvol(int volno)
350 printf("Initializing volumes is not implemented yet\n");
353 void
354 initplex(int plexno, char *name)
356 int sdno;
357 int plexfh = 0; /* file handle for plex */
358 pid_t pid;
359 char filename[MAXPATHLEN]; /* create a file name here */
361 /* Variables for use by children */
362 int failed = 0; /* set if a child dies badly */
364 sprintf(filename, VINUM_DIR "/plex/%s", name);
365 if ((plexfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* got a plex, open it */
367 * We don't actually write anything to the
368 * plex. We open it to ensure that nobody
369 * else tries to open it while we initialize
370 * its subdisks.
372 fprintf(stderr, "can't open plex %s: %s\n", filename, strerror(errno));
373 return;
375 if (dowait == 0) {
376 pid = fork(); /* into the background with you */
377 if (pid != 0) { /* I'm the parent, or we failed */
378 if (pid < 0) /* failure */
379 printf("Couldn't fork: %s", strerror(errno));
380 close(plexfh); /* we don't need this any more */
381 return;
385 * If we get here, we're either the first-level
386 * child (if we're not waiting) or we're going
387 * to wait.
389 for (sdno = 0; sdno < plex.subdisks; sdno++) { /* initialize each subdisk */
390 get_plex_sd_info(&sd, plexno, sdno);
391 initsd(sd.sdno, 0);
393 /* Now wait for them to complete */
394 while (1) {
395 int status;
396 pid = wait(&status);
397 if (((int) pid == -1)
398 && (errno == ECHILD)) /* all gone */
399 break;
400 if (WEXITSTATUS(status) != 0) { /* oh, oh */
401 printf("child %d exited with status 0x%x\n", pid, WEXITSTATUS(status));
402 failed++;
405 if (failed == 0) {
406 #if 0
407 message->index = plexno; /* pass object number */
408 message->type = plex_object; /* and type of object */
409 message->state = object_up;
410 message->force = 1; /* insist */
411 ioctl(superdev, VINUM_SETSTATE, message);
412 #endif
413 syslog(LOG_INFO | LOG_KERN, "plex %s initialized", plex.name);
414 } else
415 syslog(LOG_ERR | LOG_KERN, "couldn't initialize plex %s, %d processes died",
416 plex.name,
417 failed);
418 if (dowait == 0) /* we're the waiting child, */
419 exit(0); /* we've done our dash */
422 /* Initialize a subdisk. */
423 void
424 initsd(int sdno, int dowait)
426 pid_t pid;
427 struct _ioctl_reply reply;
428 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
429 char filename[MAXPATHLEN]; /* create a file name here */
431 /* Variables for use by children */
432 int sdfh; /* and for subdisk */
433 int initsize; /* actual size to write */
434 int64_t sdsize; /* size of subdisk */
436 if (dowait == 0) {
437 pid = fork(); /* into the background with you */
438 if (pid > 0) /* I'm the parent */
439 return;
440 else if (pid < 0) { /* failure */
441 printf("couldn't fork for subdisk %d: %s", sdno, strerror(errno));
442 return;
445 if (SSize != 0) { /* specified a size for init */
446 if (SSize < 512)
447 SSize <<= DEV_BSHIFT;
448 initsize = min(SSize, MAXPLEXINITSIZE);
449 } else
450 initsize = PLEXINITSIZE;
451 openlog("vinum", LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
452 get_sd_info(&sd, sdno);
453 sdsize = sd.sectors * DEV_BSIZE; /* size of subdisk in bytes */
454 sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
455 setproctitle("initializing %s", filename); /* show what we're doing */
456 syslog(LOG_INFO | LOG_KERN, "initializing subdisk %s", filename);
457 if ((sdfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* no go */
458 syslog(LOG_ERR | LOG_KERN,
459 "can't open subdisk %s: %s",
460 filename,
461 strerror(errno));
462 exit(1);
464 /* Set the subdisk in initializing state */
465 message->index = sd.sdno; /* pass object number */
466 message->type = sd_object; /* and type of object */
467 message->state = object_initializing;
468 message->verify = vflag; /* verify what we write? */
469 message->force = 1; /* insist */
470 ioctl(superdev, VINUM_SETSTATE, message);
471 if ((SSize > 0) /* specified a size for init */
472 &&(SSize < 512))
473 SSize <<= DEV_BSHIFT;
474 if (reply.error) {
475 fprintf(stderr,
476 "Can't initialize %s: %s (%d)\n",
477 filename,
478 strerror(reply.error),
479 reply.error);
480 exit(1);
481 } else {
482 do {
483 if (interval) /* pause between copies */
484 usleep(interval * 1000);
485 message->index = sd.sdno; /* pass object number */
486 message->type = sd_object; /* and type of object */
487 message->state = object_up;
488 message->verify = vflag; /* verify what we write? */
489 message->blocksize = SSize;
490 ioctl(superdev, VINUM_SETSTATE, message);
492 while (reply.error == EAGAIN); /* until we're done */
493 if (reply.error) {
494 fprintf(stderr,
495 "Can't initialize %s: %s (%d)\n",
496 filename,
497 strerror(reply.error),
498 reply.error);
499 get_sd_info(&sd, sdno);
500 if (sd.state != sd_up)
501 /* Set the subdisk down */
502 message->index = sd.sdno; /* pass object number */
503 message->type = sd_object; /* and type of object */
504 message->state = object_down;
505 message->verify = vflag; /* verify what we write? */
506 message->force = 1; /* insist */
507 ioctl(superdev, VINUM_SETSTATE, message);
510 printf("subdisk %s initialized\n", filename);
511 if (!dowait)
512 exit(0);
515 void
516 vinum_start(int argc, char *argv[], char *arg0[])
518 int object;
519 struct _ioctl_reply reply;
520 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
522 if (argc == 0) { /* start everything */
523 int devs = getnumdevs();
524 struct statinfo statinfo;
525 char *namelist;
526 char *enamelist; /* end of name list */
527 int i;
528 char **token; /* list of tokens */
529 int tokens; /* and their number */
531 bzero(&statinfo, sizeof(struct statinfo));
532 statinfo.dinfo = malloc(devs * sizeof(struct statinfo));
533 namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8));
534 token = malloc((devs + 1) * sizeof(char *));
535 if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) {
536 fprintf(stderr, "Can't allocate memory for drive list\n");
537 return;
539 bzero(statinfo.dinfo, sizeof(struct devinfo));
541 tokens = 0; /* no tokens yet */
542 if (getdevs(&statinfo) < 0) { /* find out what devices we have */
543 perror("Can't get device list");
544 return;
546 namelist[0] = '\0'; /* start with empty namelist */
547 enamelist = namelist; /* point to the end of the list */
549 for (i = 0; i < devs; i++) {
550 struct devstat *stat = &statinfo.dinfo->devices[i];
552 if ((((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */
553 || ((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) /* storage array */
554 &&((stat->device_type & DEVSTAT_TYPE_IF_MASK) != DEVSTAT_TYPE_IF_OTHER) /* and not md */
555 &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */
556 &&((stat->device_name[0] != '\0'))) { /* and it has a name */
557 sprintf(enamelist, "%s%s%d", _PATH_DEV, stat->device_name, stat->unit_number);
558 token[tokens] = enamelist; /* point to it */
559 tokens++; /* one more token */
560 enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */
563 free(statinfo.dinfo); /* don't need the list any more */
564 vinum_read(tokens, token, &token[0]); /* start the system */
565 free(namelist);
566 free(token);
567 list_defective_objects(); /* and list anything that's down */
568 } else { /* start specified objects */
569 int index;
570 enum objecttype type;
572 for (index = 0; index < argc; index++) {
573 object = find_object(argv[index], &type); /* look for it */
574 if (type == invalid_object)
575 fprintf(stderr, "Can't find object: %s\n", argv[index]);
576 else {
577 int doit = 0; /* set to 1 if we pass our tests */
578 switch (type) {
579 case drive_object:
580 if (drive.state == drive_up) /* already up */
581 fprintf(stderr, "%s is already up\n", drive.label.name);
582 else
583 doit = 1;
584 break;
586 case sd_object:
587 if (sd.state == sd_up) /* already up */
588 fprintf(stderr, "%s is already up\n", sd.name);
589 else
590 doit = 1;
591 break;
593 case plex_object:
594 if (plex.state == plex_up) /* already up */
595 fprintf(stderr, "%s is already up\n", plex.name);
596 else {
597 int sdno;
600 * First, see if we can bring it up
601 * just by asking. This might happen
602 * if somebody has used setupstate on
603 * the subdisks. If we don't do this,
604 * we'll return success, but the plex
605 * won't have changed state. Note
606 * that we don't check for errors
607 * here.
609 message->index = plex.plexno; /* pass object number */
610 message->type = plex_object; /* it's a plex */
611 message->state = object_up;
612 message->force = 0; /* don't force it */
613 ioctl(superdev, VINUM_SETSTATE, message);
614 for (sdno = 0; sdno < plex.subdisks; sdno++) {
615 get_plex_sd_info(&sd, object, sdno);
616 if ((sd.state >= sd_empty)
617 && (sd.state <= sd_reviving)) { /* candidate for start */
618 message->index = sd.sdno; /* pass object number */
619 message->type = sd_object; /* it's a subdisk */
620 message->state = object_up;
621 message->force = force; /* don't force it, use a larger hammer */
624 * We don't do any checking here.
625 * The kernel module has a better
626 * understanding of these things,
627 * let it do it.
629 if (SSize != 0) { /* specified a size for init */
630 if (SSize < 512)
631 SSize <<= DEV_BSHIFT;
632 message->blocksize = SSize;
633 } else
634 message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
635 ioctl(superdev, VINUM_SETSTATE, message);
636 if (reply.error != 0) {
637 if (reply.error == EAGAIN) /* we're reviving */
638 continue_revive(sd.sdno);
639 else
640 fprintf(stderr,
641 "Can't start %s: %s (%d)\n",
642 sd.name,
643 reply.msg[0] ? reply.msg : strerror(reply.error),
644 reply.error);
646 if (Verbose)
647 vinum_lsi(sd.sdno, 0);
651 break;
653 case volume_object:
654 if (vol.state == volume_up) /* already up */
655 fprintf(stderr, "%s is already up\n", vol.name);
656 else
657 doit = 1;
658 break;
660 default:
661 break;
664 if (doit) {
665 message->index = object; /* pass object number */
666 message->type = type; /* and type of object */
667 message->state = object_up;
668 message->force = force; /* don't force it, use a larger hammer */
671 * We don't do any checking here.
672 * The kernel module has a better
673 * understanding of these things,
674 * let it do it.
676 if (SSize != 0) { /* specified a size for init or revive */
677 if (SSize < 512)
678 SSize <<= DEV_BSHIFT;
679 message->blocksize = SSize;
680 } else
681 message->blocksize = 0;
682 ioctl(superdev, VINUM_SETSTATE, message);
683 if (reply.error != 0) {
684 if ((reply.error == EAGAIN) /* we're reviving */
685 &&(type == sd_object))
686 continue_revive(object);
687 else
688 fprintf(stderr,
689 "Can't start %s: %s (%d)\n",
690 argv[index],
691 reply.msg[0] ? reply.msg : strerror(reply.error),
692 reply.error);
694 if (Verbose)
695 vinum_li(object, type);
700 checkupdates(); /* make sure we're updating */
703 void
704 vinum_stop(int argc, char *argv[], char *arg0[])
706 int object;
707 struct _ioctl_reply reply;
708 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
710 if (checkupdates() && (!force)) /* not updating? */
711 return;
712 message->force = force; /* should we force the transition? */
713 if (argc == 0) { /* stop vinum */
714 int fileid = 0; /* ID of Vinum kld */
716 close(superdev); /* we can't stop if we have vinum open */
717 sleep(1); /* wait for the daemon to let go */
718 fileid = kldfind(VINUMMOD);
719 if ((fileid < 0) /* no go */
720 ||(kldunload(fileid) < 0))
721 perror("Can't unload " VINUMMOD);
722 else {
723 fprintf(stderr, VINUMMOD " unloaded\n");
724 exit(0);
727 /* If we got here, the stop failed. Reopen the superdevice. */
728 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */
729 if (superdev < 0) {
730 perror("Can't reopen Vinum superdevice");
731 exit(1);
733 } else { /* stop specified objects */
734 int i;
735 enum objecttype type;
737 for (i = 0; i < argc; i++) {
738 object = find_object(argv[i], &type); /* look for it */
739 if (type == invalid_object)
740 fprintf(stderr, "Can't find object: %s\n", argv[i]);
741 else {
742 message->index = object; /* pass object number */
743 message->type = type; /* and type of object */
744 message->state = object_down;
745 ioctl(superdev, VINUM_SETSTATE, message);
746 if (reply.error != 0)
747 fprintf(stderr,
748 "Can't stop %s: %s (%d)\n",
749 argv[i],
750 reply.msg[0] ? reply.msg : strerror(reply.error),
751 reply.error);
752 if (Verbose)
753 vinum_li(object, type);
759 void
760 vinum_label(int argc, char *argv[], char *arg0[])
762 int object;
763 struct _ioctl_reply reply;
764 int *message = (int *) &reply;
766 if (argc == 0) /* start everything */
767 fprintf(stderr, "label: please specify one or more volume names\n");
768 else { /* start specified objects */
769 int i;
770 enum objecttype type;
772 for (i = 0; i < argc; i++) {
773 object = find_object(argv[i], &type); /* look for it */
774 if (type == invalid_object)
775 fprintf(stderr, "Can't find object: %s\n", argv[i]);
776 else if (type != volume_object) /* it exists, but it isn't a volume */
777 fprintf(stderr, "%s is not a volume\n", argv[i]);
778 else {
779 message[0] = object; /* pass object number */
780 ioctl(superdev, VINUM_LABEL, message);
781 if (reply.error != 0)
782 fprintf(stderr,
783 "Can't label %s: %s (%d)\n",
784 argv[i],
785 reply.msg[0] ? reply.msg : strerror(reply.error),
786 reply.error);
787 if (Verbose)
788 vinum_li(object, type);
792 checkupdates(); /* not updating? */
795 void
796 reset_volume_stats(int volno, int recurse)
798 struct vinum_ioctl_msg msg;
799 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
801 msg.index = volno;
802 msg.type = volume_object;
803 /* XXX get these numbers right if we ever
804 * actually return errors */
805 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
806 fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg);
807 longjmp(command_fail, -1);
808 } else if (recurse) {
809 struct volume vol;
810 int plexno;
812 get_volume_info(&vol, volno);
813 for (plexno = 0; plexno < vol.plexes; plexno++)
814 reset_plex_stats(vol.plex[plexno], recurse);
818 void
819 reset_plex_stats(int plexno, int recurse)
821 struct vinum_ioctl_msg msg;
822 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
824 msg.index = plexno;
825 msg.type = plex_object;
826 /* XXX get these numbers right if we ever
827 * actually return errors */
828 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
829 fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg);
830 longjmp(command_fail, -1);
831 } else if (recurse) {
832 struct plex plex;
833 struct sd sd;
834 int sdno;
836 get_plex_info(&plex, plexno);
837 for (sdno = 0; sdno < plex.subdisks; sdno++) {
838 get_plex_sd_info(&sd, plex.plexno, sdno);
839 reset_sd_stats(sd.sdno, recurse);
844 void
845 reset_sd_stats(int sdno, int recurse)
847 struct vinum_ioctl_msg msg;
848 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
850 msg.index = sdno;
851 msg.type = sd_object;
852 /* XXX get these numbers right if we ever
853 * actually return errors */
854 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
855 fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg);
856 longjmp(command_fail, -1);
857 } else if (recurse) {
858 get_sd_info(&sd, sdno); /* get the info */
859 reset_drive_stats(sd.driveno); /* and clear the drive */
863 void
864 reset_drive_stats(int driveno)
866 struct vinum_ioctl_msg msg;
867 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
869 msg.index = driveno;
870 msg.type = drive_object;
871 /* XXX get these numbers right if we ever
872 * actually return errors */
873 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
874 fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg);
875 longjmp(command_fail, -1);
879 void
880 vinum_resetstats(int argc, char *argv[], char *argv0[])
882 int i;
883 int objno;
884 enum objecttype type;
886 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
887 perror("Can't get vinum config");
888 return;
890 if (argc == 0) {
891 for (objno = 0; objno < vinum_conf.volumes_allocated; objno++)
892 reset_volume_stats(objno, 1); /* clear everything recursively */
893 } else {
894 for (i = 0; i < argc; i++) {
895 objno = find_object(argv[i], &type);
896 if (objno >= 0) { /* not invalid */
897 switch (type) {
898 case drive_object:
899 reset_drive_stats(objno);
900 break;
902 case sd_object:
903 reset_sd_stats(objno, recurse);
904 break;
906 case plex_object:
907 reset_plex_stats(objno, recurse);
908 break;
910 case volume_object:
911 reset_volume_stats(objno, recurse);
912 break;
914 case invalid_object: /* can't get this */
915 break;
922 /* Attach a subdisk to a plex, or a plex to a volume.
923 * attach subdisk plex [offset] [rename]
924 * attach plex volume [rename]
926 void
927 vinum_attach(int argc, char *argv[], char *argv0[])
929 int i;
930 enum objecttype supertype;
931 struct vinum_ioctl_msg msg;
932 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
933 const char *objname = argv[0];
934 const char *supername = argv[1];
935 int sdno = -1;
936 int plexno = -1;
937 char oldname[MAXNAME + 8];
938 char newname[MAXNAME + 8];
939 int rename = 0; /* set if we want to rename the object */
941 if ((argc < 2)
942 || (argc > 4)) {
943 fprintf(stderr,
944 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
945 "\tattach <plex> <volume> [rename]\n");
946 return;
948 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
949 perror("Can't get vinum config");
950 return;
952 msg.index = find_object(objname, &msg.type); /* find the object to attach */
953 msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */
954 msg.force = force; /* did we specify the use of force? */
955 msg.recurse = recurse;
956 msg.offset = -1; /* and no offset */
958 for (i = 2; i < argc; i++) {
959 if (!strcmp(argv[i], "rename")) {
960 rename = 1;
961 msg.rename = 1; /* do renaming */
962 } else if (!isdigit(argv[i][0])) { /* not an offset */
963 fprintf(stderr, "Unknown attribute: %s\n", supername);
964 return;
965 } else
966 msg.offset = sizespec(argv[i]);
969 switch (msg.type) {
970 case sd_object:
971 find_object(argv[1], &supertype);
972 if (supertype != plex_object) { /* huh? */
973 fprintf(stderr, "%s can only be attached to a plex\n", objname);
974 return;
976 if ((plex.organization != plex_concat) /* not a cat plex, */
977 &&(!force)) {
978 fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization));
979 return;
981 sdno = msg.index; /* note the subdisk number for later */
982 break;
984 case plex_object:
985 find_object(argv[1], &supertype);
986 if (supertype != volume_object) { /* huh? */
987 fprintf(stderr, "%s can only be attached to a volume\n", objname);
988 return;
990 break;
992 case volume_object:
993 case drive_object:
994 fprintf(stderr, "Can only attach subdisks and plexes\n");
995 return;
997 default:
998 fprintf(stderr, "%s is not a Vinum object\n", objname);
999 return;
1002 ioctl(superdev, VINUM_ATTACH, &msg);
1003 if (reply->error != 0) {
1004 if (reply->error == EAGAIN) /* reviving */
1005 continue_revive(sdno); /* continue the revive */
1006 else
1007 fprintf(stderr,
1008 "Can't attach %s to %s: %s (%d)\n",
1009 objname,
1010 supername,
1011 reply->msg[0] ? reply->msg : strerror(reply->error),
1012 reply->error);
1014 if (rename) {
1015 struct sd;
1016 struct plex;
1017 struct volume;
1019 /* we've overwritten msg with the
1020 * ioctl reply, start again */
1021 msg.index = find_object(objname, &msg.type); /* find the object to rename */
1022 switch (msg.type) {
1023 case sd_object:
1024 get_sd_info(&sd, msg.index);
1025 get_plex_info(&plex, sd.plexno);
1026 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1027 if (plex.sdnos[sdno] == msg.index) /* found our subdisk */
1028 break;
1030 sprintf(newname, "%s.s%d", plex.name, sdno);
1031 sprintf(oldname, "%s", sd.name);
1032 vinum_rename_2(oldname, newname);
1033 break;
1035 case plex_object:
1036 get_plex_info(&plex, msg.index);
1037 get_volume_info(&vol, plex.volno);
1038 for (plexno = 0; plexno < vol.plexes; plexno++) {
1039 if (vol.plex[plexno] == msg.index) /* found our subdisk */
1040 break;
1042 sprintf(newname, "%s.p%d", vol.name, plexno);
1043 sprintf(oldname, "%s", plex.name);
1044 vinum_rename_2(oldname, newname); /* this may recurse */
1045 break;
1047 default: /* can't get here */
1048 break;
1051 checkupdates(); /* make sure we're updating */
1054 /* Detach a subdisk from a plex, or a plex from a volume.
1055 * detach subdisk plex [rename]
1056 * detach plex volume [rename]
1058 void
1059 vinum_detach(int argc, char *argv[], char *argv0[])
1061 struct vinum_ioctl_msg msg;
1062 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
1064 if ((argc < 1)
1065 || (argc > 2)) {
1066 fprintf(stderr,
1067 "Usage: \tdetach <subdisk> [rename]\n"
1068 "\tdetach <plex> [rename]\n");
1069 return;
1071 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1072 perror("Can't get vinum config");
1073 return;
1075 msg.index = find_object(argv[0], &msg.type); /* find the object to detach */
1076 msg.force = force; /* did we specify the use of force? */
1077 msg.rename = 0; /* don't specify new name */
1078 msg.recurse = recurse; /* but recurse if we have to */
1080 /* XXX are we going to keep this?
1081 * Don't document it yet, since the
1082 * kernel side of things doesn't
1083 * implement it */
1084 if (argc == 2) {
1085 if (!strcmp(argv[1], "rename"))
1086 msg.rename = 1; /* do renaming */
1087 else {
1088 fprintf(stderr, "Unknown attribute: %s\n", argv[1]);
1089 return;
1092 if ((msg.type != sd_object)
1093 && (msg.type != plex_object)) {
1094 fprintf(stderr, "Can only detach subdisks and plexes\n");
1095 return;
1097 ioctl(superdev, VINUM_DETACH, &msg);
1098 if (reply->error != 0)
1099 fprintf(stderr,
1100 "Can't detach %s: %s (%d)\n",
1101 argv[0],
1102 reply->msg[0] ? reply->msg : strerror(reply->error),
1103 reply->error);
1104 checkupdates(); /* make sure we're updating */
1108 * Reparse a line from the configuration file
1110 static void
1111 reparse(char *buf, char *tmp)
1113 char *ptr;
1114 const char *ws = " \t\r\n";
1115 int dodevpath = 0;
1116 int doskip = 0;
1118 strcpy(tmp, buf);
1119 ptr = strtok(tmp, ws);
1120 if (ptr == NULL || *ptr == '#')
1121 return;
1122 if (strcmp(ptr, "drive") != 0)
1123 return;
1124 strcpy(buf, ptr);
1125 while ((ptr = strtok(NULL, ws)) != NULL) {
1126 if (dodevpath) {
1127 dodevpath = 0;
1128 ptr = getdevpath(ptr, 0);
1129 } else if (doskip) {
1130 doskip = 0;
1131 } else if (strcmp(ptr, "drive") == 0) {
1132 doskip = 1;
1133 } else if (strcmp(ptr, "device") == 0) {
1134 dodevpath = 1;
1136 strcat(buf, " ");
1137 strcat(buf, ptr);
1141 static void
1142 dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen)
1144 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
1146 if (strlen(name) > maxlen) {
1147 fprintf(stderr, "%s is too long\n", name);
1148 return;
1150 strcpy(msg->newname, name);
1151 ioctl(superdev, VINUM_RENAME, msg);
1152 if (reply->error != 0)
1153 fprintf(stderr,
1154 "Can't rename %s to %s: %s (%d)\n",
1155 oldname,
1156 name,
1157 reply->msg[0] ? reply->msg : strerror(reply->error),
1158 reply->error);
1161 /* Rename an object:
1162 * rename <object> "newname"
1164 void
1165 vinum_rename_2(char *oldname, char *newname)
1167 struct vinum_rename_msg msg;
1168 int volno;
1169 int plexno;
1171 msg.index = find_object(oldname, &msg.type); /* find the object to rename */
1172 msg.recurse = recurse;
1174 /* Ugh. Determine how long the name may be */
1175 switch (msg.type) {
1176 case drive_object:
1177 dorename(&msg, oldname, newname, MAXDRIVENAME);
1178 break;
1180 case sd_object:
1181 dorename(&msg, oldname, newname, MAXSDNAME);
1182 break;
1184 case plex_object:
1185 plexno = msg.index;
1186 dorename(&msg, oldname, newname, MAXPLEXNAME);
1187 if (recurse) {
1188 int sdno;
1190 get_plex_info(&plex, plexno); /* find out who we are */
1191 msg.type = sd_object;
1192 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1193 char sdname[MAXPLEXNAME + 8];
1195 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1196 sprintf(sdname, "%s.s%d", newname, sdno);
1197 msg.index = sd.sdno; /* number of the subdisk */
1198 dorename(&msg, sd.name, sdname, MAXSDNAME);
1201 break;
1203 case volume_object:
1204 volno = msg.index;
1205 dorename(&msg, oldname, newname, MAXVOLNAME);
1206 if (recurse) {
1207 int sdno;
1208 int plexno;
1210 get_volume_info(&vol, volno); /* find out who we are */
1211 for (plexno = 0; plexno < vol.plexes; plexno++) {
1212 char plexname[MAXVOLNAME + 8];
1214 msg.type = plex_object;
1215 sprintf(plexname, "%s.p%d", newname, plexno);
1216 msg.index = vol.plex[plexno]; /* number of the plex */
1217 dorename(&msg, plex.name, plexname, MAXPLEXNAME);
1218 get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */
1219 msg.type = sd_object;
1220 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1221 char sdname[MAXPLEXNAME + 8];
1223 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1224 sprintf(sdname, "%s.s%d", plexname, sdno);
1225 msg.index = sd.sdno; /* number of the subdisk */
1226 dorename(&msg, sd.name, sdname, MAXSDNAME);
1230 break;
1232 default:
1233 fprintf(stderr, "%s is not a Vinum object\n", oldname);
1234 return;
1238 void
1239 vinum_rename(int argc, char *argv[], char *argv0[])
1241 if (argc != 2) {
1242 fprintf(stderr, "Usage: \trename <object> <new name>\n");
1243 return;
1245 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1246 perror("Can't get vinum config");
1247 return;
1249 vinum_rename_2(argv[0], argv[1]);
1250 checkupdates(); /* make sure we're updating */
1254 * Move objects:
1256 * mv <dest> <src> ...
1258 void
1259 vinum_mv(int argc, char *argv[], char *argv0[])
1261 int i; /* loop index */
1262 int srcobj;
1263 int destobj;
1264 enum objecttype srct;
1265 enum objecttype destt;
1266 int sdno;
1267 struct _ioctl_reply reply;
1268 struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply;
1270 if (argc < 2) {
1271 fprintf(stderr, "Usage: \tmove <dest> <src> ...\n");
1272 return;
1274 /* Get current config */
1275 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1276 perror("Cannot get vinum config\n");
1277 return;
1279 /* Get our destination */
1280 destobj = find_object(argv[0], &destt);
1281 if (destobj == -1) {
1282 fprintf(stderr, "Can't find %s\n", argv[0]);
1283 return;
1285 /* Verify that the target is a drive */
1286 if (destt != drive_object) {
1287 fprintf(stderr, "%s is not a drive\n", argv[0]);
1288 return;
1290 for (i = 1; i < argc; i++) { /* for all the sources */
1291 srcobj = find_object(argv[i], &srct);
1292 if (srcobj == -1) {
1293 fprintf(stderr, "Can't find %s\n", argv[i]);
1294 continue;
1296 msg->index = destobj;
1297 switch (srct) { /* Handle the source object */
1298 case drive_object: /* Move all subdisks on the drive to dst. */
1299 get_drive_info(&drive, srcobj); /* get info on drive */
1300 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) {
1301 get_sd_info(&sd, sdno);
1302 if (sd.driveno == srcobj) {
1303 msg->index = destobj;
1304 msg->otherobject = sd.sdno;
1305 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1306 fprintf(stderr,
1307 "Can't move %s (part of %s) to %s: %s (%d)\n",
1308 sd.name,
1309 drive.label.name,
1310 argv[0],
1311 strerror(reply.error),
1312 reply.error);
1315 break;
1317 case sd_object:
1318 msg->otherobject = srcobj;
1319 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1320 fprintf(stderr,
1321 "Can't move %s to %s: %s (%d)\n",
1322 sd.name,
1323 argv[0],
1324 strerror(reply.error),
1325 reply.error);
1326 break;
1328 case plex_object:
1329 get_plex_info(&plex, srcobj);
1330 for (sdno = 0; sdno < plex.subdisks; ++sdno) {
1331 get_plex_sd_info(&sd, plex.plexno, sdno);
1332 msg->index = destobj;
1333 msg->otherobject = sd.sdno;
1334 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1335 fprintf(stderr,
1336 "Can't move %s (part of %s) to %s: %s (%d)\n",
1337 sd.name,
1338 plex.name,
1339 argv[0],
1340 strerror(reply.error),
1341 reply.error);
1343 break;
1345 case volume_object:
1346 case invalid_object:
1347 default:
1348 fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]);
1349 break;
1351 if (reply.error)
1352 fprintf(stderr,
1353 "Can't move %s to %s: %s (%d)\n",
1354 argv[i],
1355 argv[0],
1356 strerror(reply.error),
1357 reply.error);
1359 checkupdates(); /* make sure we're updating */
1363 * Replace objects. Not implemented, may never be.
1365 void
1366 vinum_replace(int argc, char *argv[], char *argv0[])
1368 fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n");
1371 /* Primitive help function */
1372 void
1373 vinum_help(int argc, char *argv[], char *argv0[])
1375 char commands[] =
1377 "COMMANDS\n"
1378 "create [-f description-file]\n"
1379 " Create a volume as described in description-file\n"
1380 "attach plex volume [rename]\n"
1381 "attach subdisk plex [offset] [rename]\n"
1382 " Attach a plex to a volume, or a subdisk to a plex.\n"
1383 "debug\n"
1384 " Cause the volume manager to enter the kernel debugger.\n"
1385 "debug flags\n"
1386 " Set debugging flags.\n"
1387 "detach [plex | subdisk]\n"
1388 " Detach a plex or subdisk from the volume or plex to which it is\n"
1389 " attached.\n"
1390 "info [-v]\n"
1391 " List information about volume manager state.\n"
1392 "init [-v] [-w] plex\n"
1393 " Initialize a plex by writing zeroes to all its subdisks.\n"
1394 "label volume\n"
1395 " Create a volume label\n"
1396 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1397 " List information about specified objects\n"
1398 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1399 " List information about specified objects (alternative to\n"
1400 " list command)\n"
1401 "ld [-r] [-s] [-v] [-V] [volume]\n"
1402 " List information about drives\n"
1403 "ls [-r] [-s] [-v] [-V] [subdisk]\n"
1404 " List information about subdisks\n"
1405 "lp [-r] [-s] [-v] [-V] [plex]\n"
1406 " List information about plexes\n"
1407 "lv [-r] [-s] [-v] [-V] [volume]\n"
1408 " List information about volumes\n"
1409 "printconfig [file]\n"
1410 " Write a copy of the current configuration to file.\n"
1411 "makedev\n"
1412 " Remake the device nodes in " _PATH_DEV "vinum.\n"
1413 "move drive [subdisk | plex | drive]\n"
1414 " Move the subdisks of the specified object(s) to drive.\n"
1415 "quit\n"
1416 " Exit the vinum program when running in interactive mode. Nor-\n"
1417 " mally this would be done by entering the EOF character.\n"
1418 "read disk [disk...]\n"
1419 " Read the vinum configuration from the specified disks.\n"
1420 "rename [-r] [drive | subdisk | plex | volume] newname\n"
1421 " Change the name of the specified object.\n"
1422 "resetconfig\n"
1423 " Reset the complete vinum configuration.\n"
1424 "resetstats [-r] [volume | plex | subdisk]\n"
1425 " Reset statistisc counters for the specified objects, or for all\n"
1426 " objects if none are specified.\n"
1427 "rm [-f] [-r] volume | plex | subdisk\n"
1428 " Remove an object\n"
1429 "saveconfig\n"
1430 " Save vinum configuration to disk.\n"
1431 "setdaemon [value]\n"
1432 " Set daemon configuration.\n"
1433 "start\n"
1434 " Read configuration from all vinum drives.\n"
1435 "start [volume | plex | subdisk]\n"
1436 " Allow the system to access the objects\n"
1437 "stop [-f] [volume | plex | subdisk]\n"
1438 " Terminate access to the objects, or stop vinum if no parameters\n"
1439 " are specified.\n"
1441 puts(commands);
1444 /* Set daemon options.
1445 * XXX quick and dirty: use a bitmap, which requires
1446 * knowing which bit does what. FIXME */
1447 void
1448 vinum_setdaemon(int argc, char *argv[], char *argv0[])
1450 int options;
1452 switch (argc) {
1453 case 0:
1454 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1455 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1456 else
1457 printf("Options mask: %d\n", options);
1458 break;
1460 case 1:
1461 options = atoi(argv[0]);
1462 if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0)
1463 fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno);
1464 break;
1466 default:
1467 fprintf(stderr, "Usage: \tsetdaemon [<bitmask>]\n");
1469 checkupdates(); /* make sure we're updating */
1473 checkupdates(void)
1475 int options;
1477 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1478 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1479 if (options & daemon_noupdate) {
1480 fprintf(stderr, "*** Warning: configuration updates are disabled. ***\n");
1481 return 1;
1482 } else
1483 return 0;
1486 /* Save config info */
1487 void
1488 vinum_saveconfig(int argc, char *argv[], char *argv0[])
1490 int ioctltype;
1492 if (argc != 0) {
1493 printf("Usage: saveconfig\n");
1494 return;
1496 ioctltype = 1; /* user saveconfig */
1497 if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0)
1498 fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno);
1499 checkupdates(); /* make sure we're updating */
1503 * Create a volume name for the quick and dirty
1504 * commands. It will be of the form "vinum#",
1505 * where # is a small positive number.
1507 void
1508 genvolname(void)
1510 int v; /* volume number */
1511 static char volumename[MAXVOLNAME]; /* name to create */
1512 enum objecttype type;
1514 objectname = volumename; /* point to it */
1515 for (v = 0;; v++) {
1516 sprintf(objectname, "vinum%d", v); /* create the name */
1517 if (find_object(objectname, &type) == -1) /* does it exist? */
1518 return; /* no, it's ours */
1523 * Create a drive for the quick and dirty
1524 * commands. The name will be of the form
1525 * vinumdrive#, where # is a small positive
1526 * number. Return the name of the drive.
1528 struct drive *
1529 create_drive(char *devicename)
1531 int d; /* volume number */
1532 static char drivename[MAXDRIVENAME]; /* name to create */
1533 enum objecttype type;
1534 struct _ioctl_reply *reply;
1536 devicename = getdevpath(devicename, 0);
1539 * We're never likely to get anything
1540 * like 10000 drives. The only reason for
1541 * this limit is to stop the thing
1542 * looping if we have a bug somewhere.
1544 for (d = 0; d < 100000; d++) { /* look for a free drive number */
1545 sprintf(drivename, "vinumdrive%d", d); /* create the name */
1546 if (find_object(drivename, &type) == -1) { /* does it exist? */
1547 char command[MAXDRIVENAME * 2];
1549 sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */
1550 if (vflag)
1551 printf("drive %s device %s\n", drivename, devicename); /* create a create command */
1552 ioctl(superdev, VINUM_CREATE, command);
1553 reply = (struct _ioctl_reply *) &command;
1554 if (reply->error != 0) { /* error in config */
1555 if (reply->msg[0])
1556 fprintf(stderr,
1557 "Can't create drive %s, device %s: %s\n",
1558 drivename,
1559 devicename,
1560 reply->msg);
1561 else
1562 fprintf(stderr,
1563 "Can't create drive %s, device %s: %s (%d)\n",
1564 drivename,
1565 devicename,
1566 strerror(reply->error),
1567 reply->error);
1568 longjmp(command_fail, -1); /* give up */
1570 find_object(drivename, &type);
1571 free(devicename);
1572 return &drive; /* return the name of the drive */
1575 fprintf(stderr, "Can't generate a drive name\n");
1576 /* NOTREACHED */
1577 free(devicename);
1578 return NULL;
1582 * Create a volume with a single concatenated plex from
1583 * as much space as we can get on the specified drives.
1584 * If the drives aren't Vinum drives, make them so.
1586 void
1587 vinum_concat(int argc, char *argv[], char *argv0[])
1589 int o; /* object number */
1590 char buffer[BUFSIZE];
1591 struct drive *drive; /* drive we're currently looking at */
1592 struct _ioctl_reply *reply;
1593 int ioctltype;
1594 int error;
1595 enum objecttype type;
1597 reply = (struct _ioctl_reply *) &buffer;
1598 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1599 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1600 return;
1602 if (!objectname) /* we need a name for our object */
1603 genvolname();
1604 sprintf(buffer, "volume %s", objectname);
1605 if (vflag)
1606 printf("volume %s\n", objectname);
1607 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1608 if (reply->error != 0) { /* error in config */
1609 if (reply->msg[0])
1610 fprintf(stderr,
1611 "Can't create volume %s: %s\n",
1612 objectname,
1613 reply->msg);
1614 else
1615 fprintf(stderr,
1616 "Can't create volume %s: %s (%d)\n",
1617 objectname,
1618 strerror(reply->error),
1619 reply->error);
1620 longjmp(command_fail, -1); /* give up */
1622 sprintf(buffer, "plex name %s.p0 org concat", objectname);
1623 if (vflag)
1624 printf(" plex name %s.p0 org concat\n", objectname);
1625 ioctl(superdev, VINUM_CREATE, buffer);
1626 if (reply->error != 0) { /* error in config */
1627 if (reply->msg[0])
1628 fprintf(stderr,
1629 "Can't create plex %s.p0: %s\n",
1630 objectname,
1631 reply->msg);
1632 else
1633 fprintf(stderr,
1634 "Can't create plex %s.p0: %s (%d)\n",
1635 objectname,
1636 strerror(reply->error),
1637 reply->error);
1638 longjmp(command_fail, -1); /* give up */
1640 for (o = 0; o < argc; o++) {
1641 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1642 drive = create_drive(argv[o]); /* create it */
1643 sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name);
1644 if (vflag)
1645 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name);
1646 ioctl(superdev, VINUM_CREATE, buffer);
1647 if (reply->error != 0) { /* error in config */
1648 if (reply->msg[0])
1649 fprintf(stderr,
1650 "Can't create subdisk %s.p0.s%d: %s\n",
1651 objectname,
1653 reply->msg);
1654 else
1655 fprintf(stderr,
1656 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1657 objectname,
1659 strerror(reply->error),
1660 reply->error);
1661 longjmp(command_fail, -1); /* give up */
1665 /* done, save the config */
1666 ioctltype = 0; /* saveconfig after update */
1667 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1668 if (error != 0)
1669 perror("Can't save Vinum config");
1670 find_object(objectname, &type); /* find the index of the volume */
1671 #if 0
1672 make_vol_dev(vol.volno, 1); /* and create the devices */
1673 #endif
1674 if (vflag) {
1675 vflag--; /* XXX don't give too much detail */
1676 find_object(objectname, &type); /* point to the volume */
1677 vinum_lvi(vol.volno, 1); /* and print info about it */
1683 * Create a volume with a single striped plex from
1684 * as much space as we can get on the specified drives.
1685 * If the drives aren't Vinum drives, make them so.
1687 void
1688 vinum_stripe(int argc, char *argv[], char *argv0[])
1690 int o; /* object number */
1691 char buffer[BUFSIZE];
1692 struct drive *drive; /* drive we're currently looking at */
1693 struct _ioctl_reply *reply;
1694 int ioctltype;
1695 int error;
1696 enum objecttype type;
1697 off_t maxsize;
1698 int fe; /* freelist entry index */
1699 union freeunion {
1700 struct drive_freelist freelist;
1701 struct ferq { /* request to pass to ioctl */
1702 int driveno;
1703 int fe;
1704 } ferq;
1705 } freeunion;
1706 u_int64_t bigchunk; /* biggest chunk in freelist */
1708 maxsize = QUAD_MAX;
1709 reply = (struct _ioctl_reply *) &buffer;
1712 * First, check our drives.
1714 if (argc < 2) {
1715 fprintf(stderr, "You need at least two drives to create a striped plex\n");
1716 return;
1718 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1719 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1720 return;
1722 if (!objectname) /* we need a name for our object */
1723 genvolname();
1724 for (o = 0; o < argc; o++) {
1725 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1726 drive = create_drive(argv[o]); /* create it */
1727 /* Now find the largest chunk available on the drive */
1728 bigchunk = 0; /* ain't found nothin' yet */
1729 for (fe = 0; fe < drive->freelist_entries; fe++) {
1730 freeunion.ferq.driveno = drive->driveno;
1731 freeunion.ferq.fe = fe;
1732 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
1733 fprintf(stderr,
1734 "Can't get free list element %d: %s\n",
1736 strerror(errno));
1737 longjmp(command_fail, -1);
1739 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
1741 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1744 /* Now create the volume */
1745 sprintf(buffer, "volume %s", objectname);
1746 if (vflag)
1747 printf("volume %s\n", objectname);
1748 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1749 if (reply->error != 0) { /* error in config */
1750 if (reply->msg[0])
1751 fprintf(stderr,
1752 "Can't create volume %s: %s\n",
1753 objectname,
1754 reply->msg);
1755 else
1756 fprintf(stderr,
1757 "Can't create volume %s: %s (%d)\n",
1758 objectname,
1759 strerror(reply->error),
1760 reply->error);
1761 longjmp(command_fail, -1); /* give up */
1763 sprintf(buffer, "plex name %s.p0 org striped 256k", objectname);
1764 if (vflag)
1765 printf(" plex name %s.p0 org striped 256k\n", objectname);
1766 ioctl(superdev, VINUM_CREATE, buffer);
1767 if (reply->error != 0) { /* error in config */
1768 if (reply->msg[0])
1769 fprintf(stderr,
1770 "Can't create plex %s.p0: %s\n",
1771 objectname,
1772 reply->msg);
1773 else
1774 fprintf(stderr,
1775 "Can't create plex %s.p0: %s (%d)\n",
1776 objectname,
1777 strerror(reply->error),
1778 reply->error);
1779 longjmp(command_fail, -1); /* give up */
1781 for (o = 0; o < argc; o++) {
1782 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1783 sprintf(buffer,
1784 "sd name %s.p0.s%d drive %s size %lldb",
1785 objectname,
1787 drive->label.name,
1788 (long long) maxsize);
1789 if (vflag)
1790 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1791 objectname,
1793 drive->label.name,
1794 (long long) maxsize);
1795 ioctl(superdev, VINUM_CREATE, buffer);
1796 if (reply->error != 0) { /* error in config */
1797 if (reply->msg[0])
1798 fprintf(stderr,
1799 "Can't create subdisk %s.p0.s%d: %s\n",
1800 objectname,
1802 reply->msg);
1803 else
1804 fprintf(stderr,
1805 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1806 objectname,
1808 strerror(reply->error),
1809 reply->error);
1810 longjmp(command_fail, -1); /* give up */
1814 /* done, save the config */
1815 ioctltype = 0; /* saveconfig after update */
1816 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1817 if (error != 0)
1818 perror("Can't save Vinum config");
1819 find_object(objectname, &type); /* find the index of the volume */
1820 #if 0
1821 make_vol_dev(vol.volno, 1); /* and create the devices */
1822 #endif
1823 if (vflag) {
1824 vflag--; /* XXX don't give too much detail */
1825 find_object(objectname, &type); /* point to the volume */
1826 vinum_lvi(vol.volno, 1); /* and print info about it */
1831 * Create a volume with a single RAID-4 plex from
1832 * as much space as we can get on the specified drives.
1833 * If the drives aren't Vinum drives, make them so.
1835 void
1836 vinum_raid4(int argc, char *argv[], char *argv0[])
1838 int o; /* object number */
1839 char buffer[BUFSIZE];
1840 struct drive *drive; /* drive we're currently looking at */
1841 struct _ioctl_reply *reply;
1842 int ioctltype;
1843 int error;
1844 enum objecttype type;
1845 off_t maxsize;
1846 int fe; /* freelist entry index */
1847 union freeunion {
1848 struct drive_freelist freelist;
1849 struct ferq { /* request to pass to ioctl */
1850 int driveno;
1851 int fe;
1852 } ferq;
1853 } freeunion;
1854 u_int64_t bigchunk; /* biggest chunk in freelist */
1856 maxsize = QUAD_MAX;
1857 reply = (struct _ioctl_reply *) &buffer;
1860 * First, check our drives.
1862 if (argc < 3) {
1863 fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n");
1864 return;
1866 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1867 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1868 return;
1870 if (!objectname) /* we need a name for our object */
1871 genvolname();
1872 for (o = 0; o < argc; o++) {
1873 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1874 drive = create_drive(argv[o]); /* create it */
1875 /* Now find the largest chunk available on the drive */
1876 bigchunk = 0; /* ain't found nothin' yet */
1877 for (fe = 0; fe < drive->freelist_entries; fe++) {
1878 freeunion.ferq.driveno = drive->driveno;
1879 freeunion.ferq.fe = fe;
1880 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
1881 fprintf(stderr,
1882 "Can't get free list element %d: %s\n",
1884 strerror(errno));
1885 longjmp(command_fail, -1);
1887 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
1889 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1892 /* Now create the volume */
1893 sprintf(buffer, "volume %s", objectname);
1894 if (vflag)
1895 printf("volume %s\n", objectname);
1896 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1897 if (reply->error != 0) { /* error in config */
1898 if (reply->msg[0])
1899 fprintf(stderr,
1900 "Can't create volume %s: %s\n",
1901 objectname,
1902 reply->msg);
1903 else
1904 fprintf(stderr,
1905 "Can't create volume %s: %s (%d)\n",
1906 objectname,
1907 strerror(reply->error),
1908 reply->error);
1909 longjmp(command_fail, -1); /* give up */
1911 sprintf(buffer, "plex name %s.p0 org raid4 256k", objectname);
1912 if (vflag)
1913 printf(" plex name %s.p0 org raid4 256k\n", objectname);
1914 ioctl(superdev, VINUM_CREATE, buffer);
1915 if (reply->error != 0) { /* error in config */
1916 if (reply->msg[0])
1917 fprintf(stderr,
1918 "Can't create plex %s.p0: %s\n",
1919 objectname,
1920 reply->msg);
1921 else
1922 fprintf(stderr,
1923 "Can't create plex %s.p0: %s (%d)\n",
1924 objectname,
1925 strerror(reply->error),
1926 reply->error);
1927 longjmp(command_fail, -1); /* give up */
1929 for (o = 0; o < argc; o++) {
1930 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1931 sprintf(buffer,
1932 "sd name %s.p0.s%d drive %s size %lldb",
1933 objectname,
1935 drive->label.name,
1936 (long long) maxsize);
1937 if (vflag)
1938 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1939 objectname,
1941 drive->label.name,
1942 (long long) maxsize);
1943 ioctl(superdev, VINUM_CREATE, buffer);
1944 if (reply->error != 0) { /* error in config */
1945 if (reply->msg[0])
1946 fprintf(stderr,
1947 "Can't create subdisk %s.p0.s%d: %s\n",
1948 objectname,
1950 reply->msg);
1951 else
1952 fprintf(stderr,
1953 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1954 objectname,
1956 strerror(reply->error),
1957 reply->error);
1958 longjmp(command_fail, -1); /* give up */
1962 /* done, save the config */
1963 ioctltype = 0; /* saveconfig after update */
1964 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1965 if (error != 0)
1966 perror("Can't save Vinum config");
1967 find_object(objectname, &type); /* find the index of the volume */
1968 #if 0
1969 make_vol_dev(vol.volno, 1); /* and create the devices */
1970 #endif
1971 if (vflag) {
1972 vflag--; /* XXX don't give too much detail */
1973 find_object(objectname, &type); /* point to the volume */
1974 vinum_lvi(vol.volno, 1); /* and print info about it */
1979 * Create a volume with a single RAID-4 plex from
1980 * as much space as we can get on the specified drives.
1981 * If the drives aren't Vinum drives, make them so.
1983 void
1984 vinum_raid5(int argc, char *argv[], char *argv0[])
1986 int o; /* object number */
1987 char buffer[BUFSIZE];
1988 struct drive *drive; /* drive we're currently looking at */
1989 struct _ioctl_reply *reply;
1990 int ioctltype;
1991 int error;
1992 enum objecttype type;
1993 off_t maxsize;
1994 int fe; /* freelist entry index */
1995 union freeunion {
1996 struct drive_freelist freelist;
1997 struct ferq { /* request to pass to ioctl */
1998 int driveno;
1999 int fe;
2000 } ferq;
2001 } freeunion;
2002 u_int64_t bigchunk; /* biggest chunk in freelist */
2004 maxsize = QUAD_MAX;
2005 reply = (struct _ioctl_reply *) &buffer;
2008 * First, check our drives.
2010 if (argc < 3) {
2011 fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n");
2012 return;
2014 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
2015 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
2016 return;
2018 if (!objectname) /* we need a name for our object */
2019 genvolname();
2020 for (o = 0; o < argc; o++) {
2021 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
2022 drive = create_drive(argv[o]); /* create it */
2023 /* Now find the largest chunk available on the drive */
2024 bigchunk = 0; /* ain't found nothin' yet */
2025 for (fe = 0; fe < drive->freelist_entries; fe++) {
2026 freeunion.ferq.driveno = drive->driveno;
2027 freeunion.ferq.fe = fe;
2028 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
2029 fprintf(stderr,
2030 "Can't get free list element %d: %s\n",
2032 strerror(errno));
2033 longjmp(command_fail, -1);
2035 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
2037 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
2040 /* Now create the volume */
2041 sprintf(buffer, "volume %s", objectname);
2042 if (vflag)
2043 printf("volume %s\n", objectname);
2044 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
2045 if (reply->error != 0) { /* error in config */
2046 if (reply->msg[0])
2047 fprintf(stderr,
2048 "Can't create volume %s: %s\n",
2049 objectname,
2050 reply->msg);
2051 else
2052 fprintf(stderr,
2053 "Can't create volume %s: %s (%d)\n",
2054 objectname,
2055 strerror(reply->error),
2056 reply->error);
2057 longjmp(command_fail, -1); /* give up */
2059 sprintf(buffer, "plex name %s.p0 org raid5 256k", objectname);
2060 if (vflag)
2061 printf(" plex name %s.p0 org raid5 256k\n", objectname);
2062 ioctl(superdev, VINUM_CREATE, buffer);
2063 if (reply->error != 0) { /* error in config */
2064 if (reply->msg[0])
2065 fprintf(stderr,
2066 "Can't create plex %s.p0: %s\n",
2067 objectname,
2068 reply->msg);
2069 else
2070 fprintf(stderr,
2071 "Can't create plex %s.p0: %s (%d)\n",
2072 objectname,
2073 strerror(reply->error),
2074 reply->error);
2075 longjmp(command_fail, -1); /* give up */
2077 for (o = 0; o < argc; o++) {
2078 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2079 sprintf(buffer,
2080 "sd name %s.p0.s%d drive %s size %lldb",
2081 objectname,
2083 drive->label.name,
2084 (long long) maxsize);
2085 if (vflag)
2086 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
2087 objectname,
2089 drive->label.name,
2090 (long long) maxsize);
2091 ioctl(superdev, VINUM_CREATE, buffer);
2092 if (reply->error != 0) { /* error in config */
2093 if (reply->msg[0])
2094 fprintf(stderr,
2095 "Can't create subdisk %s.p0.s%d: %s\n",
2096 objectname,
2098 reply->msg);
2099 else
2100 fprintf(stderr,
2101 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2102 objectname,
2104 strerror(reply->error),
2105 reply->error);
2106 longjmp(command_fail, -1); /* give up */
2110 /* done, save the config */
2111 ioctltype = 0; /* saveconfig after update */
2112 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2113 if (error != 0)
2114 perror("Can't save Vinum config");
2115 find_object(objectname, &type); /* find the index of the volume */
2116 #if 0
2117 make_vol_dev(vol.volno, 1); /* and create the devices */
2118 #endif
2119 if (vflag) {
2120 vflag--; /* XXX don't give too much detail */
2121 find_object(objectname, &type); /* point to the volume */
2122 vinum_lvi(vol.volno, 1); /* and print info about it */
2127 * Create a volume with a two plexes from as much space
2128 * as we can get on the specified drives. If the
2129 * drives aren't Vinum drives, make them so.
2131 * The number of drives must be even, and at least 4
2132 * for a striped plex. Specify striped plexes with the
2133 * -s flag; otherwise they will be concatenated. It's
2134 * possible that the two plexes may differ in length.
2136 void
2137 vinum_mirror(int argc, char *argv[], char *argv0[])
2139 int o; /* object number */
2140 int p; /* plex number */
2141 char buffer[BUFSIZE];
2142 struct drive *drive; /* drive we're currently looking at */
2143 struct _ioctl_reply *reply;
2144 int ioctltype;
2145 int error;
2146 enum objecttype type;
2147 off_t maxsize[2]; /* maximum subdisk size for striped plexes */
2148 int fe; /* freelist entry index */
2149 union freeunion {
2150 struct drive_freelist freelist;
2151 struct ferq { /* request to pass to ioctl */
2152 int driveno;
2153 int fe;
2154 } ferq;
2155 } freeunion;
2156 u_int64_t bigchunk; /* biggest chunk in freelist */
2158 if (sflag) /* striped, */
2159 maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */
2160 else
2161 maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */
2163 reply = (struct _ioctl_reply *) &buffer;
2166 * First, check our drives.
2168 if (argc & 1) {
2169 fprintf(stderr, "You need an even number of drives to create a mirrored volume\n");
2170 return;
2172 if (sflag && (argc < 4)) {
2173 fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n");
2174 return;
2176 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
2177 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
2178 return;
2180 if (!objectname) /* we need a name for our object */
2181 genvolname();
2182 for (o = 0; o < argc; o++) {
2183 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
2184 drive = create_drive(argv[o]); /* create it */
2185 if (sflag) { /* striping, */
2186 /* Find the largest chunk available on the drive */
2187 bigchunk = 0; /* ain't found nothin' yet */
2188 for (fe = 0; fe < drive->freelist_entries; fe++) {
2189 freeunion.ferq.driveno = drive->driveno;
2190 freeunion.ferq.fe = fe;
2191 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) {
2192 fprintf(stderr,
2193 "Can't get free list element %d: %s\n",
2195 strerror(errno));
2196 longjmp(command_fail, -1);
2198 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */
2200 maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */
2204 /* Now create the volume */
2205 sprintf(buffer, "volume %s setupstate", objectname);
2206 if (vflag)
2207 printf("volume %s setupstate\n", objectname);
2208 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
2209 if (reply->error != 0) { /* error in config */
2210 if (reply->msg[0])
2211 fprintf(stderr,
2212 "Can't create volume %s: %s\n",
2213 objectname,
2214 reply->msg);
2215 else
2216 fprintf(stderr,
2217 "Can't create volume %s: %s (%d)\n",
2218 objectname,
2219 strerror(reply->error),
2220 reply->error);
2221 longjmp(command_fail, -1); /* give up */
2223 for (p = 0; p < 2; p++) { /* create each plex */
2224 if (sflag) {
2225 sprintf(buffer, "plex name %s.p%d org striped 256k", objectname, p);
2226 if (vflag)
2227 printf(" plex name %s.p%d org striped 256k\n", objectname, p);
2228 } else { /* concat */
2229 sprintf(buffer, "plex name %s.p%d org concat", objectname, p);
2230 if (vflag)
2231 printf(" plex name %s.p%d org concat\n", objectname, p);
2233 ioctl(superdev, VINUM_CREATE, buffer);
2234 if (reply->error != 0) { /* error in config */
2235 if (reply->msg[0])
2236 fprintf(stderr,
2237 "Can't create plex %s.p%d: %s\n",
2238 objectname,
2240 reply->msg);
2241 else
2242 fprintf(stderr,
2243 "Can't create plex %s.p%d: %s (%d)\n",
2244 objectname,
2246 strerror(reply->error),
2247 reply->error);
2248 longjmp(command_fail, -1); /* give up */
2250 /* Now look at the subdisks */
2251 for (o = p; o < argc; o += 2) { /* every second one */
2252 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2253 sprintf(buffer,
2254 "sd name %s.p%d.s%d drive %s size %lldb",
2255 objectname,
2257 o >> 1,
2258 drive->label.name,
2259 (long long) maxsize[p]);
2260 if (vflag)
2261 printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
2262 objectname,
2264 o >> 1,
2265 drive->label.name,
2266 (long long) maxsize[p]);
2267 ioctl(superdev, VINUM_CREATE, buffer);
2268 if (reply->error != 0) { /* error in config */
2269 if (reply->msg[0])
2270 fprintf(stderr,
2271 "Can't create subdisk %s.p%d.s%d: %s\n",
2272 objectname,
2274 o >> 1,
2275 reply->msg);
2276 else
2277 fprintf(stderr,
2278 "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2279 objectname,
2281 o >> 1,
2282 strerror(reply->error),
2283 reply->error);
2284 longjmp(command_fail, -1); /* give up */
2289 /* done, save the config */
2290 ioctltype = 0; /* saveconfig after update */
2291 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2292 if (error != 0)
2293 perror("Can't save Vinum config");
2294 find_object(objectname, &type); /* find the index of the volume */
2295 #if 0
2296 make_vol_dev(vol.volno, 1); /* and create the devices */
2297 #endif
2298 if (vflag) {
2299 vflag--; /* XXX don't give too much detail */
2300 sflag = 0; /* no stats, please */
2301 find_object(objectname, &type); /* point to the volume */
2302 vinum_lvi(vol.volno, 1); /* and print info about it */
2306 void
2307 vinum_readpol(int argc, char *argv[], char *argv0[])
2309 int object;
2310 struct _ioctl_reply reply;
2311 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2312 enum objecttype type;
2313 struct plex plex;
2314 struct volume vol;
2315 int plexno;
2317 if (argc == 0) { /* start everything */
2318 fprintf(stderr, "Usage: readpol <volume> <plex>|round\n");
2319 return;
2321 object = find_object(argv[1], &type); /* look for it */
2322 if (type != volume_object) {
2323 fprintf(stderr, "%s is not a volume\n", argv[1]);
2324 return;
2326 get_volume_info(&vol, object);
2327 if (strcmp(argv[2], "round")) { /* not 'round' */
2328 object = find_object(argv[2], &type); /* look for it */
2329 if (type != plex_object) {
2330 fprintf(stderr, "%s is not a plex\n", argv[2]);
2331 return;
2333 get_plex_info(&plex, object);
2334 plexno = plex.plexno;
2335 } else /* round */
2336 plexno = -1;
2338 /* Set the value */
2339 message->index = vol.volno;
2340 message->otherobject = plexno;
2341 if (ioctl(superdev, VINUM_READPOL, message) < 0)
2342 fprintf(stderr, "Can't set read policy: %s (%d)\n", strerror(errno), errno);
2343 if (vflag)
2344 vinum_lpi(plexno, recurse);
2348 * Brute force set state function. Don't look at
2349 * any dependencies, just do it.
2351 void
2352 vinum_setstate(int argc, char *argv[], char *argv0[])
2354 int object;
2355 struct _ioctl_reply reply;
2356 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2357 int index;
2358 enum objecttype type;
2359 int state;
2361 for (index = 1; index < argc; index++) {
2362 object = find_object(argv[index], &type); /* look for it */
2363 if (type == invalid_object)
2364 fprintf(stderr, "Can't find object: %s\n", argv[index]);
2365 else {
2366 int doit = 0; /* set to 1 if we pass our tests */
2367 switch (type) {
2368 case drive_object:
2369 state = DriveState(argv[0]); /* get the state */
2370 if (drive.state == state) /* already in that state */
2371 fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]);
2372 else
2373 doit = 1;
2374 break;
2376 case sd_object:
2377 state = SdState(argv[0]); /* get the state */
2378 if (sd.state == state) /* already in that state */
2379 fprintf(stderr, "%s is already %s\n", sd.name, argv[0]);
2380 else
2381 doit = 1;
2382 break;
2384 case plex_object:
2385 state = PlexState(argv[0]); /* get the state */
2386 if (plex.state == state) /* already in that state */
2387 fprintf(stderr, "%s is already %s\n", plex.name, argv[0]);
2388 else
2389 doit = 1;
2390 break;
2392 case volume_object:
2393 state = VolState(argv[0]); /* get the state */
2394 if (vol.state == state) /* already in that state */
2395 fprintf(stderr, "%s is already %s\n", vol.name, argv[0]);
2396 else
2397 doit = 1;
2398 break;
2400 default:
2401 state = 0; /* to keep the compiler happy */
2404 if (state == -1)
2405 fprintf(stderr, "Invalid state for object: %s\n", argv[0]);
2406 else if (doit) {
2407 message->index = object; /* pass object number */
2408 message->type = type; /* and type of object */
2409 message->state = state;
2410 message->force = force; /* don't force it, use a larger hammer */
2411 ioctl(superdev, VINUM_SETSTATE_FORCE, message);
2412 if (reply.error != 0)
2413 fprintf(stderr,
2414 "Can't start %s: %s (%d)\n",
2415 argv[index],
2416 reply.msg[0] ? reply.msg : strerror(reply.error),
2417 reply.error);
2418 if (Verbose)
2419 vinum_li(object, type);
2425 void
2426 vinum_checkparity(int argc, char *argv[], char *argv0[])
2428 Verbose = vflag; /* accept -v for verbose */
2429 if (argc == 0) /* no parameters? */
2430 fprintf(stderr, "Usage: checkparity object [object...]\n");
2431 else
2432 parityops(argc, argv, checkparity);
2435 void
2436 vinum_rebuildparity(int argc, char *argv[], char *argv0[])
2438 if (argc == 0) /* no parameters? */
2439 fprintf(stderr, "Usage: rebuildparity object [object...]\n");
2440 else
2441 parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity);
2445 * Common code for rebuildparity and checkparity.
2446 * We bend the meanings of some flags here:
2448 * -v: Report incorrect parity on rebuild.
2449 * -V: Show running count of position being checked.
2450 * -f: Start from beginning of the plex.
2452 void
2453 parityops(int argc, char *argv[], enum parityop op)
2455 int object;
2456 struct plex plex;
2457 struct _ioctl_reply reply;
2458 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2459 int index;
2460 enum objecttype type;
2461 char *msg;
2462 off_t block;
2464 if (op == checkparity)
2465 msg = "Checking";
2466 else
2467 msg = "Rebuilding";
2468 for (index = 0; index < argc; index++) {
2469 object = find_object(argv[index], &type); /* look for it */
2470 if (type != plex_object)
2471 fprintf(stderr, "%s is not a plex\n", argv[index]);
2472 else {
2473 get_plex_info(&plex, object);
2474 if (!isparity((&plex)))
2475 fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]);
2476 else {
2477 do {
2478 message->index = object; /* pass object number */
2479 message->type = type; /* and type of object */
2480 message->op = op; /* what to do */
2481 if (force)
2482 message->offset = 0; /* start at the beginning */
2483 else
2484 message->offset = plex.checkblock; /* continue where we left off */
2485 force = 0; /* don't reset after the first time */
2486 ioctl(superdev, VINUM_PARITYOP, message);
2487 get_plex_info(&plex, object);
2488 if (Verbose) {
2489 block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1);
2490 if (block != 0)
2491 printf("\r%s at %s (%d%%) ",
2492 msg,
2493 roughlength(block, 1),
2494 ((int) (block * 100 / plex.length) >> DEV_BSHIFT));
2495 if ((reply.error == EAGAIN)
2496 && (reply.msg[0])) /* got a comment back */
2497 fputs(reply.msg, stderr); /* show it */
2498 fflush(stdout);
2501 while (reply.error == EAGAIN);
2502 if (reply.error != 0) {
2503 if (reply.msg[0])
2504 fputs(reply.msg, stderr);
2505 else
2506 fprintf(stderr,
2507 "%s failed: %s\n",
2508 msg,
2509 strerror(reply.error));
2510 } else if (Verbose) {
2511 if (op == checkparity)
2512 fprintf(stderr, "%s has correct parity\n", argv[index]);
2513 else
2514 fprintf(stderr, "Rebuilt parity on %s\n", argv[index]);
2521 /* Local Variables: */
2522 /* fill-column: 50 */
2523 /* End: */