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