Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvfork.cc

Go to the documentation of this file.
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  *
00005  * wvfork() just runs fork(), but it closes all file descriptors that
00006  * are flagged close-on-exec, since we don't necessarily always run
00007  * exec() after we fork()...
00008  *
00009  * This fixes the year-old mystery bug where WvTapeBackup caused
00010  * watchdog reboots because the CHILD process wasn't touching it, and
00011  * it was already open before the fork()...
00012  *
00013  * If you want to explicitly leave a file descriptor OPEN, even if
00014  * it's marked close-on-exec, then add the fd number to dontclose, and
00015  * pass that to wvfork().  This is mainly useful for WvLoopbacks --
00016  * you may want certain ones open or closed depending on which call to
00017  * wvfork() you're making.  (for WvTapeBackup, you want the three
00018  * backup loopbacks open, and, say, any WvResolver loopbacks closed.)
00019  */
00020 
00021 #include <fcntl.h>
00022 
00023 #include "wvfork.h"
00024 #include "wvlinklist.h"
00025 
00026 #define MAX_FD sysconf(_SC_OPEN_MAX) + 1
00027 
00028 DeclareWvList(WvForkCallback);
00029 WvForkCallbackList callbacks;
00030 
00031 
00032 void add_wvfork_callback(WvForkCallback cb)
00033 {
00034 #if 0
00035     // be sure we don't add this twice
00036     WvForkCallbackList::Iter i(callbacks);
00037     for (i.rewind(); i.next(); )
00038         if (*i == cb) return;
00039 #endif
00040     callbacks.append(new WvForkCallback(cb), true);
00041 }
00042 
00043 #if 0
00044 void remove_wvfork_callback(WvForkCallback cb)
00045 {
00046     WvForkCallbackList::Iter i(callbacks);
00047     for (i.rewind(); i.next(); )
00048         if (*i == cb) i.xunlink();
00049 }
00050 #endif
00051 
00052 pid_t wvfork(int dontclose1, int dontclose2)
00053 {
00054     intTable t(1);
00055     if (dontclose1 >= 0)
00056         t.add(&dontclose1, false);
00057     if (dontclose2 >= 0)
00058         t.add(&dontclose2, false);
00059     return (wvfork(t));
00060 }
00061 
00062 pid_t wvfork_start(int *waitfd)
00063 {
00064     int waitpipe[2];
00065 
00066     if (pipe(waitpipe) < 0)
00067         return -1;
00068 
00069     pid_t pid = fork();
00070 
00071     WvForkCallbackList::Iter i(callbacks);
00072     for (i.rewind(); i.next(); )
00073     {
00074         WvForkCallback *cb = i.ptr();
00075         (*cb)(pid);
00076     }
00077 
00078     if (pid < 0)
00079         return pid;
00080     else if (pid > 0)
00081     {
00082         // parent process. close its writing end of the pipe and wait
00083         // for its reading end to close.
00084         char buf;
00085         close(waitpipe[1]);
00086         read(waitpipe[0], &buf, 1);
00087         close(waitpipe[0]);
00088     }
00089     else
00090     {
00091         // child process. close its reading end of the pipe.
00092         close(waitpipe[0]);
00093         *waitfd = waitpipe[1];
00094     }
00095 
00096     return pid;
00097 }
00098 
00099 pid_t wvfork(intTable &dontclose)
00100 {
00101     int waitfd = -1;
00102     pid_t pid = wvfork_start(&waitfd);
00103 
00104     if (pid != 0)
00105     {
00106         // parent or error
00107         return pid;
00108     }
00109 
00110     // child process
00111     // check the close-on-exec flag of all file descriptors
00112     for (int fd = 0; fd < MAX_FD; fd++)
00113     {
00114         if (!dontclose[fd] && fd != waitfd &&
00115             (fcntl(fd, F_GETFD) & FD_CLOEXEC) > 0)
00116             close(fd);
00117     }
00118 
00119     close(waitfd);
00120 
00121     return pid;
00122 }

Generated on Sat Feb 21 21:05:27 2004 for WvStreams by doxygen 1.3.5