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