2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
5 * wvfork() just runs fork(), but it closes all file descriptors that
6 * are flagged close-on-exec, since we don't necessarily always run
7 * exec() after we fork()...
9 * This fixes the year-old mystery bug where WvTapeBackup caused
10 * watchdog reboots because the CHILD process wasn't touching it, and
11 * it was already open before the fork()...
13 * If you want to explicitly leave a file descriptor OPEN, even if
14 * it's marked close-on-exec, then add the fd number to dontclose, and
15 * pass that to wvfork(). This is mainly useful for WvLoopbacks --
16 * you may want certain ones open or closed depending on which call to
17 * wvfork() you're making. (for WvTapeBackup, you want the three
18 * backup loopbacks open, and, say, any WvResolver loopbacks closed.)
23 #include "wvlinklist.h"
25 #define MAX_FD sysconf(_SC_OPEN_MAX) + 1
27 DeclareWvList(WvForkCallback
);
28 static WvForkCallbackList
*callbacks
;
30 class StupidWvForkDeallocator
33 ~StupidWvForkDeallocator()
34 { if (callbacks
) delete callbacks
; }
37 static StupidWvForkDeallocator sfd
;
40 // note: this shouldn't really be needed (it would be better to use a simple
41 // static list), but might be needed if your dynamic linker (ld.so) runs
42 // global constructors in the wrong order.
43 static WvForkCallbackList
&get_callbacks()
46 callbacks
= new WvForkCallbackList
;
51 void add_wvfork_callback(WvForkCallback cb
)
54 // be sure we don't add this twice
55 WvForkCallbackList::Iter
i(get_callbacks());
56 for (i
.rewind(); i
.next(); )
59 get_callbacks().append(new WvForkCallback(cb
), true);
63 void remove_wvfork_callback(WvForkCallback cb
)
65 WvForkCallbackList::Iter
i(get_callbacks());
66 for (i
.rewind(); i
.next(); )
67 if (*i
== cb
) i
.xunlink();
71 pid_t
wvfork(int dontclose1
, int dontclose2
)
75 t
.add(&dontclose1
, false);
77 t
.add(&dontclose2
, false);
81 pid_t
wvfork_start(int *waitfd
)
85 if (pipe(waitpipe
) < 0)
90 WvForkCallbackList::Iter
i(get_callbacks());
91 for (i
.rewind(); i
.next(); )
93 WvForkCallback
*cb
= i
.ptr();
101 // parent process. close its writing end of the pipe and wait
102 // for its reading end to close.
105 read(waitpipe
[0], &buf
, 1);
110 // child process. close its reading end of the pipe.
112 *waitfd
= waitpipe
[1];
118 pid_t
wvfork(intTable
&dontclose
)
121 pid_t pid
= wvfork_start(&waitfd
);
130 // check the close-on-exec flag of all file descriptors
131 for (int fd
= 0; fd
< MAX_FD
; fd
++)
133 if (!dontclose
[fd
] && fd
!= waitfd
&&
134 (fcntl(fd
, F_GETFD
) & FD_CLOEXEC
) > 0)