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