1 /* commands.c: vinum interface program, main commands */
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
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Company nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * This software is provided ``as is'', and any express or implied
24 * warranties, including, but not limited to, the implied warranties of
25 * merchantability and fitness for a particular purpose are disclaimed.
26 * In no event shall the company or contributors be liable for any
27 * direct, indirect, incidental, special, exemplary, or consequential
28 * damages (including, but not limited to, procurement of substitute
29 * goods or services; loss of use, data, or profits; or business
30 * interruption) however caused and on any theory of liability, whether
31 * in contract, strict liability, or tort (including negligence or
32 * otherwise) arising in any way out of the use of this software, even if
33 * advised of the possibility of such damage.
35 * $Id: commands.c,v 1.14 2000/11/14 20:01:23 grog Exp grog $
36 * $FreeBSD: src/sbin/vinum/commands.c,v 1.31.2.6 2003/06/06 05:13:29 grog Exp $
37 * $DragonFly: src/sbin/vinum/commands.c,v 1.7 2007/01/20 20:20:39 dillon Exp $
40 #define _KERNEL_STRUCTURES
54 #include <sys/ioctl.h>
55 #include <dev/raid/vinum/vinumhdr.h>
56 #include <dev/raid/vinum/request.h>
58 #include <sys/types.h>
59 #include <sys/linker.h>
60 #include <sys/module.h>
62 #include <readline/history.h>
63 #include <readline/readline.h>
66 static void dorename(struct vinum_rename_msg
*msg
, const char *oldname
, const char *name
, int maxlen
);
69 vinum_create(int argc
, char *argv
[], char *arg0
[])
72 FILE *dfd
; /* file descriptor for the config file */
73 char buffer
[BUFSIZE
]; /* read config file in here */
74 char commandline
[BUFSIZE
]; /* issue command from here */
75 struct _ioctl_reply
*reply
;
76 int ioctltype
; /* for ioctl call */
77 char tempfile
[PATH_MAX
]; /* name of temp file for direct editing */
78 char *file
; /* file to read */
79 FILE *tf
; /* temp file */
81 if (argc
== 0) { /* no args, */
82 char *editor
; /* editor to start */
85 editor
= getenv("EDITOR");
87 editor
= "/usr/bin/vi";
88 sprintf(tempfile
, "/var/tmp/" VINUMMOD
".create.%d", getpid()); /* create a temp file */
89 tf
= fopen(tempfile
, "w"); /* open it */
91 fprintf(stderr
, "Can't open %s: %s\n", argv
[0], strerror(errno
));
94 printconfig(tf
, "# "); /* and put the current config it */
96 sprintf(commandline
, "%s %s", editor
, tempfile
); /* create an edit command */
97 status
= system(commandline
); /* do it */
99 fprintf(stderr
, "Can't edit config: status %d\n", status
);
103 } else if (argc
== 1)
106 fprintf(stderr
, "Expecting 1 parameter, not %d\n", argc
);
109 reply
= (struct _ioctl_reply
*) &buffer
;
110 dfd
= fopen(file
, "r");
111 if (dfd
== NULL
) { /* no go */
112 fprintf(stderr
, "Can't open %s: %s\n", file
, strerror(errno
));
115 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
116 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
119 file_line
= 0; /* start with line 1 */
120 /* Parse the configuration, and add it to the global configuration */
121 for (;;) { /* love this style(9) */
124 configline
= fgets(buffer
, BUFSIZE
, dfd
);
126 fprintf(history
, "%s", buffer
);
128 if (configline
== NULL
) {
130 perror("Can't read config file");
133 file_line
++; /* count the lines */
135 printf("%4d: %s", file_line
, buffer
);
136 strcpy(commandline
, buffer
); /* make a copy */
137 ioctl(superdev
, VINUM_CREATE
, buffer
);
138 if (reply
->error
!= 0) { /* error in config */
139 if (!vflag
) /* print this line anyway */
140 printf("%4d: %s", file_line
, commandline
);
141 fprintf(stdout
, "** %d %s: %s\n",
144 strerror(reply
->error
));
147 * XXX at the moment, we reset the config
148 * lock on error, so try to get it again.
149 * If we fail, don't cry again.
151 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) /* can't get config? */
155 fclose(dfd
); /* done with the config file */
156 ioctltype
= 0; /* saveconfig after update */
157 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
159 perror("Can't save Vinum config");
162 checkupdates(); /* make sure we're updating */
165 /* Read vinum config from a disk */
167 vinum_read(int argc
, char *argv
[], char *arg0
[])
170 char buffer
[BUFSIZE
]; /* read config file in here */
171 struct _ioctl_reply
*reply
;
174 reply
= (struct _ioctl_reply
*) &buffer
;
175 if (argc
< 1) { /* wrong arg count */
176 fprintf(stderr
, "Usage: read drive [drive ...]\n");
179 strcpy(buffer
, "read ");
180 for (i
= 0; i
< argc
; i
++) { /* each drive name */
181 strcat(buffer
, argv
[i
]);
185 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
186 fprintf(stderr
, "Can't configure: %s (%d)\n", strerror(errno
), errno
);
189 ioctl(superdev
, VINUM_CREATE
, &buffer
);
190 if (reply
->error
!= 0) { /* error in config */
191 fprintf(stdout
, "** %s: %s\n", reply
->msg
, strerror(reply
->error
));
192 error
= ioctl(superdev
, VINUM_RELEASECONFIG
, NULL
); /* save the config to disk */
194 perror("Can't save Vinum config");
196 error
= ioctl(superdev
, VINUM_RELEASECONFIG
, NULL
); /* save the config to disk */
198 perror("Can't save Vinum config");
201 checkupdates(); /* make sure we're updating */
206 vinum_debug(int argc
, char *argv
[], char *arg0
[])
208 struct debuginfo info
;
211 info
.param
= atoi(argv
[0]);
215 sleep(2); /* give a chance to leave the window */
217 ioctl(superdev
, VINUM_DEBUG
, (caddr_t
) & info
);
222 vinum_modify(int argc
, char *argv
[], char *arg0
[])
224 fprintf(stderr
, "Modify command is currently not implemented\n");
225 checkupdates(); /* make sure we're updating */
229 vinum_set(int argc
, char *argv
[], char *arg0
[])
231 fprintf(stderr
, "set is not implemented yet\n");
235 vinum_rm(int argc
, char *argv
[], char *arg0
[])
238 struct _ioctl_reply reply
;
239 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
241 if (argc
== 0) /* start everything */
242 fprintf(stderr
, "Usage: rm object [object...]\n");
243 else { /* start specified objects */
245 enum objecttype type
;
247 for (index
= 0; index
< argc
; index
++) {
248 object
= find_object(argv
[index
], &type
); /* look for it */
249 if (type
== invalid_object
)
250 fprintf(stderr
, "Can't find object: %s\n", argv
[index
]);
252 message
->index
= object
; /* pass object number */
253 message
->type
= type
; /* and type of object */
254 message
->force
= force
; /* do we want to force the operation? */
255 message
->recurse
= recurse
; /* do we want to remove subordinates? */
256 ioctl(superdev
, VINUM_REMOVE
, message
);
257 if (reply
.error
!= 0) {
259 "Can't remove %s: %s (%d)\n",
261 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
264 fprintf(stderr
, "%s removed\n", argv
[index
]);
267 checkupdates(); /* make sure we're updating */
272 vinum_resetconfig(int argc
, char *argv
[], char *arg0
[])
277 if (! isatty (STDIN_FILENO
)) {
278 fprintf (stderr
, "Please enter this command from a tty device\n");
281 printf(" WARNING! This command will completely wipe out your vinum configuration.\n"
282 " All data will be lost. If you really want to do this, enter the text\n\n"
285 fgets(reply
, sizeof(reply
), stdin
);
286 if (strcmp(reply
, "NO FUTURE\n")) /* changed his mind */
287 printf("\n No change\n");
289 error
= ioctl(superdev
, VINUM_RESETCONFIG
, NULL
); /* trash config on disk */
292 fprintf(stderr
, "Can't reset configuration: objects are in use\n");
294 perror("Can't find vinum config");
296 make_devices(); /* recreate the /dev/vinum hierarchy */
297 printf("\b Vinum configuration obliterated\n");
298 start_daemon(); /* then restart the daemon */
301 checkupdates(); /* make sure we're updating */
304 /* Initialize subdisks */
306 vinum_init(int argc
, char *argv
[], char *arg0
[])
308 if (argc
> 0) { /* initialize plexes */
311 enum objecttype type
; /* type returned */
314 fflush(history
); /* don't let all the kids do it. */
315 for (objindex
= 0; objindex
< argc
; objindex
++) {
316 objno
= find_object(argv
[objindex
], &type
); /* find the object */
318 printf("Can't find %s\n", argv
[objindex
]);
326 initplex(objno
, argv
[objindex
]);
330 initsd(objno
, dowait
);
334 printf("Can't initialize %s: wrong object type\n", argv
[objindex
]);
340 checkupdates(); /* make sure we're updating */
346 printf("Initializing volumes is not implemented yet\n");
350 initplex(int plexno
, char *name
)
353 int plexfh
= NULL
; /* file handle for plex */
355 char filename
[MAXPATHLEN
]; /* create a file name here */
357 /* Variables for use by children */
358 int failed
= 0; /* set if a child dies badly */
360 sprintf(filename
, VINUM_DIR
"/plex/%s", name
);
361 if ((plexfh
= open(filename
, O_RDWR
, S_IRWXU
)) < 0) { /* got a plex, open it */
363 * We don't actually write anything to the
364 * plex. We open it to ensure that nobody
365 * else tries to open it while we initialize
368 fprintf(stderr
, "can't open plex %s: %s\n", filename
, strerror(errno
));
372 pid
= fork(); /* into the background with you */
373 if (pid
!= 0) { /* I'm the parent, or we failed */
374 if (pid
< 0) /* failure */
375 printf("Couldn't fork: %s", strerror(errno
));
376 close(plexfh
); /* we don't need this any more */
381 * If we get here, we're either the first-level
382 * child (if we're not waiting) or we're going
385 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) { /* initialize each subdisk */
386 get_plex_sd_info(&sd
, plexno
, sdno
);
389 /* Now wait for them to complete */
393 if (((int) pid
== -1)
394 && (errno
== ECHILD
)) /* all gone */
396 if (WEXITSTATUS(status
) != 0) { /* oh, oh */
397 printf("child %d exited with status 0x%x\n", pid
, WEXITSTATUS(status
));
403 message
->index
= plexno
; /* pass object number */
404 message
->type
= plex_object
; /* and type of object */
405 message
->state
= object_up
;
406 message
->force
= 1; /* insist */
407 ioctl(superdev
, VINUM_SETSTATE
, message
);
409 syslog(LOG_INFO
| LOG_KERN
, "plex %s initialized", plex
.name
);
411 syslog(LOG_ERR
| LOG_KERN
, "couldn't initialize plex %s, %d processes died",
414 if (dowait
== 0) /* we're the waiting child, */
415 exit(0); /* we've done our dash */
418 /* Initialize a subdisk. */
420 initsd(int sdno
, int dowait
)
423 struct _ioctl_reply reply
;
424 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
425 char filename
[MAXPATHLEN
]; /* create a file name here */
427 /* Variables for use by children */
428 int sdfh
; /* and for subdisk */
429 int initsize
; /* actual size to write */
430 int64_t sdsize
; /* size of subdisk */
433 pid
= fork(); /* into the background with you */
434 if (pid
> 0) /* I'm the parent */
436 else if (pid
< 0) { /* failure */
437 printf("couldn't fork for subdisk %d: %s", sdno
, strerror(errno
));
441 if (SSize
!= 0) { /* specified a size for init */
443 SSize
<<= DEV_BSHIFT
;
444 initsize
= min(SSize
, MAXPLEXINITSIZE
);
446 initsize
= PLEXINITSIZE
;
447 openlog("vinum", LOG_CONS
| LOG_PERROR
| LOG_PID
, LOG_KERN
);
448 get_sd_info(&sd
, sdno
);
449 sdsize
= sd
.sectors
* DEV_BSIZE
; /* size of subdisk in bytes */
450 sprintf(filename
, VINUM_DIR
"/sd/%s", sd
.name
);
451 setproctitle("initializing %s", filename
); /* show what we're doing */
452 syslog(LOG_INFO
| LOG_KERN
, "initializing subdisk %s", filename
);
453 if ((sdfh
= open(filename
, O_RDWR
, S_IRWXU
)) < 0) { /* no go */
454 syslog(LOG_ERR
| LOG_KERN
,
455 "can't open subdisk %s: %s",
460 /* Set the subdisk in initializing state */
461 message
->index
= sd
.sdno
; /* pass object number */
462 message
->type
= sd_object
; /* and type of object */
463 message
->state
= object_initializing
;
464 message
->verify
= vflag
; /* verify what we write? */
465 message
->force
= 1; /* insist */
466 ioctl(superdev
, VINUM_SETSTATE
, message
);
467 if ((SSize
> 0) /* specified a size for init */
469 SSize
<<= DEV_BSHIFT
;
472 "Can't initialize %s: %s (%d)\n",
474 strerror(reply
.error
),
479 if (interval
) /* pause between copies */
480 usleep(interval
* 1000);
481 message
->index
= sd
.sdno
; /* pass object number */
482 message
->type
= sd_object
; /* and type of object */
483 message
->state
= object_up
;
484 message
->verify
= vflag
; /* verify what we write? */
485 message
->blocksize
= SSize
;
486 ioctl(superdev
, VINUM_SETSTATE
, message
);
488 while (reply
.error
== EAGAIN
); /* until we're done */
491 "Can't initialize %s: %s (%d)\n",
493 strerror(reply
.error
),
495 get_sd_info(&sd
, sdno
);
496 if (sd
.state
!= sd_up
)
497 /* Set the subdisk down */
498 message
->index
= sd
.sdno
; /* pass object number */
499 message
->type
= sd_object
; /* and type of object */
500 message
->state
= object_down
;
501 message
->verify
= vflag
; /* verify what we write? */
502 message
->force
= 1; /* insist */
503 ioctl(superdev
, VINUM_SETSTATE
, message
);
506 printf("subdisk %s initialized\n", filename
);
512 vinum_start(int argc
, char *argv
[], char *arg0
[])
515 struct _ioctl_reply reply
;
516 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
518 if (argc
== 0) { /* start everything */
519 int devs
= getnumdevs();
520 struct statinfo statinfo
;
522 char *enamelist
; /* end of name list */
524 char **token
; /* list of tokens */
525 int tokens
; /* and their number */
527 bzero(&statinfo
, sizeof(struct statinfo
));
528 statinfo
.dinfo
= malloc(devs
* sizeof(struct statinfo
));
529 namelist
= malloc(devs
* (DEVSTAT_NAME_LEN
+ 8));
530 token
= malloc((devs
+ 1) * sizeof(char *));
531 if ((statinfo
.dinfo
== NULL
) || (namelist
== NULL
) || (token
== NULL
)) {
532 fprintf(stderr
, "Can't allocate memory for drive list\n");
535 bzero(statinfo
.dinfo
, sizeof(struct devinfo
));
537 tokens
= 0; /* no tokens yet */
538 if (getdevs(&statinfo
) < 0) { /* find out what devices we have */
539 perror("Can't get device list");
542 namelist
[0] = '\0'; /* start with empty namelist */
543 enamelist
= namelist
; /* point to the end of the list */
545 for (i
= 0; i
< devs
; i
++) {
546 struct devstat
*stat
= &statinfo
.dinfo
->devices
[i
];
548 if ((((stat
->device_type
& DEVSTAT_TYPE_MASK
) == DEVSTAT_TYPE_DIRECT
) /* disk device */
549 || ((stat
->device_type
& DEVSTAT_TYPE_MASK
) == DEVSTAT_TYPE_STORARRAY
)) /* storage array */
550 &&((stat
->device_type
& DEVSTAT_TYPE_IF_MASK
) != DEVSTAT_TYPE_IF_OTHER
) /* and not md */
551 &&((stat
->device_type
& DEVSTAT_TYPE_PASS
) == 0) /* and not passthrough */
552 &&((stat
->device_name
[0] != '\0'))) { /* and it has a name */
553 sprintf(enamelist
, "%s%s%d", _PATH_DEV
, stat
->device_name
, stat
->unit_number
);
554 token
[tokens
] = enamelist
; /* point to it */
555 tokens
++; /* one more token */
556 enamelist
= &enamelist
[strlen(enamelist
) + 1]; /* and start beyond the end */
559 free(statinfo
.dinfo
); /* don't need the list any more */
560 vinum_read(tokens
, token
, &token
[0]); /* start the system */
563 list_defective_objects(); /* and list anything that's down */
564 } else { /* start specified objects */
566 enum objecttype type
;
568 for (index
= 0; index
< argc
; index
++) {
569 object
= find_object(argv
[index
], &type
); /* look for it */
570 if (type
== invalid_object
)
571 fprintf(stderr
, "Can't find object: %s\n", argv
[index
]);
573 int doit
= 0; /* set to 1 if we pass our tests */
576 if (drive
.state
== drive_up
) /* already up */
577 fprintf(stderr
, "%s is already up\n", drive
.label
.name
);
583 if (sd
.state
== sd_up
) /* already up */
584 fprintf(stderr
, "%s is already up\n", sd
.name
);
590 if (plex
.state
== plex_up
) /* already up */
591 fprintf(stderr
, "%s is already up\n", plex
.name
);
596 * First, see if we can bring it up
597 * just by asking. This might happen
598 * if somebody has used setupstate on
599 * the subdisks. If we don't do this,
600 * we'll return success, but the plex
601 * won't have changed state. Note
602 * that we don't check for errors
605 message
->index
= plex
.plexno
; /* pass object number */
606 message
->type
= plex_object
; /* it's a plex */
607 message
->state
= object_up
;
608 message
->force
= 0; /* don't force it */
609 ioctl(superdev
, VINUM_SETSTATE
, message
);
610 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
611 get_plex_sd_info(&sd
, object
, sdno
);
612 if ((sd
.state
>= sd_empty
)
613 && (sd
.state
<= sd_reviving
)) { /* candidate for start */
614 message
->index
= sd
.sdno
; /* pass object number */
615 message
->type
= sd_object
; /* it's a subdisk */
616 message
->state
= object_up
;
617 message
->force
= force
; /* don't force it, use a larger hammer */
620 * We don't do any checking here.
621 * The kernel module has a better
622 * understanding of these things,
625 if (SSize
!= 0) { /* specified a size for init */
627 SSize
<<= DEV_BSHIFT
;
628 message
->blocksize
= SSize
;
630 message
->blocksize
= DEFAULT_REVIVE_BLOCKSIZE
;
631 ioctl(superdev
, VINUM_SETSTATE
, message
);
632 if (reply
.error
!= 0) {
633 if (reply
.error
== EAGAIN
) /* we're reviving */
634 continue_revive(sd
.sdno
);
637 "Can't start %s: %s (%d)\n",
639 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
643 vinum_lsi(sd
.sdno
, 0);
650 if (vol
.state
== volume_up
) /* already up */
651 fprintf(stderr
, "%s is already up\n", vol
.name
);
661 message
->index
= object
; /* pass object number */
662 message
->type
= type
; /* and type of object */
663 message
->state
= object_up
;
664 message
->force
= force
; /* don't force it, use a larger hammer */
667 * We don't do any checking here.
668 * The kernel module has a better
669 * understanding of these things,
672 if (SSize
!= 0) { /* specified a size for init or revive */
674 SSize
<<= DEV_BSHIFT
;
675 message
->blocksize
= SSize
;
677 message
->blocksize
= 0;
678 ioctl(superdev
, VINUM_SETSTATE
, message
);
679 if (reply
.error
!= 0) {
680 if ((reply
.error
== EAGAIN
) /* we're reviving */
681 &&(type
== sd_object
))
682 continue_revive(object
);
685 "Can't start %s: %s (%d)\n",
687 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
691 vinum_li(object
, type
);
696 checkupdates(); /* make sure we're updating */
700 vinum_stop(int argc
, char *argv
[], char *arg0
[])
703 struct _ioctl_reply reply
;
704 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
706 if (checkupdates() && (!force
)) /* not updating? */
708 message
->force
= force
; /* should we force the transition? */
709 if (argc
== 0) { /* stop vinum */
710 int fileid
= 0; /* ID of Vinum kld */
712 close(superdev
); /* we can't stop if we have vinum open */
713 sleep(1); /* wait for the daemon to let go */
714 fileid
= kldfind(VINUMMOD
);
715 if ((fileid
< 0) /* no go */
716 ||(kldunload(fileid
) < 0))
717 perror("Can't unload " VINUMMOD
);
719 fprintf(stderr
, VINUMMOD
" unloaded\n");
723 /* If we got here, the stop failed. Reopen the superdevice. */
724 superdev
= open(VINUM_SUPERDEV_NAME
, O_RDWR
); /* reopen vinum superdevice */
726 perror("Can't reopen Vinum superdevice");
729 } else { /* stop specified objects */
731 enum objecttype type
;
733 for (i
= 0; i
< argc
; i
++) {
734 object
= find_object(argv
[i
], &type
); /* look for it */
735 if (type
== invalid_object
)
736 fprintf(stderr
, "Can't find object: %s\n", argv
[i
]);
738 message
->index
= object
; /* pass object number */
739 message
->type
= type
; /* and type of object */
740 message
->state
= object_down
;
741 ioctl(superdev
, VINUM_SETSTATE
, message
);
742 if (reply
.error
!= 0)
744 "Can't stop %s: %s (%d)\n",
746 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
749 vinum_li(object
, type
);
756 vinum_label(int argc
, char *argv
[], char *arg0
[])
759 struct _ioctl_reply reply
;
760 int *message
= (int *) &reply
;
762 if (argc
== 0) /* start everything */
763 fprintf(stderr
, "label: please specify one or more volume names\n");
764 else { /* start specified objects */
766 enum objecttype type
;
768 for (i
= 0; i
< argc
; i
++) {
769 object
= find_object(argv
[i
], &type
); /* look for it */
770 if (type
== invalid_object
)
771 fprintf(stderr
, "Can't find object: %s\n", argv
[i
]);
772 else if (type
!= volume_object
) /* it exists, but it isn't a volume */
773 fprintf(stderr
, "%s is not a volume\n", argv
[i
]);
775 message
[0] = object
; /* pass object number */
776 ioctl(superdev
, VINUM_LABEL
, message
);
777 if (reply
.error
!= 0)
779 "Can't label %s: %s (%d)\n",
781 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
784 vinum_li(object
, type
);
788 checkupdates(); /* not updating? */
792 reset_volume_stats(int volno
, int recurse
)
794 struct vinum_ioctl_msg msg
;
795 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
798 msg
.type
= volume_object
;
799 /* XXX get these numbers right if we ever
800 * actually return errors */
801 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
802 fprintf(stderr
, "Can't reset stats for volume %d: %s\n", volno
, reply
->msg
);
803 longjmp(command_fail
, -1);
804 } else if (recurse
) {
808 get_volume_info(&vol
, volno
);
809 for (plexno
= 0; plexno
< vol
.plexes
; plexno
++)
810 reset_plex_stats(vol
.plex
[plexno
], recurse
);
815 reset_plex_stats(int plexno
, int recurse
)
817 struct vinum_ioctl_msg msg
;
818 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
821 msg
.type
= plex_object
;
822 /* XXX get these numbers right if we ever
823 * actually return errors */
824 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
825 fprintf(stderr
, "Can't reset stats for plex %d: %s\n", plexno
, reply
->msg
);
826 longjmp(command_fail
, -1);
827 } else if (recurse
) {
832 get_plex_info(&plex
, plexno
);
833 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
834 get_plex_sd_info(&sd
, plex
.plexno
, sdno
);
835 reset_sd_stats(sd
.sdno
, recurse
);
841 reset_sd_stats(int sdno
, int recurse
)
843 struct vinum_ioctl_msg msg
;
844 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
847 msg
.type
= sd_object
;
848 /* XXX get these numbers right if we ever
849 * actually return errors */
850 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
851 fprintf(stderr
, "Can't reset stats for subdisk %d: %s\n", sdno
, reply
->msg
);
852 longjmp(command_fail
, -1);
853 } else if (recurse
) {
854 get_sd_info(&sd
, sdno
); /* get the info */
855 reset_drive_stats(sd
.driveno
); /* and clear the drive */
860 reset_drive_stats(int driveno
)
862 struct vinum_ioctl_msg msg
;
863 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
866 msg
.type
= drive_object
;
867 /* XXX get these numbers right if we ever
868 * actually return errors */
869 if (ioctl(superdev
, VINUM_RESETSTATS
, &msg
) < 0) {
870 fprintf(stderr
, "Can't reset stats for drive %d: %s\n", driveno
, reply
->msg
);
871 longjmp(command_fail
, -1);
876 vinum_resetstats(int argc
, char *argv
[], char *argv0
[])
880 enum objecttype type
;
882 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
883 perror("Can't get vinum config");
887 for (objno
= 0; objno
< vinum_conf
.volumes_allocated
; objno
++)
888 reset_volume_stats(objno
, 1); /* clear everything recursively */
890 for (i
= 0; i
< argc
; i
++) {
891 objno
= find_object(argv
[i
], &type
);
892 if (objno
>= 0) { /* not invalid */
895 reset_drive_stats(objno
);
899 reset_sd_stats(objno
, recurse
);
903 reset_plex_stats(objno
, recurse
);
907 reset_volume_stats(objno
, recurse
);
910 case invalid_object
: /* can't get this */
918 /* Attach a subdisk to a plex, or a plex to a volume.
919 * attach subdisk plex [offset] [rename]
920 * attach plex volume [rename]
923 vinum_attach(int argc
, char *argv
[], char *argv0
[])
926 enum objecttype supertype
;
927 struct vinum_ioctl_msg msg
;
928 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
929 const char *objname
= argv
[0];
930 const char *supername
= argv
[1];
933 char oldname
[MAXNAME
+ 8];
934 char newname
[MAXNAME
+ 8];
935 int rename
= 0; /* set if we want to rename the object */
940 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
941 "\tattach <plex> <volume> [rename]\n");
944 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
945 perror("Can't get vinum config");
948 msg
.index
= find_object(objname
, &msg
.type
); /* find the object to attach */
949 msg
.otherobject
= find_object(supername
, &supertype
); /* and the object to attach to */
950 msg
.force
= force
; /* did we specify the use of force? */
951 msg
.recurse
= recurse
;
952 msg
.offset
= -1; /* and no offset */
954 for (i
= 2; i
< argc
; i
++) {
955 if (!strcmp(argv
[i
], "rename")) {
957 msg
.rename
= 1; /* do renaming */
958 } else if (!isdigit(argv
[i
][0])) { /* not an offset */
959 fprintf(stderr
, "Unknown attribute: %s\n", supername
);
962 msg
.offset
= sizespec(argv
[i
]);
967 find_object(argv
[1], &supertype
);
968 if (supertype
!= plex_object
) { /* huh? */
969 fprintf(stderr
, "%s can only be attached to a plex\n", objname
);
972 if ((plex
.organization
!= plex_concat
) /* not a cat plex, */
974 fprintf(stderr
, "Can't attach subdisks to a %s plex\n", plex_org(plex
.organization
));
977 sdno
= msg
.index
; /* note the subdisk number for later */
981 find_object(argv
[1], &supertype
);
982 if (supertype
!= volume_object
) { /* huh? */
983 fprintf(stderr
, "%s can only be attached to a volume\n", objname
);
990 fprintf(stderr
, "Can only attach subdisks and plexes\n");
994 fprintf(stderr
, "%s is not a Vinum object\n", objname
);
998 ioctl(superdev
, VINUM_ATTACH
, &msg
);
999 if (reply
->error
!= 0) {
1000 if (reply
->error
== EAGAIN
) /* reviving */
1001 continue_revive(sdno
); /* continue the revive */
1004 "Can't attach %s to %s: %s (%d)\n",
1007 reply
->msg
[0] ? reply
->msg
: strerror(reply
->error
),
1015 /* we've overwritten msg with the
1016 * ioctl reply, start again */
1017 msg
.index
= find_object(objname
, &msg
.type
); /* find the object to rename */
1020 get_sd_info(&sd
, msg
.index
);
1021 get_plex_info(&plex
, sd
.plexno
);
1022 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
1023 if (plex
.sdnos
[sdno
] == msg
.index
) /* found our subdisk */
1026 sprintf(newname
, "%s.s%d", plex
.name
, sdno
);
1027 sprintf(oldname
, "%s", sd
.name
);
1028 vinum_rename_2(oldname
, newname
);
1032 get_plex_info(&plex
, msg
.index
);
1033 get_volume_info(&vol
, plex
.volno
);
1034 for (plexno
= 0; plexno
< vol
.plexes
; plexno
++) {
1035 if (vol
.plex
[plexno
] == msg
.index
) /* found our subdisk */
1038 sprintf(newname
, "%s.p%d", vol
.name
, plexno
);
1039 sprintf(oldname
, "%s", plex
.name
);
1040 vinum_rename_2(oldname
, newname
); /* this may recurse */
1043 default: /* can't get here */
1047 checkupdates(); /* make sure we're updating */
1050 /* Detach a subdisk from a plex, or a plex from a volume.
1051 * detach subdisk plex [rename]
1052 * detach plex volume [rename]
1055 vinum_detach(int argc
, char *argv
[], char *argv0
[])
1057 struct vinum_ioctl_msg msg
;
1058 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) &msg
;
1063 "Usage: \tdetach <subdisk> [rename]\n"
1064 "\tdetach <plex> [rename]\n");
1067 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
1068 perror("Can't get vinum config");
1071 msg
.index
= find_object(argv
[0], &msg
.type
); /* find the object to detach */
1072 msg
.force
= force
; /* did we specify the use of force? */
1073 msg
.rename
= 0; /* don't specify new name */
1074 msg
.recurse
= recurse
; /* but recurse if we have to */
1076 /* XXX are we going to keep this?
1077 * Don't document it yet, since the
1078 * kernel side of things doesn't
1081 if (!strcmp(argv
[1], "rename"))
1082 msg
.rename
= 1; /* do renaming */
1084 fprintf(stderr
, "Unknown attribute: %s\n", argv
[1]);
1088 if ((msg
.type
!= sd_object
)
1089 && (msg
.type
!= plex_object
)) {
1090 fprintf(stderr
, "Can only detach subdisks and plexes\n");
1093 ioctl(superdev
, VINUM_DETACH
, &msg
);
1094 if (reply
->error
!= 0)
1096 "Can't detach %s: %s (%d)\n",
1098 reply
->msg
[0] ? reply
->msg
: strerror(reply
->error
),
1100 checkupdates(); /* make sure we're updating */
1104 dorename(struct vinum_rename_msg
*msg
, const char *oldname
, const char *name
, int maxlen
)
1106 struct _ioctl_reply
*reply
= (struct _ioctl_reply
*) msg
;
1108 if (strlen(name
) > maxlen
) {
1109 fprintf(stderr
, "%s is too long\n", name
);
1112 strcpy(msg
->newname
, name
);
1113 ioctl(superdev
, VINUM_RENAME
, msg
);
1114 if (reply
->error
!= 0)
1116 "Can't rename %s to %s: %s (%d)\n",
1119 reply
->msg
[0] ? reply
->msg
: strerror(reply
->error
),
1123 /* Rename an object:
1124 * rename <object> "newname"
1127 vinum_rename_2(char *oldname
, char *newname
)
1129 struct vinum_rename_msg msg
;
1133 msg
.index
= find_object(oldname
, &msg
.type
); /* find the object to rename */
1134 msg
.recurse
= recurse
;
1136 /* Ugh. Determine how long the name may be */
1139 dorename(&msg
, oldname
, newname
, MAXDRIVENAME
);
1143 dorename(&msg
, oldname
, newname
, MAXSDNAME
);
1148 dorename(&msg
, oldname
, newname
, MAXPLEXNAME
);
1152 get_plex_info(&plex
, plexno
); /* find out who we are */
1153 msg
.type
= sd_object
;
1154 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
1155 char sdname
[MAXPLEXNAME
+ 8];
1157 get_plex_sd_info(&sd
, plex
.plexno
, sdno
); /* get info about the subdisk */
1158 sprintf(sdname
, "%s.s%d", newname
, sdno
);
1159 msg
.index
= sd
.sdno
; /* number of the subdisk */
1160 dorename(&msg
, sd
.name
, sdname
, MAXSDNAME
);
1167 dorename(&msg
, oldname
, newname
, MAXVOLNAME
);
1172 get_volume_info(&vol
, volno
); /* find out who we are */
1173 for (plexno
= 0; plexno
< vol
.plexes
; plexno
++) {
1174 char plexname
[MAXVOLNAME
+ 8];
1176 msg
.type
= plex_object
;
1177 sprintf(plexname
, "%s.p%d", newname
, plexno
);
1178 msg
.index
= vol
.plex
[plexno
]; /* number of the plex */
1179 dorename(&msg
, plex
.name
, plexname
, MAXPLEXNAME
);
1180 get_plex_info(&plex
, vol
.plex
[plexno
]); /* find out who we are */
1181 msg
.type
= sd_object
;
1182 for (sdno
= 0; sdno
< plex
.subdisks
; sdno
++) {
1183 char sdname
[MAXPLEXNAME
+ 8];
1185 get_plex_sd_info(&sd
, plex
.plexno
, sdno
); /* get info about the subdisk */
1186 sprintf(sdname
, "%s.s%d", plexname
, sdno
);
1187 msg
.index
= sd
.sdno
; /* number of the subdisk */
1188 dorename(&msg
, sd
.name
, sdname
, MAXSDNAME
);
1195 fprintf(stderr
, "%s is not a Vinum object\n", oldname
);
1201 vinum_rename(int argc
, char *argv
[], char *argv0
[])
1204 fprintf(stderr
, "Usage: \trename <object> <new name>\n");
1207 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
1208 perror("Can't get vinum config");
1211 vinum_rename_2(argv
[0], argv
[1]);
1212 checkupdates(); /* make sure we're updating */
1218 * mv <dest> <src> ...
1221 vinum_mv(int argc
, char *argv
[], char *argv0
[])
1223 int i
; /* loop index */
1226 enum objecttype srct
;
1227 enum objecttype destt
;
1229 struct _ioctl_reply reply
;
1230 struct vinum_ioctl_msg
*msg
= (struct vinum_ioctl_msg
*) &reply
;
1233 fprintf(stderr
, "Usage: \tmove <dest> <src> ...\n");
1236 /* Get current config */
1237 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
1238 perror("Cannot get vinum config\n");
1241 /* Get our destination */
1242 destobj
= find_object(argv
[0], &destt
);
1243 if (destobj
== -1) {
1244 fprintf(stderr
, "Can't find %s\n", argv
[0]);
1247 /* Verify that the target is a drive */
1248 if (destt
!= drive_object
) {
1249 fprintf(stderr
, "%s is not a drive\n", argv
[0]);
1252 for (i
= 1; i
< argc
; i
++) { /* for all the sources */
1253 srcobj
= find_object(argv
[i
], &srct
);
1255 fprintf(stderr
, "Can't find %s\n", argv
[i
]);
1258 msg
->index
= destobj
;
1259 switch (srct
) { /* Handle the source object */
1260 case drive_object
: /* Move all subdisks on the drive to dst. */
1261 get_drive_info(&drive
, srcobj
); /* get info on drive */
1262 for (sdno
= 0; sdno
< vinum_conf
.subdisks_allocated
; ++sdno
) {
1263 get_sd_info(&sd
, sdno
);
1264 if (sd
.driveno
== srcobj
) {
1265 msg
->index
= destobj
;
1266 msg
->otherobject
= sd
.sdno
;
1267 if (ioctl(superdev
, VINUM_MOVE
, msg
) < 0)
1269 "Can't move %s (part of %s) to %s: %s (%d)\n",
1273 strerror(reply
.error
),
1280 msg
->otherobject
= srcobj
;
1281 if (ioctl(superdev
, VINUM_MOVE
, msg
) < 0)
1283 "Can't move %s to %s: %s (%d)\n",
1286 strerror(reply
.error
),
1291 get_plex_info(&plex
, srcobj
);
1292 for (sdno
= 0; sdno
< plex
.subdisks
; ++sdno
) {
1293 get_plex_sd_info(&sd
, plex
.plexno
, sdno
);
1294 msg
->index
= destobj
;
1295 msg
->otherobject
= sd
.sdno
;
1296 if (ioctl(superdev
, VINUM_MOVE
, msg
) < 0)
1298 "Can't move %s (part of %s) to %s: %s (%d)\n",
1302 strerror(reply
.error
),
1308 case invalid_object
:
1310 fprintf(stderr
, "Can't move %s (inappropriate object).\n", argv
[i
]);
1315 "Can't move %s to %s: %s (%d)\n",
1318 strerror(reply
.error
),
1321 checkupdates(); /* make sure we're updating */
1325 * Replace objects. Not implemented, may never be.
1328 vinum_replace(int argc
, char *argv
[], char *argv0
[])
1330 fprintf(stderr
, "'replace' not implemented yet. Use 'move' instead\n");
1333 /* Primitive help function */
1335 vinum_help(int argc
, char *argv
[], char *argv0
[])
1340 "create [-f description-file]\n"
1341 " Create a volume as described in description-file\n"
1342 "attach plex volume [rename]\n"
1343 "attach subdisk plex [offset] [rename]\n"
1344 " Attach a plex to a volume, or a subdisk to a plex.\n"
1346 " Cause the volume manager to enter the kernel debugger.\n"
1348 " Set debugging flags.\n"
1349 "detach [plex | subdisk]\n"
1350 " Detach a plex or subdisk from the volume or plex to which it is\n"
1353 " List information about volume manager state.\n"
1354 "init [-v] [-w] plex\n"
1355 " Initialize a plex by writing zeroes to all its subdisks.\n"
1357 " Create a volume label\n"
1358 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1359 " List information about specified objects\n"
1360 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1361 " List information about specified objects (alternative to\n"
1363 "ld [-r] [-s] [-v] [-V] [volume]\n"
1364 " List information about drives\n"
1365 "ls [-r] [-s] [-v] [-V] [subdisk]\n"
1366 " List information about subdisks\n"
1367 "lp [-r] [-s] [-v] [-V] [plex]\n"
1368 " List information about plexes\n"
1369 "lv [-r] [-s] [-v] [-V] [volume]\n"
1370 " List information about volumes\n"
1371 "printconfig [file]\n"
1372 " Write a copy of the current configuration to file.\n"
1374 " Remake the device nodes in " _PATH_DEV
"vinum.\n"
1375 "move drive [subdisk | plex | drive]\n"
1376 " Move the subdisks of the specified object(s) to drive.\n"
1378 " Exit the vinum program when running in interactive mode. Nor-\n"
1379 " mally this would be done by entering the EOF character.\n"
1380 "read disk [disk...]\n"
1381 " Read the vinum configuration from the specified disks.\n"
1382 "rename [-r] [drive | subdisk | plex | volume] newname\n"
1383 " Change the name of the specified object.\n"
1385 " Reset the complete vinum configuration.\n"
1386 "resetstats [-r] [volume | plex | subdisk]\n"
1387 " Reset statistisc counters for the specified objects, or for all\n"
1388 " objects if none are specified.\n"
1389 "rm [-f] [-r] volume | plex | subdisk\n"
1390 " Remove an object\n"
1392 " Save vinum configuration to disk.\n"
1393 "setdaemon [value]\n"
1394 " Set daemon configuration.\n"
1396 " Read configuration from all vinum drives.\n"
1397 "start [volume | plex | subdisk]\n"
1398 " Allow the system to access the objects\n"
1399 "stop [-f] [volume | plex | subdisk]\n"
1400 " Terminate access to the objects, or stop vinum if no parameters\n"
1406 /* Set daemon options.
1407 * XXX quick and dirty: use a bitmap, which requires
1408 * knowing which bit does what. FIXME */
1410 vinum_setdaemon(int argc
, char *argv
[], char *argv0
[])
1416 if (ioctl(superdev
, VINUM_GETDAEMON
, &options
) < 0)
1417 fprintf(stderr
, "Can't get daemon options: %s (%d)\n", strerror(errno
), errno
);
1419 printf("Options mask: %d\n", options
);
1423 options
= atoi(argv
[0]);
1424 if (ioctl(superdev
, VINUM_SETDAEMON
, &options
) < 0)
1425 fprintf(stderr
, "Can't set daemon options: %s (%d)\n", strerror(errno
), errno
);
1429 fprintf(stderr
, "Usage: \tsetdaemon [<bitmask>]\n");
1431 checkupdates(); /* make sure we're updating */
1439 if (ioctl(superdev
, VINUM_GETDAEMON
, &options
) < 0)
1440 fprintf(stderr
, "Can't get daemon options: %s (%d)\n", strerror(errno
), errno
);
1441 if (options
& daemon_noupdate
) {
1442 fprintf(stderr
, "*** Warning: configuration updates are disabled. ***\n");
1448 /* Save config info */
1450 vinum_saveconfig(int argc
, char *argv
[], char *argv0
[])
1455 printf("Usage: saveconfig\n");
1458 ioctltype
= 1; /* user saveconfig */
1459 if (ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
) < 0)
1460 fprintf(stderr
, "Can't save configuration: %s (%d)\n", strerror(errno
), errno
);
1461 checkupdates(); /* make sure we're updating */
1465 * Create a volume name for the quick and dirty
1466 * commands. It will be of the form "vinum#",
1467 * where # is a small positive number.
1472 int v
; /* volume number */
1473 static char volumename
[MAXVOLNAME
]; /* name to create */
1474 enum objecttype type
;
1476 objectname
= volumename
; /* point to it */
1478 sprintf(objectname
, "vinum%d", v
); /* create the name */
1479 if (find_object(objectname
, &type
) == -1) /* does it exist? */
1480 return; /* no, it's ours */
1485 * Create a drive for the quick and dirty
1486 * commands. The name will be of the form
1487 * vinumdrive#, where # is a small positive
1488 * number. Return the name of the drive.
1491 create_drive(char *devicename
)
1493 int d
; /* volume number */
1494 static char drivename
[MAXDRIVENAME
]; /* name to create */
1495 enum objecttype type
;
1496 struct _ioctl_reply
*reply
;
1499 * We're never likely to get anything
1500 * like 10000 drives. The only reason for
1501 * this limit is to stop the thing
1502 * looping if we have a bug somewhere.
1504 for (d
= 0; d
< 100000; d
++) { /* look for a free drive number */
1505 sprintf(drivename
, "vinumdrive%d", d
); /* create the name */
1506 if (find_object(drivename
, &type
) == -1) { /* does it exist? */
1507 char command
[MAXDRIVENAME
* 2];
1509 sprintf(command
, "drive %s device %s", drivename
, devicename
); /* create a create command */
1511 printf("drive %s device %s\n", drivename
, devicename
); /* create a create command */
1512 ioctl(superdev
, VINUM_CREATE
, command
);
1513 reply
= (struct _ioctl_reply
*) &command
;
1514 if (reply
->error
!= 0) { /* error in config */
1517 "Can't create drive %s, device %s: %s\n",
1523 "Can't create drive %s, device %s: %s (%d)\n",
1526 strerror(reply
->error
),
1528 longjmp(command_fail
, -1); /* give up */
1530 find_object(drivename
, &type
);
1531 return &drive
; /* return the name of the drive */
1534 fprintf(stderr
, "Can't generate a drive name\n");
1540 * Create a volume with a single concatenated plex from
1541 * as much space as we can get on the specified drives.
1542 * If the drives aren't Vinum drives, make them so.
1545 vinum_concat(int argc
, char *argv
[], char *argv0
[])
1547 int o
; /* object number */
1548 char buffer
[BUFSIZE
];
1549 struct drive
*drive
; /* drive we're currently looking at */
1550 struct _ioctl_reply
*reply
;
1553 enum objecttype type
;
1555 reply
= (struct _ioctl_reply
*) &buffer
;
1556 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
1557 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
1560 if (!objectname
) /* we need a name for our object */
1562 sprintf(buffer
, "volume %s", objectname
);
1564 printf("volume %s\n", objectname
);
1565 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
1566 if (reply
->error
!= 0) { /* error in config */
1569 "Can't create volume %s: %s\n",
1574 "Can't create volume %s: %s (%d)\n",
1576 strerror(reply
->error
),
1578 longjmp(command_fail
, -1); /* give up */
1580 sprintf(buffer
, "plex name %s.p0 org concat", objectname
);
1582 printf(" plex name %s.p0 org concat\n", objectname
);
1583 ioctl(superdev
, VINUM_CREATE
, buffer
);
1584 if (reply
->error
!= 0) { /* error in config */
1587 "Can't create plex %s.p0: %s\n",
1592 "Can't create plex %s.p0: %s (%d)\n",
1594 strerror(reply
->error
),
1596 longjmp(command_fail
, -1); /* give up */
1598 for (o
= 0; o
< argc
; o
++) {
1599 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
1600 drive
= create_drive(argv
[o
]); /* create it */
1601 sprintf(buffer
, "sd name %s.p0.s%d drive %s size 0", objectname
, o
, drive
->label
.name
);
1603 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname
, o
, drive
->label
.name
);
1604 ioctl(superdev
, VINUM_CREATE
, buffer
);
1605 if (reply
->error
!= 0) { /* error in config */
1608 "Can't create subdisk %s.p0.s%d: %s\n",
1614 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1617 strerror(reply
->error
),
1619 longjmp(command_fail
, -1); /* give up */
1623 /* done, save the config */
1624 ioctltype
= 0; /* saveconfig after update */
1625 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
1627 perror("Can't save Vinum config");
1628 find_object(objectname
, &type
); /* find the index of the volume */
1629 make_vol_dev(vol
.volno
, 1); /* and create the devices */
1631 vflag
--; /* XXX don't give too much detail */
1632 find_object(objectname
, &type
); /* point to the volume */
1633 vinum_lvi(vol
.volno
, 1); /* and print info about it */
1639 * Create a volume with a single striped plex from
1640 * as much space as we can get on the specified drives.
1641 * If the drives aren't Vinum drives, make them so.
1644 vinum_stripe(int argc
, char *argv
[], char *argv0
[])
1646 int o
; /* object number */
1647 char buffer
[BUFSIZE
];
1648 struct drive
*drive
; /* drive we're currently looking at */
1649 struct _ioctl_reply
*reply
;
1652 enum objecttype type
;
1654 int fe
; /* freelist entry index */
1656 struct drive_freelist freelist
;
1657 struct ferq
{ /* request to pass to ioctl */
1662 u_int64_t bigchunk
; /* biggest chunk in freelist */
1665 reply
= (struct _ioctl_reply
*) &buffer
;
1668 * First, check our drives.
1671 fprintf(stderr
, "You need at least two drives to create a striped plex\n");
1674 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
1675 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
1678 if (!objectname
) /* we need a name for our object */
1680 for (o
= 0; o
< argc
; o
++) {
1681 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
1682 drive
= create_drive(argv
[o
]); /* create it */
1683 /* Now find the largest chunk available on the drive */
1684 bigchunk
= 0; /* ain't found nothin' yet */
1685 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
1686 freeunion
.ferq
.driveno
= drive
->driveno
;
1687 freeunion
.ferq
.fe
= fe
;
1688 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
1690 "Can't get free list element %d: %s\n",
1693 longjmp(command_fail
, -1);
1695 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
1697 maxsize
= min(maxsize
, bigchunk
); /* this is as much as we can do */
1700 /* Now create the volume */
1701 sprintf(buffer
, "volume %s", objectname
);
1703 printf("volume %s\n", objectname
);
1704 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
1705 if (reply
->error
!= 0) { /* error in config */
1708 "Can't create volume %s: %s\n",
1713 "Can't create volume %s: %s (%d)\n",
1715 strerror(reply
->error
),
1717 longjmp(command_fail
, -1); /* give up */
1719 sprintf(buffer
, "plex name %s.p0 org striped 256k", objectname
);
1721 printf(" plex name %s.p0 org striped 256k\n", objectname
);
1722 ioctl(superdev
, VINUM_CREATE
, buffer
);
1723 if (reply
->error
!= 0) { /* error in config */
1726 "Can't create plex %s.p0: %s\n",
1731 "Can't create plex %s.p0: %s (%d)\n",
1733 strerror(reply
->error
),
1735 longjmp(command_fail
, -1); /* give up */
1737 for (o
= 0; o
< argc
; o
++) {
1738 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
1740 "sd name %s.p0.s%d drive %s size %lldb",
1744 (long long) maxsize
);
1746 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1750 (long long) maxsize
);
1751 ioctl(superdev
, VINUM_CREATE
, buffer
);
1752 if (reply
->error
!= 0) { /* error in config */
1755 "Can't create subdisk %s.p0.s%d: %s\n",
1761 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1764 strerror(reply
->error
),
1766 longjmp(command_fail
, -1); /* give up */
1770 /* done, save the config */
1771 ioctltype
= 0; /* saveconfig after update */
1772 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
1774 perror("Can't save Vinum config");
1775 find_object(objectname
, &type
); /* find the index of the volume */
1776 make_vol_dev(vol
.volno
, 1); /* and create the devices */
1778 vflag
--; /* XXX don't give too much detail */
1779 find_object(objectname
, &type
); /* point to the volume */
1780 vinum_lvi(vol
.volno
, 1); /* and print info about it */
1785 * Create a volume with a single RAID-4 plex from
1786 * as much space as we can get on the specified drives.
1787 * If the drives aren't Vinum drives, make them so.
1790 vinum_raid4(int argc
, char *argv
[], char *argv0
[])
1792 int o
; /* object number */
1793 char buffer
[BUFSIZE
];
1794 struct drive
*drive
; /* drive we're currently looking at */
1795 struct _ioctl_reply
*reply
;
1798 enum objecttype type
;
1800 int fe
; /* freelist entry index */
1802 struct drive_freelist freelist
;
1803 struct ferq
{ /* request to pass to ioctl */
1808 u_int64_t bigchunk
; /* biggest chunk in freelist */
1811 reply
= (struct _ioctl_reply
*) &buffer
;
1814 * First, check our drives.
1817 fprintf(stderr
, "You need at least three drives to create a RAID-4 plex\n");
1820 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
1821 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
1824 if (!objectname
) /* we need a name for our object */
1826 for (o
= 0; o
< argc
; o
++) {
1827 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
1828 drive
= create_drive(argv
[o
]); /* create it */
1829 /* Now find the largest chunk available on the drive */
1830 bigchunk
= 0; /* ain't found nothin' yet */
1831 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
1832 freeunion
.ferq
.driveno
= drive
->driveno
;
1833 freeunion
.ferq
.fe
= fe
;
1834 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
1836 "Can't get free list element %d: %s\n",
1839 longjmp(command_fail
, -1);
1841 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
1843 maxsize
= min(maxsize
, bigchunk
); /* this is as much as we can do */
1846 /* Now create the volume */
1847 sprintf(buffer
, "volume %s", objectname
);
1849 printf("volume %s\n", objectname
);
1850 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
1851 if (reply
->error
!= 0) { /* error in config */
1854 "Can't create volume %s: %s\n",
1859 "Can't create volume %s: %s (%d)\n",
1861 strerror(reply
->error
),
1863 longjmp(command_fail
, -1); /* give up */
1865 sprintf(buffer
, "plex name %s.p0 org raid4 256k", objectname
);
1867 printf(" plex name %s.p0 org raid4 256k\n", objectname
);
1868 ioctl(superdev
, VINUM_CREATE
, buffer
);
1869 if (reply
->error
!= 0) { /* error in config */
1872 "Can't create plex %s.p0: %s\n",
1877 "Can't create plex %s.p0: %s (%d)\n",
1879 strerror(reply
->error
),
1881 longjmp(command_fail
, -1); /* give up */
1883 for (o
= 0; o
< argc
; o
++) {
1884 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
1886 "sd name %s.p0.s%d drive %s size %lldb",
1890 (long long) maxsize
);
1892 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1896 (long long) maxsize
);
1897 ioctl(superdev
, VINUM_CREATE
, buffer
);
1898 if (reply
->error
!= 0) { /* error in config */
1901 "Can't create subdisk %s.p0.s%d: %s\n",
1907 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1910 strerror(reply
->error
),
1912 longjmp(command_fail
, -1); /* give up */
1916 /* done, save the config */
1917 ioctltype
= 0; /* saveconfig after update */
1918 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
1920 perror("Can't save Vinum config");
1921 find_object(objectname
, &type
); /* find the index of the volume */
1922 make_vol_dev(vol
.volno
, 1); /* and create the devices */
1924 vflag
--; /* XXX don't give too much detail */
1925 find_object(objectname
, &type
); /* point to the volume */
1926 vinum_lvi(vol
.volno
, 1); /* and print info about it */
1931 * Create a volume with a single RAID-4 plex from
1932 * as much space as we can get on the specified drives.
1933 * If the drives aren't Vinum drives, make them so.
1936 vinum_raid5(int argc
, char *argv
[], char *argv0
[])
1938 int o
; /* object number */
1939 char buffer
[BUFSIZE
];
1940 struct drive
*drive
; /* drive we're currently looking at */
1941 struct _ioctl_reply
*reply
;
1944 enum objecttype type
;
1946 int fe
; /* freelist entry index */
1948 struct drive_freelist freelist
;
1949 struct ferq
{ /* request to pass to ioctl */
1954 u_int64_t bigchunk
; /* biggest chunk in freelist */
1957 reply
= (struct _ioctl_reply
*) &buffer
;
1960 * First, check our drives.
1963 fprintf(stderr
, "You need at least three drives to create a RAID-5 plex\n");
1966 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
1967 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
1970 if (!objectname
) /* we need a name for our object */
1972 for (o
= 0; o
< argc
; o
++) {
1973 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
1974 drive
= create_drive(argv
[o
]); /* create it */
1975 /* Now find the largest chunk available on the drive */
1976 bigchunk
= 0; /* ain't found nothin' yet */
1977 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
1978 freeunion
.ferq
.driveno
= drive
->driveno
;
1979 freeunion
.ferq
.fe
= fe
;
1980 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
1982 "Can't get free list element %d: %s\n",
1985 longjmp(command_fail
, -1);
1987 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
1989 maxsize
= min(maxsize
, bigchunk
); /* this is as much as we can do */
1992 /* Now create the volume */
1993 sprintf(buffer
, "volume %s", objectname
);
1995 printf("volume %s\n", objectname
);
1996 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
1997 if (reply
->error
!= 0) { /* error in config */
2000 "Can't create volume %s: %s\n",
2005 "Can't create volume %s: %s (%d)\n",
2007 strerror(reply
->error
),
2009 longjmp(command_fail
, -1); /* give up */
2011 sprintf(buffer
, "plex name %s.p0 org raid5 256k", objectname
);
2013 printf(" plex name %s.p0 org raid5 256k\n", objectname
);
2014 ioctl(superdev
, VINUM_CREATE
, buffer
);
2015 if (reply
->error
!= 0) { /* error in config */
2018 "Can't create plex %s.p0: %s\n",
2023 "Can't create plex %s.p0: %s (%d)\n",
2025 strerror(reply
->error
),
2027 longjmp(command_fail
, -1); /* give up */
2029 for (o
= 0; o
< argc
; o
++) {
2030 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
2032 "sd name %s.p0.s%d drive %s size %lldb",
2036 (long long) maxsize
);
2038 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
2042 (long long) maxsize
);
2043 ioctl(superdev
, VINUM_CREATE
, buffer
);
2044 if (reply
->error
!= 0) { /* error in config */
2047 "Can't create subdisk %s.p0.s%d: %s\n",
2053 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2056 strerror(reply
->error
),
2058 longjmp(command_fail
, -1); /* give up */
2062 /* done, save the config */
2063 ioctltype
= 0; /* saveconfig after update */
2064 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
2066 perror("Can't save Vinum config");
2067 find_object(objectname
, &type
); /* find the index of the volume */
2068 make_vol_dev(vol
.volno
, 1); /* and create the devices */
2070 vflag
--; /* XXX don't give too much detail */
2071 find_object(objectname
, &type
); /* point to the volume */
2072 vinum_lvi(vol
.volno
, 1); /* and print info about it */
2077 * Create a volume with a two plexes from as much space
2078 * as we can get on the specified drives. If the
2079 * drives aren't Vinum drives, make them so.
2081 * The number of drives must be even, and at least 4
2082 * for a striped plex. Specify striped plexes with the
2083 * -s flag; otherwise they will be concatenated. It's
2084 * possible that the two plexes may differ in length.
2087 vinum_mirror(int argc
, char *argv
[], char *argv0
[])
2089 int o
; /* object number */
2090 int p
; /* plex number */
2091 char buffer
[BUFSIZE
];
2092 struct drive
*drive
; /* drive we're currently looking at */
2093 struct _ioctl_reply
*reply
;
2096 enum objecttype type
;
2097 off_t maxsize
[2]; /* maximum subdisk size for striped plexes */
2098 int fe
; /* freelist entry index */
2100 struct drive_freelist freelist
;
2101 struct ferq
{ /* request to pass to ioctl */
2106 u_int64_t bigchunk
; /* biggest chunk in freelist */
2108 if (sflag
) /* striped, */
2109 maxsize
[0] = maxsize
[1] = QUAD_MAX
; /* we need to calculate sd size */
2111 maxsize
[0] = maxsize
[1] = 0; /* let the kernel routines do it */
2113 reply
= (struct _ioctl_reply
*) &buffer
;
2116 * First, check our drives.
2119 fprintf(stderr
, "You need an even number of drives to create a mirrored volume\n");
2122 if (sflag
&& (argc
< 4)) {
2123 fprintf(stderr
, "You need at least 4 drives to create a mirrored, striped volume\n");
2126 if (ioctl(superdev
, VINUM_STARTCONFIG
, &force
)) { /* can't get config? */
2127 printf("Can't configure: %s (%d)\n", strerror(errno
), errno
);
2130 if (!objectname
) /* we need a name for our object */
2132 for (o
= 0; o
< argc
; o
++) {
2133 if ((drive
= find_drive_by_devname(argv
[o
])) == NULL
) /* doesn't exist */
2134 drive
= create_drive(argv
[o
]); /* create it */
2135 if (sflag
) { /* striping, */
2136 /* Find the largest chunk available on the drive */
2137 bigchunk
= 0; /* ain't found nothin' yet */
2138 for (fe
= 0; fe
< drive
->freelist_entries
; fe
++) {
2139 freeunion
.ferq
.driveno
= drive
->driveno
;
2140 freeunion
.ferq
.fe
= fe
;
2141 if (ioctl(superdev
, VINUM_GETFREELIST
, &freeunion
.freelist
) < 0) {
2143 "Can't get free list element %d: %s\n",
2146 longjmp(command_fail
, -1);
2148 bigchunk
= bigchunk
> freeunion
.freelist
.sectors
? bigchunk
: freeunion
.freelist
.sectors
; /* max it */
2150 maxsize
[o
& 1] = min(maxsize
[o
& 1], bigchunk
); /* get the maximum size of a subdisk */
2154 /* Now create the volume */
2155 sprintf(buffer
, "volume %s setupstate", objectname
);
2157 printf("volume %s setupstate\n", objectname
);
2158 ioctl(superdev
, VINUM_CREATE
, buffer
); /* create the volume */
2159 if (reply
->error
!= 0) { /* error in config */
2162 "Can't create volume %s: %s\n",
2167 "Can't create volume %s: %s (%d)\n",
2169 strerror(reply
->error
),
2171 longjmp(command_fail
, -1); /* give up */
2173 for (p
= 0; p
< 2; p
++) { /* create each plex */
2175 sprintf(buffer
, "plex name %s.p%d org striped 256k", objectname
, p
);
2177 printf(" plex name %s.p%d org striped 256k\n", objectname
, p
);
2178 } else { /* concat */
2179 sprintf(buffer
, "plex name %s.p%d org concat", objectname
, p
);
2181 printf(" plex name %s.p%d org concat\n", objectname
, p
);
2183 ioctl(superdev
, VINUM_CREATE
, buffer
);
2184 if (reply
->error
!= 0) { /* error in config */
2187 "Can't create plex %s.p%d: %s\n",
2193 "Can't create plex %s.p%d: %s (%d)\n",
2196 strerror(reply
->error
),
2198 longjmp(command_fail
, -1); /* give up */
2200 /* Now look at the subdisks */
2201 for (o
= p
; o
< argc
; o
+= 2) { /* every second one */
2202 drive
= find_drive_by_devname(argv
[o
]); /* we know it exists... */
2204 "sd name %s.p%d.s%d drive %s size %lldb",
2209 (long long) maxsize
[p
]);
2211 printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
2216 (long long) maxsize
[p
]);
2217 ioctl(superdev
, VINUM_CREATE
, buffer
);
2218 if (reply
->error
!= 0) { /* error in config */
2221 "Can't create subdisk %s.p%d.s%d: %s\n",
2228 "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2232 strerror(reply
->error
),
2234 longjmp(command_fail
, -1); /* give up */
2239 /* done, save the config */
2240 ioctltype
= 0; /* saveconfig after update */
2241 error
= ioctl(superdev
, VINUM_SAVECONFIG
, &ioctltype
); /* save the config to disk */
2243 perror("Can't save Vinum config");
2244 find_object(objectname
, &type
); /* find the index of the volume */
2245 make_vol_dev(vol
.volno
, 1); /* and create the devices */
2247 vflag
--; /* XXX don't give too much detail */
2248 sflag
= 0; /* no stats, please */
2249 find_object(objectname
, &type
); /* point to the volume */
2250 vinum_lvi(vol
.volno
, 1); /* and print info about it */
2255 vinum_readpol(int argc
, char *argv
[], char *argv0
[])
2258 struct _ioctl_reply reply
;
2259 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
2260 enum objecttype type
;
2265 if (argc
== 0) { /* start everything */
2266 fprintf(stderr
, "Usage: readpol <volume> <plex>|round\n");
2269 object
= find_object(argv
[1], &type
); /* look for it */
2270 if (type
!= volume_object
) {
2271 fprintf(stderr
, "%s is not a volume\n", argv
[1]);
2274 get_volume_info(&vol
, object
);
2275 if (strcmp(argv
[2], "round")) { /* not 'round' */
2276 object
= find_object(argv
[2], &type
); /* look for it */
2277 if (type
!= plex_object
) {
2278 fprintf(stderr
, "%s is not a plex\n", argv
[2]);
2281 get_plex_info(&plex
, object
);
2282 plexno
= plex
.plexno
;
2287 message
->index
= vol
.volno
;
2288 message
->otherobject
= plexno
;
2289 if (ioctl(superdev
, VINUM_READPOL
, message
) < 0)
2290 fprintf(stderr
, "Can't set read policy: %s (%d)\n", strerror(errno
), errno
);
2292 vinum_lpi(plexno
, recurse
);
2296 * Brute force set state function. Don't look at
2297 * any dependencies, just do it.
2300 vinum_setstate(int argc
, char *argv
[], char *argv0
[])
2303 struct _ioctl_reply reply
;
2304 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
2306 enum objecttype type
;
2309 for (index
= 1; index
< argc
; index
++) {
2310 object
= find_object(argv
[index
], &type
); /* look for it */
2311 if (type
== invalid_object
)
2312 fprintf(stderr
, "Can't find object: %s\n", argv
[index
]);
2314 int doit
= 0; /* set to 1 if we pass our tests */
2317 state
= DriveState(argv
[0]); /* get the state */
2318 if (drive
.state
== state
) /* already in that state */
2319 fprintf(stderr
, "%s is already %s\n", drive
.label
.name
, argv
[0]);
2325 state
= SdState(argv
[0]); /* get the state */
2326 if (sd
.state
== state
) /* already in that state */
2327 fprintf(stderr
, "%s is already %s\n", sd
.name
, argv
[0]);
2333 state
= PlexState(argv
[0]); /* get the state */
2334 if (plex
.state
== state
) /* already in that state */
2335 fprintf(stderr
, "%s is already %s\n", plex
.name
, argv
[0]);
2341 state
= VolState(argv
[0]); /* get the state */
2342 if (vol
.state
== state
) /* already in that state */
2343 fprintf(stderr
, "%s is already %s\n", vol
.name
, argv
[0]);
2349 state
= 0; /* to keep the compiler happy */
2353 fprintf(stderr
, "Invalid state for object: %s\n", argv
[0]);
2355 message
->index
= object
; /* pass object number */
2356 message
->type
= type
; /* and type of object */
2357 message
->state
= state
;
2358 message
->force
= force
; /* don't force it, use a larger hammer */
2359 ioctl(superdev
, VINUM_SETSTATE_FORCE
, message
);
2360 if (reply
.error
!= 0)
2362 "Can't start %s: %s (%d)\n",
2364 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
),
2367 vinum_li(object
, type
);
2374 vinum_checkparity(int argc
, char *argv
[], char *argv0
[])
2376 Verbose
= vflag
; /* accept -v for verbose */
2377 if (argc
== 0) /* no parameters? */
2378 fprintf(stderr
, "Usage: checkparity object [object...]\n");
2380 parityops(argc
, argv
, checkparity
);
2384 vinum_rebuildparity(int argc
, char *argv
[], char *argv0
[])
2386 if (argc
== 0) /* no parameters? */
2387 fprintf(stderr
, "Usage: rebuildparity object [object...]\n");
2389 parityops(argc
, argv
, vflag
? rebuildandcheckparity
: rebuildparity
);
2393 * Common code for rebuildparity and checkparity.
2394 * We bend the meanings of some flags here:
2396 * -v: Report incorrect parity on rebuild.
2397 * -V: Show running count of position being checked.
2398 * -f: Start from beginning of the plex.
2401 parityops(int argc
, char *argv
[], enum parityop op
)
2405 struct _ioctl_reply reply
;
2406 struct vinum_ioctl_msg
*message
= (struct vinum_ioctl_msg
*) &reply
;
2408 enum objecttype type
;
2412 if (op
== checkparity
)
2416 for (index
= 0; index
< argc
; index
++) {
2417 object
= find_object(argv
[index
], &type
); /* look for it */
2418 if (type
!= plex_object
)
2419 fprintf(stderr
, "%s is not a plex\n", argv
[index
]);
2421 get_plex_info(&plex
, object
);
2422 if (!isparity((&plex
)))
2423 fprintf(stderr
, "%s is not a RAID-4 or RAID-5 plex\n", argv
[index
]);
2426 message
->index
= object
; /* pass object number */
2427 message
->type
= type
; /* and type of object */
2428 message
->op
= op
; /* what to do */
2430 message
->offset
= 0; /* start at the beginning */
2432 message
->offset
= plex
.checkblock
; /* continue where we left off */
2433 force
= 0; /* don't reset after the first time */
2434 ioctl(superdev
, VINUM_PARITYOP
, message
);
2435 get_plex_info(&plex
, object
);
2437 block
= (plex
.checkblock
<< DEV_BSHIFT
) * (plex
.subdisks
- 1);
2439 printf("\r%s at %s (%d%%) ",
2441 roughlength(block
, 1),
2442 ((int) (block
* 100 / plex
.length
) >> DEV_BSHIFT
));
2443 if ((reply
.error
== EAGAIN
)
2444 && (reply
.msg
[0])) /* got a comment back */
2445 fputs(reply
.msg
, stderr
); /* show it */
2449 while (reply
.error
== EAGAIN
);
2450 if (reply
.error
!= 0) {
2452 fputs(reply
.msg
, stderr
);
2457 strerror(reply
.error
));
2458 } else if (Verbose
) {
2459 if (op
== checkparity
)
2460 fprintf(stderr
, "%s has correct parity\n", argv
[index
]);
2462 fprintf(stderr
, "Rebuilt parity on %s\n", argv
[index
]);
2469 /* Local Variables: */
2470 /* fill-column: 50 */