Fix compilation with old g++ 3.3.5 and debian-sarge.
[wvstreams.git] / utils / wvfork.cc
blob37c133672810da6ee19531514967e19182053af0
1 /*
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.)
20 #include <fcntl.h>
22 #include "wvfork.h"
23 #include "wvlinklist.h"
25 #define MAX_FD sysconf(_SC_OPEN_MAX) + 1
27 DeclareWvList(WvForkCallback);
28 static WvForkCallbackList *callbacks;
30 class StupidWvForkDeallocator
32 public:
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()
45 if (!callbacks)
46 callbacks = new WvForkCallbackList;
47 return *callbacks;
51 void add_wvfork_callback(WvForkCallback cb)
53 #if 0
54 // be sure we don't add this twice
55 WvForkCallbackList::Iter i(get_callbacks());
56 for (i.rewind(); i.next(); )
57 if (*i == cb) return;
58 #endif
59 get_callbacks().append(new WvForkCallback(cb), true);
62 #if 0
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();
69 #endif
71 pid_t wvfork(int dontclose1, int dontclose2)
73 intTable t(1);
74 if (dontclose1 >= 0)
75 t.add(&dontclose1, false);
76 if (dontclose2 >= 0)
77 t.add(&dontclose2, false);
78 return (wvfork(t));
81 pid_t wvfork_start(int *waitfd)
83 int waitpipe[2];
85 if (pipe(waitpipe) < 0)
86 return -1;
88 pid_t pid = fork();
90 WvForkCallbackList::Iter i(get_callbacks());
91 for (i.rewind(); i.next(); )
93 WvForkCallback *cb = i.ptr();
94 (*cb)(pid);
97 if (pid < 0)
98 return pid;
99 else if (pid > 0)
101 // parent process. close its writing end of the pipe and wait
102 // for its reading end to close.
103 char buf;
104 close(waitpipe[1]);
105 read(waitpipe[0], &buf, 1);
106 close(waitpipe[0]);
108 else
110 // child process. close its reading end of the pipe.
111 close(waitpipe[0]);
112 *waitfd = waitpipe[1];
115 return pid;
118 pid_t wvfork(intTable &dontclose)
120 int waitfd = -1;
121 pid_t pid = wvfork_start(&waitfd);
123 if (pid != 0)
125 // parent or error
126 return pid;
129 // child process
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)
135 close(fd);
138 close(waitfd);
140 return pid;