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