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