hammer2 - Cleanup manual page, add help, remove bulkfree-async
[dragonfly.git] / sbin / vinum / v.c
blob880413a0fb64b7a2e7506484a2776d1da8b65fac
1 /* vinum.c: vinum interface program */
2 /*-
3 * Copyright (c) 1997, 1998
4 * Nan Yang Computer Services Limited. All rights reserved.
6 * Written by Greg Lehey
8 * This software is distributed under the so-called ``Berkeley
9 * License'':
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.
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.
35 * $Id: v.c,v 1.31 2000/09/03 01:29:26 grog Exp grog $
36 * $FreeBSD: src/sbin/vinum/v.c,v 1.26.2.3 2001/03/13 03:04:06 grog Exp $
39 #include <ctype.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <sys/mman.h>
43 #include <netdb.h>
44 #include <setjmp.h>
45 #include <fstab.h>
46 #include <signal.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <syslog.h>
51 #include <unistd.h>
52 #include <sys/ioctl.h>
53 #include <dev/raid/vinum/vinumhdr.h>
54 #include "vext.h"
55 #include <sys/types.h>
56 #include <sys/wait.h>
57 #include <readline/readline.h>
58 #include <sys/linker.h>
59 #include <sys/module.h>
60 #include <sys/resource.h>
62 FILE *cf; /* config file handle */
63 FILE *hist; /* history file */
64 char *historyfile; /* and its name */
66 char *dateformat; /* format in which to store date */
68 char buffer[BUFSIZE]; /* buffer to read in to */
70 int line = 0; /* stdin line number for error messages */
71 int file_line = 0; /* and line in input file (yes, this is tacky) */
72 int inerror; /* set to 1 to exit after end of config file */
74 /* flags */
76 #if VINUMDEBUG
77 int debug = 0; /* debug flag, usage varies */
78 #endif
79 int force = 0; /* set to 1 to force some dangerous ops */
80 int interval = 0; /* interval in ms between init/revive */
81 int vflag = 0; /* set verbose operation or verify */
82 int Verbose = 0; /* set very verbose operation */
83 int recurse = 0; /* set recursion */
84 int sflag = 0; /* show statistics */
85 int SSize = 0; /* sector size for revive */
86 int dowait = 0; /* wait for completion */
87 char *objectname; /* name to be passed for -n flag */
89 /* Structures to read kernel data into */
90 struct _vinum_conf vinum_conf; /* configuration information */
92 struct volume vol;
93 struct plex plex;
94 struct sd sd;
95 struct drive drive;
97 jmp_buf command_fail; /* return on a failed command */
98 int superdev; /* vinum super device */
100 void start_daemon(void);
102 char *token[MAXARGS]; /* pointers to individual tokens */
103 int tokens; /* number of tokens */
106 main(int argc, char *argv[], char *envp[])
108 struct stat histstat;
110 if (modfind(VINUMMOD) < 0) {
111 /* need to load the vinum module */
112 if (kldload(VINUMMOD) < 0 || modfind(VINUMMOD) < 0) {
113 perror(VINUMMOD ": Kernel module not available");
114 return 1;
117 dateformat = getenv("VINUM_DATEFORMAT");
118 if (dateformat == NULL)
119 dateformat = "%e %b %Y %H:%M:%S";
120 historyfile = getenv("VINUM_HISTORY");
121 if (historyfile == NULL)
122 historyfile = DEFAULT_HISTORYFILE;
123 if (stat(historyfile, &histstat) == 0) { /* history file exists */
124 if ((histstat.st_mode & S_IFMT) != S_IFREG) {
125 fprintf(stderr,
126 "Vinum history file %s must be a regular file\n",
127 historyfile);
128 exit(1);
130 } else if ((errno != ENOENT) /* not "not there", */
131 &&(errno != EROFS)) { /* and not read-only file system */
132 fprintf(stderr,
133 "Can't open %s: %s (%d)\n",
134 historyfile,
135 strerror(errno),
136 errno);
137 exit(1);
139 hist = fopen(historyfile, "a+");
140 if (hist != NULL) {
141 timestamp();
142 fprintf(hist, "*** " VINUMMOD " started ***\n");
143 fflush(hist); /* before we start the daemon */
145 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* open vinum superdevice */
146 if (superdev < 0) { /* no go */
147 if (errno == ENODEV) { /* not configured, */
148 superdev = open(VINUM_WRONGSUPERDEV_NAME, O_RDWR); /* do we have a debug mismatch? */
149 if (superdev >= 0) { /* yup! */
150 #if VINUMDEBUG
151 fprintf(stderr,
152 "This program is compiled with debug support, but the kernel module does\n"
153 "not have debug support. This program must be matched with the kernel\n"
154 "module. Please alter /usr/src/sbin/" VINUMMOD "/Makefile and remove\n"
155 "the option -DVINUMDEBUG from the CFLAGS definition, or alternatively\n"
156 "edit /usr/src/sys/modules/" VINUMMOD "/Makefile and add the option\n"
157 "-DVINUMDEBUG to the CFLAGS definition. Then rebuild the component\n"
158 "of your choice with 'make clean all install'. If you rebuild the kernel\n"
159 "module, you must stop " VINUMMOD " and restart it\n");
160 #else
161 fprintf(stderr,
162 "This program is compiled without debug support, but the kernel module\n"
163 "includes debug support. This program must be matched with the kernel\n"
164 "module. Please alter /usr/src/sbin/" VINUMMOD "/Makefile and add\n"
165 "the option -DVINUMDEBUG to the CFLAGS definition, or alternatively\n"
166 "edit /usr/src/sys/modules/" VINUMMOD "/Makefile and remove the option\n"
167 "-DVINUMDEBUG from the CFLAGS definition. Then rebuild the component\n"
168 "of your choice with 'make clean all install'. If you rebuild the kernel\n"
169 "module, you must stop " VINUMMOD " and restart it\n");
170 #endif
171 return 1;
173 } else if (errno == ENOENT) /* we don't have our node, */
174 make_devices(); /* create them first */
175 if (superdev < 0) {
176 perror("Can't open " VINUM_SUPERDEV_NAME);
177 return 1;
180 /* Check if the dæmon is running. If not, start it in the
181 * background */
182 start_daemon();
184 if (argc > 1) { /* we have a command on the line */
185 if (setjmp(command_fail) != 0) /* long jumped out */
186 return -1;
187 parseline(argc - 1, &argv[1]); /* do it */
188 } else {
190 * Catch a possible race condition which could cause us to
191 * longjmp() into nowhere if we receive a SIGINT in the next few
192 * lines.
194 if (setjmp(command_fail)) /* come back here on catastrophic failure */
195 return 1;
196 setsigs(); /* set signal handler */
197 for (;;) { /* ugh */
198 char *c;
199 int childstatus; /* from wait4 */
201 if (setjmp(command_fail) == 2) /* come back here on catastrophic failure */
202 fprintf(stderr, "*** interrupted ***\n"); /* interrupted */
204 while (wait4(-1, &childstatus, WNOHANG, NULL) > 0); /* wait for all dead children */
205 c = readline(VINUMMOD " -> "); /* get an input */
206 if (c == NULL) { /* EOF or error */
207 if (ferror(stdin)) {
208 fprintf(stderr, "Can't read input: %s (%d)\n", strerror(errno), errno);
209 return 1;
210 } else { /* EOF */
211 printf("\n");
212 return 0;
214 } else if (*c) { /* got something there */
215 add_history(c); /* save it in the history */
216 strcpy(buffer, c); /* put it where we can munge it */
217 free(c);
218 line++; /* count the lines */
219 tokens = tokenize(buffer, token);
220 /* got something potentially worth parsing */
221 if (tokens)
222 parseline(tokens, token); /* and do what he says */
224 if (hist)
225 fflush(hist);
228 return 0; /* normal completion */
231 /* stop the hard way */
232 void
233 vinum_quit(int argc, char *argv[], char *argv0[])
235 exit(0);
238 /* Set action on receiving a SIGINT */
239 void
240 setsigs(void)
242 struct sigaction act;
244 act.sa_handler = catchsig;
245 act.sa_flags = 0;
246 sigemptyset(&act.sa_mask);
247 sigaction(SIGINT, &act, NULL);
250 void
251 catchsig(int ignore)
253 longjmp(command_fail, 2);
256 #define FUNKEY(x) { kw_##x, &vinum_##x } /* create pair "kw_foo", vinum_foo */
257 #define vinum_move vinum_mv /* synonym for 'mv' */
259 struct funkey {
260 enum keyword kw;
261 void (*fun) (int argc, char *argv[], char *arg0[]);
262 } funkeys[] = {
264 FUNKEY(create),
265 FUNKEY(read),
266 #ifdef VINUMDEBUG
267 FUNKEY(debug),
268 #endif
269 FUNKEY(modify),
270 FUNKEY(list),
271 FUNKEY(ld),
272 FUNKEY(ls),
273 FUNKEY(lp),
274 FUNKEY(lv),
275 FUNKEY(info),
276 FUNKEY(set),
277 FUNKEY(init),
278 FUNKEY(label),
279 FUNKEY(resetconfig),
280 FUNKEY(rm),
281 FUNKEY(mv),
282 FUNKEY(move),
283 FUNKEY(attach),
284 FUNKEY(detach),
285 FUNKEY(rename),
286 FUNKEY(replace),
287 FUNKEY(printconfig),
288 FUNKEY(saveconfig),
289 FUNKEY(start),
290 FUNKEY(stop),
291 FUNKEY(makedev),
292 FUNKEY(help),
293 FUNKEY(quit),
294 FUNKEY(concat),
295 FUNKEY(stripe),
296 FUNKEY(raid4),
297 FUNKEY(raid5),
298 FUNKEY(mirror),
299 FUNKEY(setdaemon),
300 FUNKEY(readpol),
301 FUNKEY(resetstats),
302 FUNKEY(setstate),
303 FUNKEY(checkparity),
304 FUNKEY(rebuildparity),
305 FUNKEY(dumpconfig)
308 /* Take args arguments at argv and attempt to perform the operation specified */
309 void
310 parseline(int args, char *argv[])
312 int i;
313 int j;
314 enum keyword command; /* command to execute */
316 if (hist != NULL) { /* save the command to history file */
317 timestamp();
318 for (i = 0; i < args; i++) /* all args */
319 fprintf(hist, "%s ", argv[i]);
320 fputs("\n", hist);
322 if ((args == 0) /* empty line */
323 ||(*argv[0] == '#')) /* or a comment, */
324 return;
325 if (args == MAXARGS) { /* too many arguments, */
326 fprintf(stderr, "Too many arguments to %s, this can't be right\n", argv[0]);
327 return;
329 command = get_keyword(argv[0], &keyword_set);
330 dowait = 0; /* initialize flags */
331 force = 0; /* initialize flags */
332 vflag = 0; /* initialize flags */
333 Verbose = 0; /* initialize flags */
334 recurse = 0; /* initialize flags */
335 sflag = 0; /* initialize flags */
336 objectname = NULL; /* no name yet */
339 * first handle generic options
340 * We don't use getopt(3) because
341 * getopt doesn't allow merging flags
342 * (for example, -fr).
344 for (i = 1; (i < args) && (argv[i][0] == '-'); i++) { /* while we have flags */
345 for (j = 1; j < strlen(argv[i]); j++)
346 switch (argv[i][j]) {
347 #if VINUMDEBUG
348 case 'd': /* -d: debug */
349 debug = 1;
350 break;
351 #endif
353 case 'f': /* -f: force */
354 force = 1;
355 break;
357 case 'i': /* interval */
358 interval = 0;
359 if (argv[i][j + 1] != '\0') /* operand follows, */
360 interval = atoi(&argv[i][j + 1]); /* use it */
361 else if (args > (i + 1)) /* another following, */
362 interval = atoi(argv[++i]); /* use it */
363 if (interval == 0) /* nothing valid, */
364 fprintf(stderr, "-i: no interval specified\n");
365 break;
367 case 'n': /* -n: get name */
368 if (i == args - 1) { /* last arg */
369 fprintf(stderr, "-n requires a name parameter\n");
370 return;
372 objectname = argv[++i]; /* pick it up */
373 j = strlen(argv[i]); /* skip the next parm */
374 break;
376 case 'r': /* -r: recurse */
377 recurse = 1;
378 break;
380 case 's': /* -s: show statistics */
381 sflag = 1;
382 break;
384 case 'S':
385 SSize = 0;
386 if (argv[i][j + 1] != '\0') /* operand follows, */
387 SSize = atoi(&argv[i][j + 1]); /* use it */
388 else if (args > (i + 1)) /* another following, */
389 SSize = atoi(argv[++i]); /* use it */
390 if (SSize == 0) /* nothing valid, */
391 fprintf(stderr, "-S: no size specified\n");
392 break;
394 case 'v': /* -v: verbose */
395 vflag++;
396 break;
398 case 'V': /* -V: Very verbose */
399 vflag++;
400 Verbose++;
401 break;
403 case 'w': /* -w: wait for completion */
404 dowait = 1;
405 break;
407 default:
408 fprintf(stderr, "Invalid flag: %s\n", argv[i]);
412 /* Pass what we have left to the command to handle it */
413 for (j = 0; j < (sizeof(funkeys) / sizeof(struct funkey)); j++) {
414 if (funkeys[j].kw == command) { /* found the command */
415 funkeys[j].fun(args - i, &argv[i], &argv[0]);
416 return;
419 fprintf(stderr, "Unknown command: %s\n", argv[0]);
422 void
423 get_drive_info(struct drive *drive, int index)
425 *(int *) drive = index; /* put in drive to hand to driver */
426 if (ioctl(superdev, VINUM_DRIVECONFIG, drive) < 0) {
427 fprintf(stderr,
428 "Can't get config for drive %d: %s\n",
429 index,
430 strerror(errno));
431 longjmp(command_fail, -1);
435 void
436 get_sd_info(struct sd *sd, int index)
438 *(int *) sd = index; /* put in sd to hand to driver */
439 if (ioctl(superdev, VINUM_SDCONFIG, sd) < 0) {
440 fprintf(stderr,
441 "Can't get config for subdisk %d: %s\n",
442 index,
443 strerror(errno));
444 longjmp(command_fail, -1);
448 /* Get the contents of the sd entry for subdisk <sdno>
449 * of the specified plex. */
450 void
451 get_plex_sd_info(struct sd *sd, int plexno, int sdno)
453 ((int *) sd)[0] = plexno;
454 ((int *) sd)[1] = sdno; /* pass parameters */
455 if (ioctl(superdev, VINUM_PLEXSDCONFIG, sd) < 0) {
456 fprintf(stderr,
457 "Can't get config for subdisk %d (part of plex %d): %s\n",
458 sdno,
459 plexno,
460 strerror(errno));
461 longjmp(command_fail, -1);
465 void
466 get_plex_info(struct plex *plex, int index)
468 *(int *) plex = index; /* put in plex to hand to driver */
469 if (ioctl(superdev, VINUM_PLEXCONFIG, plex) < 0) {
470 fprintf(stderr,
471 "Can't get config for plex %d: %s\n",
472 index,
473 strerror(errno));
474 longjmp(command_fail, -1);
478 void
479 get_volume_info(struct volume *volume, int index)
481 *(int *) volume = index; /* put in volume to hand to driver */
482 if (ioctl(superdev, VINUM_VOLCONFIG, volume) < 0) {
483 fprintf(stderr,
484 "Can't get config for volume %d: %s\n",
485 index,
486 strerror(errno));
487 longjmp(command_fail, -1);
491 struct drive *
492 find_drive_by_devname(char *name)
494 int driveno;
495 char *devpath;
496 struct drive *drivep = NULL;
498 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
499 perror("Can't get vinum config");
500 return NULL;
502 devpath = getdevpath(name, 0);
503 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
504 get_drive_info(&drive, driveno);
505 if (drive.state == drive_unallocated)
506 continue;
507 if (strcmp(drive.devicename, name) == 0) {
508 drivep = &drive;
509 break;
511 if (strcmp(drive.devicename, devpath) == 0) {
512 drivep = &drive;
513 break;
516 free(devpath);
517 return (drivep);
521 * Create the device nodes for vinum objects
523 * XXX - Obsolete, vinum kernel module now creates is own devices.
525 void
526 make_devices(void)
528 #if 0
529 int volno;
530 int plexno;
531 int sdno;
532 int driveno;
533 #endif
535 if (hist) {
536 timestamp();
537 fprintf(hist, "*** Created devices ***\n");
540 #if 0
541 system("rm -rf " VINUM_DIR); /* remove the old directories */
542 system("mkdir -p " VINUM_DIR "/drive " /* and make them again */
543 VINUM_DIR "/plex "
544 VINUM_DIR "/sd "
545 VINUM_DIR "/vol");
547 if (mknod(VINUM_SUPERDEV_NAME,
548 S_IRUSR | S_IWUSR | S_IFCHR, /* user only */
549 makedev(VINUM_CDEV_MAJOR, VINUM_SUPERDEV)) < 0)
550 fprintf(stderr, "Can't create %s: %s\n", VINUM_SUPERDEV_NAME, strerror(errno));
552 if (mknod(VINUM_WRONGSUPERDEV_NAME,
553 S_IRUSR | S_IWUSR | S_IFCHR, /* user only */
554 makedev(VINUM_CDEV_MAJOR, VINUM_WRONGSUPERDEV)) < 0)
555 fprintf(stderr, "Can't create %s: %s\n", VINUM_WRONGSUPERDEV_NAME, strerror(errno));
557 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* open the super device */
559 if (mknod(VINUM_DAEMON_DEV_NAME, /* daemon super device */
560 S_IRUSR | S_IWUSR | S_IFCHR, /* user only */
561 makedev(VINUM_CDEV_MAJOR, VINUM_DAEMON_DEV)) < 0)
562 fprintf(stderr, "Can't create %s: %s\n", VINUM_DAEMON_DEV_NAME, strerror(errno));
563 #endif
564 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
565 perror("Can't get vinum config");
566 return;
568 #if 0
569 for (volno = 0; volno < vinum_conf.volumes_allocated; volno++)
570 make_vol_dev(volno, 0);
572 for (plexno = 0; plexno < vinum_conf.plexes_allocated; plexno++)
573 make_plex_dev(plexno, 0);
575 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++)
576 make_sd_dev(sdno);
577 /* Drives. Do this later (both logical and physical names) XXX */
578 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
579 char filename[PATH_MAX]; /* for forming file names */
581 get_drive_info(&drive, driveno);
582 if (drive.state > drive_referenced) {
583 sprintf(filename, "ln -s %s " VINUM_DIR "/drive/%s", drive.devicename, drive.label.name);
584 system(filename);
587 #endif
590 #if 0
592 /* make the devices for a volume */
593 void
594 make_vol_dev(int volno, int recurse)
596 dev_t voldev;
597 char filename[PATH_MAX]; /* for forming file names */
598 int plexno;
600 get_volume_info(&vol, volno);
601 if (vol.state != volume_unallocated) { /* we could have holes in our lists */
602 voldev = VINUMDEV(volno, 0, 0, VINUM_VOLUME_TYPE); /* create a device number */
604 /* Create /dev/vinum/<myvol> */
605 sprintf(filename, VINUM_DIR "/%s", vol.name);
606 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, voldev) < 0)
607 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
609 /* Create /dev/vinum/vol/<myvol> */
610 sprintf(filename, VINUM_DIR "/vol/%s", vol.name);
611 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, voldev) < 0)
612 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
614 if (vol.plexes > 0) {
615 /* Create /dev/vinum/vol/<myvol>.plex/ */
616 sprintf(filename, VINUM_DIR "/vol/%s.plex", vol.name);
617 if (mkdir(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IXOTH) < 0)
618 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
620 if (recurse)
621 for (plexno = 0; plexno < vol.plexes; plexno++)
622 make_plex_dev(plex.plexno, recurse);
627 * Create device entries for the plexes in
628 * /dev/vinum/<vol>.plex/ and /dev/vinum/plex.
630 void
631 make_plex_dev(int plexno, int recurse)
633 dev_t plexdev; /* device */
634 char filename[PATH_MAX]; /* for forming file names */
635 int sdno;
637 get_plex_info(&plex, plexno);
638 if (plex.state != plex_unallocated) {
639 plexdev = VINUM_PLEX(plexno);
641 /* /dev/vinum/plex/<plex> */
642 sprintf(filename, VINUM_DIR "/plex/%s", plex.name);
643 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, plexdev) < 0)
644 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
646 if (plex.volno >= 0) {
647 get_volume_info(&vol, plex.volno);
648 plexdev = VINUMDEV(plex.volno, plexno, 0, VINUM_PLEX_TYPE);
650 /* Create device /dev/vinum/vol/<vol>.plex/<plex> */
651 sprintf(filename, VINUM_DIR "/vol/%s.plex/%s", vol.name, plex.name);
652 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, plexdev) < 0)
653 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
655 /* Create directory /dev/vinum/vol/<vol>.plex/<plex>.sd */
656 sprintf(filename, VINUM_DIR "/vol/%s.plex/%s.sd", vol.name, plex.name);
657 if (mkdir(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IXOTH) < 0)
658 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
660 if (recurse) {
661 for (sdno = 0; sdno < plex.subdisks; sdno++) {
662 get_plex_sd_info(&sd, plex.plexno, sdno);
663 make_sd_dev(sd.sdno);
669 /* Create the contents of /dev/vinum/sd and /dev/vinum/rsd */
670 void
671 make_sd_dev(int sdno)
673 dev_t sddev; /* device */
674 char filename[PATH_MAX]; /* for forming file names */
676 get_sd_info(&sd, sdno);
677 if (sd.state != sd_unallocated) {
678 sddev = VINUM_SD(sdno);
680 /* /dev/vinum/sd/<sd> */
681 sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
682 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, sddev) < 0)
683 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
687 #endif
689 /* command line interface for the 'makedev' command */
690 void
691 vinum_makedev(int argc, char *argv[], char *arg0[])
693 make_devices();
697 * Find the object "name". Return object type at type,
698 * and the index as the return value.
699 * If not found, return -1 and invalid_object.
702 find_object(const char *name, enum objecttype *type)
704 int object;
706 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
707 perror("Can't get vinum config");
708 *type = invalid_object;
709 return -1;
711 /* Search the drive table */
712 for (object = 0; object < vinum_conf.drives_allocated; object++) {
713 get_drive_info(&drive, object);
714 if (strcmp(name, drive.label.name) == 0) {
715 *type = drive_object;
716 return object;
720 /* Search the subdisk table */
721 for (object = 0; object < vinum_conf.subdisks_allocated; object++) {
722 get_sd_info(&sd, object);
723 if (strcmp(name, sd.name) == 0) {
724 *type = sd_object;
725 return object;
729 /* Search the plex table */
730 for (object = 0; object < vinum_conf.plexes_allocated; object++) {
731 get_plex_info(&plex, object);
732 if (strcmp(name, plex.name) == 0) {
733 *type = plex_object;
734 return object;
738 /* Search the volume table */
739 for (object = 0; object < vinum_conf.volumes_allocated; object++) {
740 get_volume_info(&vol, object);
741 if (strcmp(name, vol.name) == 0) {
742 *type = volume_object;
743 return object;
747 /* Didn't find the name: invalid */
748 *type = invalid_object;
749 return -1;
752 /* Continue reviving a subdisk in the background */
753 void
754 continue_revive(int sdno)
756 struct sd sd;
757 pid_t pid;
758 get_sd_info(&sd, sdno);
760 if (dowait == 0)
761 pid = fork(); /* do this in the background */
762 else
763 pid = 0;
764 if (pid == 0) { /* we're the child */
765 struct _ioctl_reply reply;
766 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
768 openlog(VINUMMOD, LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
769 syslog(LOG_INFO | LOG_KERN, "reviving %s", sd.name);
770 setproctitle("reviving %s", sd.name);
772 for (reply.error = EAGAIN; reply.error == EAGAIN;) { /* revive the subdisk */
773 if (interval)
774 usleep(interval * 1000); /* pause between each copy */
775 message->index = sdno; /* pass sd number */
776 message->type = sd_object; /* and type of object */
777 message->state = object_up;
778 if (SSize != 0) { /* specified a size for init */
779 if (SSize < 512)
780 SSize <<= DEV_BSHIFT;
781 message->blocksize = SSize;
782 } else
783 message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
784 ioctl(superdev, VINUM_SETSTATE, message);
786 if (reply.error) {
787 syslog(LOG_ERR | LOG_KERN,
788 "can't revive %s: %s",
789 sd.name,
790 reply.msg[0] ? reply.msg : strerror(reply.error));
791 if (dowait == 0)
792 exit(1);
793 } else {
794 get_sd_info(&sd, sdno); /* update the info */
795 syslog(LOG_INFO | LOG_KERN, "%s is %s", sd.name, sd_state(sd.state));
796 if (dowait == 0)
797 exit(0);
799 } else if (pid < 0) /* couldn't fork? */
800 fprintf(stderr, "Can't continue reviving %s: %s\n", sd.name, strerror(errno));
801 else /* parent */
802 printf("Reviving %s in the background\n", sd.name);
806 * Check if the daemon is running,
807 * start it if it isn't. The check itself
808 * could take a while, so we do it as a separate
809 * process, which will become the daemon if one isn't
810 * running already
812 void
813 start_daemon(void)
815 int pid;
816 int status;
817 int error;
819 pid = (int) fork();
821 if (pid == 0) { /* We're the child, do the work */
823 * We have a problem when stopping the subsystem:
824 * The only way to know that we're idle is when
825 * all open superdevs close. But we want the
826 * daemon to clean up for us, and since we can't
827 * count the opens, we need to have the main device
828 * closed when we stop. We solve this conundrum
829 * by getting the daemon to open a separate device.
831 close(superdev); /* this is the wrong device */
832 superdev = open(VINUM_DAEMON_DEV_NAME, O_RDWR); /* open deamon superdevice */
833 if (superdev < 0) {
834 perror("Can't open " VINUM_DAEMON_DEV_NAME);
835 exit(1);
837 error = daemon(0, 0); /* this will fork again, but who's counting? */
838 if (error != 0) {
839 fprintf(stderr, "Can't start daemon: %s (%d)\n", strerror(errno), errno);
840 exit(1);
842 setproctitle(VINUMMOD " daemon"); /* show what we're doing */
843 status = ioctl(superdev, VINUM_FINDDAEMON, NULL);
844 if (status != 0) { /* no daemon, */
845 ioctl(superdev, VINUM_DAEMON, &vflag); /* we should hang here */
846 syslog(LOG_ERR | LOG_KERN, "%s", strerror(errno));
847 exit(1);
849 exit(0); /* when told to die */
850 } else if (pid < 0) /* couldn't fork */
851 printf("Can't fork to check daemon\n");
854 void
855 timestamp(void)
857 struct timeval now;
858 struct tm *date;
859 char datetext[MAXDATETEXT];
860 time_t sec;
862 if (hist != NULL) {
863 if (gettimeofday(&now, NULL) != 0) {
864 fprintf(stderr, "Can't get time: %s\n", strerror(errno));
865 return;
867 sec = now.tv_sec;
868 date = localtime(&sec);
869 strftime(datetext, MAXDATETEXT, dateformat, date);
870 fprintf(hist, "%s.%06ld ", datetext, now.tv_usec);