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