Pre-2.0 release, MFC firewire disk changes to properly detach SIMs.
[dragonfly.git] / sbin / vinum / v.c
blob8a1ca4cf073eb816db050b43d60642b7ca1c8d3e
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 $
37 * $DragonFly: src/sbin/vinum/v.c,v 1.6 2007/07/22 22:46:09 corecode Exp $
40 #include <ctype.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <sys/mman.h>
44 #include <netdb.h>
45 #include <setjmp.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 #define ofs(x) ((void *) (& ((struct confdata *) 0)->x)) /* offset of x in struct confdata */
104 char *token[MAXARGS]; /* pointers to individual tokens */
105 int tokens; /* number of tokens */
108 main(int argc, char *argv[], char *envp[])
110 struct stat histstat;
112 if (modfind(VINUMMOD) < 0) {
113 /* need to load the vinum module */
114 if (kldload(VINUMMOD) < 0 || modfind(VINUMMOD) < 0) {
115 perror(VINUMMOD ": Kernel module not available");
116 return 1;
119 dateformat = getenv("VINUM_DATEFORMAT");
120 if (dateformat == NULL)
121 dateformat = "%e %b %Y %H:%M:%S";
122 historyfile = getenv("VINUM_HISTORY");
123 if (historyfile == NULL)
124 historyfile = DEFAULT_HISTORYFILE;
125 if (stat(historyfile, &histstat) == 0) { /* history file exists */
126 if ((histstat.st_mode & S_IFMT) != S_IFREG) {
127 fprintf(stderr,
128 "Vinum history file %s must be a regular file\n",
129 historyfile);
130 exit(1);
132 } else if ((errno != ENOENT) /* not "not there", */
133 &&(errno != EROFS)) { /* and not read-only file system */
134 fprintf(stderr,
135 "Can't open %s: %s (%d)\n",
136 historyfile,
137 strerror(errno),
138 errno);
139 exit(1);
141 hist = fopen(historyfile, "a+");
142 if (hist != NULL) {
143 timestamp();
144 fprintf(hist, "*** " VINUMMOD " started ***\n");
145 fflush(hist); /* before we start the daemon */
147 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* open vinum superdevice */
148 if (superdev < 0) { /* no go */
149 if (errno == ENODEV) { /* not configured, */
150 superdev = open(VINUM_WRONGSUPERDEV_NAME, O_RDWR); /* do we have a debug mismatch? */
151 if (superdev >= 0) { /* yup! */
152 #if VINUMDEBUG
153 fprintf(stderr,
154 "This program is compiled with debug support, but the kernel module does\n"
155 "not have debug support. This program must be matched with the kernel\n"
156 "module. Please alter /usr/src/sbin/" VINUMMOD "/Makefile and remove\n"
157 "the option -DVINUMDEBUG from the CFLAGS definition, or alternatively\n"
158 "edit /usr/src/sys/modules/" VINUMMOD "/Makefile and add the option\n"
159 "-DVINUMDEBUG to the CFLAGS definition. Then rebuild the component\n"
160 "of your choice with 'make clean all install'. If you rebuild the kernel\n"
161 "module, you must stop " VINUMMOD " and restart it\n");
162 #else
163 fprintf(stderr,
164 "This program is compiled without debug support, but the kernel module\n"
165 "includes debug support. This program must be matched with the kernel\n"
166 "module. Please alter /usr/src/sbin/" VINUMMOD "/Makefile and add\n"
167 "the option -DVINUMDEBUG to the CFLAGS definition, or alternatively\n"
168 "edit /usr/src/sys/modules/" VINUMMOD "/Makefile and remove the option\n"
169 "-DVINUMDEBUG from the CFLAGS definition. Then rebuild the component\n"
170 "of your choice with 'make clean all install'. If you rebuild the kernel\n"
171 "module, you must stop " VINUMMOD " and restart it\n");
172 #endif
173 return 1;
175 } else if (errno == ENOENT) /* we don't have our node, */
176 make_devices(); /* create them first */
177 if (superdev < 0) {
178 perror("Can't open " VINUM_SUPERDEV_NAME);
179 return 1;
182 /* Check if the dæmon is running. If not, start it in the
183 * background */
184 start_daemon();
186 if (argc > 1) { /* we have a command on the line */
187 if (setjmp(command_fail) != 0) /* long jumped out */
188 return -1;
189 parseline(argc - 1, &argv[1]); /* do it */
190 } else {
192 * Catch a possible race condition which could cause us to
193 * longjmp() into nowhere if we receive a SIGINT in the next few
194 * lines.
196 if (setjmp(command_fail)) /* come back here on catastrophic failure */
197 return 1;
198 setsigs(); /* set signal handler */
199 for (;;) { /* ugh */
200 char *c;
201 int childstatus; /* from wait4 */
203 if (setjmp(command_fail) == 2) /* come back here on catastrophic failure */
204 fprintf(stderr, "*** interrupted ***\n"); /* interrupted */
206 while (wait4(-1, &childstatus, WNOHANG, NULL) > 0); /* wait for all dead children */
207 c = readline(VINUMMOD " -> "); /* get an input */
208 if (c == NULL) { /* EOF or error */
209 if (ferror(stdin)) {
210 fprintf(stderr, "Can't read input: %s (%d)\n", strerror(errno), errno);
211 return 1;
212 } else { /* EOF */
213 printf("\n");
214 return 0;
216 } else if (*c) { /* got something there */
217 add_history(c); /* save it in the history */
218 strcpy(buffer, c); /* put it where we can munge it */
219 free(c);
220 line++; /* count the lines */
221 tokens = tokenize(buffer, token);
222 /* got something potentially worth parsing */
223 if (tokens)
224 parseline(tokens, token); /* and do what he says */
226 if (hist)
227 fflush(hist);
230 return 0; /* normal completion */
233 /* stop the hard way */
234 void
235 vinum_quit(int argc, char *argv[], char *argv0[])
237 exit(0);
240 /* Set action on receiving a SIGINT */
241 void
242 setsigs(void)
244 struct sigaction act;
246 act.sa_handler = catchsig;
247 act.sa_flags = 0;
248 sigemptyset(&act.sa_mask);
249 sigaction(SIGINT, &act, NULL);
252 void
253 catchsig(int ignore)
255 longjmp(command_fail, 2);
258 #define FUNKEY(x) { kw_##x, &vinum_##x } /* create pair "kw_foo", vinum_foo */
259 #define vinum_move vinum_mv /* synonym for 'mv' */
261 struct funkey {
262 enum keyword kw;
263 void (*fun) (int argc, char *argv[], char *arg0[]);
264 } funkeys[] = {
266 FUNKEY(create),
267 FUNKEY(read),
268 #ifdef VINUMDEBUG
269 FUNKEY(debug),
270 #endif
271 FUNKEY(modify),
272 FUNKEY(list),
273 FUNKEY(ld),
274 FUNKEY(ls),
275 FUNKEY(lp),
276 FUNKEY(lv),
277 FUNKEY(info),
278 FUNKEY(set),
279 FUNKEY(init),
280 FUNKEY(label),
281 FUNKEY(resetconfig),
282 FUNKEY(rm),
283 FUNKEY(mv),
284 FUNKEY(move),
285 FUNKEY(attach),
286 FUNKEY(detach),
287 FUNKEY(rename),
288 FUNKEY(replace),
289 FUNKEY(printconfig),
290 FUNKEY(saveconfig),
291 FUNKEY(start),
292 FUNKEY(stop),
293 FUNKEY(makedev),
294 FUNKEY(help),
295 FUNKEY(quit),
296 FUNKEY(concat),
297 FUNKEY(stripe),
298 FUNKEY(raid4),
299 FUNKEY(raid5),
300 FUNKEY(mirror),
301 FUNKEY(setdaemon),
302 FUNKEY(readpol),
303 FUNKEY(resetstats),
304 FUNKEY(setstate),
305 FUNKEY(checkparity),
306 FUNKEY(rebuildparity),
307 FUNKEY(dumpconfig)
310 /* Take args arguments at argv and attempt to perform the operation specified */
311 void
312 parseline(int args, char *argv[])
314 int i;
315 int j;
316 enum keyword command; /* command to execute */
318 if (hist != NULL) { /* save the command to history file */
319 timestamp();
320 for (i = 0; i < args; i++) /* all args */
321 fprintf(hist, "%s ", argv[i]);
322 fputs("\n", hist);
324 if ((args == 0) /* empty line */
325 ||(*argv[0] == '#')) /* or a comment, */
326 return;
327 if (args == MAXARGS) { /* too many arguments, */
328 fprintf(stderr, "Too many arguments to %s, this can't be right\n", argv[0]);
329 return;
331 command = get_keyword(argv[0], &keyword_set);
332 dowait = 0; /* initialize flags */
333 force = 0; /* initialize flags */
334 vflag = 0; /* initialize flags */
335 Verbose = 0; /* initialize flags */
336 recurse = 0; /* initialize flags */
337 sflag = 0; /* initialize flags */
338 objectname = NULL; /* no name yet */
341 * first handle generic options
342 * We don't use getopt(3) because
343 * getopt doesn't allow merging flags
344 * (for example, -fr).
346 for (i = 1; (i < args) && (argv[i][0] == '-'); i++) { /* while we have flags */
347 for (j = 1; j < strlen(argv[i]); j++)
348 switch (argv[i][j]) {
349 #if VINUMDEBUG
350 case 'd': /* -d: debug */
351 debug = 1;
352 break;
353 #endif
355 case 'f': /* -f: force */
356 force = 1;
357 break;
359 case 'i': /* interval */
360 interval = 0;
361 if (argv[i][j + 1] != '\0') /* operand follows, */
362 interval = atoi(&argv[i][j + 1]); /* use it */
363 else if (args > (i + 1)) /* another following, */
364 interval = atoi(argv[++i]); /* use it */
365 if (interval == 0) /* nothing valid, */
366 fprintf(stderr, "-i: no interval specified\n");
367 break;
369 case 'n': /* -n: get name */
370 if (i == args - 1) { /* last arg */
371 fprintf(stderr, "-n requires a name parameter\n");
372 return;
374 objectname = argv[++i]; /* pick it up */
375 j = strlen(argv[i]); /* skip the next parm */
376 break;
378 case 'r': /* -r: recurse */
379 recurse = 1;
380 break;
382 case 's': /* -s: show statistics */
383 sflag = 1;
384 break;
386 case 'S':
387 SSize = 0;
388 if (argv[i][j + 1] != '\0') /* operand follows, */
389 SSize = atoi(&argv[i][j + 1]); /* use it */
390 else if (args > (i + 1)) /* another following, */
391 SSize = atoi(argv[++i]); /* use it */
392 if (SSize == 0) /* nothing valid, */
393 fprintf(stderr, "-S: no size specified\n");
394 break;
396 case 'v': /* -v: verbose */
397 vflag++;
398 break;
400 case 'V': /* -V: Very verbose */
401 vflag++;
402 Verbose++;
403 break;
405 case 'w': /* -w: wait for completion */
406 dowait = 1;
407 break;
409 default:
410 fprintf(stderr, "Invalid flag: %s\n", argv[i]);
414 /* Pass what we have left to the command to handle it */
415 for (j = 0; j < (sizeof(funkeys) / sizeof(struct funkey)); j++) {
416 if (funkeys[j].kw == command) { /* found the command */
417 funkeys[j].fun(args - i, &argv[i], &argv[0]);
418 return;
421 fprintf(stderr, "Unknown command: %s\n", argv[0]);
424 void
425 get_drive_info(struct drive *drive, int index)
427 *(int *) drive = index; /* put in drive to hand to driver */
428 if (ioctl(superdev, VINUM_DRIVECONFIG, drive) < 0) {
429 fprintf(stderr,
430 "Can't get config for drive %d: %s\n",
431 index,
432 strerror(errno));
433 longjmp(command_fail, -1);
437 void
438 get_sd_info(struct sd *sd, int index)
440 *(int *) sd = index; /* put in sd to hand to driver */
441 if (ioctl(superdev, VINUM_SDCONFIG, sd) < 0) {
442 fprintf(stderr,
443 "Can't get config for subdisk %d: %s\n",
444 index,
445 strerror(errno));
446 longjmp(command_fail, -1);
450 /* Get the contents of the sd entry for subdisk <sdno>
451 * of the specified plex. */
452 void
453 get_plex_sd_info(struct sd *sd, int plexno, int sdno)
455 ((int *) sd)[0] = plexno;
456 ((int *) sd)[1] = sdno; /* pass parameters */
457 if (ioctl(superdev, VINUM_PLEXSDCONFIG, sd) < 0) {
458 fprintf(stderr,
459 "Can't get config for subdisk %d (part of plex %d): %s\n",
460 sdno,
461 plexno,
462 strerror(errno));
463 longjmp(command_fail, -1);
467 void
468 get_plex_info(struct plex *plex, int index)
470 *(int *) plex = index; /* put in plex to hand to driver */
471 if (ioctl(superdev, VINUM_PLEXCONFIG, plex) < 0) {
472 fprintf(stderr,
473 "Can't get config for plex %d: %s\n",
474 index,
475 strerror(errno));
476 longjmp(command_fail, -1);
480 void
481 get_volume_info(struct volume *volume, int index)
483 *(int *) volume = index; /* put in volume to hand to driver */
484 if (ioctl(superdev, VINUM_VOLCONFIG, volume) < 0) {
485 fprintf(stderr,
486 "Can't get config for volume %d: %s\n",
487 index,
488 strerror(errno));
489 longjmp(command_fail, -1);
493 struct drive *
494 find_drive_by_devname(char *name)
496 int driveno;
498 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
499 perror("Can't get vinum config");
500 return NULL;
502 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
503 get_drive_info(&drive, driveno);
504 if ((drive.state != drive_unallocated) /* real drive */
505 &&(!strcmp(drive.devicename, name))) /* and the name's right, */
506 return &drive; /* found it */
508 return NULL; /* no drive of that name */
511 /* Create the device nodes for vinum objects */
512 void
513 make_devices(void)
515 int volno;
516 int plexno;
517 int sdno;
518 int driveno;
520 if (access("/dev", W_OK) < 0) { /* can't access /dev to write? */
521 if (errno == EROFS) /* because it's read-only, */
522 fprintf(stderr, VINUMMOD ": /dev is mounted read-only, not rebuilding " VINUM_DIR "\n");
523 else
524 perror(VINUMMOD ": Can't write to /dev");
525 return;
527 if (hist) {
528 timestamp();
529 fprintf(hist, "*** Created devices ***\n");
531 if (superdev >= 0) /* super device open */
532 close(superdev);
534 system("rm -rf " VINUM_DIR); /* remove the old directories */
535 system("mkdir -p " VINUM_DIR "/drive " /* and make them again */
536 VINUM_DIR "/plex "
537 VINUM_DIR "/sd "
538 VINUM_DIR "/vol");
540 if (mknod(VINUM_SUPERDEV_NAME,
541 S_IRUSR | S_IWUSR | S_IFCHR, /* user only */
542 makedev(VINUM_CDEV_MAJOR, VINUM_SUPERDEV)) < 0)
543 fprintf(stderr, "Can't create %s: %s\n", VINUM_SUPERDEV_NAME, strerror(errno));
545 if (mknod(VINUM_WRONGSUPERDEV_NAME,
546 S_IRUSR | S_IWUSR | S_IFCHR, /* user only */
547 makedev(VINUM_CDEV_MAJOR, VINUM_WRONGSUPERDEV)) < 0)
548 fprintf(stderr, "Can't create %s: %s\n", VINUM_WRONGSUPERDEV_NAME, strerror(errno));
550 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* open the super device */
552 if (mknod(VINUM_DAEMON_DEV_NAME, /* daemon super device */
553 S_IRUSR | S_IWUSR | S_IFCHR, /* user only */
554 makedev(VINUM_CDEV_MAJOR, VINUM_DAEMON_DEV)) < 0)
555 fprintf(stderr, "Can't create %s: %s\n", VINUM_DAEMON_DEV_NAME, strerror(errno));
557 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
558 perror("Can't get vinum config");
559 return;
561 for (volno = 0; volno < vinum_conf.volumes_allocated; volno++)
562 make_vol_dev(volno, 0);
564 for (plexno = 0; plexno < vinum_conf.plexes_allocated; plexno++)
565 make_plex_dev(plexno, 0);
567 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++)
568 make_sd_dev(sdno);
570 /* Drives. Do this later (both logical and physical names) XXX */
571 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
572 char filename[PATH_MAX]; /* for forming file names */
574 get_drive_info(&drive, driveno);
575 if (drive.state > drive_referenced) {
576 sprintf(filename, "ln -s %s " VINUM_DIR "/drive/%s", drive.devicename, drive.label.name);
577 system(filename);
582 /* make the devices for a volume */
583 void
584 make_vol_dev(int volno, int recurse)
586 dev_t voldev;
587 char filename[PATH_MAX]; /* for forming file names */
588 int plexno;
590 get_volume_info(&vol, volno);
591 if (vol.state != volume_unallocated) { /* we could have holes in our lists */
592 voldev = VINUMDEV(volno, 0, 0, VINUM_VOLUME_TYPE); /* create a device number */
594 /* Create /dev/vinum/<myvol> */
595 sprintf(filename, VINUM_DIR "/%s", vol.name);
596 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, voldev) < 0)
597 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
599 /* Create /dev/vinum/vol/<myvol> */
600 sprintf(filename, VINUM_DIR "/vol/%s", vol.name);
601 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, voldev) < 0)
602 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
604 if (vol.plexes > 0) {
605 /* Create /dev/vinum/vol/<myvol>.plex/ */
606 sprintf(filename, VINUM_DIR "/vol/%s.plex", vol.name);
607 if (mkdir(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IXOTH) < 0)
608 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
610 if (recurse)
611 for (plexno = 0; plexno < vol.plexes; plexno++)
612 make_plex_dev(plex.plexno, recurse);
617 * Create device entries for the plexes in
618 * /dev/vinum/<vol>.plex/ and /dev/vinum/plex.
620 void
621 make_plex_dev(int plexno, int recurse)
623 dev_t plexdev; /* device */
624 char filename[PATH_MAX]; /* for forming file names */
625 int sdno;
627 get_plex_info(&plex, plexno);
628 if (plex.state != plex_unallocated) {
629 plexdev = VINUM_PLEX(plexno);
631 /* /dev/vinum/plex/<plex> */
632 sprintf(filename, VINUM_DIR "/plex/%s", plex.name);
633 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, plexdev) < 0)
634 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
636 if (plex.volno >= 0) {
637 get_volume_info(&vol, plex.volno);
638 plexdev = VINUMDEV(plex.volno, plexno, 0, VINUM_PLEX_TYPE);
640 /* Create device /dev/vinum/vol/<vol>.plex/<plex> */
641 sprintf(filename, VINUM_DIR "/vol/%s.plex/%s", vol.name, plex.name);
642 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, plexdev) < 0)
643 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
645 /* Create directory /dev/vinum/vol/<vol>.plex/<plex>.sd */
646 sprintf(filename, VINUM_DIR "/vol/%s.plex/%s.sd", vol.name, plex.name);
647 if (mkdir(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IXOTH) < 0)
648 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
650 if (recurse) {
651 for (sdno = 0; sdno < plex.subdisks; sdno++) {
652 get_plex_sd_info(&sd, plex.plexno, sdno);
653 make_sd_dev(sd.sdno);
659 /* Create the contents of /dev/vinum/sd and /dev/vinum/rsd */
660 void
661 make_sd_dev(int sdno)
663 dev_t sddev; /* device */
664 char filename[PATH_MAX]; /* for forming file names */
666 get_sd_info(&sd, sdno);
667 if (sd.state != sd_unallocated) {
668 sddev = VINUM_SD(sdno);
670 /* /dev/vinum/sd/<sd> */
671 sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
672 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, sddev) < 0)
673 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
678 /* command line interface for the 'makedev' command */
679 void
680 vinum_makedev(int argc, char *argv[], char *arg0[])
682 make_devices();
686 * Find the object "name". Return object type at type,
687 * and the index as the return value.
688 * If not found, return -1 and invalid_object.
691 find_object(const char *name, enum objecttype *type)
693 int object;
695 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
696 perror("Can't get vinum config");
697 *type = invalid_object;
698 return -1;
700 /* Search the drive table */
701 for (object = 0; object < vinum_conf.drives_allocated; object++) {
702 get_drive_info(&drive, object);
703 if (strcmp(name, drive.label.name) == 0) {
704 *type = drive_object;
705 return object;
709 /* Search the subdisk table */
710 for (object = 0; object < vinum_conf.subdisks_allocated; object++) {
711 get_sd_info(&sd, object);
712 if (strcmp(name, sd.name) == 0) {
713 *type = sd_object;
714 return object;
718 /* Search the plex table */
719 for (object = 0; object < vinum_conf.plexes_allocated; object++) {
720 get_plex_info(&plex, object);
721 if (strcmp(name, plex.name) == 0) {
722 *type = plex_object;
723 return object;
727 /* Search the volume table */
728 for (object = 0; object < vinum_conf.volumes_allocated; object++) {
729 get_volume_info(&vol, object);
730 if (strcmp(name, vol.name) == 0) {
731 *type = volume_object;
732 return object;
736 /* Didn't find the name: invalid */
737 *type = invalid_object;
738 return -1;
741 /* Continue reviving a subdisk in the background */
742 void
743 continue_revive(int sdno)
745 struct sd sd;
746 pid_t pid;
747 get_sd_info(&sd, sdno);
749 if (dowait == 0)
750 pid = fork(); /* do this in the background */
751 else
752 pid = 0;
753 if (pid == 0) { /* we're the child */
754 struct _ioctl_reply reply;
755 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
757 openlog(VINUMMOD, LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
758 syslog(LOG_INFO | LOG_KERN, "reviving %s", sd.name);
759 setproctitle("reviving %s", sd.name);
761 for (reply.error = EAGAIN; reply.error == EAGAIN;) { /* revive the subdisk */
762 if (interval)
763 usleep(interval * 1000); /* pause between each copy */
764 message->index = sdno; /* pass sd number */
765 message->type = sd_object; /* and type of object */
766 message->state = object_up;
767 if (SSize != 0) { /* specified a size for init */
768 if (SSize < 512)
769 SSize <<= DEV_BSHIFT;
770 message->blocksize = SSize;
771 } else
772 message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
773 ioctl(superdev, VINUM_SETSTATE, message);
775 if (reply.error) {
776 syslog(LOG_ERR | LOG_KERN,
777 "can't revive %s: %s",
778 sd.name,
779 reply.msg[0] ? reply.msg : strerror(reply.error));
780 if (dowait == 0)
781 exit(1);
782 } else {
783 get_sd_info(&sd, sdno); /* update the info */
784 syslog(LOG_INFO | LOG_KERN, "%s is %s", sd.name, sd_state(sd.state));
785 if (dowait == 0)
786 exit(0);
788 } else if (pid < 0) /* couldn't fork? */
789 fprintf(stderr, "Can't continue reviving %s: %s\n", sd.name, strerror(errno));
790 else /* parent */
791 printf("Reviving %s in the background\n", sd.name);
795 * Check if the daemon is running,
796 * start it if it isn't. The check itself
797 * could take a while, so we do it as a separate
798 * process, which will become the daemon if one isn't
799 * running already
801 void
802 start_daemon(void)
804 int pid;
805 int status;
806 int error;
808 pid = (int) fork();
810 if (pid == 0) { /* We're the child, do the work */
812 * We have a problem when stopping the subsystem:
813 * The only way to know that we're idle is when
814 * all open superdevs close. But we want the
815 * daemon to clean up for us, and since we can't
816 * count the opens, we need to have the main device
817 * closed when we stop. We solve this conundrum
818 * by getting the daemon to open a separate device.
820 close(superdev); /* this is the wrong device */
821 superdev = open(VINUM_DAEMON_DEV_NAME, O_RDWR); /* open deamon superdevice */
822 if (superdev < 0) {
823 perror("Can't open " VINUM_DAEMON_DEV_NAME);
824 exit(1);
826 error = daemon(0, 0); /* this will fork again, but who's counting? */
827 if (error != 0) {
828 fprintf(stderr, "Can't start daemon: %s (%d)\n", strerror(errno), errno);
829 exit(1);
831 setproctitle(VINUMMOD " daemon"); /* show what we're doing */
832 status = ioctl(superdev, VINUM_FINDDAEMON, NULL);
833 if (status != 0) { /* no daemon, */
834 ioctl(superdev, VINUM_DAEMON, &vflag); /* we should hang here */
835 syslog(LOG_ERR | LOG_KERN, "%s", strerror(errno));
836 exit(1);
838 exit(0); /* when told to die */
839 } else if (pid < 0) /* couldn't fork */
840 printf("Can't fork to check daemon\n");
843 void
844 timestamp(void)
846 struct timeval now;
847 struct tm *date;
848 char datetext[MAXDATETEXT];
849 time_t sec;
851 if (hist != NULL) {
852 if (gettimeofday(&now, NULL) != 0) {
853 fprintf(stderr, "Can't get time: %s\n", strerror(errno));
854 return;
856 sec = now.tv_sec;
857 date = localtime(&sec);
858 strftime(datetext, MAXDATETEXT, dateformat, date),
859 fprintf(hist,
860 "%s.%06ld ",
861 datetext,
862 now.tv_usec);