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