Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sbin / vinum / commands.c
1 /* commands.c: vinum interface program, main commands */
2 /*-
3  * Copyright (c) 1997, 1998
4  *      Nan Yang Computer Services Limited.  All rights reserved.
5  *
6  *  Written by Greg Lehey
7  *
8  *  This software is distributed under the so-called ``Berkeley
9  *  License'':
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *      This product includes software developed by Nan Yang Computer
22  *      Services Limited.
23  * 4. Neither the name of the Company nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * This software is provided ``as is'', and any express or implied
28  * warranties, including, but not limited to, the implied warranties of
29  * merchantability and fitness for a particular purpose are disclaimed.
30  * In no event shall the company or contributors be liable for any
31  * direct, indirect, incidental, special, exemplary, or consequential
32  * damages (including, but not limited to, procurement of substitute
33  * goods or services; loss of use, data, or profits; or business
34  * interruption) however caused and on any theory of liability, whether
35  * in contract, strict liability, or tort (including negligence or
36  * otherwise) arising in any way out of the use of this software, even if
37  * advised of the possibility of such damage.
38  *
39  * $Id: commands.c,v 1.14 2000/11/14 20:01:23 grog Exp grog $
40  * $FreeBSD: src/sbin/vinum/commands.c,v 1.31.2.6 2003/06/06 05:13:29 grog Exp $
41  */
42
43 #include <ctype.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <sys/mman.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/vinum/vinumhdr.h>
57 #include <dev/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/history.h>
64 #include <readline/readline.h>
65 #include <devstat.h>
66
67 static void dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen);
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         if (history)
127             fprintf(history, "%s", buffer);
128
129         if (configline == NULL) {
130             if (ferror(dfd))
131                 perror("Can't read config file");
132             break;
133         }
134         file_line++;                                        /* count the lines */
135         if (vflag)
136             printf("%4d: %s", file_line, buffer);
137         strcpy(commandline, buffer);                        /* make a copy */
138         ioctl(superdev, VINUM_CREATE, buffer);
139         if (reply->error != 0) {                            /* error in config */
140             if (!vflag)                                     /* print this line anyway */
141                 printf("%4d: %s", file_line, commandline);
142             fprintf(stdout, "** %d %s: %s\n",
143                 file_line,
144                 reply->msg,
145                 strerror(reply->error));
146
147             /*
148              * XXX at the moment, we reset the config
149              * lock on error, so try to get it again.
150              * If we fail, don't cry again.
151              */
152             if (ioctl(superdev, VINUM_STARTCONFIG, &force)) /* can't get config? */
153                 return;
154         }
155     }
156     fclose(dfd);                                            /* done with the config file */
157     ioctltype = 0;                                          /* saveconfig after update */
158     error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype);  /* save the config to disk */
159     if (error != 0)
160         perror("Can't save Vinum config");
161     make_devices();
162     listconfig();
163     checkupdates();                                         /* make sure we're updating */
164 }
165
166 /* Read vinum config from a disk */
167 void
168 vinum_read(int argc, char *argv[], char *arg0[])
169 {
170     int error;
171     char buffer[BUFSIZE];                                   /* read config file in here */
172     struct _ioctl_reply *reply;
173     int i;
174
175     reply = (struct _ioctl_reply *) &buffer;
176     if (argc < 1) {                                         /* wrong arg count */
177         fprintf(stderr, "Usage: read drive [drive ...]\n");
178         return;
179     }
180     strcpy(buffer, "read ");
181     for (i = 0; i < argc; i++) {                            /* each drive name */
182         strcat(buffer, argv[i]);
183         strcat(buffer, " ");
184     }
185
186     if (ioctl(superdev, VINUM_STARTCONFIG, &force)) {       /* can't get config? */
187         fprintf(stderr, "Can't configure: %s (%d)\n", strerror(errno), errno);
188         return;
189     }
190     ioctl(superdev, VINUM_CREATE, &buffer);
191     if (reply->error != 0) {                                /* error in config */
192         fprintf(stdout, "** %s: %s\n", reply->msg, strerror(reply->error));
193         error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
194         if (error != 0)
195             perror("Can't save Vinum config");
196     } else {
197         error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */
198         if (error != 0)
199             perror("Can't save Vinum config");
200         make_devices();
201     }
202     checkupdates();                                         /* make sure we're updating */
203 }
204
205 #ifdef VINUMDEBUG
206 void
207 vinum_debug(int argc, char *argv[], char *arg0[])
208 {
209     struct debuginfo info;
210
211     if (argc > 0) {
212         info.param = atoi(argv[0]);
213         info.changeit = 1;
214     } else {
215         info.changeit = 0;
216         sleep(2);                                           /* give a chance to leave the window */
217     }
218     ioctl(superdev, VINUM_DEBUG, (caddr_t) & info);
219 }
220 #endif
221
222 void
223 vinum_modify(int argc, char *argv[], char *arg0[])
224 {
225     fprintf(stderr, "Modify command is currently not implemented\n");
226     checkupdates();                                         /* make sure we're updating */
227 }
228
229 void
230 vinum_set(int argc, char *argv[], char *arg0[])
231 {
232     fprintf(stderr, "set is not implemented yet\n");
233 }
234
235 void
236 vinum_rm(int argc, char *argv[], char *arg0[])
237 {
238     int object;
239     struct _ioctl_reply reply;
240     struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
241
242     if (argc == 0)                                          /* start everything */
243         fprintf(stderr, "Usage: rm object [object...]\n");
244     else {                                                  /* start specified objects */
245         int index;
246         enum objecttype type;
247
248         for (index = 0; index < argc; index++) {
249             object = find_object(argv[index], &type);       /* look for it */
250             if (type == invalid_object)
251                 fprintf(stderr, "Can't find object: %s\n", argv[index]);
252             else {
253                 message->index = object;                    /* pass object number */
254                 message->type = type;                       /* and type of object */
255                 message->force = force;                     /* do we want to force the operation? */
256                 message->recurse = recurse;                 /* do we want to remove subordinates? */
257                 ioctl(superdev, VINUM_REMOVE, message);
258                 if (reply.error != 0) {
259                     fprintf(stderr,
260                         "Can't remove %s: %s (%d)\n",
261                         argv[index],
262                         reply.msg[0] ? reply.msg : strerror(reply.error),
263                         reply.error);
264                 } else if (vflag)
265                     fprintf(stderr, "%s removed\n", argv[index]);
266             }
267         }
268         checkupdates();                                     /* make sure we're updating */
269     }
270 }
271
272 void
273 vinum_resetconfig(int argc, char *argv[], char *arg0[])
274 {
275     char reply[32];
276     int error;
277
278     if (! isatty (STDIN_FILENO)) {
279         fprintf (stderr, "Please enter this command from a tty device\n");
280         return;
281     }
282     printf(" WARNING!  This command will completely wipe out your vinum configuration.\n"
283         " All data will be lost.  If you really want to do this, enter the text\n\n"
284         " NO FUTURE\n"
285         " Enter text -> ");
286     fgets(reply, sizeof(reply), stdin);
287     if (strcmp(reply, "NO FUTURE\n"))                       /* changed his mind */
288         printf("\n No change\n");
289     else {
290         error = ioctl(superdev, VINUM_RESETCONFIG, NULL);   /* trash config on disk */
291         if (error) {
292             if (errno == EBUSY)
293                 fprintf(stderr, "Can't reset configuration: objects are in use\n");
294             else
295                 perror("Can't find vinum config");
296         } else {
297             make_devices();                                 /* recreate the /dev/vinum hierarchy */
298             printf("\b Vinum configuration obliterated\n");
299             start_daemon();                                 /* then restart the daemon */
300         }
301     }
302     checkupdates();                                         /* make sure we're updating */
303 }
304
305 /* Initialize subdisks */
306 void
307 vinum_init(int argc, char *argv[], char *arg0[])
308 {
309     if (argc > 0) {                                         /* initialize plexes */
310         int objindex;
311         int objno;
312         enum objecttype type;                               /* type returned */
313
314         if (history)
315             fflush(history);                                /* don't let all the kids do it. */
316         for (objindex = 0; objindex < argc; objindex++) {
317             objno = find_object(argv[objindex], &type);     /* find the object */
318             if (objno < 0)
319                 printf("Can't find %s\n", argv[objindex]);
320             else {
321                 switch (type) {
322                 case volume_object:
323                     initvol(objno);
324                     break;
325
326                 case plex_object:
327                     initplex(objno, argv[objindex]);
328                     break;
329
330                 case sd_object:
331                     initsd(objno, dowait);
332                     break;
333
334                 default:
335                     printf("Can't initialize %s: wrong object type\n", argv[objindex]);
336                     break;
337                 }
338             }
339         }
340     }
341     checkupdates();                                         /* make sure we're updating */
342 }
343
344 void
345 initvol(int volno)
346 {
347     printf("Initializing volumes is not implemented yet\n");
348 }
349
350 void
351 initplex(int plexno, char *name)
352 {
353     int sdno;
354     int plexfh = NULL;                                      /* file handle for plex */
355     pid_t pid;
356     char filename[MAXPATHLEN];                              /* create a file name here */
357
358     /* Variables for use by children */
359     int failed = 0;                                         /* set if a child dies badly */
360
361     sprintf(filename, VINUM_DIR "/plex/%s", name);
362     if ((plexfh = open(filename, O_RDWR, S_IRWXU)) < 0) {   /* got a plex, open it */
363         /*
364            * We don't actually write anything to the
365            * plex.  We open it to ensure that nobody
366            * else tries to open it while we initialize
367            * its subdisks.
368          */
369         fprintf(stderr, "can't open plex %s: %s\n", filename, strerror(errno));
370         return;
371     }
372     if (dowait == 0) {
373         pid = fork();                                       /* into the background with you */
374         if (pid != 0) {                                     /* I'm the parent, or we failed */
375             if (pid < 0)                                    /* failure */
376                 printf("Couldn't fork: %s", strerror(errno));
377             close(plexfh);                                  /* we don't need this any more */
378             return;
379         }
380     }
381     /*
382      * If we get here, we're either the first-level
383      * child (if we're not waiting) or we're going
384      * to wait.
385      */
386     for (sdno = 0; sdno < plex.subdisks; sdno++) {          /* initialize each subdisk */
387         get_plex_sd_info(&sd, plexno, sdno);
388         initsd(sd.sdno, 0);
389     }
390     /* Now wait for them to complete */
391     while (1) {
392         int status;
393         pid = wait(&status);
394         if (((int) pid == -1)
395             && (errno == ECHILD))                           /* all gone */
396             break;
397         if (WEXITSTATUS(status) != 0) {                     /* oh, oh */
398             printf("child %d exited with status 0x%x\n", pid, WEXITSTATUS(status));
399             failed++;
400         }
401     }
402     if (failed == 0) {
403 #if 0
404         message->index = plexno;                            /* pass object number */
405         message->type = plex_object;                        /* and type of object */
406         message->state = object_up;
407         message->force = 1;                                 /* insist */
408         ioctl(superdev, VINUM_SETSTATE, message);
409 #endif
410         syslog(LOG_INFO | LOG_KERN, "plex %s initialized", plex.name);
411     } else
412         syslog(LOG_ERR | LOG_KERN, "couldn't initialize plex %s, %d processes died",
413             plex.name,
414             failed);
415     if (dowait == 0)                                        /* we're the waiting child, */
416         exit(0);                                            /* we've done our dash */
417 }
418
419 /* Initialize a subdisk. */
420 void
421 initsd(int sdno, int dowait)
422 {
423     pid_t pid;
424     struct _ioctl_reply reply;
425     struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
426     char filename[MAXPATHLEN];                              /* create a file name here */
427
428     /* Variables for use by children */
429     int sdfh;                                               /* and for subdisk */
430     int initsize;                                           /* actual size to write */
431     int64_t sdsize;                                         /* size of subdisk */
432
433     if (dowait == 0) {
434         pid = fork();                                       /* into the background with you */
435         if (pid > 0)                                        /* I'm the parent */
436             return;
437         else if (pid < 0) {                                 /* failure */
438             printf("couldn't fork for subdisk %d: %s", sdno, strerror(errno));
439             return;
440         }
441     }
442     if (SSize != 0) {                                       /* specified a size for init */
443         if (SSize < 512)
444             SSize <<= DEV_BSHIFT;
445         initsize = min(SSize, MAXPLEXINITSIZE);
446     } else
447         initsize = PLEXINITSIZE;
448     openlog("vinum", LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
449     get_sd_info(&sd, sdno);
450     sdsize = sd.sectors * DEV_BSIZE;                        /* size of subdisk in bytes */
451     sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
452     setproctitle("initializing %s", filename);              /* show what we're doing */
453     syslog(LOG_INFO | LOG_KERN, "initializing subdisk %s", filename);
454     if ((sdfh = open(filename, O_RDWR, S_IRWXU)) < 0) {     /* no go */
455         syslog(LOG_ERR | LOG_KERN,
456             "can't open subdisk %s: %s",
457             filename,
458             strerror(errno));
459         exit(1);
460     }
461     /* Set the subdisk in initializing state */
462     message->index = sd.sdno;                               /* pass object number */
463     message->type = sd_object;                              /* and type of object */
464     message->state = object_initializing;
465     message->verify = vflag;                                /* verify what we write? */
466     message->force = 1;                                     /* insist */
467     ioctl(superdev, VINUM_SETSTATE, message);
468     if ((SSize > 0)                                         /* specified a size for init */
469     &&(SSize < 512))
470         SSize <<= DEV_BSHIFT;
471     if (reply.error) {
472         fprintf(stderr,
473             "Can't initialize %s: %s (%d)\n",
474             filename,
475             strerror(reply.error),
476             reply.error);
477         exit(1);
478     } else {
479         do {
480             if (interval)                                   /* pause between copies */
481                 usleep(interval * 1000);
482             message->index = sd.sdno;                       /* pass object number */
483             message->type = sd_object;                      /* and type of object */
484             message->state = object_up;
485             message->verify = vflag;                        /* verify what we write? */
486             message->blocksize = SSize;
487             ioctl(superdev, VINUM_SETSTATE, message);
488         }
489         while (reply.error == EAGAIN);                      /* until we're done */
490         if (reply.error) {
491             fprintf(stderr,
492                 "Can't initialize %s: %s (%d)\n",
493                 filename,
494                 strerror(reply.error),
495                 reply.error);
496             get_sd_info(&sd, sdno);
497             if (sd.state != sd_up)
498                 /* Set the subdisk down */
499                 message->index = sd.sdno;                   /* pass object number */
500             message->type = sd_object;                      /* and type of object */
501             message->state = object_down;
502             message->verify = vflag;                        /* verify what we write? */
503             message->force = 1;                             /* insist */
504             ioctl(superdev, VINUM_SETSTATE, message);
505         }
506     }
507     printf("subdisk %s initialized\n", filename);
508     if (!dowait)
509         exit(0);
510 }
511
512 void
513 vinum_start(int argc, char *argv[], char *arg0[])
514 {
515     int object;
516     struct _ioctl_reply reply;
517     struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
518
519     if (argc == 0) {                                        /* start everything */
520         int devs = getnumdevs();
521         struct statinfo statinfo;
522         char *namelist;
523         char *enamelist;                                    /* end of name list */
524         int i;
525         char **token;                                       /* list of tokens */
526         int tokens;                                         /* and their number */
527
528         bzero(&statinfo, sizeof(struct statinfo));
529         statinfo.dinfo = malloc(devs * sizeof(struct statinfo));
530         namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8));
531         token = malloc((devs + 1) * sizeof(char *));
532         if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) {
533             fprintf(stderr, "Can't allocate memory for drive list\n");
534             return;
535         }
536         bzero(statinfo.dinfo, sizeof(struct devinfo));
537
538         tokens = 0;                                         /* no tokens yet */
539         if (getdevs(&statinfo) < 0) {                       /* find out what devices we have */
540             perror("Can't get device list");
541             return;
542         }
543         namelist[0] = '\0';                                 /* start with empty namelist */
544         enamelist = namelist;                               /* point to the end of the list */
545
546         for (i = 0; i < devs; i++) {
547             struct devstat *stat = &statinfo.dinfo->devices[i];
548
549             if ((((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */
550                  || ((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) /* storage array */
551             &&((stat->device_type & DEVSTAT_TYPE_IF_MASK) != DEVSTAT_TYPE_IF_OTHER) /* and not md */
552             &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */
553             &&((stat->device_name[0] != '\0'))) {           /* and it has a name */
554                 sprintf(enamelist, "%s%s%d", _PATH_DEV, stat->device_name, stat->unit_number);
555                 token[tokens] = enamelist;                  /* point to it */
556                 tokens++;                                   /* one more token */
557                 enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */
558             }
559         }
560         free(statinfo.dinfo);                               /* don't need the list any more */
561         vinum_read(tokens, token, &token[0]);               /* start the system */
562         free(namelist);
563         free(token);
564         list_defective_objects();                           /* and list anything that's down */
565     } else {                                                /* start specified objects */
566         int index;
567         enum objecttype type;
568
569         for (index = 0; index < argc; index++) {
570             object = find_object(argv[index], &type);       /* look for it */
571             if (type == invalid_object)
572                 fprintf(stderr, "Can't find object: %s\n", argv[index]);
573             else {
574                 int doit = 0;                               /* set to 1 if we pass our tests */
575                 switch (type) {
576                 case drive_object:
577                     if (drive.state == drive_up)            /* already up */
578                         fprintf(stderr, "%s is already up\n", drive.label.name);
579                     else
580                         doit = 1;
581                     break;
582
583                 case sd_object:
584                     if (sd.state == sd_up)                  /* already up */
585                         fprintf(stderr, "%s is already up\n", sd.name);
586                     else
587                         doit = 1;
588                     break;
589
590                 case plex_object:
591                     if (plex.state == plex_up)              /* already up */
592                         fprintf(stderr, "%s is already up\n", plex.name);
593                     else {
594                         int sdno;
595
596                         /*
597                          * First, see if we can bring it up
598                          * just by asking.  This might happen
599                          * if somebody has used setupstate on
600                          * the subdisks.  If we don't do this,
601                          * we'll return success, but the plex
602                          * won't have changed state.  Note
603                          * that we don't check for errors
604                          * here.
605                          */
606                         message->index = plex.plexno;       /* pass object number */
607                         message->type = plex_object;        /* it's a plex */
608                         message->state = object_up;
609                         message->force = 0;                 /* don't force it */
610                         ioctl(superdev, VINUM_SETSTATE, message);
611                         for (sdno = 0; sdno < plex.subdisks; sdno++) {
612                             get_plex_sd_info(&sd, object, sdno);
613                             if ((sd.state >= sd_empty)
614                                 && (sd.state <= sd_reviving)) { /* candidate for start */
615                                 message->index = sd.sdno;   /* pass object number */
616                                 message->type = sd_object;  /* it's a subdisk */
617                                 message->state = object_up;
618                                 message->force = force;     /* don't force it, use a larger hammer */
619
620                                 /*
621                                  * We don't do any checking here.
622                                  * The kernel module has a better
623                                  * understanding of these things,
624                                  * let it do it.
625                                  */
626                                 if (SSize != 0) {           /* specified a size for init */
627                                     if (SSize < 512)
628                                         SSize <<= DEV_BSHIFT;
629                                     message->blocksize = SSize;
630                                 } else
631                                     message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
632                                 ioctl(superdev, VINUM_SETSTATE, message);
633                                 if (reply.error != 0) {
634                                     if (reply.error == EAGAIN) /* we're reviving */
635                                         continue_revive(sd.sdno);
636                                     else
637                                         fprintf(stderr,
638                                             "Can't start %s: %s (%d)\n",
639                                             sd.name,
640                                             reply.msg[0] ? reply.msg : strerror(reply.error),
641                                             reply.error);
642                                 }
643                                 if (Verbose)
644                                     vinum_lsi(sd.sdno, 0);
645                             }
646                         }
647                     }
648                     break;
649
650                 case volume_object:
651                     if (vol.state == volume_up)             /* already up */
652                         fprintf(stderr, "%s is already up\n", vol.name);
653                     else
654                         doit = 1;
655                     break;
656
657                 default:
658                 }
659
660                 if (doit) {
661                     message->index = object;                /* pass object number */
662                     message->type = type;                   /* and type of object */
663                     message->state = object_up;
664                     message->force = force;                 /* don't force it, use a larger hammer */
665
666                     /*
667                      * We don't do any checking here.
668                      * The kernel module has a better
669                      * understanding of these things,
670                      * let it do it.
671                      */
672                     if (SSize != 0) {                       /* specified a size for init or revive */
673                         if (SSize < 512)
674                             SSize <<= DEV_BSHIFT;
675                         message->blocksize = SSize;
676                     } else
677                         message->blocksize = 0;
678                     ioctl(superdev, VINUM_SETSTATE, message);
679                     if (reply.error != 0) {
680                         if ((reply.error == EAGAIN)         /* we're reviving */
681                         &&(type == sd_object))
682                             continue_revive(object);
683                         else
684                             fprintf(stderr,
685                                 "Can't start %s: %s (%d)\n",
686                                 argv[index],
687                                 reply.msg[0] ? reply.msg : strerror(reply.error),
688                                 reply.error);
689                     }
690                     if (Verbose)
691                         vinum_li(object, type);
692                 }
693             }
694         }
695     }
696     checkupdates();                                         /* make sure we're updating */
697 }
698
699 void
700 vinum_stop(int argc, char *argv[], char *arg0[])
701 {
702     int object;
703     struct _ioctl_reply reply;
704     struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
705
706     if (checkupdates() && (!force))                         /* not updating? */
707         return;
708     message->force = force;                                 /* should we force the transition? */
709     if (argc == 0) {                                        /* stop vinum */
710         int fileid = 0;                                     /* ID of Vinum kld */
711
712         close(superdev);                                    /* we can't stop if we have vinum open */
713         sleep(1);                                           /* wait for the daemon to let go */
714         fileid = kldfind(VINUMMOD);
715         if ((fileid < 0)                                    /* no go */
716         ||(kldunload(fileid) < 0))
717             perror("Can't unload " VINUMMOD);
718         else {
719             fprintf(stderr, VINUMMOD " unloaded\n");
720             exit(0);
721         }
722
723         /* If we got here, the stop failed.  Reopen the superdevice. */
724         superdev = open(VINUM_SUPERDEV_NAME, O_RDWR);       /* reopen vinum superdevice */
725         if (superdev < 0) {
726             perror("Can't reopen Vinum superdevice");
727             exit(1);
728         }
729     } else {                                                /* stop specified objects */
730         int i;
731         enum objecttype type;
732
733         for (i = 0; i < argc; i++) {
734             object = find_object(argv[i], &type);           /* look for it */
735             if (type == invalid_object)
736                 fprintf(stderr, "Can't find object: %s\n", argv[i]);
737             else {
738                 message->index = object;                    /* pass object number */
739                 message->type = type;                       /* and type of object */
740                 message->state = object_down;
741                 ioctl(superdev, VINUM_SETSTATE, message);
742                 if (reply.error != 0)
743                     fprintf(stderr,
744                         "Can't stop %s: %s (%d)\n",
745                         argv[i],
746                         reply.msg[0] ? reply.msg : strerror(reply.error),
747                         reply.error);
748                 if (Verbose)
749                     vinum_li(object, type);
750             }
751         }
752     }
753 }
754
755 void
756 vinum_label(int argc, char *argv[], char *arg0[])
757 {
758     int object;
759     struct _ioctl_reply reply;
760     int *message = (int *) &reply;
761
762     if (argc == 0)                                          /* start everything */
763         fprintf(stderr, "label: please specify one or more volume names\n");
764     else {                                                  /* start specified objects */
765         int i;
766         enum objecttype type;
767
768         for (i = 0; i < argc; i++) {
769             object = find_object(argv[i], &type);           /* look for it */
770             if (type == invalid_object)
771                 fprintf(stderr, "Can't find object: %s\n", argv[i]);
772             else if (type != volume_object)                 /* it exists, but it isn't a volume */
773                 fprintf(stderr, "%s is not a volume\n", argv[i]);
774             else {
775                 message[0] = object;                        /* pass object number */
776                 ioctl(superdev, VINUM_LABEL, message);
777                 if (reply.error != 0)
778                     fprintf(stderr,
779                         "Can't label %s: %s (%d)\n",
780                         argv[i],
781                         reply.msg[0] ? reply.msg : strerror(reply.error),
782                         reply.error);
783                 if (Verbose)
784                     vinum_li(object, type);
785             }
786         }
787     }
788     checkupdates();                                         /* not updating? */
789 }
790
791 void
792 reset_volume_stats(int volno, int recurse)
793 {
794     struct vinum_ioctl_msg msg;
795     struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
796
797     msg.index = volno;
798     msg.type = volume_object;
799     /* XXX get these numbers right if we ever
800      * actually return errors */
801     if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
802         fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg);
803         longjmp(command_fail, -1);
804     } else if (recurse) {
805         struct volume vol;
806         int plexno;
807
808         get_volume_info(&vol, volno);
809         for (plexno = 0; plexno < vol.plexes; plexno++)
810             reset_plex_stats(vol.plex[plexno], recurse);
811     }
812 }
813
814 void
815 reset_plex_stats(int plexno, int recurse)
816 {
817     struct vinum_ioctl_msg msg;
818     struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
819
820     msg.index = plexno;
821     msg.type = plex_object;
822     /* XXX get these numbers right if we ever
823      * actually return errors */
824     if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
825         fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg);
826         longjmp(command_fail, -1);
827     } else if (recurse) {
828         struct plex plex;
829         struct sd sd;
830         int sdno;
831
832         get_plex_info(&plex, plexno);
833         for (sdno = 0; sdno < plex.subdisks; sdno++) {
834             get_plex_sd_info(&sd, plex.plexno, sdno);
835             reset_sd_stats(sd.sdno, recurse);
836         }
837     }
838 }
839
840 void
841 reset_sd_stats(int sdno, int recurse)
842 {
843     struct vinum_ioctl_msg msg;
844     struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
845
846     msg.index = sdno;
847     msg.type = sd_object;
848     /* XXX get these numbers right if we ever
849      * actually return errors */
850     if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
851         fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg);
852         longjmp(command_fail, -1);
853     } else if (recurse) {
854         get_sd_info(&sd, sdno);                             /* get the info */
855         reset_drive_stats(sd.driveno);                      /* and clear the drive */
856     }
857 }
858
859 void
860 reset_drive_stats(int driveno)
861 {
862     struct vinum_ioctl_msg msg;
863     struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
864
865     msg.index = driveno;
866     msg.type = drive_object;
867     /* XXX get these numbers right if we ever
868      * actually return errors */
869     if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
870         fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg);
871         longjmp(command_fail, -1);
872     }
873 }
874
875 void
876 vinum_resetstats(int argc, char *argv[], char *argv0[])
877 {
878     int i;
879     int objno;
880     enum objecttype type;
881
882     if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
883         perror("Can't get vinum config");
884         return;
885     }
886     if (argc == 0) {
887         for (objno = 0; objno < vinum_conf.volumes_allocated; objno++)
888             reset_volume_stats(objno, 1);                   /* clear everything recursively */
889     } else {
890         for (i = 0; i < argc; i++) {
891             objno = find_object(argv[i], &type);
892             if (objno >= 0) {                               /* not invalid */
893                 switch (type) {
894                 case drive_object:
895                     reset_drive_stats(objno);
896                     break;
897
898                 case sd_object:
899                     reset_sd_stats(objno, recurse);
900                     break;
901
902                 case plex_object:
903                     reset_plex_stats(objno, recurse);
904                     break;
905
906                 case volume_object:
907                     reset_volume_stats(objno, recurse);
908                     break;
909
910                 case invalid_object:                        /* can't get this */
911                     break;
912                 }
913             }
914         }
915     }
916 }
917
918 /* Attach a subdisk to a plex, or a plex to a volume.
919  * attach subdisk plex [offset] [rename]
920  * attach plex volume  [rename]
921  */
922 void
923 vinum_attach(int argc, char *argv[], char *argv0[])
924 {
925     int i;
926     enum objecttype supertype;
927     struct vinum_ioctl_msg msg;
928     struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
929     const char *objname = argv[0];
930     const char *supername = argv[1];
931     int sdno = -1;
932     int plexno = -1;
933     char oldname[MAXNAME + 8];
934     char newname[MAXNAME + 8];
935     int rename = 0;                                         /* set if we want to rename the object */
936
937     if ((argc < 2)
938         || (argc > 4)) {
939         fprintf(stderr,
940             "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
941             "\tattach <plex> <volume> [rename]\n");
942         return;
943     }
944     if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
945         perror("Can't get vinum config");
946         return;
947     }
948     msg.index = find_object(objname, &msg.type);            /* find the object to attach */
949     msg.otherobject = find_object(supername, &supertype);   /* and the object to attach to */
950     msg.force = force;                                      /* did we specify the use of force? */
951     msg.recurse = recurse;
952     msg.offset = -1;                                        /* and no offset */
953
954     for (i = 2; i < argc; i++) {
955         if (!strcmp(argv[i], "rename")) {
956             rename = 1;
957             msg.rename = 1;                                 /* do renaming */
958         } else if (!isdigit(argv[i][0])) {                  /* not an offset */
959             fprintf(stderr, "Unknown attribute: %s\n", supername);
960             return;
961         } else
962             msg.offset = sizespec(argv[i]);
963     }
964
965     switch (msg.type) {
966     case sd_object:
967         find_object(argv[1], &supertype);
968         if (supertype != plex_object) {                     /* huh? */
969             fprintf(stderr, "%s can only be attached to a plex\n", objname);
970             return;
971         }
972         if ((plex.organization != plex_concat)              /* not a cat plex, */
973         &&(!force)) {
974             fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization));
975             return;
976         }
977         sdno = msg.index;                                   /* note the subdisk number for later */
978         break;
979
980     case plex_object:
981         find_object(argv[1], &supertype);
982         if (supertype != volume_object) {                   /* huh? */
983             fprintf(stderr, "%s can only be attached to a volume\n", objname);
984             return;
985         }
986         break;
987
988     case volume_object:
989     case drive_object:
990         fprintf(stderr, "Can only attach subdisks and plexes\n");
991         return;
992
993     default:
994         fprintf(stderr, "%s is not a Vinum object\n", objname);
995         return;
996     }
997
998     ioctl(superdev, VINUM_ATTACH, &msg);
999     if (reply->error != 0) {
1000         if (reply->error == EAGAIN)                         /* reviving */
1001             continue_revive(sdno);                          /* continue the revive */
1002         else
1003             fprintf(stderr,
1004                 "Can't attach %s to %s: %s (%d)\n",
1005                 objname,
1006                 supername,
1007                 reply->msg[0] ? reply->msg : strerror(reply->error),
1008                 reply->error);
1009     }
1010     if (rename) {
1011         struct sd;
1012         struct plex;
1013         struct volume;
1014
1015         /* we've overwritten msg with the
1016          * ioctl reply, start again */
1017         msg.index = find_object(objname, &msg.type);        /* find the object to rename */
1018         switch (msg.type) {
1019         case sd_object:
1020             get_sd_info(&sd, msg.index);
1021             get_plex_info(&plex, sd.plexno);
1022             for (sdno = 0; sdno < plex.subdisks; sdno++) {
1023                 if (plex.sdnos[sdno] == msg.index)          /* found our subdisk */
1024                     break;
1025             }
1026             sprintf(newname, "%s.s%d", plex.name, sdno);
1027             sprintf(oldname, "%s", sd.name);
1028             vinum_rename_2(oldname, newname);
1029             break;
1030
1031         case plex_object:
1032             get_plex_info(&plex, msg.index);
1033             get_volume_info(&vol, plex.volno);
1034             for (plexno = 0; plexno < vol.plexes; plexno++) {
1035                 if (vol.plex[plexno] == msg.index)          /* found our subdisk */
1036                     break;
1037             }
1038             sprintf(newname, "%s.p%d", vol.name, plexno);
1039             sprintf(oldname, "%s", plex.name);
1040             vinum_rename_2(oldname, newname);               /* this may recurse */
1041             break;
1042
1043         default:                                            /* can't get here */
1044         }
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()
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()
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     struct drive_freelist freelist;
1655     struct ferq {                                           /* request to pass to ioctl */
1656         int driveno;
1657         int fe;
1658     } *ferq = (struct ferq *) &freelist;
1659     u_int64_t bigchunk;                                     /* biggest chunk in freelist */
1660
1661     maxsize = QUAD_MAX;
1662     reply = (struct _ioctl_reply *) &buffer;
1663
1664     /*
1665      * First, check our drives.
1666      */
1667     if (argc < 2) {
1668         fprintf(stderr, "You need at least two drives to create a striped plex\n");
1669         return;
1670     }
1671     if (ioctl(superdev, VINUM_STARTCONFIG, &force)) {       /* can't get config? */
1672         printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1673         return;
1674     }
1675     if (!objectname)                                        /* we need a name for our object */
1676         genvolname();
1677     for (o = 0; o < argc; o++) {
1678         if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1679             drive = create_drive(argv[o]);                  /* create it */
1680         /* Now find the largest chunk available on the drive */
1681         bigchunk = 0;                                       /* ain't found nothin' yet */
1682         for (fe = 0; fe < drive->freelist_entries; fe++) {
1683             ferq->driveno = drive->driveno;
1684             ferq->fe = fe;
1685             if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1686                 fprintf(stderr,
1687                     "Can't get free list element %d: %s\n",
1688                     fe,
1689                     strerror(errno));
1690                 longjmp(command_fail, -1);
1691             }
1692             bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1693         }
1694         maxsize = min(maxsize, bigchunk);                   /* this is as much as we can do */
1695     }
1696
1697     /* Now create the volume */
1698     sprintf(buffer, "volume %s", objectname);
1699     if (vflag)
1700         printf("volume %s\n", objectname);
1701     ioctl(superdev, VINUM_CREATE, buffer);                  /* create the volume */
1702     if (reply->error != 0) {                                /* error in config */
1703         if (reply->msg[0])
1704             fprintf(stderr,
1705                 "Can't create volume %s: %s\n",
1706                 objectname,
1707                 reply->msg);
1708         else
1709             fprintf(stderr,
1710                 "Can't create volume %s: %s (%d)\n",
1711                 objectname,
1712                 strerror(reply->error),
1713                 reply->error);
1714         longjmp(command_fail, -1);                          /* give up */
1715     }
1716     sprintf(buffer, "plex name %s.p0 org striped 256k", objectname);
1717     if (vflag)
1718         printf("  plex name %s.p0 org striped 256k\n", objectname);
1719     ioctl(superdev, VINUM_CREATE, buffer);
1720     if (reply->error != 0) {                                /* error in config */
1721         if (reply->msg[0])
1722             fprintf(stderr,
1723                 "Can't create plex %s.p0: %s\n",
1724                 objectname,
1725                 reply->msg);
1726         else
1727             fprintf(stderr,
1728                 "Can't create plex %s.p0: %s (%d)\n",
1729                 objectname,
1730                 strerror(reply->error),
1731                 reply->error);
1732         longjmp(command_fail, -1);                          /* give up */
1733     }
1734     for (o = 0; o < argc; o++) {
1735         drive = find_drive_by_devname(argv[o]);             /* we know it exists... */
1736         sprintf(buffer,
1737             "sd name %s.p0.s%d drive %s size %lldb",
1738             objectname,
1739             o,
1740             drive->label.name,
1741             (long long) maxsize);
1742         if (vflag)
1743             printf("    sd name %s.p0.s%d drive %s size %lldb\n",
1744                 objectname,
1745                 o,
1746                 drive->label.name,
1747                 (long long) maxsize);
1748         ioctl(superdev, VINUM_CREATE, buffer);
1749         if (reply->error != 0) {                            /* error in config */
1750             if (reply->msg[0])
1751                 fprintf(stderr,
1752                     "Can't create subdisk %s.p0.s%d: %s\n",
1753                     objectname,
1754                     o,
1755                     reply->msg);
1756             else
1757                 fprintf(stderr,
1758                     "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1759                     objectname,
1760                     o,
1761                     strerror(reply->error),
1762                     reply->error);
1763             longjmp(command_fail, -1);                      /* give up */
1764         }
1765     }
1766
1767     /* done, save the config */
1768     ioctltype = 0;                                          /* saveconfig after update */
1769     error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype);  /* save the config to disk */
1770     if (error != 0)
1771         perror("Can't save Vinum config");
1772     find_object(objectname, &type);                         /* find the index of the volume */
1773     make_vol_dev(vol.volno, 1);                             /* and create the devices */
1774     if (vflag) {
1775         vflag--;                                            /* XXX don't give too much detail */
1776         find_object(objectname, &type);                     /* point to the volume */
1777         vinum_lvi(vol.volno, 1);                            /* and print info about it */
1778     }
1779 }
1780
1781 /*
1782  * Create a volume with a single RAID-4 plex from
1783  * as much space as we can get on the specified drives.
1784  * If the drives aren't Vinum drives, make them so.
1785  */
1786 void
1787 vinum_raid4(int argc, char *argv[], char *argv0[])
1788 {
1789     int o;                                                  /* object number */
1790     char buffer[BUFSIZE];
1791     struct drive *drive;                                    /* drive we're currently looking at */
1792     struct _ioctl_reply *reply;
1793     int ioctltype;
1794     int error;
1795     enum objecttype type;
1796     off_t maxsize;
1797     int fe;                                                 /* freelist entry index */
1798     struct drive_freelist freelist;
1799     struct ferq {                                           /* request to pass to ioctl */
1800         int driveno;
1801         int fe;
1802     } *ferq = (struct ferq *) &freelist;
1803     u_int64_t bigchunk;                                     /* biggest chunk in freelist */
1804
1805     maxsize = QUAD_MAX;
1806     reply = (struct _ioctl_reply *) &buffer;
1807
1808     /*
1809      * First, check our drives.
1810      */
1811     if (argc < 3) {
1812         fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n");
1813         return;
1814     }
1815     if (ioctl(superdev, VINUM_STARTCONFIG, &force)) {       /* can't get config? */
1816         printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1817         return;
1818     }
1819     if (!objectname)                                        /* we need a name for our object */
1820         genvolname();
1821     for (o = 0; o < argc; o++) {
1822         if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1823             drive = create_drive(argv[o]);                  /* create it */
1824         /* Now find the largest chunk available on the drive */
1825         bigchunk = 0;                                       /* ain't found nothin' yet */
1826         for (fe = 0; fe < drive->freelist_entries; fe++) {
1827             ferq->driveno = drive->driveno;
1828             ferq->fe = fe;
1829             if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1830                 fprintf(stderr,
1831                     "Can't get free list element %d: %s\n",
1832                     fe,
1833                     strerror(errno));
1834                 longjmp(command_fail, -1);
1835             }
1836             bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1837         }
1838         maxsize = min(maxsize, bigchunk);                   /* this is as much as we can do */
1839     }
1840
1841     /* Now create the volume */
1842     sprintf(buffer, "volume %s", objectname);
1843     if (vflag)
1844         printf("volume %s\n", objectname);
1845     ioctl(superdev, VINUM_CREATE, buffer);                  /* create the volume */
1846     if (reply->error != 0) {                                /* error in config */
1847         if (reply->msg[0])
1848             fprintf(stderr,
1849                 "Can't create volume %s: %s\n",
1850                 objectname,
1851                 reply->msg);
1852         else
1853             fprintf(stderr,
1854                 "Can't create volume %s: %s (%d)\n",
1855                 objectname,
1856                 strerror(reply->error),
1857                 reply->error);
1858         longjmp(command_fail, -1);                          /* give up */
1859     }
1860     sprintf(buffer, "plex name %s.p0 org raid4 256k", objectname);
1861     if (vflag)
1862         printf("  plex name %s.p0 org raid4 256k\n", objectname);
1863     ioctl(superdev, VINUM_CREATE, buffer);
1864     if (reply->error != 0) {                                /* error in config */
1865         if (reply->msg[0])
1866             fprintf(stderr,
1867                 "Can't create plex %s.p0: %s\n",
1868                 objectname,
1869                 reply->msg);
1870         else
1871             fprintf(stderr,
1872                 "Can't create plex %s.p0: %s (%d)\n",
1873                 objectname,
1874                 strerror(reply->error),
1875                 reply->error);
1876         longjmp(command_fail, -1);                          /* give up */
1877     }
1878     for (o = 0; o < argc; o++) {
1879         drive = find_drive_by_devname(argv[o]);             /* we know it exists... */
1880         sprintf(buffer,
1881             "sd name %s.p0.s%d drive %s size %lldb",
1882             objectname,
1883             o,
1884             drive->label.name,
1885             (long long) maxsize);
1886         if (vflag)
1887             printf("    sd name %s.p0.s%d drive %s size %lldb\n",
1888                 objectname,
1889                 o,
1890                 drive->label.name,
1891                 (long long) maxsize);
1892         ioctl(superdev, VINUM_CREATE, buffer);
1893         if (reply->error != 0) {                            /* error in config */
1894             if (reply->msg[0])
1895                 fprintf(stderr,
1896                     "Can't create subdisk %s.p0.s%d: %s\n",
1897                     objectname,
1898                     o,
1899                     reply->msg);
1900             else
1901                 fprintf(stderr,
1902                     "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1903                     objectname,
1904                     o,
1905                     strerror(reply->error),
1906                     reply->error);
1907             longjmp(command_fail, -1);                      /* give up */
1908         }
1909     }
1910
1911     /* done, save the config */
1912     ioctltype = 0;                                          /* saveconfig after update */
1913     error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype);  /* save the config to disk */
1914     if (error != 0)
1915         perror("Can't save Vinum config");
1916     find_object(objectname, &type);                         /* find the index of the volume */
1917     make_vol_dev(vol.volno, 1);                             /* and create the devices */
1918     if (vflag) {
1919         vflag--;                                            /* XXX don't give too much detail */
1920         find_object(objectname, &type);                     /* point to the volume */
1921         vinum_lvi(vol.volno, 1);                            /* and print info about it */
1922     }
1923 }
1924
1925 /*
1926  * Create a volume with a single RAID-4 plex from
1927  * as much space as we can get on the specified drives.
1928  * If the drives aren't Vinum drives, make them so.
1929  */
1930 void
1931 vinum_raid5(int argc, char *argv[], char *argv0[])
1932 {
1933     int o;                                                  /* object number */
1934     char buffer[BUFSIZE];
1935     struct drive *drive;                                    /* drive we're currently looking at */
1936     struct _ioctl_reply *reply;
1937     int ioctltype;
1938     int error;
1939     enum objecttype type;
1940     off_t maxsize;
1941     int fe;                                                 /* freelist entry index */
1942     struct drive_freelist freelist;
1943     struct ferq {                                           /* request to pass to ioctl */
1944         int driveno;
1945         int fe;
1946     } *ferq = (struct ferq *) &freelist;
1947     u_int64_t bigchunk;                                     /* biggest chunk in freelist */
1948
1949     maxsize = QUAD_MAX;
1950     reply = (struct _ioctl_reply *) &buffer;
1951
1952     /*
1953      * First, check our drives.
1954      */
1955     if (argc < 3) {
1956         fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n");
1957         return;
1958     }
1959     if (ioctl(superdev, VINUM_STARTCONFIG, &force)) {       /* can't get config? */
1960         printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1961         return;
1962     }
1963     if (!objectname)                                        /* we need a name for our object */
1964         genvolname();
1965     for (o = 0; o < argc; o++) {
1966         if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1967             drive = create_drive(argv[o]);                  /* create it */
1968         /* Now find the largest chunk available on the drive */
1969         bigchunk = 0;                                       /* ain't found nothin' yet */
1970         for (fe = 0; fe < drive->freelist_entries; fe++) {
1971             ferq->driveno = drive->driveno;
1972             ferq->fe = fe;
1973             if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1974                 fprintf(stderr,
1975                     "Can't get free list element %d: %s\n",
1976                     fe,
1977                     strerror(errno));
1978                 longjmp(command_fail, -1);
1979             }
1980             bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1981         }
1982         maxsize = min(maxsize, bigchunk);                   /* this is as much as we can do */
1983     }
1984
1985     /* Now create the volume */
1986     sprintf(buffer, "volume %s", objectname);
1987     if (vflag)
1988         printf("volume %s\n", objectname);
1989     ioctl(superdev, VINUM_CREATE, buffer);                  /* create the volume */
1990     if (reply->error != 0) {                                /* error in config */
1991         if (reply->msg[0])
1992             fprintf(stderr,
1993                 "Can't create volume %s: %s\n",
1994                 objectname,
1995                 reply->msg);
1996         else
1997             fprintf(stderr,
1998                 "Can't create volume %s: %s (%d)\n",
1999                 objectname,
2000                 strerror(reply->error),
2001                 reply->error);
2002         longjmp(command_fail, -1);                          /* give up */
2003     }
2004     sprintf(buffer, "plex name %s.p0 org raid5 256k", objectname);
2005     if (vflag)
2006         printf("  plex name %s.p0 org raid5 256k\n", objectname);
2007     ioctl(superdev, VINUM_CREATE, buffer);
2008     if (reply->error != 0) {                                /* error in config */
2009         if (reply->msg[0])
2010             fprintf(stderr,
2011                 "Can't create plex %s.p0: %s\n",
2012                 objectname,
2013                 reply->msg);
2014         else
2015             fprintf(stderr,
2016                 "Can't create plex %s.p0: %s (%d)\n",
2017                 objectname,
2018                 strerror(reply->error),
2019                 reply->error);
2020         longjmp(command_fail, -1);                          /* give up */
2021     }
2022     for (o = 0; o < argc; o++) {
2023         drive = find_drive_by_devname(argv[o]);             /* we know it exists... */
2024         sprintf(buffer,
2025             "sd name %s.p0.s%d drive %s size %lldb",
2026             objectname,
2027             o,
2028             drive->label.name,
2029             (long long) maxsize);
2030         if (vflag)
2031             printf("    sd name %s.p0.s%d drive %s size %lldb\n",
2032                 objectname,
2033                 o,
2034                 drive->label.name,
2035                 (long long) maxsize);
2036         ioctl(superdev, VINUM_CREATE, buffer);
2037         if (reply->error != 0) {                            /* error in config */
2038             if (reply->msg[0])
2039                 fprintf(stderr,
2040                     "Can't create subdisk %s.p0.s%d: %s\n",
2041                     objectname,
2042                     o,
2043                     reply->msg);
2044             else
2045                 fprintf(stderr,
2046                     "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2047                     objectname,
2048                     o,
2049                     strerror(reply->error),
2050                     reply->error);
2051             longjmp(command_fail, -1);                      /* give up */
2052         }
2053     }
2054
2055     /* done, save the config */
2056     ioctltype = 0;                                          /* saveconfig after update */
2057     error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype);  /* save the config to disk */
2058     if (error != 0)
2059         perror("Can't save Vinum config");
2060     find_object(objectname, &type);                         /* find the index of the volume */
2061     make_vol_dev(vol.volno, 1);                             /* and create the devices */
2062     if (vflag) {
2063         vflag--;                                            /* XXX don't give too much detail */
2064         find_object(objectname, &type);                     /* point to the volume */
2065         vinum_lvi(vol.volno, 1);                            /* and print info about it */
2066     }
2067 }
2068
2069 /*
2070  * Create a volume with a two plexes from as much space
2071  * as we can get on the specified drives.  If the
2072  * drives aren't Vinum drives, make them so.
2073  *
2074  * The number of drives must be even, and at least 4
2075  * for a striped plex.  Specify striped plexes with the
2076  * -s flag; otherwise they will be concatenated.  It's
2077  * possible that the two plexes may differ in length.
2078  */
2079 void
2080 vinum_mirror(int argc, char *argv[], char *argv0[])
2081 {
2082     int o;                                                  /* object number */
2083     int p;                                                  /* plex number */
2084     char buffer[BUFSIZE];
2085     struct drive *drive;                                    /* drive we're currently looking at */
2086     struct _ioctl_reply *reply;
2087     int ioctltype;
2088     int error;
2089     enum objecttype type;
2090     off_t maxsize[2];                                       /* maximum subdisk size for striped plexes */
2091     int fe;                                                 /* freelist entry index */
2092     struct drive_freelist freelist;
2093     struct ferq {                                           /* request to pass to ioctl */
2094         int driveno;
2095         int fe;
2096     } *ferq = (struct ferq *) &freelist;
2097     u_int64_t bigchunk;                                     /* biggest chunk in freelist */
2098
2099     if (sflag)                                              /* striped, */
2100         maxsize[0] = maxsize[1] = QUAD_MAX;                 /* we need to calculate sd size */
2101     else
2102         maxsize[0] = maxsize[1] = 0;                        /* let the kernel routines do it */
2103
2104     reply = (struct _ioctl_reply *) &buffer;
2105
2106     /*
2107      * First, check our drives.
2108      */
2109     if (argc & 1) {
2110         fprintf(stderr, "You need an even number of drives to create a mirrored volume\n");
2111         return;
2112     }
2113     if (sflag && (argc < 4)) {
2114         fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n");
2115         return;
2116     }
2117     if (ioctl(superdev, VINUM_STARTCONFIG, &force)) {       /* can't get config? */
2118         printf("Can't configure: %s (%d)\n", strerror(errno), errno);
2119         return;
2120     }
2121     if (!objectname)                                        /* we need a name for our object */
2122         genvolname();
2123     for (o = 0; o < argc; o++) {
2124         if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
2125             drive = create_drive(argv[o]);                  /* create it */
2126         if (sflag) {                                        /* striping, */
2127             /* Find the largest chunk available on the drive */
2128             bigchunk = 0;                                   /* ain't found nothin' yet */
2129             for (fe = 0; fe < drive->freelist_entries; fe++) {
2130                 ferq->driveno = drive->driveno;
2131                 ferq->fe = fe;
2132                 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
2133                     fprintf(stderr,
2134                         "Can't get free list element %d: %s\n",
2135                         fe,
2136                         strerror(errno));
2137                     longjmp(command_fail, -1);
2138                 }
2139                 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
2140             }
2141             maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk  */
2142         }
2143     }
2144
2145     /* Now create the volume */
2146     sprintf(buffer, "volume %s setupstate", objectname);
2147     if (vflag)
2148         printf("volume %s setupstate\n", objectname);
2149     ioctl(superdev, VINUM_CREATE, buffer);                  /* create the volume */
2150     if (reply->error != 0) {                                /* error in config */
2151         if (reply->msg[0])
2152             fprintf(stderr,
2153                 "Can't create volume %s: %s\n",
2154                 objectname,
2155                 reply->msg);
2156         else
2157             fprintf(stderr,
2158                 "Can't create volume %s: %s (%d)\n",
2159                 objectname,
2160                 strerror(reply->error),
2161                 reply->error);
2162         longjmp(command_fail, -1);                          /* give up */
2163     }
2164     for (p = 0; p < 2; p++) {                               /* create each plex */
2165         if (sflag) {
2166             sprintf(buffer, "plex name %s.p%d org striped 256k", objectname, p);
2167             if (vflag)
2168                 printf("  plex name %s.p%d org striped 256k\n", objectname, p);
2169         } else {                                            /* concat */
2170             sprintf(buffer, "plex name %s.p%d org concat", objectname, p);
2171             if (vflag)
2172                 printf("  plex name %s.p%d org concat\n", objectname, p);
2173         }
2174         ioctl(superdev, VINUM_CREATE, buffer);
2175         if (reply->error != 0) {                            /* error in config */
2176             if (reply->msg[0])
2177                 fprintf(stderr,
2178                     "Can't create plex %s.p%d: %s\n",
2179                     objectname,
2180                     p,
2181                     reply->msg);
2182             else
2183                 fprintf(stderr,
2184                     "Can't create plex %s.p%d: %s (%d)\n",
2185                     objectname,
2186                     p,
2187                     strerror(reply->error),
2188                     reply->error);
2189             longjmp(command_fail, -1);                      /* give up */
2190         }
2191         /* Now look at the subdisks */
2192         for (o = p; o < argc; o += 2) {                     /* every second one */
2193             drive = find_drive_by_devname(argv[o]);         /* we know it exists... */
2194             sprintf(buffer,
2195                 "sd name %s.p%d.s%d drive %s size %lldb",
2196                 objectname,
2197                 p,
2198                 o >> 1,
2199                 drive->label.name,
2200                 (long long) maxsize[p]);
2201             if (vflag)
2202                 printf("    sd name %s.p%d.s%d drive %s size %lldb\n",
2203                     objectname,
2204                     p,
2205                     o >> 1,
2206                     drive->label.name,
2207                     (long long) maxsize[p]);
2208             ioctl(superdev, VINUM_CREATE, buffer);
2209             if (reply->error != 0) {                        /* error in config */
2210                 if (reply->msg[0])
2211                     fprintf(stderr,
2212                         "Can't create subdisk %s.p%d.s%d: %s\n",
2213                         objectname,
2214                         p,
2215                         o >> 1,
2216                         reply->msg);
2217                 else
2218                     fprintf(stderr,
2219                         "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2220                         objectname,
2221                         p,
2222                         o >> 1,
2223                         strerror(reply->error),
2224                         reply->error);
2225                 longjmp(command_fail, -1);                  /* give up */
2226             }
2227         }
2228     }
2229
2230     /* done, save the config */
2231     ioctltype = 0;                                          /* saveconfig after update */
2232     error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype);  /* save the config to disk */
2233     if (error != 0)
2234         perror("Can't save Vinum config");
2235     find_object(objectname, &type);                         /* find the index of the volume */
2236     make_vol_dev(vol.volno, 1);                             /* and create the devices */
2237     if (vflag) {
2238         vflag--;                                            /* XXX don't give too much detail */
2239         sflag = 0;                                          /* no stats, please */
2240         find_object(objectname, &type);                     /* point to the volume */
2241         vinum_lvi(vol.volno, 1);                            /* and print info about it */
2242     }
2243 }
2244
2245 void
2246 vinum_readpol(int argc, char *argv[], char *argv0[])
2247 {
2248     int object;
2249     struct _ioctl_reply reply;
2250     struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2251     enum objecttype type;
2252     struct plex plex;
2253     struct volume vol;
2254     int plexno;
2255
2256     if (argc == 0) {                                        /* start everything */
2257         fprintf(stderr, "Usage: readpol <volume> <plex>|round\n");
2258         return;
2259     }
2260     object = find_object(argv[1], &type);                   /* look for it */
2261     if (type != volume_object) {
2262         fprintf(stderr, "%s is not a volume\n", argv[1]);
2263         return;
2264     }
2265     get_volume_info(&vol, object);
2266     if (strcmp(argv[2], "round")) {                         /* not 'round' */
2267         object = find_object(argv[2], &type);               /* look for it */
2268         if (type != plex_object) {
2269             fprintf(stderr, "%s is not a plex\n", argv[2]);
2270             return;
2271         }
2272         get_plex_info(&plex, object);
2273         plexno = plex.plexno;
2274     } else                                                  /* round */
2275         plexno = -1;
2276
2277     /* Set the value */
2278     message->index = vol.volno;
2279     message->otherobject = plexno;
2280     if (ioctl(superdev, VINUM_READPOL, message) < 0)
2281         fprintf(stderr, "Can't set read policy: %s (%d)\n", strerror(errno), errno);
2282     if (vflag)
2283         vinum_lpi(plexno, recurse);
2284 }
2285
2286 /*
2287  * Brute force set state function.  Don't look at
2288  * any dependencies, just do it.
2289  */
2290 void
2291 vinum_setstate(int argc, char *argv[], char *argv0[])
2292 {
2293     int object;
2294     struct _ioctl_reply reply;
2295     struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2296     int index;
2297     enum objecttype type;
2298     int state;
2299
2300     for (index = 1; index < argc; index++) {
2301         object = find_object(argv[index], &type);           /* look for it */
2302         if (type == invalid_object)
2303             fprintf(stderr, "Can't find object: %s\n", argv[index]);
2304         else {
2305             int doit = 0;                                   /* set to 1 if we pass our tests */
2306             switch (type) {
2307             case drive_object:
2308                 state = DriveState(argv[0]);                /* get the state */
2309                 if (drive.state == state)                   /* already in that state */
2310                     fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]);
2311                 else
2312                     doit = 1;
2313                 break;
2314
2315             case sd_object:
2316                 state = SdState(argv[0]);                   /* get the state */
2317                 if (sd.state == state)                      /* already in that state */
2318                     fprintf(stderr, "%s is already %s\n", sd.name, argv[0]);
2319                 else
2320                     doit = 1;
2321                 break;
2322
2323             case plex_object:
2324                 state = PlexState(argv[0]);                 /* get the state */
2325                 if (plex.state == state)                    /* already in that state */
2326                     fprintf(stderr, "%s is already %s\n", plex.name, argv[0]);
2327                 else
2328                     doit = 1;
2329                 break;
2330
2331             case volume_object:
2332                 state = VolState(argv[0]);                  /* get the state */
2333                 if (vol.state == state)                     /* already in that state */
2334                     fprintf(stderr, "%s is already %s\n", vol.name, argv[0]);
2335                 else
2336                     doit = 1;
2337                 break;
2338
2339             default:
2340                 state = 0;                                  /* to keep the compiler happy */
2341             }
2342
2343             if (state == -1)
2344                 fprintf(stderr, "Invalid state for object: %s\n", argv[0]);
2345             else if (doit) {
2346                 message->index = object;                    /* pass object number */
2347                 message->type = type;                       /* and type of object */
2348                 message->state = state;
2349                 message->force = force;                     /* don't force it, use a larger hammer */
2350                 ioctl(superdev, VINUM_SETSTATE_FORCE, message);
2351                 if (reply.error != 0)
2352                     fprintf(stderr,
2353                         "Can't start %s: %s (%d)\n",
2354                         argv[index],
2355                         reply.msg[0] ? reply.msg : strerror(reply.error),
2356                         reply.error);
2357                 if (Verbose)
2358                     vinum_li(object, type);
2359             }
2360         }
2361     }
2362 }
2363
2364 void
2365 vinum_checkparity(int argc, char *argv[], char *argv0[])
2366 {
2367     Verbose = vflag;                                        /* accept -v for verbose */
2368     if (argc == 0)                                          /* no parameters? */
2369         fprintf(stderr, "Usage: checkparity object [object...]\n");
2370     else
2371         parityops(argc, argv, checkparity);
2372 }
2373
2374 void
2375 vinum_rebuildparity(int argc, char *argv[], char *argv0[])
2376 {
2377     if (argc == 0)                                          /* no parameters? */
2378         fprintf(stderr, "Usage: rebuildparity object [object...]\n");
2379     else
2380         parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity);
2381 }
2382
2383 /*
2384  * Common code for rebuildparity and checkparity.
2385  * We bend the meanings of some flags here:
2386  *
2387  * -v: Report incorrect parity on rebuild.
2388  * -V: Show running count of position being checked.
2389  * -f: Start from beginning of the plex.
2390  */
2391 void
2392 parityops(int argc, char *argv[], enum parityop op)
2393 {
2394     int object;
2395     struct plex plex;
2396     struct _ioctl_reply reply;
2397     struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2398     int index;
2399     enum objecttype type;
2400     char *msg;
2401     off_t block;
2402
2403     if (op == checkparity)
2404         msg = "Checking";
2405     else
2406         msg = "Rebuilding";
2407     for (index = 0; index < argc; index++) {
2408         object = find_object(argv[index], &type);           /* look for it */
2409         if (type != plex_object)
2410             fprintf(stderr, "%s is not a plex\n", argv[index]);
2411         else {
2412             get_plex_info(&plex, object);
2413             if (!isparity((&plex)))
2414                 fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]);
2415             else {
2416                 do {
2417                     message->index = object;                /* pass object number */
2418                     message->type = type;                   /* and type of object */
2419                     message->op = op;                       /* what to do */
2420                     if (force)
2421                         message->offset = 0;                /* start at the beginning */
2422                     else
2423                         message->offset = plex.checkblock;  /* continue where we left off */
2424                     force = 0;                              /* don't reset after the first time */
2425                     ioctl(superdev, VINUM_PARITYOP, message);
2426                     get_plex_info(&plex, object);
2427                     if (Verbose) {
2428                         block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1);
2429                         if (block != 0)
2430                             printf("\r%s at %s (%d%%)    ",
2431                                 msg,
2432                                 roughlength(block, 1),
2433                                 ((int) (block * 100 / plex.length) >> DEV_BSHIFT));
2434                         if ((reply.error == EAGAIN)
2435                             && (reply.msg[0]))              /* got a comment back */
2436                             fputs(reply.msg, stderr);       /* show it */
2437                         fflush(stdout);
2438                     }
2439                 }
2440                 while (reply.error == EAGAIN);
2441                 if (reply.error != 0) {
2442                     if (reply.msg[0])
2443                         fputs(reply.msg, stderr);
2444                     else
2445                         fprintf(stderr,
2446                             "%s failed: %s\n",
2447                             msg,
2448                             strerror(reply.error));
2449                 } else if (Verbose) {
2450                     if (op == checkparity)
2451                         fprintf(stderr, "%s has correct parity\n", argv[index]);
2452                     else
2453                         fprintf(stderr, "Rebuilt parity on %s\n", argv[index]);
2454                 }
2455             }
2456         }
2457     }
2458 }
2459
2460 /* Local Variables: */
2461 /* fill-column: 50 */
2462 /* End: */