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