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