1 /* vinum.c: vinum interface program */
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
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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 $
52 #include <sys/ioctl.h>
53 #include <dev/raid/vinum/vinumhdr.h>
55 #include <sys/types.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 */
77 int debug
= 0; /* debug flag, usage varies */
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 */
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");
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
) {
128 "Vinum history file %s must be a regular file\n",
132 } else if ((errno
!= ENOENT
) /* not "not there", */
133 &&(errno
!= EROFS
)) { /* and not read-only file system */
135 "Can't open %s: %s (%d)\n",
141 hist
= fopen(historyfile
, "a+");
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! */
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");
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");
175 } else if (errno
== ENOENT
) /* we don't have our node, */
176 make_devices(); /* create them first */
178 perror("Can't open " VINUM_SUPERDEV_NAME
);
182 /* Check if the dæmon is running. If not, start it in the
186 if (argc
> 1) { /* we have a command on the line */
187 if (setjmp(command_fail
) != 0) /* long jumped out */
189 parseline(argc
- 1, &argv
[1]); /* do it */
192 * Catch a possible race condition which could cause us to
193 * longjmp() into nowhere if we receive a SIGINT in the next few
196 if (setjmp(command_fail
)) /* come back here on catastrophic failure */
198 setsigs(); /* set signal handler */
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 */
210 fprintf(stderr
, "Can't read input: %s (%d)\n", strerror(errno
), errno
);
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 */
220 line
++; /* count the lines */
221 tokens
= tokenize(buffer
, token
);
222 /* got something potentially worth parsing */
224 parseline(tokens
, token
); /* and do what he says */
230 return 0; /* normal completion */
233 /* stop the hard way */
235 vinum_quit(int argc
, char *argv
[], char *argv0
[])
240 /* Set action on receiving a SIGINT */
244 struct sigaction act
;
246 act
.sa_handler
= catchsig
;
248 sigemptyset(&act
.sa_mask
);
249 sigaction(SIGINT
, &act
, NULL
);
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' */
263 void (*fun
) (int argc
, char *argv
[], char *arg0
[]);
306 FUNKEY(rebuildparity
),
310 /* Take args arguments at argv and attempt to perform the operation specified */
312 parseline(int args
, char *argv
[])
316 enum keyword command
; /* command to execute */
318 if (hist
!= NULL
) { /* save the command to history file */
320 for (i
= 0; i
< args
; i
++) /* all args */
321 fprintf(hist
, "%s ", argv
[i
]);
324 if ((args
== 0) /* empty line */
325 ||(*argv
[0] == '#')) /* or a comment, */
327 if (args
== MAXARGS
) { /* too many arguments, */
328 fprintf(stderr
, "Too many arguments to %s, this can't be right\n", argv
[0]);
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
]) {
350 case 'd': /* -d: debug */
355 case 'f': /* -f: force */
359 case 'i': /* interval */
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");
369 case 'n': /* -n: get name */
370 if (i
== args
- 1) { /* last arg */
371 fprintf(stderr
, "-n requires a name parameter\n");
374 objectname
= argv
[++i
]; /* pick it up */
375 j
= strlen(argv
[i
]); /* skip the next parm */
378 case 'r': /* -r: recurse */
382 case 's': /* -s: show statistics */
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");
396 case 'v': /* -v: verbose */
400 case 'V': /* -V: Very verbose */
405 case 'w': /* -w: wait for completion */
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]);
421 fprintf(stderr
, "Unknown command: %s\n", argv
[0]);
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) {
430 "Can't get config for drive %d: %s\n",
433 longjmp(command_fail
, -1);
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) {
443 "Can't get config for subdisk %d: %s\n",
446 longjmp(command_fail
, -1);
450 /* Get the contents of the sd entry for subdisk <sdno>
451 * of the specified plex. */
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) {
459 "Can't get config for subdisk %d (part of plex %d): %s\n",
463 longjmp(command_fail
, -1);
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) {
473 "Can't get config for plex %d: %s\n",
476 longjmp(command_fail
, -1);
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) {
486 "Can't get config for volume %d: %s\n",
489 longjmp(command_fail
, -1);
494 find_drive_by_devname(char *name
)
498 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
499 perror("Can't get vinum config");
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 */
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");
524 perror(VINUMMOD
": Can't write to /dev");
529 fprintf(hist
, "*** Created devices ***\n");
531 if (superdev
>= 0) /* super device open */
534 system("rm -rf " VINUM_DIR
); /* remove the old directories */
535 system("mkdir -p " VINUM_DIR
"/drive " /* and make them again */
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");
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
++)
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
);
582 /* make the devices for a volume */
584 make_vol_dev(int volno
, int recurse
)
587 char filename
[PATH_MAX
]; /* for forming file names */
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
));
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.
621 make_plex_dev(int plexno
, int recurse
)
623 dev_t plexdev
; /* device */
624 char filename
[PATH_MAX
]; /* for forming file names */
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
));
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 */
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 */
680 vinum_makedev(int argc
, char *argv
[], char *arg0
[])
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
)
695 if (ioctl(superdev
, VINUM_GETCONFIG
, &vinum_conf
) < 0) {
696 perror("Can't get vinum config");
697 *type
= invalid_object
;
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
;
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) {
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) {
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
;
736 /* Didn't find the name: invalid */
737 *type
= invalid_object
;
741 /* Continue reviving a subdisk in the background */
743 continue_revive(int sdno
)
747 get_sd_info(&sd
, sdno
);
750 pid
= fork(); /* do this in the background */
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 */
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 */
769 SSize
<<= DEV_BSHIFT
;
770 message
->blocksize
= SSize
;
772 message
->blocksize
= DEFAULT_REVIVE_BLOCKSIZE
;
773 ioctl(superdev
, VINUM_SETSTATE
, message
);
776 syslog(LOG_ERR
| LOG_KERN
,
777 "can't revive %s: %s",
779 reply
.msg
[0] ? reply
.msg
: strerror(reply
.error
));
783 get_sd_info(&sd
, sdno
); /* update the info */
784 syslog(LOG_INFO
| LOG_KERN
, "%s is %s", sd
.name
, sd_state(sd
.state
));
788 } else if (pid
< 0) /* couldn't fork? */
789 fprintf(stderr
, "Can't continue reviving %s: %s\n", sd
.name
, strerror(errno
));
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
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 */
823 perror("Can't open " VINUM_DAEMON_DEV_NAME
);
826 error
= daemon(0, 0); /* this will fork again, but who's counting? */
828 fprintf(stderr
, "Can't start daemon: %s (%d)\n", strerror(errno
), errno
);
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
));
838 exit(0); /* when told to die */
839 } else if (pid
< 0) /* couldn't fork */
840 printf("Can't fork to check daemon\n");
848 char datetext
[MAXDATETEXT
];
852 if (gettimeofday(&now
, NULL
) != 0) {
853 fprintf(stderr
, "Can't get time: %s\n", strerror(errno
));
857 date
= localtime(&sec
);
858 strftime(datetext
, MAXDATETEXT
, dateformat
, date
),