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