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