Hook resident.conf(5) and varsym.conf(5) into the build and add some
[dragonfly/vkernel-mp.git] / sbin / vinum / v.c
blob375ee0cda2e26044a8a54deee3fbdb0b45ebe7fb
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.5 2007/01/20 20:20:39 dillon 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/history.h>
58 #include <readline/readline.h>
59 #include <sys/linker.h>
60 #include <sys/module.h>
61 #include <sys/resource.h>
63 FILE *cf; /* config file handle */
64 FILE *history; /* history file */
65 char *historyfile; /* and its name */
67 char *dateformat; /* format in which to store date */
69 char buffer[BUFSIZE]; /* buffer to read in to */
71 int line = 0; /* stdin line number for error messages */
72 int file_line = 0; /* and line in input file (yes, this is tacky) */
73 int inerror; /* set to 1 to exit after end of config file */
75 /* flags */
77 #if VINUMDEBUG
78 int debug = 0; /* debug flag, usage varies */
79 #endif
80 int force = 0; /* set to 1 to force some dangerous ops */
81 int interval = 0; /* interval in ms between init/revive */
82 int vflag = 0; /* set verbose operation or verify */
83 int Verbose = 0; /* set very verbose operation */
84 int recurse = 0; /* set recursion */
85 int sflag = 0; /* show statistics */
86 int SSize = 0; /* sector size for revive */
87 int dowait = 0; /* wait for completion */
88 char *objectname; /* name to be passed for -n flag */
90 /* Structures to read kernel data into */
91 struct _vinum_conf vinum_conf; /* configuration information */
93 struct volume vol;
94 struct plex plex;
95 struct sd sd;
96 struct drive drive;
98 jmp_buf command_fail; /* return on a failed command */
99 int superdev; /* vinum super device */
101 void start_daemon(void);
103 #define ofs(x) ((void *) (& ((struct confdata *) 0)->x)) /* offset of x in struct confdata */
105 char *token[MAXARGS]; /* pointers to individual tokens */
106 int tokens; /* number of tokens */
109 main(int argc, char *argv[], char *envp[])
111 struct stat histstat;
113 if (modfind(VINUMMOD) < 0) {
114 /* need to load the vinum module */
115 if (kldload(VINUMMOD) < 0 || modfind(VINUMMOD) < 0) {
116 perror(VINUMMOD ": Kernel module not available");
117 return 1;
120 dateformat = getenv("VINUM_DATEFORMAT");
121 if (dateformat == NULL)
122 dateformat = "%e %b %Y %H:%M:%S";
123 historyfile = getenv("VINUM_HISTORY");
124 if (historyfile == NULL)
125 historyfile = DEFAULT_HISTORYFILE;
126 if (stat(historyfile, &histstat) == 0) { /* history file exists */
127 if ((histstat.st_mode & S_IFMT) != S_IFREG) {
128 fprintf(stderr,
129 "Vinum history file %s must be a regular file\n",
130 historyfile);
131 exit(1);
133 } else if ((errno != ENOENT) /* not "not there", */
134 &&(errno != EROFS)) { /* and not read-only file system */
135 fprintf(stderr,
136 "Can't open %s: %s (%d)\n",
137 historyfile,
138 strerror(errno),
139 errno);
140 exit(1);
142 history = fopen(historyfile, "a+");
143 if (history != NULL) {
144 timestamp();
145 fprintf(history, "*** " VINUMMOD " started ***\n");
146 fflush(history); /* before we start the daemon */
148 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* open vinum superdevice */
149 if (superdev < 0) { /* no go */
150 if (errno == ENODEV) { /* not configured, */
151 superdev = open(VINUM_WRONGSUPERDEV_NAME, O_RDWR); /* do we have a debug mismatch? */
152 if (superdev >= 0) { /* yup! */
153 #if VINUMDEBUG
154 fprintf(stderr,
155 "This program is compiled with debug support, but the kernel module does\n"
156 "not have debug support. This program must be matched with the kernel\n"
157 "module. Please alter /usr/src/sbin/" VINUMMOD "/Makefile and remove\n"
158 "the option -DVINUMDEBUG from the CFLAGS definition, or alternatively\n"
159 "edit /usr/src/sys/modules/" VINUMMOD "/Makefile and add the option\n"
160 "-DVINUMDEBUG to the CFLAGS definition. Then rebuild the component\n"
161 "of your choice with 'make clean all install'. If you rebuild the kernel\n"
162 "module, you must stop " VINUMMOD " and restart it\n");
163 #else
164 fprintf(stderr,
165 "This program is compiled without debug support, but the kernel module\n"
166 "includes debug support. This program must be matched with the kernel\n"
167 "module. Please alter /usr/src/sbin/" VINUMMOD "/Makefile and add\n"
168 "the option -DVINUMDEBUG to the CFLAGS definition, or alternatively\n"
169 "edit /usr/src/sys/modules/" VINUMMOD "/Makefile and remove the option\n"
170 "-DVINUMDEBUG from the CFLAGS definition. Then rebuild the component\n"
171 "of your choice with 'make clean all install'. If you rebuild the kernel\n"
172 "module, you must stop " VINUMMOD " and restart it\n");
173 #endif
174 return 1;
176 } else if (errno == ENOENT) /* we don't have our node, */
177 make_devices(); /* create them first */
178 if (superdev < 0) {
179 perror("Can't open " VINUM_SUPERDEV_NAME);
180 return 1;
183 /* Check if the dæmon is running. If not, start it in the
184 * background */
185 start_daemon();
187 if (argc > 1) { /* we have a command on the line */
188 if (setjmp(command_fail) != 0) /* long jumped out */
189 return -1;
190 parseline(argc - 1, &argv[1]); /* do it */
191 } else {
193 * Catch a possible race condition which could cause us to
194 * longjmp() into nowhere if we receive a SIGINT in the next few
195 * lines.
197 if (setjmp(command_fail)) /* come back here on catastrophic failure */
198 return 1;
199 setsigs(); /* set signal handler */
200 for (;;) { /* ugh */
201 char *c;
202 int childstatus; /* from wait4 */
204 if (setjmp(command_fail) == 2) /* come back here on catastrophic failure */
205 fprintf(stderr, "*** interrupted ***\n"); /* interrupted */
207 while (wait4(-1, &childstatus, WNOHANG, NULL) > 0); /* wait for all dead children */
208 c = readline(VINUMMOD " -> "); /* get an input */
209 if (c == NULL) { /* EOF or error */
210 if (ferror(stdin)) {
211 fprintf(stderr, "Can't read input: %s (%d)\n", strerror(errno), errno);
212 return 1;
213 } else { /* EOF */
214 printf("\n");
215 return 0;
217 } else if (*c) { /* got something there */
218 add_history(c); /* save it in the history */
219 strcpy(buffer, c); /* put it where we can munge it */
220 free(c);
221 line++; /* count the lines */
222 tokens = tokenize(buffer, token);
223 /* got something potentially worth parsing */
224 if (tokens)
225 parseline(tokens, token); /* and do what he says */
227 if (history)
228 fflush(history);
231 return 0; /* normal completion */
234 /* stop the hard way */
235 void
236 vinum_quit(int argc, char *argv[], char *argv0[])
238 exit(0);
241 /* Set action on receiving a SIGINT */
242 void
243 setsigs(void)
245 struct sigaction act;
247 act.sa_handler = catchsig;
248 act.sa_flags = 0;
249 sigemptyset(&act.sa_mask);
250 sigaction(SIGINT, &act, NULL);
253 void
254 catchsig(int ignore)
256 longjmp(command_fail, 2);
259 #define FUNKEY(x) { kw_##x, &vinum_##x } /* create pair "kw_foo", vinum_foo */
260 #define vinum_move vinum_mv /* synonym for 'mv' */
262 struct funkey {
263 enum keyword kw;
264 void (*fun) (int argc, char *argv[], char *arg0[]);
265 } funkeys[] = {
267 FUNKEY(create),
268 FUNKEY(read),
269 #ifdef VINUMDEBUG
270 FUNKEY(debug),
271 #endif
272 FUNKEY(modify),
273 FUNKEY(list),
274 FUNKEY(ld),
275 FUNKEY(ls),
276 FUNKEY(lp),
277 FUNKEY(lv),
278 FUNKEY(info),
279 FUNKEY(set),
280 FUNKEY(init),
281 FUNKEY(label),
282 FUNKEY(resetconfig),
283 FUNKEY(rm),
284 FUNKEY(mv),
285 FUNKEY(move),
286 FUNKEY(attach),
287 FUNKEY(detach),
288 FUNKEY(rename),
289 FUNKEY(replace),
290 FUNKEY(printconfig),
291 FUNKEY(saveconfig),
292 FUNKEY(start),
293 FUNKEY(stop),
294 FUNKEY(makedev),
295 FUNKEY(help),
296 FUNKEY(quit),
297 FUNKEY(concat),
298 FUNKEY(stripe),
299 FUNKEY(raid4),
300 FUNKEY(raid5),
301 FUNKEY(mirror),
302 FUNKEY(setdaemon),
303 FUNKEY(readpol),
304 FUNKEY(resetstats),
305 FUNKEY(setstate),
306 FUNKEY(checkparity),
307 FUNKEY(rebuildparity),
308 FUNKEY(dumpconfig)
311 /* Take args arguments at argv and attempt to perform the operation specified */
312 void
313 parseline(int args, char *argv[])
315 int i;
316 int j;
317 enum keyword command; /* command to execute */
319 if (history != NULL) { /* save the command to history file */
320 timestamp();
321 for (i = 0; i < args; i++) /* all args */
322 fprintf(history, "%s ", argv[i]);
323 fputs("\n", history);
325 if ((args == 0) /* empty line */
326 ||(*argv[0] == '#')) /* or a comment, */
327 return;
328 if (args == MAXARGS) { /* too many arguments, */
329 fprintf(stderr, "Too many arguments to %s, this can't be right\n", argv[0]);
330 return;
332 command = get_keyword(argv[0], &keyword_set);
333 dowait = 0; /* initialize flags */
334 force = 0; /* initialize flags */
335 vflag = 0; /* initialize flags */
336 Verbose = 0; /* initialize flags */
337 recurse = 0; /* initialize flags */
338 sflag = 0; /* initialize flags */
339 objectname = NULL; /* no name yet */
342 * first handle generic options
343 * We don't use getopt(3) because
344 * getopt doesn't allow merging flags
345 * (for example, -fr).
347 for (i = 1; (i < args) && (argv[i][0] == '-'); i++) { /* while we have flags */
348 for (j = 1; j < strlen(argv[i]); j++)
349 switch (argv[i][j]) {
350 #if VINUMDEBUG
351 case 'd': /* -d: debug */
352 debug = 1;
353 break;
354 #endif
356 case 'f': /* -f: force */
357 force = 1;
358 break;
360 case 'i': /* interval */
361 interval = 0;
362 if (argv[i][j + 1] != '\0') /* operand follows, */
363 interval = atoi(&argv[i][j + 1]); /* use it */
364 else if (args > (i + 1)) /* another following, */
365 interval = atoi(argv[++i]); /* use it */
366 if (interval == 0) /* nothing valid, */
367 fprintf(stderr, "-i: no interval specified\n");
368 break;
370 case 'n': /* -n: get name */
371 if (i == args - 1) { /* last arg */
372 fprintf(stderr, "-n requires a name parameter\n");
373 return;
375 objectname = argv[++i]; /* pick it up */
376 j = strlen(argv[i]); /* skip the next parm */
377 break;
379 case 'r': /* -r: recurse */
380 recurse = 1;
381 break;
383 case 's': /* -s: show statistics */
384 sflag = 1;
385 break;
387 case 'S':
388 SSize = 0;
389 if (argv[i][j + 1] != '\0') /* operand follows, */
390 SSize = atoi(&argv[i][j + 1]); /* use it */
391 else if (args > (i + 1)) /* another following, */
392 SSize = atoi(argv[++i]); /* use it */
393 if (SSize == 0) /* nothing valid, */
394 fprintf(stderr, "-S: no size specified\n");
395 break;
397 case 'v': /* -v: verbose */
398 vflag++;
399 break;
401 case 'V': /* -V: Very verbose */
402 vflag++;
403 Verbose++;
404 break;
406 case 'w': /* -w: wait for completion */
407 dowait = 1;
408 break;
410 default:
411 fprintf(stderr, "Invalid flag: %s\n", argv[i]);
415 /* Pass what we have left to the command to handle it */
416 for (j = 0; j < (sizeof(funkeys) / sizeof(struct funkey)); j++) {
417 if (funkeys[j].kw == command) { /* found the command */
418 funkeys[j].fun(args - i, &argv[i], &argv[0]);
419 return;
422 fprintf(stderr, "Unknown command: %s\n", argv[0]);
425 void
426 get_drive_info(struct drive *drive, int index)
428 *(int *) drive = index; /* put in drive to hand to driver */
429 if (ioctl(superdev, VINUM_DRIVECONFIG, drive) < 0) {
430 fprintf(stderr,
431 "Can't get config for drive %d: %s\n",
432 index,
433 strerror(errno));
434 longjmp(command_fail, -1);
438 void
439 get_sd_info(struct sd *sd, int index)
441 *(int *) sd = index; /* put in sd to hand to driver */
442 if (ioctl(superdev, VINUM_SDCONFIG, sd) < 0) {
443 fprintf(stderr,
444 "Can't get config for subdisk %d: %s\n",
445 index,
446 strerror(errno));
447 longjmp(command_fail, -1);
451 /* Get the contents of the sd entry for subdisk <sdno>
452 * of the specified plex. */
453 void
454 get_plex_sd_info(struct sd *sd, int plexno, int sdno)
456 ((int *) sd)[0] = plexno;
457 ((int *) sd)[1] = sdno; /* pass parameters */
458 if (ioctl(superdev, VINUM_PLEXSDCONFIG, sd) < 0) {
459 fprintf(stderr,
460 "Can't get config for subdisk %d (part of plex %d): %s\n",
461 sdno,
462 plexno,
463 strerror(errno));
464 longjmp(command_fail, -1);
468 void
469 get_plex_info(struct plex *plex, int index)
471 *(int *) plex = index; /* put in plex to hand to driver */
472 if (ioctl(superdev, VINUM_PLEXCONFIG, plex) < 0) {
473 fprintf(stderr,
474 "Can't get config for plex %d: %s\n",
475 index,
476 strerror(errno));
477 longjmp(command_fail, -1);
481 void
482 get_volume_info(struct volume *volume, int index)
484 *(int *) volume = index; /* put in volume to hand to driver */
485 if (ioctl(superdev, VINUM_VOLCONFIG, volume) < 0) {
486 fprintf(stderr,
487 "Can't get config for volume %d: %s\n",
488 index,
489 strerror(errno));
490 longjmp(command_fail, -1);
494 struct drive *
495 find_drive_by_devname(char *name)
497 int driveno;
499 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
500 perror("Can't get vinum config");
501 return NULL;
503 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
504 get_drive_info(&drive, driveno);
505 if ((drive.state != drive_unallocated) /* real drive */
506 &&(!strcmp(drive.devicename, name))) /* and the name's right, */
507 return &drive; /* found it */
509 return NULL; /* no drive of that name */
512 /* Create the device nodes for vinum objects */
513 void
514 make_devices(void)
516 int volno;
517 int plexno;
518 int sdno;
519 int driveno;
521 if (access("/dev", W_OK) < 0) { /* can't access /dev to write? */
522 if (errno == EROFS) /* because it's read-only, */
523 fprintf(stderr, VINUMMOD ": /dev is mounted read-only, not rebuilding " VINUM_DIR "\n");
524 else
525 perror(VINUMMOD ": Can't write to /dev");
526 return;
528 if (history) {
529 timestamp();
530 fprintf(history, "*** Created devices ***\n");
532 if (superdev >= 0) /* super device open */
533 close(superdev);
535 system("rm -rf " VINUM_DIR); /* remove the old directories */
536 system("mkdir -p " VINUM_DIR "/drive " /* and make them again */
537 VINUM_DIR "/plex "
538 VINUM_DIR "/sd "
539 VINUM_DIR "/vol");
541 if (mknod(VINUM_SUPERDEV_NAME,
542 S_IRUSR | S_IWUSR | S_IFCHR, /* user only */
543 makedev(VINUM_CDEV_MAJOR, VINUM_SUPERDEV)) < 0)
544 fprintf(stderr, "Can't create %s: %s\n", VINUM_SUPERDEV_NAME, strerror(errno));
546 if (mknod(VINUM_WRONGSUPERDEV_NAME,
547 S_IRUSR | S_IWUSR | S_IFCHR, /* user only */
548 makedev(VINUM_CDEV_MAJOR, VINUM_WRONGSUPERDEV)) < 0)
549 fprintf(stderr, "Can't create %s: %s\n", VINUM_WRONGSUPERDEV_NAME, strerror(errno));
551 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* open the super device */
553 if (mknod(VINUM_DAEMON_DEV_NAME, /* daemon super device */
554 S_IRUSR | S_IWUSR | S_IFCHR, /* user only */
555 makedev(VINUM_CDEV_MAJOR, VINUM_DAEMON_DEV)) < 0)
556 fprintf(stderr, "Can't create %s: %s\n", VINUM_DAEMON_DEV_NAME, strerror(errno));
558 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
559 perror("Can't get vinum config");
560 return;
562 for (volno = 0; volno < vinum_conf.volumes_allocated; volno++)
563 make_vol_dev(volno, 0);
565 for (plexno = 0; plexno < vinum_conf.plexes_allocated; plexno++)
566 make_plex_dev(plexno, 0);
568 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++)
569 make_sd_dev(sdno);
571 /* Drives. Do this later (both logical and physical names) XXX */
572 for (driveno = 0; driveno < vinum_conf.drives_allocated; driveno++) {
573 char filename[PATH_MAX]; /* for forming file names */
575 get_drive_info(&drive, driveno);
576 if (drive.state > drive_referenced) {
577 sprintf(filename, "ln -s %s " VINUM_DIR "/drive/%s", drive.devicename, drive.label.name);
578 system(filename);
583 /* make the devices for a volume */
584 void
585 make_vol_dev(int volno, int recurse)
587 dev_t voldev;
588 char filename[PATH_MAX]; /* for forming file names */
589 int plexno;
591 get_volume_info(&vol, volno);
592 if (vol.state != volume_unallocated) { /* we could have holes in our lists */
593 voldev = VINUMDEV(volno, 0, 0, VINUM_VOLUME_TYPE); /* create a device number */
595 /* Create /dev/vinum/<myvol> */
596 sprintf(filename, VINUM_DIR "/%s", vol.name);
597 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, voldev) < 0)
598 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
600 /* Create /dev/vinum/vol/<myvol> */
601 sprintf(filename, VINUM_DIR "/vol/%s", vol.name);
602 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, voldev) < 0)
603 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
605 if (vol.plexes > 0) {
606 /* Create /dev/vinum/vol/<myvol>.plex/ */
607 sprintf(filename, VINUM_DIR "/vol/%s.plex", vol.name);
608 if (mkdir(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IXOTH) < 0)
609 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
611 if (recurse)
612 for (plexno = 0; plexno < vol.plexes; plexno++)
613 make_plex_dev(plex.plexno, recurse);
618 * Create device entries for the plexes in
619 * /dev/vinum/<vol>.plex/ and /dev/vinum/plex.
621 void
622 make_plex_dev(int plexno, int recurse)
624 dev_t plexdev; /* device */
625 char filename[PATH_MAX]; /* for forming file names */
626 int sdno;
628 get_plex_info(&plex, plexno);
629 if (plex.state != plex_unallocated) {
630 plexdev = VINUM_PLEX(plexno);
632 /* /dev/vinum/plex/<plex> */
633 sprintf(filename, VINUM_DIR "/plex/%s", plex.name);
634 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, plexdev) < 0)
635 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
637 if (plex.volno >= 0) {
638 get_volume_info(&vol, plex.volno);
639 plexdev = VINUMDEV(plex.volno, plexno, 0, VINUM_PLEX_TYPE);
641 /* Create device /dev/vinum/vol/<vol>.plex/<plex> */
642 sprintf(filename, VINUM_DIR "/vol/%s.plex/%s", vol.name, 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 /* Create directory /dev/vinum/vol/<vol>.plex/<plex>.sd */
647 sprintf(filename, VINUM_DIR "/vol/%s.plex/%s.sd", vol.name, plex.name);
648 if (mkdir(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IXOTH) < 0)
649 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
651 if (recurse) {
652 for (sdno = 0; sdno < plex.subdisks; sdno++) {
653 get_plex_sd_info(&sd, plex.plexno, sdno);
654 make_sd_dev(sd.sdno);
660 /* Create the contents of /dev/vinum/sd and /dev/vinum/rsd */
661 void
662 make_sd_dev(int sdno)
664 dev_t sddev; /* device */
665 char filename[PATH_MAX]; /* for forming file names */
667 get_sd_info(&sd, sdno);
668 if (sd.state != sd_unallocated) {
669 sddev = VINUM_SD(sdno);
671 /* /dev/vinum/sd/<sd> */
672 sprintf(filename, VINUM_DIR "/sd/%s", sd.name);
673 if (mknod(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, sddev) < 0)
674 fprintf(stderr, "Can't create %s: %s\n", filename, strerror(errno));
679 /* command line interface for the 'makedev' command */
680 void
681 vinum_makedev(int argc, char *argv[], char *arg0[])
683 make_devices();
687 * Find the object "name". Return object type at type,
688 * and the index as the return value.
689 * If not found, return -1 and invalid_object.
692 find_object(const char *name, enum objecttype *type)
694 int object;
696 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) {
697 perror("Can't get vinum config");
698 *type = invalid_object;
699 return -1;
701 /* Search the drive table */
702 for (object = 0; object < vinum_conf.drives_allocated; object++) {
703 get_drive_info(&drive, object);
704 if (strcmp(name, drive.label.name) == 0) {
705 *type = drive_object;
706 return object;
710 /* Search the subdisk table */
711 for (object = 0; object < vinum_conf.subdisks_allocated; object++) {
712 get_sd_info(&sd, object);
713 if (strcmp(name, sd.name) == 0) {
714 *type = sd_object;
715 return object;
719 /* Search the plex table */
720 for (object = 0; object < vinum_conf.plexes_allocated; object++) {
721 get_plex_info(&plex, object);
722 if (strcmp(name, plex.name) == 0) {
723 *type = plex_object;
724 return object;
728 /* Search the volume table */
729 for (object = 0; object < vinum_conf.volumes_allocated; object++) {
730 get_volume_info(&vol, object);
731 if (strcmp(name, vol.name) == 0) {
732 *type = volume_object;
733 return object;
737 /* Didn't find the name: invalid */
738 *type = invalid_object;
739 return -1;
742 /* Continue reviving a subdisk in the background */
743 void
744 continue_revive(int sdno)
746 struct sd sd;
747 pid_t pid;
748 get_sd_info(&sd, sdno);
750 if (dowait == 0)
751 pid = fork(); /* do this in the background */
752 else
753 pid = 0;
754 if (pid == 0) { /* we're the child */
755 struct _ioctl_reply reply;
756 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply;
758 openlog(VINUMMOD, LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN);
759 syslog(LOG_INFO | LOG_KERN, "reviving %s", sd.name);
760 setproctitle("reviving %s", sd.name);
762 for (reply.error = EAGAIN; reply.error == EAGAIN;) { /* revive the subdisk */
763 if (interval)
764 usleep(interval * 1000); /* pause between each copy */
765 message->index = sdno; /* pass sd number */
766 message->type = sd_object; /* and type of object */
767 message->state = object_up;
768 if (SSize != 0) { /* specified a size for init */
769 if (SSize < 512)
770 SSize <<= DEV_BSHIFT;
771 message->blocksize = SSize;
772 } else
773 message->blocksize = DEFAULT_REVIVE_BLOCKSIZE;
774 ioctl(superdev, VINUM_SETSTATE, message);
776 if (reply.error) {
777 syslog(LOG_ERR | LOG_KERN,
778 "can't revive %s: %s",
779 sd.name,
780 reply.msg[0] ? reply.msg : strerror(reply.error));
781 if (dowait == 0)
782 exit(1);
783 } else {
784 get_sd_info(&sd, sdno); /* update the info */
785 syslog(LOG_INFO | LOG_KERN, "%s is %s", sd.name, sd_state(sd.state));
786 if (dowait == 0)
787 exit(0);
789 } else if (pid < 0) /* couldn't fork? */
790 fprintf(stderr, "Can't continue reviving %s: %s\n", sd.name, strerror(errno));
791 else /* parent */
792 printf("Reviving %s in the background\n", sd.name);
796 * Check if the daemon is running,
797 * start it if it isn't. The check itself
798 * could take a while, so we do it as a separate
799 * process, which will become the daemon if one isn't
800 * running already
802 void
803 start_daemon(void)
805 int pid;
806 int status;
807 int error;
809 pid = (int) fork();
811 if (pid == 0) { /* We're the child, do the work */
813 * We have a problem when stopping the subsystem:
814 * The only way to know that we're idle is when
815 * all open superdevs close. But we want the
816 * daemon to clean up for us, and since we can't
817 * count the opens, we need to have the main device
818 * closed when we stop. We solve this conundrum
819 * by getting the daemon to open a separate device.
821 close(superdev); /* this is the wrong device */
822 superdev = open(VINUM_DAEMON_DEV_NAME, O_RDWR); /* open deamon superdevice */
823 if (superdev < 0) {
824 perror("Can't open " VINUM_DAEMON_DEV_NAME);
825 exit(1);
827 error = daemon(0, 0); /* this will fork again, but who's counting? */
828 if (error != 0) {
829 fprintf(stderr, "Can't start daemon: %s (%d)\n", strerror(errno), errno);
830 exit(1);
832 setproctitle(VINUMMOD " daemon"); /* show what we're doing */
833 status = ioctl(superdev, VINUM_FINDDAEMON, NULL);
834 if (status != 0) { /* no daemon, */
835 ioctl(superdev, VINUM_DAEMON, &vflag); /* we should hang here */
836 syslog(LOG_ERR | LOG_KERN, "%s", strerror(errno));
837 exit(1);
839 exit(0); /* when told to die */
840 } else if (pid < 0) /* couldn't fork */
841 printf("Can't fork to check daemon\n");
844 void
845 timestamp(void)
847 struct timeval now;
848 struct tm *date;
849 char datetext[MAXDATETEXT];
850 time_t sec;
852 if (history != NULL) {
853 if (gettimeofday(&now, NULL) != 0) {
854 fprintf(stderr, "Can't get time: %s\n", strerror(errno));
855 return;
857 sec = now.tv_sec;
858 date = localtime(&sec);
859 strftime(datetext, MAXDATETEXT, dateformat, date),
860 fprintf(history,
861 "%s.%06ld ",
862 datetext,
863 now.tv_usec);