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

wvpipe.cc

Go to the documentation of this file.
00001 /* 00002 * Worldvisions Weaver Software: 00003 * Copyright (C) 1997-2002 Net Integration Technologies, Inc. 00004 * 00005 * Implementation of a WvPipe stream. WvPipes allow you to create a new 00006 * process, attaching its stdin/stdout to a WvStream. 00007 * 00008 * See wvpipe.h for more information. 00009 */ 00010 #include <fcntl.h> 00011 #include <sys/types.h> 00012 #include <sys/socket.h> 00013 #include <signal.h> 00014 #include <sys/wait.h> 00015 #include <errno.h> 00016 #include <sys/ioctl.h> 00017 #include <assert.h> 00018 #include "wvpipe.h" 00019 00020 // this code is pretty handy for debugging, since 'netstat -nap' can't tell 00021 // you the endpoints of a socketpair(), but it can tell you the name of a 00022 // "real" Unix domain socket. 00023 #if 0 00024 #include "wvaddr.h" 00025 static int socketpair(int d, int type, int protocol, int sv[2]) 00026 { 00027 static int counter = 10; 00028 00029 int f1 = socket(PF_UNIX, SOCK_STREAM, protocol); 00030 int f2 = socket(PF_UNIX, SOCK_STREAM, protocol); 00031 00032 WvString s("/tmp/sock%s", ++counter); 00033 WvString s2("/tmp/sock%sb", counter); 00034 WvUnixAddr a(s), a2(s2); 00035 00036 unlink(s); 00037 unlink(s2); 00038 00039 bind(f1, a.sockaddr(), a.sockaddr_len()); 00040 bind(f2, a2.sockaddr(), a2.sockaddr_len()); 00041 listen(f1, 10); 00042 connect(f2, a.sockaddr(), a.sockaddr_len()); 00043 00044 socklen_t ll = a.sockaddr_len(); 00045 int f3 = accept(f1, a.sockaddr(), &ll); 00046 close(f1); 00047 00048 sv[0] = f3; 00049 sv[1] = f2; 00050 00051 return 0; 00052 } 00053 #endif 00054 00055 00056 // The assorted WvPipe::WvPipe() constructors are described in wvpipe.h 00057 00058 WvPipe::WvPipe(const char *program, const char * const *argv, 00059 bool writable, bool readable, bool catch_stderr, 00060 int stdin_fd, int stdout_fd, int stderr_fd) 00061 { 00062 setup(program, argv, writable, readable, catch_stderr, 00063 stdin_fd, stdout_fd, stderr_fd); 00064 } 00065 00066 00067 WvPipe::WvPipe(const char *program, const char * const *argv, 00068 bool writable, bool readable, bool catch_stderr, 00069 WvFDStream *stdin_str, WvFDStream *stdout_str, 00070 WvFDStream *stderr_str) 00071 { 00072 int fd0 = 0, fd1 = 1, fd2 = 2; 00073 if (stdin_str) 00074 fd0 = stdin_str->getrfd(); 00075 if (stdout_str) 00076 fd1 = stdout_str->getwfd(); 00077 if (stderr_str) 00078 fd2 = stderr_str->getwfd(); 00079 setup(program, argv, writable, readable, catch_stderr, fd0, fd1, fd2); 00080 } 00081 00082 00083 WvPipe::WvPipe(const char *program, const char **argv, 00084 bool writable, bool readable, bool catch_stderr, 00085 WvFDStream *stdio_str) 00086 { 00087 if (stdio_str) 00088 { 00089 int rfd = stdio_str->getrfd(), wfd = stdio_str->getwfd(); 00090 setup(program, argv, writable, readable, catch_stderr, 00091 rfd, wfd, wfd); 00092 } 00093 else 00094 setup(program, argv, writable, readable, catch_stderr, 0, 1, 2); 00095 } 00096 00097 00098 void WvPipe::setup(const char *program, const char * const *argv, 00099 bool writable, bool readable, bool catch_stderr, 00100 int stdin_fd, int stdout_fd, int stderr_fd) 00101 { 00102 int socks[2]; 00103 int flags; 00104 int waitfd; 00105 int pid; 00106 00107 if (!program || !argv) 00108 { 00109 errnum = EINVAL; 00110 return; 00111 } 00112 00113 if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks)) 00114 { 00115 errnum = errno; 00116 return; 00117 } 00118 00119 fcntl(socks[0], F_SETFL, O_RDWR|O_NONBLOCK); 00120 setfd(socks[0]); 00121 00122 pid = proc.fork(&waitfd); 00123 00124 if (!pid) 00125 { 00126 // child process 00127 ::close(socks[0]); 00128 00129 if (writable) 00130 dup2(socks[1], 0); // writable means redirect child stdin 00131 else if (stdin_fd == -1) 00132 ::close(0); 00133 else 00134 dup2(stdin_fd, 0); 00135 if (readable) 00136 dup2(socks[1], 1); // readable means we redirect child stdout 00137 else if (stdout_fd == -1) 00138 ::close(1); 00139 else 00140 dup2(stdout_fd, 1); 00141 if (catch_stderr) 00142 dup2(socks[1], 2); // but catch_stderr does what you think 00143 else if (stderr_fd == -1) 00144 ::close(2); 00145 else 00146 dup2(stderr_fd, 2); 00147 00148 /* never close stdin/stdout/stderr */ 00149 fcntl(0, F_SETFD, 0); 00150 fcntl(1, F_SETFD, 0); 00151 fcntl(2, F_SETFD, 0); 00152 00153 /* drop the O_NONBLOCK from stdin/stdout/stderr, it confuses 00154 * some programs */ 00155 flags = fcntl(0, F_GETFL); 00156 fcntl(0, F_SETFL, flags & (O_APPEND|O_ASYNC)); 00157 flags = fcntl(1, F_GETFL); 00158 fcntl(1, F_SETFL, flags & (O_APPEND|O_ASYNC)); 00159 flags = fcntl(2, F_GETFL); 00160 fcntl(2, F_SETFL, flags & (O_APPEND|O_ASYNC)); 00161 00162 /* If we're not capturing any of these through the socket, it 00163 * means that the child end of the socket will be closed right 00164 * at the execvp, which is bad. If we set the close-on-exec to 00165 * false, the child end of the socket will be closed when the 00166 * child (or sub-) process exits. */ 00167 if (!writable && !readable && !catch_stderr) 00168 fcntl(socks[1], F_SETFD, 0); // never close the socketpair 00169 else 00170 ::close(socks[1]); // has already been duplicated 00171 00172 // this will often fail, but when it does work it is probably 00173 // the Right Thing To Do (tm) 00174 if (!readable && stdout_fd != 1) 00175 { 00176 setsid(); 00177 ioctl(1, TIOCSCTTY, 1); 00178 } 00179 00180 ::close(waitfd); 00181 00182 // now run the program. If it fails, use _exit() so no destructors 00183 // get called and make a mess. 00184 execvp(program, (char * const *)argv); 00185 _exit(242); 00186 } 00187 else if (pid > 0) 00188 { 00189 // parent process. 00190 // now that we've forked, it's okay to close this fd if we fork again. 00191 fcntl(socks[0], F_SETFD, 1); 00192 ::close(socks[1]); 00193 } 00194 else 00195 { 00196 ::close(socks[0]); 00197 ::close(socks[1]); 00198 return; 00199 } 00200 } 00201 00202 00203 // send the child process a signal 00204 void WvPipe::kill(int signum) 00205 { 00206 if (proc.running) 00207 proc.kill(signum); 00208 } 00209 00210 00211 // wait for the child to die 00212 int WvPipe::finish(bool wait_children) 00213 { 00214 shutdown(getwfd(), SHUT_WR); 00215 close(); 00216 while (proc.running) 00217 proc.wait(1000, wait_children); 00218 00219 return proc.estatus; 00220 } 00221 00222 00223 bool WvPipe::child_exited() 00224 { 00225 /* FIXME: bug in WvSubProc? */ 00226 proc.wait(0); 00227 proc.wait(0); 00228 return !proc.running; 00229 } 00230 00231 00232 // if child_exited(), return true if it died because of a signal, or 00233 // false if it died due to a call to exit(). 00234 bool WvPipe::child_killed() const 00235 { 00236 int st = proc.estatus; 00237 assert (WIFEXITED(st) || WIFSIGNALED(st)); 00238 return WIFSIGNALED(st); 00239 } 00240 00241 00242 // return the numeric exit status of the child (if it exited) or the 00243 // signal that killed the child (if it was killed). 00244 int WvPipe::exit_status() 00245 { 00246 /* FIXME: bug in WvSubProc? */ 00247 proc.wait(0); 00248 proc.wait(0); 00249 00250 int st = proc.estatus; 00251 assert (WIFEXITED(st) || WIFSIGNALED(st)); 00252 if (child_killed()) 00253 return WTERMSIG(st); 00254 else 00255 return WEXITSTATUS(st); 00256 } 00257 00258 00259 WvPipe::~WvPipe() 00260 { 00261 close(); 00262 } 00263 00264 00265 // this is necessary when putting, say, sendmail through a WvPipe on the 00266 // globallist so we can forget about it. We call nowrite() so that it'll 00267 // get the EOF and then go away when it's done, but we need to read from it 00268 // for it the WvPipe stop selecting true and get deleted. 00269 void WvPipe::ignore_read(WvStream& s, void *userdata) 00270 { 00271 char c; 00272 s.read(&c, 1); 00273 }

Generated on Tue Oct 5 01:09:20 2004 for WvStreams by doxygen 1.3.7