Do some fairly major include file cleanups to further separate kernelland
[dragonfly.git] / sbin / vinum / commands.c
CommitLineData
984263bc
MD
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 $
05220613 41 * $DragonFly: src/sbin/vinum/commands.c,v 1.4 2003/11/21 22:46:13 dillon Exp $
984263bc
MD
42 */
43
05220613
MD
44#define _KERNEL_STRUCTURES
45
984263bc
MD
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>
38a690d7
MD
59#include <dev/raid/vinum/vinumhdr.h>
60#include <dev/raid/vinum/request.h>
984263bc
MD
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
70static void dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen);
71
72void
73vinum_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 */
170void
171vinum_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
209void
210vinum_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
225void
226vinum_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
232void
233vinum_set(int argc, char *argv[], char *arg0[])
234{
235 fprintf(stderr, "set is not implemented yet\n");
236}
237
238void
239vinum_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
275void
276vinum_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 */
309void
310vinum_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
347void
348initvol(int volno)
349{
350 printf("Initializing volumes is not implemented yet\n");
351}
352
353void
354initplex(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. */
423void
424initsd(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
515void
516vinum_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 }
662
663 if (doit) {
664 message->index = object; /* pass object number */
665 message->type = type; /* and type of object */
666 message->state = object_up;
667 message->force = force; /* don't force it, use a larger hammer */
668
669 /*
670 * We don't do any checking here.
671 * The kernel module has a better
672 * understanding of these things,
673 * let it do it.
674 */
675 if (SSize != 0) { /* specified a size for init or revive */
676 if (SSize < 512)
677 SSize <<= DEV_BSHIFT;
678 message->blocksize = SSize;
679 } else
680 message->blocksize = 0;
681 ioctl(superdev, VINUM_SETSTATE, message);
682 if (reply.error != 0) {
683 if ((reply.error == EAGAIN) /* we're reviving */
684 &&(type == sd_object))
685 continue_revive(object);
686 else
687 fprintf(stderr,
688 "Can't start %s: %s (%d)\n",
689 argv[index],
690 reply.msg[0] ? reply.msg : strerror(reply.error),
691 reply.error);
692 }
693 if (Verbose)
694 vinum_li(object, type);
695 }
696 }
697 }
698 }
699 checkupdates(); /* make sure we're updating */
700}
701
702void
703vinum_stop(int argc, char *argv[], char *arg0[])
704{
705 int object;
706 struct _ioctl_reply reply;
707 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
708
709 if (checkupdates() && (!force)) /* not updating? */
710 return;
711 message->force = force; /* should we force the transition? */
712 if (argc == 0) { /* stop vinum */
713 int fileid = 0; /* ID of Vinum kld */
714
715 close(superdev); /* we can't stop if we have vinum open */
716 sleep(1); /* wait for the daemon to let go */
717 fileid = kldfind(VINUMMOD);
718 if ((fileid < 0) /* no go */
719 ||(kldunload(fileid) < 0))
720 perror("Can't unload " VINUMMOD);
721 else {
722 fprintf(stderr, VINUMMOD " unloaded\n");
723 exit(0);
724 }
725
726 /* If we got here, the stop failed. Reopen the superdevice. */
727 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */
728 if (superdev < 0) {
729 perror("Can't reopen Vinum superdevice");
730 exit(1);
731 }
732 } else { /* stop specified objects */
733 int i;
734 enum objecttype type;
735
736 for (i = 0; i < argc; i++) {
737 object = find_object(argv[i], &type); /* look for it */
738 if (type == invalid_object)
739 fprintf(stderr, "Can't find object: %s\n", argv[i]);
740 else {
741 message->index = object; /* pass object number */
742 message->type = type; /* and type of object */
743 message->state = object_down;
744 ioctl(superdev, VINUM_SETSTATE, message);
745 if (reply.error != 0)
746 fprintf(stderr,
747 "Can't stop %s: %s (%d)\n",
748 argv[i],
749 reply.msg[0] ? reply.msg : strerror(reply.error),
750 reply.error);
751 if (Verbose)
752 vinum_li(object, type);
753 }
754 }
755 }
756}
757
758void
759vinum_label(int argc, char *argv[], char *arg0[])
760{
761 int object;
762 struct _ioctl_reply reply;
763 int *message = (int *) &reply;
764
765 if (argc == 0) /* start everything */
766 fprintf(stderr, "label: please specify one or more volume names\n");
767 else { /* start specified objects */
768 int i;
769 enum objecttype type;
770
771 for (i = 0; i < argc; i++) {
772 object = find_object(argv[i], &type); /* look for it */
773 if (type == invalid_object)
774 fprintf(stderr, "Can't find object: %s\n", argv[i]);
775 else if (type != volume_object) /* it exists, but it isn't a volume */
776 fprintf(stderr, "%s is not a volume\n", argv[i]);
777 else {
778 message[0] = object; /* pass object number */
779 ioctl(superdev, VINUM_LABEL, message);
780 if (reply.error != 0)
781 fprintf(stderr,
782 "Can't label %s: %s (%d)\n",
783 argv[i],
784 reply.msg[0] ? reply.msg : strerror(reply.error),
785 reply.error);
786 if (Verbose)
787 vinum_li(object, type);
788 }
789 }
790 }
791 checkupdates(); /* not updating? */
792}
793
794void
795reset_volume_stats(int volno, int recurse)
796{
797 struct vinum_ioctl_msg msg;
798 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
799
800 msg.index = volno;
801 msg.type = volume_object;
802 /* XXX get these numbers right if we ever
803 * actually return errors */
804 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
805 fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg);
806 longjmp(command_fail, -1);
807 } else if (recurse) {
808 struct volume vol;
809 int plexno;
810
811 get_volume_info(&vol, volno);
812 for (plexno = 0; plexno < vol.plexes; plexno++)
813 reset_plex_stats(vol.plex[plexno], recurse);
814 }
815}
816
817void
818reset_plex_stats(int plexno, int recurse)
819{
820 struct vinum_ioctl_msg msg;
821 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
822
823 msg.index = plexno;
824 msg.type = plex_object;
825 /* XXX get these numbers right if we ever
826 * actually return errors */
827 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
828 fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg);
829 longjmp(command_fail, -1);
830 } else if (recurse) {
831 struct plex plex;
832 struct sd sd;
833 int sdno;
834
835 get_plex_info(&plex, plexno);
836 for (sdno = 0; sdno < plex.subdisks; sdno++) {
837 get_plex_sd_info(&sd, plex.plexno, sdno);
838 reset_sd_stats(sd.sdno, recurse);
839 }
840 }
841}
842
843void
844reset_sd_stats(int sdno, int recurse)
845{
846 struct vinum_ioctl_msg msg;
847 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
848
849 msg.index = sdno;
850 msg.type = sd_object;
851 /* XXX get these numbers right if we ever
852 * actually return errors */
853 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
854 fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg);
855 longjmp(command_fail, -1);
856 } else if (recurse) {
857 get_sd_info(&sd, sdno); /* get the info */
858 reset_drive_stats(sd.driveno); /* and clear the drive */
859 }
860}
861
862void
863reset_drive_stats(int driveno)
864{
865 struct vinum_ioctl_msg msg;
866 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
867
868 msg.index = driveno;
869 msg.type = drive_object;
870 /* XXX get these numbers right if we ever
871 * actually return errors */
872 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) {
873 fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg);
874 longjmp(command_fail, -1);
875 }
876}
877
878void
879vinum_resetstats(int argc, char *argv[], char *argv0[])
880{
881 int i;
882 int objno;
883 enum objecttype type;
884
885 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
886 perror("Can't get vinum config");
887 return;
888 }
889 if (argc == 0) {
890 for (objno = 0; objno < vinum_conf.volumes_allocated; objno++)
891 reset_volume_stats(objno, 1); /* clear everything recursively */
892 } else {
893 for (i = 0; i < argc; i++) {
894 objno = find_object(argv[i], &type);
895 if (objno >= 0) { /* not invalid */
896 switch (type) {
897 case drive_object:
898 reset_drive_stats(objno);
899 break;
900
901 case sd_object:
902 reset_sd_stats(objno, recurse);
903 break;
904
905 case plex_object:
906 reset_plex_stats(objno, recurse);
907 break;
908
909 case volume_object:
910 reset_volume_stats(objno, recurse);
911 break;
912
913 case invalid_object: /* can't get this */
914 break;
915 }
916 }
917 }
918 }
919}
920
921/* Attach a subdisk to a plex, or a plex to a volume.
922 * attach subdisk plex [offset] [rename]
923 * attach plex volume [rename]
924 */
925void
926vinum_attach(int argc, char *argv[], char *argv0[])
927{
928 int i;
929 enum objecttype supertype;
930 struct vinum_ioctl_msg msg;
931 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
932 const char *objname = argv[0];
933 const char *supername = argv[1];
934 int sdno = -1;
935 int plexno = -1;
936 char oldname[MAXNAME + 8];
937 char newname[MAXNAME + 8];
938 int rename = 0; /* set if we want to rename the object */
939
940 if ((argc < 2)
941 || (argc > 4)) {
942 fprintf(stderr,
943 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n"
944 "\tattach <plex> <volume> [rename]\n");
945 return;
946 }
947 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
948 perror("Can't get vinum config");
949 return;
950 }
951 msg.index = find_object(objname, &msg.type); /* find the object to attach */
952 msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */
953 msg.force = force; /* did we specify the use of force? */
954 msg.recurse = recurse;
955 msg.offset = -1; /* and no offset */
956
957 for (i = 2; i < argc; i++) {
958 if (!strcmp(argv[i], "rename")) {
959 rename = 1;
960 msg.rename = 1; /* do renaming */
961 } else if (!isdigit(argv[i][0])) { /* not an offset */
962 fprintf(stderr, "Unknown attribute: %s\n", supername);
963 return;
964 } else
965 msg.offset = sizespec(argv[i]);
966 }
967
968 switch (msg.type) {
969 case sd_object:
970 find_object(argv[1], &supertype);
971 if (supertype != plex_object) { /* huh? */
972 fprintf(stderr, "%s can only be attached to a plex\n", objname);
973 return;
974 }
975 if ((plex.organization != plex_concat) /* not a cat plex, */
976 &&(!force)) {
977 fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization));
978 return;
979 }
980 sdno = msg.index; /* note the subdisk number for later */
981 break;
982
983 case plex_object:
984 find_object(argv[1], &supertype);
985 if (supertype != volume_object) { /* huh? */
986 fprintf(stderr, "%s can only be attached to a volume\n", objname);
987 return;
988 }
989 break;
990
991 case volume_object:
992 case drive_object:
993 fprintf(stderr, "Can only attach subdisks and plexes\n");
994 return;
995
996 default:
997 fprintf(stderr, "%s is not a Vinum object\n", objname);
998 return;
999 }
1000
1001 ioctl(superdev, VINUM_ATTACH, &msg);
1002 if (reply->error != 0) {
1003 if (reply->error == EAGAIN) /* reviving */
1004 continue_revive(sdno); /* continue the revive */
1005 else
1006 fprintf(stderr,
1007 "Can't attach %s to %s: %s (%d)\n",
1008 objname,
1009 supername,
1010 reply->msg[0] ? reply->msg : strerror(reply->error),
1011 reply->error);
1012 }
1013 if (rename) {
1014 struct sd;
1015 struct plex;
1016 struct volume;
1017
1018 /* we've overwritten msg with the
1019 * ioctl reply, start again */
1020 msg.index = find_object(objname, &msg.type); /* find the object to rename */
1021 switch (msg.type) {
1022 case sd_object:
1023 get_sd_info(&sd, msg.index);
1024 get_plex_info(&plex, sd.plexno);
1025 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1026 if (plex.sdnos[sdno] == msg.index) /* found our subdisk */
1027 break;
1028 }
1029 sprintf(newname, "%s.s%d", plex.name, sdno);
1030 sprintf(oldname, "%s", sd.name);
1031 vinum_rename_2(oldname, newname);
1032 break;
1033
1034 case plex_object:
1035 get_plex_info(&plex, msg.index);
1036 get_volume_info(&vol, plex.volno);
1037 for (plexno = 0; plexno < vol.plexes; plexno++) {
1038 if (vol.plex[plexno] == msg.index) /* found our subdisk */
1039 break;
1040 }
1041 sprintf(newname, "%s.p%d", vol.name, plexno);
1042 sprintf(oldname, "%s", plex.name);
1043 vinum_rename_2(oldname, newname); /* this may recurse */
1044 break;
1045
1046 default: /* can't get here */
1047 }
1048 }
1049 checkupdates(); /* make sure we're updating */
1050}
1051
1052/* Detach a subdisk from a plex, or a plex from a volume.
1053 * detach subdisk plex [rename]
1054 * detach plex volume [rename]
1055 */
1056void
1057vinum_detach(int argc, char *argv[], char *argv0[])
1058{
1059 struct vinum_ioctl_msg msg;
1060 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg;
1061
1062 if ((argc < 1)
1063 || (argc > 2)) {
1064 fprintf(stderr,
1065 "Usage: \tdetach <subdisk> [rename]\n"
1066 "\tdetach <plex> [rename]\n");
1067 return;
1068 }
1069 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1070 perror("Can't get vinum config");
1071 return;
1072 }
1073 msg.index = find_object(argv[0], &msg.type); /* find the object to detach */
1074 msg.force = force; /* did we specify the use of force? */
1075 msg.rename = 0; /* don't specify new name */
1076 msg.recurse = recurse; /* but recurse if we have to */
1077
1078 /* XXX are we going to keep this?
1079 * Don't document it yet, since the
1080 * kernel side of things doesn't
1081 * implement it */
1082 if (argc == 2) {
1083 if (!strcmp(argv[1], "rename"))
1084 msg.rename = 1; /* do renaming */
1085 else {
1086 fprintf(stderr, "Unknown attribute: %s\n", argv[1]);
1087 return;
1088 }
1089 }
1090 if ((msg.type != sd_object)
1091 && (msg.type != plex_object)) {
1092 fprintf(stderr, "Can only detach subdisks and plexes\n");
1093 return;
1094 }
1095 ioctl(superdev, VINUM_DETACH, &msg);
1096 if (reply->error != 0)
1097 fprintf(stderr,
1098 "Can't detach %s: %s (%d)\n",
1099 argv[0],
1100 reply->msg[0] ? reply->msg : strerror(reply->error),
1101 reply->error);
1102 checkupdates(); /* make sure we're updating */
1103}
1104
1105static void
1106dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen)
1107{
1108 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
1109
1110 if (strlen(name) > maxlen) {
1111 fprintf(stderr, "%s is too long\n", name);
1112 return;
1113 }
1114 strcpy(msg->newname, name);
1115 ioctl(superdev, VINUM_RENAME, msg);
1116 if (reply->error != 0)
1117 fprintf(stderr,
1118 "Can't rename %s to %s: %s (%d)\n",
1119 oldname,
1120 name,
1121 reply->msg[0] ? reply->msg : strerror(reply->error),
1122 reply->error);
1123}
1124
1125/* Rename an object:
1126 * rename <object> "newname"
1127 */
1128void
1129vinum_rename_2(char *oldname, char *newname)
1130{
1131 struct vinum_rename_msg msg;
1132 int volno;
1133 int plexno;
1134
1135 msg.index = find_object(oldname, &msg.type); /* find the object to rename */
1136 msg.recurse = recurse;
1137
1138 /* Ugh. Determine how long the name may be */
1139 switch (msg.type) {
1140 case drive_object:
1141 dorename(&msg, oldname, newname, MAXDRIVENAME);
1142 break;
1143
1144 case sd_object:
1145 dorename(&msg, oldname, newname, MAXSDNAME);
1146 break;
1147
1148 case plex_object:
1149 plexno = msg.index;
1150 dorename(&msg, oldname, newname, MAXPLEXNAME);
1151 if (recurse) {
1152 int sdno;
1153
1154 get_plex_info(&plex, plexno); /* find out who we are */
1155 msg.type = sd_object;
1156 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1157 char sdname[MAXPLEXNAME + 8];
1158
1159 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1160 sprintf(sdname, "%s.s%d", newname, sdno);
1161 msg.index = sd.sdno; /* number of the subdisk */
1162 dorename(&msg, sd.name, sdname, MAXSDNAME);
1163 }
1164 }
1165 break;
1166
1167 case volume_object:
1168 volno = msg.index;
1169 dorename(&msg, oldname, newname, MAXVOLNAME);
1170 if (recurse) {
1171 int sdno;
1172 int plexno;
1173
1174 get_volume_info(&vol, volno); /* find out who we are */
1175 for (plexno = 0; plexno < vol.plexes; plexno++) {
1176 char plexname[MAXVOLNAME + 8];
1177
1178 msg.type = plex_object;
1179 sprintf(plexname, "%s.p%d", newname, plexno);
1180 msg.index = vol.plex[plexno]; /* number of the plex */
1181 dorename(&msg, plex.name, plexname, MAXPLEXNAME);
1182 get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */
1183 msg.type = sd_object;
1184 for (sdno = 0; sdno < plex.subdisks; sdno++) {
1185 char sdname[MAXPLEXNAME + 8];
1186
1187 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */
1188 sprintf(sdname, "%s.s%d", plexname, sdno);
1189 msg.index = sd.sdno; /* number of the subdisk */
1190 dorename(&msg, sd.name, sdname, MAXSDNAME);
1191 }
1192 }
1193 }
1194 break;
1195
1196 default:
1197 fprintf(stderr, "%s is not a Vinum object\n", oldname);
1198 return;
1199 }
1200}
1201
1202void
1203vinum_rename(int argc, char *argv[], char *argv0[])
1204{
1205 if (argc != 2) {
1206 fprintf(stderr, "Usage: \trename <object> <new name>\n");
1207 return;
1208 }
1209 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1210 perror("Can't get vinum config");
1211 return;
1212 }
1213 vinum_rename_2(argv[0], argv[1]);
1214 checkupdates(); /* make sure we're updating */
1215}
1216
1217/*
1218 * Move objects:
1219 *
1220 * mv <dest> <src> ...
1221 */
1222void
1223vinum_mv(int argc, char *argv[], char *argv0[])
1224{
1225 int i; /* loop index */
1226 int srcobj;
1227 int destobj;
1228 enum objecttype srct;
1229 enum objecttype destt;
1230 int sdno;
1231 struct _ioctl_reply reply;
1232 struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply;
1233
1234 if (argc < 2) {
1235 fprintf(stderr, "Usage: \tmove <dest> <src> ...\n");
1236 return;
1237 }
1238 /* Get current config */
1239 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
1240 perror("Cannot get vinum config\n");
1241 return;
1242 }
1243 /* Get our destination */
1244 destobj = find_object(argv[0], &destt);
1245 if (destobj == -1) {
1246 fprintf(stderr, "Can't find %s\n", argv[0]);
1247 return;
1248 }
1249 /* Verify that the target is a drive */
1250 if (destt != drive_object) {
1251 fprintf(stderr, "%s is not a drive\n", argv[0]);
1252 return;
1253 }
1254 for (i = 1; i < argc; i++) { /* for all the sources */
1255 srcobj = find_object(argv[i], &srct);
1256 if (srcobj == -1) {
1257 fprintf(stderr, "Can't find %s\n", argv[i]);
1258 continue;
1259 }
1260 msg->index = destobj;
1261 switch (srct) { /* Handle the source object */
1262 case drive_object: /* Move all subdisks on the drive to dst. */
1263 get_drive_info(&drive, srcobj); /* get info on drive */
1264 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) {
1265 get_sd_info(&sd, sdno);
1266 if (sd.driveno == srcobj) {
1267 msg->index = destobj;
1268 msg->otherobject = sd.sdno;
1269 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1270 fprintf(stderr,
1271 "Can't move %s (part of %s) to %s: %s (%d)\n",
1272 sd.name,
1273 drive.label.name,
1274 argv[0],
1275 strerror(reply.error),
1276 reply.error);
1277 }
1278 }
1279 break;
1280
1281 case sd_object:
1282 msg->otherobject = srcobj;
1283 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1284 fprintf(stderr,
1285 "Can't move %s to %s: %s (%d)\n",
1286 sd.name,
1287 argv[0],
1288 strerror(reply.error),
1289 reply.error);
1290 break;
1291
1292 case plex_object:
1293 get_plex_info(&plex, srcobj);
1294 for (sdno = 0; sdno < plex.subdisks; ++sdno) {
1295 get_plex_sd_info(&sd, plex.plexno, sdno);
1296 msg->index = destobj;
1297 msg->otherobject = sd.sdno;
1298 if (ioctl(superdev, VINUM_MOVE, msg) < 0)
1299 fprintf(stderr,
1300 "Can't move %s (part of %s) to %s: %s (%d)\n",
1301 sd.name,
1302 plex.name,
1303 argv[0],
1304 strerror(reply.error),
1305 reply.error);
1306 }
1307 break;
1308
1309 case volume_object:
1310 case invalid_object:
1311 default:
1312 fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]);
1313 break;
1314 }
1315 if (reply.error)
1316 fprintf(stderr,
1317 "Can't move %s to %s: %s (%d)\n",
1318 argv[i],
1319 argv[0],
1320 strerror(reply.error),
1321 reply.error);
1322 }
1323 checkupdates(); /* make sure we're updating */
1324}
1325
1326/*
1327 * Replace objects. Not implemented, may never be.
1328 */
1329void
1330vinum_replace(int argc, char *argv[], char *argv0[])
1331{
1332 fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n");
1333}
1334
1335/* Primitive help function */
1336void
1337vinum_help(int argc, char *argv[], char *argv0[])
1338{
1339 char commands[] =
1340 {
1341 "COMMANDS\n"
1342 "create [-f description-file]\n"
1343 " Create a volume as described in description-file\n"
1344 "attach plex volume [rename]\n"
1345 "attach subdisk plex [offset] [rename]\n"
1346 " Attach a plex to a volume, or a subdisk to a plex.\n"
1347 "debug\n"
1348 " Cause the volume manager to enter the kernel debugger.\n"
1349 "debug flags\n"
1350 " Set debugging flags.\n"
1351 "detach [plex | subdisk]\n"
1352 " Detach a plex or subdisk from the volume or plex to which it is\n"
1353 " attached.\n"
1354 "info [-v]\n"
1355 " List information about volume manager state.\n"
1356 "init [-v] [-w] plex\n"
1357 " Initialize a plex by writing zeroes to all its subdisks.\n"
1358 "label volume\n"
1359 " Create a volume label\n"
1360 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1361 " List information about specified objects\n"
1362 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n"
1363 " List information about specified objects (alternative to\n"
1364 " list command)\n"
1365 "ld [-r] [-s] [-v] [-V] [volume]\n"
1366 " List information about drives\n"
1367 "ls [-r] [-s] [-v] [-V] [subdisk]\n"
1368 " List information about subdisks\n"
1369 "lp [-r] [-s] [-v] [-V] [plex]\n"
1370 " List information about plexes\n"
1371 "lv [-r] [-s] [-v] [-V] [volume]\n"
1372 " List information about volumes\n"
1373 "printconfig [file]\n"
1374 " Write a copy of the current configuration to file.\n"
1375 "makedev\n"
1376 " Remake the device nodes in " _PATH_DEV "vinum.\n"
1377 "move drive [subdisk | plex | drive]\n"
1378 " Move the subdisks of the specified object(s) to drive.\n"
1379 "quit\n"
1380 " Exit the vinum program when running in interactive mode. Nor-\n"
1381 " mally this would be done by entering the EOF character.\n"
1382 "read disk [disk...]\n"
1383 " Read the vinum configuration from the specified disks.\n"
1384 "rename [-r] [drive | subdisk | plex | volume] newname\n"
1385 " Change the name of the specified object.\n"
1386 "resetconfig\n"
1387 " Reset the complete vinum configuration.\n"
1388 "resetstats [-r] [volume | plex | subdisk]\n"
1389 " Reset statistisc counters for the specified objects, or for all\n"
1390 " objects if none are specified.\n"
1391 "rm [-f] [-r] volume | plex | subdisk\n"
1392 " Remove an object\n"
1393 "saveconfig\n"
1394 " Save vinum configuration to disk.\n"
1395 "setdaemon [value]\n"
1396 " Set daemon configuration.\n"
1397 "start\n"
1398 " Read configuration from all vinum drives.\n"
1399 "start [volume | plex | subdisk]\n"
1400 " Allow the system to access the objects\n"
1401 "stop [-f] [volume | plex | subdisk]\n"
1402 " Terminate access to the objects, or stop vinum if no parameters\n"
1403 " are specified.\n"
1404 };
1405 puts(commands);
1406}
1407
1408/* Set daemon options.
1409 * XXX quick and dirty: use a bitmap, which requires
1410 * knowing which bit does what. FIXME */
1411void
1412vinum_setdaemon(int argc, char *argv[], char *argv0[])
1413{
1414 int options;
1415
1416 switch (argc) {
1417 case 0:
1418 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1419 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1420 else
1421 printf("Options mask: %d\n", options);
1422 break;
1423
1424 case 1:
1425 options = atoi(argv[0]);
1426 if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0)
1427 fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno);
1428 break;
1429
1430 default:
1431 fprintf(stderr, "Usage: \tsetdaemon [<bitmask>]\n");
1432 }
1433 checkupdates(); /* make sure we're updating */
1434}
1435
1436int
1437checkupdates()
1438{
1439 int options;
1440
1441 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0)
1442 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno);
1443 if (options & daemon_noupdate) {
1444 fprintf(stderr, "*** Warning: configuration updates are disabled. ***\n");
1445 return 1;
1446 } else
1447 return 0;
1448}
1449
1450/* Save config info */
1451void
1452vinum_saveconfig(int argc, char *argv[], char *argv0[])
1453{
1454 int ioctltype;
1455
1456 if (argc != 0) {
1457 printf("Usage: saveconfig\n");
1458 return;
1459 }
1460 ioctltype = 1; /* user saveconfig */
1461 if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0)
1462 fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno);
1463 checkupdates(); /* make sure we're updating */
1464}
1465
1466/*
1467 * Create a volume name for the quick and dirty
1468 * commands. It will be of the form "vinum#",
1469 * where # is a small positive number.
1470 */
1471void
1472genvolname()
1473{
1474 int v; /* volume number */
1475 static char volumename[MAXVOLNAME]; /* name to create */
1476 enum objecttype type;
1477
1478 objectname = volumename; /* point to it */
1479 for (v = 0;; v++) {
1480 sprintf(objectname, "vinum%d", v); /* create the name */
1481 if (find_object(objectname, &type) == -1) /* does it exist? */
1482 return; /* no, it's ours */
1483 }
1484}
1485
1486/*
1487 * Create a drive for the quick and dirty
1488 * commands. The name will be of the form
1489 * vinumdrive#, where # is a small positive
1490 * number. Return the name of the drive.
1491 */
1492struct drive *
1493create_drive(char *devicename)
1494{
1495 int d; /* volume number */
1496 static char drivename[MAXDRIVENAME]; /* name to create */
1497 enum objecttype type;
1498 struct _ioctl_reply *reply;
1499
1500 /*
1501 * We're never likely to get anything
1502 * like 10000 drives. The only reason for
1503 * this limit is to stop the thing
1504 * looping if we have a bug somewhere.
1505 */
1506 for (d = 0; d < 100000; d++) { /* look for a free drive number */
1507 sprintf(drivename, "vinumdrive%d", d); /* create the name */
1508 if (find_object(drivename, &type) == -1) { /* does it exist? */
1509 char command[MAXDRIVENAME * 2];
1510
1511 sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */
1512 if (vflag)
1513 printf("drive %s device %s\n", drivename, devicename); /* create a create command */
1514 ioctl(superdev, VINUM_CREATE, command);
1515 reply = (struct _ioctl_reply *) &command;
1516 if (reply->error != 0) { /* error in config */
1517 if (reply->msg[0])
1518 fprintf(stderr,
1519 "Can't create drive %s, device %s: %s\n",
1520 drivename,
1521 devicename,
1522 reply->msg);
1523 else
1524 fprintf(stderr,
1525 "Can't create drive %s, device %s: %s (%d)\n",
1526 drivename,
1527 devicename,
1528 strerror(reply->error),
1529 reply->error);
1530 longjmp(command_fail, -1); /* give up */
1531 }
1532 find_object(drivename, &type);
1533 return &drive; /* return the name of the drive */
1534 }
1535 }
1536 fprintf(stderr, "Can't generate a drive name\n");
1537 /* NOTREACHED */
1538 return NULL;
1539}
1540
1541/*
1542 * Create a volume with a single concatenated plex from
1543 * as much space as we can get on the specified drives.
1544 * If the drives aren't Vinum drives, make them so.
1545 */
1546void
1547vinum_concat(int argc, char *argv[], char *argv0[])
1548{
1549 int o; /* object number */
1550 char buffer[BUFSIZE];
1551 struct drive *drive; /* drive we're currently looking at */
1552 struct _ioctl_reply *reply;
1553 int ioctltype;
1554 int error;
1555 enum objecttype type;
1556
1557 reply = (struct _ioctl_reply *) &buffer;
1558 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1559 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1560 return;
1561 }
1562 if (!objectname) /* we need a name for our object */
1563 genvolname();
1564 sprintf(buffer, "volume %s", objectname);
1565 if (vflag)
1566 printf("volume %s\n", objectname);
1567 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1568 if (reply->error != 0) { /* error in config */
1569 if (reply->msg[0])
1570 fprintf(stderr,
1571 "Can't create volume %s: %s\n",
1572 objectname,
1573 reply->msg);
1574 else
1575 fprintf(stderr,
1576 "Can't create volume %s: %s (%d)\n",
1577 objectname,
1578 strerror(reply->error),
1579 reply->error);
1580 longjmp(command_fail, -1); /* give up */
1581 }
1582 sprintf(buffer, "plex name %s.p0 org concat", objectname);
1583 if (vflag)
1584 printf(" plex name %s.p0 org concat\n", objectname);
1585 ioctl(superdev, VINUM_CREATE, buffer);
1586 if (reply->error != 0) { /* error in config */
1587 if (reply->msg[0])
1588 fprintf(stderr,
1589 "Can't create plex %s.p0: %s\n",
1590 objectname,
1591 reply->msg);
1592 else
1593 fprintf(stderr,
1594 "Can't create plex %s.p0: %s (%d)\n",
1595 objectname,
1596 strerror(reply->error),
1597 reply->error);
1598 longjmp(command_fail, -1); /* give up */
1599 }
1600 for (o = 0; o < argc; o++) {
1601 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1602 drive = create_drive(argv[o]); /* create it */
1603 sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name);
1604 if (vflag)
1605 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name);
1606 ioctl(superdev, VINUM_CREATE, buffer);
1607 if (reply->error != 0) { /* error in config */
1608 if (reply->msg[0])
1609 fprintf(stderr,
1610 "Can't create subdisk %s.p0.s%d: %s\n",
1611 objectname,
1612 o,
1613 reply->msg);
1614 else
1615 fprintf(stderr,
1616 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1617 objectname,
1618 o,
1619 strerror(reply->error),
1620 reply->error);
1621 longjmp(command_fail, -1); /* give up */
1622 }
1623 }
1624
1625 /* done, save the config */
1626 ioctltype = 0; /* saveconfig after update */
1627 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1628 if (error != 0)
1629 perror("Can't save Vinum config");
1630 find_object(objectname, &type); /* find the index of the volume */
1631 make_vol_dev(vol.volno, 1); /* and create the devices */
1632 if (vflag) {
1633 vflag--; /* XXX don't give too much detail */
1634 find_object(objectname, &type); /* point to the volume */
1635 vinum_lvi(vol.volno, 1); /* and print info about it */
1636 }
1637}
1638
1639
1640/*
1641 * Create a volume with a single striped plex from
1642 * as much space as we can get on the specified drives.
1643 * If the drives aren't Vinum drives, make them so.
1644 */
1645void
1646vinum_stripe(int argc, char *argv[], char *argv0[])
1647{
1648 int o; /* object number */
1649 char buffer[BUFSIZE];
1650 struct drive *drive; /* drive we're currently looking at */
1651 struct _ioctl_reply *reply;
1652 int ioctltype;
1653 int error;
1654 enum objecttype type;
1655 off_t maxsize;
1656 int fe; /* freelist entry index */
1657 struct drive_freelist freelist;
1658 struct ferq { /* request to pass to ioctl */
1659 int driveno;
1660 int fe;
1661 } *ferq = (struct ferq *) &freelist;
1662 u_int64_t bigchunk; /* biggest chunk in freelist */
1663
1664 maxsize = QUAD_MAX;
1665 reply = (struct _ioctl_reply *) &buffer;
1666
1667 /*
1668 * First, check our drives.
1669 */
1670 if (argc < 2) {
1671 fprintf(stderr, "You need at least two drives to create a striped plex\n");
1672 return;
1673 }
1674 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1675 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1676 return;
1677 }
1678 if (!objectname) /* we need a name for our object */
1679 genvolname();
1680 for (o = 0; o < argc; o++) {
1681 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1682 drive = create_drive(argv[o]); /* create it */
1683 /* Now find the largest chunk available on the drive */
1684 bigchunk = 0; /* ain't found nothin' yet */
1685 for (fe = 0; fe < drive->freelist_entries; fe++) {
1686 ferq->driveno = drive->driveno;
1687 ferq->fe = fe;
1688 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1689 fprintf(stderr,
1690 "Can't get free list element %d: %s\n",
1691 fe,
1692 strerror(errno));
1693 longjmp(command_fail, -1);
1694 }
1695 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1696 }
1697 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1698 }
1699
1700 /* Now create the volume */
1701 sprintf(buffer, "volume %s", objectname);
1702 if (vflag)
1703 printf("volume %s\n", objectname);
1704 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1705 if (reply->error != 0) { /* error in config */
1706 if (reply->msg[0])
1707 fprintf(stderr,
1708 "Can't create volume %s: %s\n",
1709 objectname,
1710 reply->msg);
1711 else
1712 fprintf(stderr,
1713 "Can't create volume %s: %s (%d)\n",
1714 objectname,
1715 strerror(reply->error),
1716 reply->error);
1717 longjmp(command_fail, -1); /* give up */
1718 }
1719 sprintf(buffer, "plex name %s.p0 org striped 256k", objectname);
1720 if (vflag)
1721 printf(" plex name %s.p0 org striped 256k\n", objectname);
1722 ioctl(superdev, VINUM_CREATE, buffer);
1723 if (reply->error != 0) { /* error in config */
1724 if (reply->msg[0])
1725 fprintf(stderr,
1726 "Can't create plex %s.p0: %s\n",
1727 objectname,
1728 reply->msg);
1729 else
1730 fprintf(stderr,
1731 "Can't create plex %s.p0: %s (%d)\n",
1732 objectname,
1733 strerror(reply->error),
1734 reply->error);
1735 longjmp(command_fail, -1); /* give up */
1736 }
1737 for (o = 0; o < argc; o++) {
1738 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1739 sprintf(buffer,
1740 "sd name %s.p0.s%d drive %s size %lldb",
1741 objectname,
1742 o,
1743 drive->label.name,
1744 (long long) maxsize);
1745 if (vflag)
1746 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1747 objectname,
1748 o,
1749 drive->label.name,
1750 (long long) maxsize);
1751 ioctl(superdev, VINUM_CREATE, buffer);
1752 if (reply->error != 0) { /* error in config */
1753 if (reply->msg[0])
1754 fprintf(stderr,
1755 "Can't create subdisk %s.p0.s%d: %s\n",
1756 objectname,
1757 o,
1758 reply->msg);
1759 else
1760 fprintf(stderr,
1761 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1762 objectname,
1763 o,
1764 strerror(reply->error),
1765 reply->error);
1766 longjmp(command_fail, -1); /* give up */
1767 }
1768 }
1769
1770 /* done, save the config */
1771 ioctltype = 0; /* saveconfig after update */
1772 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1773 if (error != 0)
1774 perror("Can't save Vinum config");
1775 find_object(objectname, &type); /* find the index of the volume */
1776 make_vol_dev(vol.volno, 1); /* and create the devices */
1777 if (vflag) {
1778 vflag--; /* XXX don't give too much detail */
1779 find_object(objectname, &type); /* point to the volume */
1780 vinum_lvi(vol.volno, 1); /* and print info about it */
1781 }
1782}
1783
1784/*
1785 * Create a volume with a single RAID-4 plex from
1786 * as much space as we can get on the specified drives.
1787 * If the drives aren't Vinum drives, make them so.
1788 */
1789void
1790vinum_raid4(int argc, char *argv[], char *argv0[])
1791{
1792 int o; /* object number */
1793 char buffer[BUFSIZE];
1794 struct drive *drive; /* drive we're currently looking at */
1795 struct _ioctl_reply *reply;
1796 int ioctltype;
1797 int error;
1798 enum objecttype type;
1799 off_t maxsize;
1800 int fe; /* freelist entry index */
1801 struct drive_freelist freelist;
1802 struct ferq { /* request to pass to ioctl */
1803 int driveno;
1804 int fe;
1805 } *ferq = (struct ferq *) &freelist;
1806 u_int64_t bigchunk; /* biggest chunk in freelist */
1807
1808 maxsize = QUAD_MAX;
1809 reply = (struct _ioctl_reply *) &buffer;
1810
1811 /*
1812 * First, check our drives.
1813 */
1814 if (argc < 3) {
1815 fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n");
1816 return;
1817 }
1818 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1819 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1820 return;
1821 }
1822 if (!objectname) /* we need a name for our object */
1823 genvolname();
1824 for (o = 0; o < argc; o++) {
1825 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1826 drive = create_drive(argv[o]); /* create it */
1827 /* Now find the largest chunk available on the drive */
1828 bigchunk = 0; /* ain't found nothin' yet */
1829 for (fe = 0; fe < drive->freelist_entries; fe++) {
1830 ferq->driveno = drive->driveno;
1831 ferq->fe = fe;
1832 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1833 fprintf(stderr,
1834 "Can't get free list element %d: %s\n",
1835 fe,
1836 strerror(errno));
1837 longjmp(command_fail, -1);
1838 }
1839 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1840 }
1841 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1842 }
1843
1844 /* Now create the volume */
1845 sprintf(buffer, "volume %s", objectname);
1846 if (vflag)
1847 printf("volume %s\n", objectname);
1848 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1849 if (reply->error != 0) { /* error in config */
1850 if (reply->msg[0])
1851 fprintf(stderr,
1852 "Can't create volume %s: %s\n",
1853 objectname,
1854 reply->msg);
1855 else
1856 fprintf(stderr,
1857 "Can't create volume %s: %s (%d)\n",
1858 objectname,
1859 strerror(reply->error),
1860 reply->error);
1861 longjmp(command_fail, -1); /* give up */
1862 }
1863 sprintf(buffer, "plex name %s.p0 org raid4 256k", objectname);
1864 if (vflag)
1865 printf(" plex name %s.p0 org raid4 256k\n", objectname);
1866 ioctl(superdev, VINUM_CREATE, buffer);
1867 if (reply->error != 0) { /* error in config */
1868 if (reply->msg[0])
1869 fprintf(stderr,
1870 "Can't create plex %s.p0: %s\n",
1871 objectname,
1872 reply->msg);
1873 else
1874 fprintf(stderr,
1875 "Can't create plex %s.p0: %s (%d)\n",
1876 objectname,
1877 strerror(reply->error),
1878 reply->error);
1879 longjmp(command_fail, -1); /* give up */
1880 }
1881 for (o = 0; o < argc; o++) {
1882 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
1883 sprintf(buffer,
1884 "sd name %s.p0.s%d drive %s size %lldb",
1885 objectname,
1886 o,
1887 drive->label.name,
1888 (long long) maxsize);
1889 if (vflag)
1890 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
1891 objectname,
1892 o,
1893 drive->label.name,
1894 (long long) maxsize);
1895 ioctl(superdev, VINUM_CREATE, buffer);
1896 if (reply->error != 0) { /* error in config */
1897 if (reply->msg[0])
1898 fprintf(stderr,
1899 "Can't create subdisk %s.p0.s%d: %s\n",
1900 objectname,
1901 o,
1902 reply->msg);
1903 else
1904 fprintf(stderr,
1905 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
1906 objectname,
1907 o,
1908 strerror(reply->error),
1909 reply->error);
1910 longjmp(command_fail, -1); /* give up */
1911 }
1912 }
1913
1914 /* done, save the config */
1915 ioctltype = 0; /* saveconfig after update */
1916 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
1917 if (error != 0)
1918 perror("Can't save Vinum config");
1919 find_object(objectname, &type); /* find the index of the volume */
1920 make_vol_dev(vol.volno, 1); /* and create the devices */
1921 if (vflag) {
1922 vflag--; /* XXX don't give too much detail */
1923 find_object(objectname, &type); /* point to the volume */
1924 vinum_lvi(vol.volno, 1); /* and print info about it */
1925 }
1926}
1927
1928/*
1929 * Create a volume with a single RAID-4 plex from
1930 * as much space as we can get on the specified drives.
1931 * If the drives aren't Vinum drives, make them so.
1932 */
1933void
1934vinum_raid5(int argc, char *argv[], char *argv0[])
1935{
1936 int o; /* object number */
1937 char buffer[BUFSIZE];
1938 struct drive *drive; /* drive we're currently looking at */
1939 struct _ioctl_reply *reply;
1940 int ioctltype;
1941 int error;
1942 enum objecttype type;
1943 off_t maxsize;
1944 int fe; /* freelist entry index */
1945 struct drive_freelist freelist;
1946 struct ferq { /* request to pass to ioctl */
1947 int driveno;
1948 int fe;
1949 } *ferq = (struct ferq *) &freelist;
1950 u_int64_t bigchunk; /* biggest chunk in freelist */
1951
1952 maxsize = QUAD_MAX;
1953 reply = (struct _ioctl_reply *) &buffer;
1954
1955 /*
1956 * First, check our drives.
1957 */
1958 if (argc < 3) {
1959 fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n");
1960 return;
1961 }
1962 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
1963 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
1964 return;
1965 }
1966 if (!objectname) /* we need a name for our object */
1967 genvolname();
1968 for (o = 0; o < argc; o++) {
1969 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
1970 drive = create_drive(argv[o]); /* create it */
1971 /* Now find the largest chunk available on the drive */
1972 bigchunk = 0; /* ain't found nothin' yet */
1973 for (fe = 0; fe < drive->freelist_entries; fe++) {
1974 ferq->driveno = drive->driveno;
1975 ferq->fe = fe;
1976 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
1977 fprintf(stderr,
1978 "Can't get free list element %d: %s\n",
1979 fe,
1980 strerror(errno));
1981 longjmp(command_fail, -1);
1982 }
1983 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
1984 }
1985 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */
1986 }
1987
1988 /* Now create the volume */
1989 sprintf(buffer, "volume %s", objectname);
1990 if (vflag)
1991 printf("volume %s\n", objectname);
1992 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
1993 if (reply->error != 0) { /* error in config */
1994 if (reply->msg[0])
1995 fprintf(stderr,
1996 "Can't create volume %s: %s\n",
1997 objectname,
1998 reply->msg);
1999 else
2000 fprintf(stderr,
2001 "Can't create volume %s: %s (%d)\n",
2002 objectname,
2003 strerror(reply->error),
2004 reply->error);
2005 longjmp(command_fail, -1); /* give up */
2006 }
2007 sprintf(buffer, "plex name %s.p0 org raid5 256k", objectname);
2008 if (vflag)
2009 printf(" plex name %s.p0 org raid5 256k\n", objectname);
2010 ioctl(superdev, VINUM_CREATE, buffer);
2011 if (reply->error != 0) { /* error in config */
2012 if (reply->msg[0])
2013 fprintf(stderr,
2014 "Can't create plex %s.p0: %s\n",
2015 objectname,
2016 reply->msg);
2017 else
2018 fprintf(stderr,
2019 "Can't create plex %s.p0: %s (%d)\n",
2020 objectname,
2021 strerror(reply->error),
2022 reply->error);
2023 longjmp(command_fail, -1); /* give up */
2024 }
2025 for (o = 0; o < argc; o++) {
2026 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2027 sprintf(buffer,
2028 "sd name %s.p0.s%d drive %s size %lldb",
2029 objectname,
2030 o,
2031 drive->label.name,
2032 (long long) maxsize);
2033 if (vflag)
2034 printf(" sd name %s.p0.s%d drive %s size %lldb\n",
2035 objectname,
2036 o,
2037 drive->label.name,
2038 (long long) maxsize);
2039 ioctl(superdev, VINUM_CREATE, buffer);
2040 if (reply->error != 0) { /* error in config */
2041 if (reply->msg[0])
2042 fprintf(stderr,
2043 "Can't create subdisk %s.p0.s%d: %s\n",
2044 objectname,
2045 o,
2046 reply->msg);
2047 else
2048 fprintf(stderr,
2049 "Can't create subdisk %s.p0.s%d: %s (%d)\n",
2050 objectname,
2051 o,
2052 strerror(reply->error),
2053 reply->error);
2054 longjmp(command_fail, -1); /* give up */
2055 }
2056 }
2057
2058 /* done, save the config */
2059 ioctltype = 0; /* saveconfig after update */
2060 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2061 if (error != 0)
2062 perror("Can't save Vinum config");
2063 find_object(objectname, &type); /* find the index of the volume */
2064 make_vol_dev(vol.volno, 1); /* and create the devices */
2065 if (vflag) {
2066 vflag--; /* XXX don't give too much detail */
2067 find_object(objectname, &type); /* point to the volume */
2068 vinum_lvi(vol.volno, 1); /* and print info about it */
2069 }
2070}
2071
2072/*
2073 * Create a volume with a two plexes from as much space
2074 * as we can get on the specified drives. If the
2075 * drives aren't Vinum drives, make them so.
2076 *
2077 * The number of drives must be even, and at least 4
2078 * for a striped plex. Specify striped plexes with the
2079 * -s flag; otherwise they will be concatenated. It's
2080 * possible that the two plexes may differ in length.
2081 */
2082void
2083vinum_mirror(int argc, char *argv[], char *argv0[])
2084{
2085 int o; /* object number */
2086 int p; /* plex number */
2087 char buffer[BUFSIZE];
2088 struct drive *drive; /* drive we're currently looking at */
2089 struct _ioctl_reply *reply;
2090 int ioctltype;
2091 int error;
2092 enum objecttype type;
2093 off_t maxsize[2]; /* maximum subdisk size for striped plexes */
2094 int fe; /* freelist entry index */
2095 struct drive_freelist freelist;
2096 struct ferq { /* request to pass to ioctl */
2097 int driveno;
2098 int fe;
2099 } *ferq = (struct ferq *) &freelist;
2100 u_int64_t bigchunk; /* biggest chunk in freelist */
2101
2102 if (sflag) /* striped, */
2103 maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */
2104 else
2105 maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */
2106
2107 reply = (struct _ioctl_reply *) &buffer;
2108
2109 /*
2110 * First, check our drives.
2111 */
2112 if (argc & 1) {
2113 fprintf(stderr, "You need an even number of drives to create a mirrored volume\n");
2114 return;
2115 }
2116 if (sflag && (argc < 4)) {
2117 fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n");
2118 return;
2119 }
2120 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */
2121 printf("Can't configure: %s (%d)\n", strerror(errno), errno);
2122 return;
2123 }
2124 if (!objectname) /* we need a name for our object */
2125 genvolname();
2126 for (o = 0; o < argc; o++) {
2127 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */
2128 drive = create_drive(argv[o]); /* create it */
2129 if (sflag) { /* striping, */
2130 /* Find the largest chunk available on the drive */
2131 bigchunk = 0; /* ain't found nothin' yet */
2132 for (fe = 0; fe < drive->freelist_entries; fe++) {
2133 ferq->driveno = drive->driveno;
2134 ferq->fe = fe;
2135 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) {
2136 fprintf(stderr,
2137 "Can't get free list element %d: %s\n",
2138 fe,
2139 strerror(errno));
2140 longjmp(command_fail, -1);
2141 }
2142 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */
2143 }
2144 maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */
2145 }
2146 }
2147
2148 /* Now create the volume */
2149 sprintf(buffer, "volume %s setupstate", objectname);
2150 if (vflag)
2151 printf("volume %s setupstate\n", objectname);
2152 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */
2153 if (reply->error != 0) { /* error in config */
2154 if (reply->msg[0])
2155 fprintf(stderr,
2156 "Can't create volume %s: %s\n",
2157 objectname,
2158 reply->msg);
2159 else
2160 fprintf(stderr,
2161 "Can't create volume %s: %s (%d)\n",
2162 objectname,
2163 strerror(reply->error),
2164 reply->error);
2165 longjmp(command_fail, -1); /* give up */
2166 }
2167 for (p = 0; p < 2; p++) { /* create each plex */
2168 if (sflag) {
2169 sprintf(buffer, "plex name %s.p%d org striped 256k", objectname, p);
2170 if (vflag)
2171 printf(" plex name %s.p%d org striped 256k\n", objectname, p);
2172 } else { /* concat */
2173 sprintf(buffer, "plex name %s.p%d org concat", objectname, p);
2174 if (vflag)
2175 printf(" plex name %s.p%d org concat\n", objectname, p);
2176 }
2177 ioctl(superdev, VINUM_CREATE, buffer);
2178 if (reply->error != 0) { /* error in config */
2179 if (reply->msg[0])
2180 fprintf(stderr,
2181 "Can't create plex %s.p%d: %s\n",
2182 objectname,
2183 p,
2184 reply->msg);
2185 else
2186 fprintf(stderr,
2187 "Can't create plex %s.p%d: %s (%d)\n",
2188 objectname,
2189 p,
2190 strerror(reply->error),
2191 reply->error);
2192 longjmp(command_fail, -1); /* give up */
2193 }
2194 /* Now look at the subdisks */
2195 for (o = p; o < argc; o += 2) { /* every second one */
2196 drive = find_drive_by_devname(argv[o]); /* we know it exists... */
2197 sprintf(buffer,
2198 "sd name %s.p%d.s%d drive %s size %lldb",
2199 objectname,
2200 p,
2201 o >> 1,
2202 drive->label.name,
2203 (long long) maxsize[p]);
2204 if (vflag)
2205 printf(" sd name %s.p%d.s%d drive %s size %lldb\n",
2206 objectname,
2207 p,
2208 o >> 1,
2209 drive->label.name,
2210 (long long) maxsize[p]);
2211 ioctl(superdev, VINUM_CREATE, buffer);
2212 if (reply->error != 0) { /* error in config */
2213 if (reply->msg[0])
2214 fprintf(stderr,
2215 "Can't create subdisk %s.p%d.s%d: %s\n",
2216 objectname,
2217 p,
2218 o >> 1,
2219 reply->msg);
2220 else
2221 fprintf(stderr,
2222 "Can't create subdisk %s.p%d.s%d: %s (%d)\n",
2223 objectname,
2224 p,
2225 o >> 1,
2226 strerror(reply->error),
2227 reply->error);
2228 longjmp(command_fail, -1); /* give up */
2229 }
2230 }
2231 }
2232
2233 /* done, save the config */
2234 ioctltype = 0; /* saveconfig after update */
2235 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */
2236 if (error != 0)
2237 perror("Can't save Vinum config");
2238 find_object(objectname, &type); /* find the index of the volume */
2239 make_vol_dev(vol.volno, 1); /* and create the devices */
2240 if (vflag) {
2241 vflag--; /* XXX don't give too much detail */
2242 sflag = 0; /* no stats, please */
2243 find_object(objectname, &type); /* point to the volume */
2244 vinum_lvi(vol.volno, 1); /* and print info about it */
2245 }
2246}
2247
2248void
2249vinum_readpol(int argc, char *argv[], char *argv0[])
2250{
2251 int object;
2252 struct _ioctl_reply reply;
2253 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2254 enum objecttype type;
2255 struct plex plex;
2256 struct volume vol;
2257 int plexno;
2258
2259 if (argc == 0) { /* start everything */
2260 fprintf(stderr, "Usage: readpol <volume> <plex>|round\n");
2261 return;
2262 }
2263 object = find_object(argv[1], &type); /* look for it */
2264 if (type != volume_object) {
2265 fprintf(stderr, "%s is not a volume\n", argv[1]);
2266 return;
2267 }
2268 get_volume_info(&vol, object);
2269 if (strcmp(argv[2], "round")) { /* not 'round' */
2270 object = find_object(argv[2], &type); /* look for it */
2271 if (type != plex_object) {
2272 fprintf(stderr, "%s is not a plex\n", argv[2]);
2273 return;
2274 }
2275 get_plex_info(&plex, object);
2276 plexno = plex.plexno;
2277 } else /* round */
2278 plexno = -1;
2279
2280 /* Set the value */
2281 message->index = vol.volno;
2282 message->otherobject = plexno;
2283 if (ioctl(superdev, VINUM_READPOL, message) < 0)
2284 fprintf(stderr, "Can't set read policy: %s (%d)\n", strerror(errno), errno);
2285 if (vflag)
2286 vinum_lpi(plexno, recurse);
2287}
2288
2289/*
2290 * Brute force set state function. Don't look at
2291 * any dependencies, just do it.
2292 */
2293void
2294vinum_setstate(int argc, char *argv[], char *argv0[])
2295{
2296 int object;
2297 struct _ioctl_reply reply;
2298 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2299 int index;
2300 enum objecttype type;
2301 int state;
2302
2303 for (index = 1; index < argc; index++) {
2304 object = find_object(argv[index], &type); /* look for it */
2305 if (type == invalid_object)
2306 fprintf(stderr, "Can't find object: %s\n", argv[index]);
2307 else {
2308 int doit = 0; /* set to 1 if we pass our tests */
2309 switch (type) {
2310 case drive_object:
2311 state = DriveState(argv[0]); /* get the state */
2312 if (drive.state == state) /* already in that state */
2313 fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]);
2314 else
2315 doit = 1;
2316 break;
2317
2318 case sd_object:
2319 state = SdState(argv[0]); /* get the state */
2320 if (sd.state == state) /* already in that state */
2321 fprintf(stderr, "%s is already %s\n", sd.name, argv[0]);
2322 else
2323 doit = 1;
2324 break;
2325
2326 case plex_object:
2327 state = PlexState(argv[0]); /* get the state */
2328 if (plex.state == state) /* already in that state */
2329 fprintf(stderr, "%s is already %s\n", plex.name, argv[0]);
2330 else
2331 doit = 1;
2332 break;
2333
2334 case volume_object:
2335 state = VolState(argv[0]); /* get the state */
2336 if (vol.state == state) /* already in that state */
2337 fprintf(stderr, "%s is already %s\n", vol.name, argv[0]);
2338 else
2339 doit = 1;
2340 break;
2341
2342 default:
2343 state = 0; /* to keep the compiler happy */
2344 }
2345
2346 if (state == -1)
2347 fprintf(stderr, "Invalid state for object: %s\n", argv[0]);
2348 else if (doit) {
2349 message->index = object; /* pass object number */
2350 message->type = type; /* and type of object */
2351 message->state = state;
2352 message->force = force; /* don't force it, use a larger hammer */
2353 ioctl(superdev, VINUM_SETSTATE_FORCE, message);
2354 if (reply.error != 0)
2355 fprintf(stderr,
2356 "Can't start %s: %s (%d)\n",
2357 argv[index],
2358 reply.msg[0] ? reply.msg : strerror(reply.error),
2359 reply.error);
2360 if (Verbose)
2361 vinum_li(object, type);
2362 }
2363 }
2364 }
2365}
2366
2367void
2368vinum_checkparity(int argc, char *argv[], char *argv0[])
2369{
2370 Verbose = vflag; /* accept -v for verbose */
2371 if (argc == 0) /* no parameters? */
2372 fprintf(stderr, "Usage: checkparity object [object...]\n");
2373 else
2374 parityops(argc, argv, checkparity);
2375}
2376
2377void
2378vinum_rebuildparity(int argc, char *argv[], char *argv0[])
2379{
2380 if (argc == 0) /* no parameters? */
2381 fprintf(stderr, "Usage: rebuildparity object [object...]\n");
2382 else
2383 parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity);
2384}
2385
2386/*
2387 * Common code for rebuildparity and checkparity.
2388 * We bend the meanings of some flags here:
2389 *
2390 * -v: Report incorrect parity on rebuild.
2391 * -V: Show running count of position being checked.
2392 * -f: Start from beginning of the plex.
2393 */
2394void
2395parityops(int argc, char *argv[], enum parityop op)
2396{
2397 int object;
2398 struct plex plex;
2399 struct _ioctl_reply reply;
2400 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
2401 int index;
2402 enum objecttype type;
2403 char *msg;
2404 off_t block;
2405
2406 if (op == checkparity)
2407 msg = "Checking";
2408 else
2409 msg = "Rebuilding";
2410 for (index = 0; index < argc; index++) {
2411 object = find_object(argv[index], &type); /* look for it */
2412 if (type != plex_object)
2413 fprintf(stderr, "%s is not a plex\n", argv[index]);
2414 else {
2415 get_plex_info(&plex, object);
2416 if (!isparity((&plex)))
2417 fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]);
2418 else {
2419 do {
2420 message->index = object; /* pass object number */
2421 message->type = type; /* and type of object */
2422 message->op = op; /* what to do */
2423 if (force)
2424 message->offset = 0; /* start at the beginning */
2425 else
2426 message->offset = plex.checkblock; /* continue where we left off */
2427 force = 0; /* don't reset after the first time */
2428 ioctl(superdev, VINUM_PARITYOP, message);
2429 get_plex_info(&plex, object);
2430 if (Verbose) {
2431 block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1);
2432 if (block != 0)
2433 printf("\r%s at %s (%d%%) ",
2434 msg,
2435 roughlength(block, 1),
2436 ((int) (block * 100 / plex.length) >> DEV_BSHIFT));
2437 if ((reply.error == EAGAIN)
2438 && (reply.msg[0])) /* got a comment back */
2439 fputs(reply.msg, stderr); /* show it */
2440 fflush(stdout);
2441 }
2442 }
2443 while (reply.error == EAGAIN);
2444 if (reply.error != 0) {
2445 if (reply.msg[0])
2446 fputs(reply.msg, stderr);
2447 else
2448 fprintf(stderr,
2449 "%s failed: %s\n",
2450 msg,
2451 strerror(reply.error));
2452 } else if (Verbose) {
2453 if (op == checkparity)
2454 fprintf(stderr, "%s has correct parity\n", argv[index]);
2455 else
2456 fprintf(stderr, "Rebuilt parity on %s\n", argv[index]);
2457 }
2458 }
2459 }
2460 }
2461}
2462
2463/* Local Variables: */
2464/* fill-column: 50 */
2465/* End: */