WvStreams
|
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, WvStringList *env) 00061 { 00062 setup(program, argv, writable, readable, catch_stderr, 00063 stdin_fd, stdout_fd, stderr_fd, env); 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, WvStringList *env) 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, env); 00080 } 00081 00082 00083 WvPipe::WvPipe(const char *program, const char **argv, 00084 bool writable, bool readable, bool catch_stderr, 00085 WvFDStream *stdio_str, WvStringList *env) 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, env); 00092 } 00093 else 00094 setup(program, argv, writable, readable, catch_stderr, 0, 1, 2, env); 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 WvStringList *env) 00102 { 00103 int socks[2]; 00104 int flags; 00105 int waitfd; 00106 int pid; 00107 00108 if (!program || !argv) 00109 { 00110 seterr(EINVAL); 00111 return; 00112 } 00113 00114 if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks)) 00115 { 00116 seterr(errno); 00117 return; 00118 } 00119 00120 fcntl(socks[0], F_SETFL, O_RDWR|O_NONBLOCK); 00121 setfd(socks[0]); 00122 00123 if (env) 00124 { 00125 WvStringList::Iter it(*env); 00126 for (it.rewind(); it.next(); ) 00127 { 00128 proc.env.append(*it); 00129 } 00130 } 00131 pid = proc.fork(&waitfd); 00132 00133 if (!pid) 00134 { 00135 // child process 00136 ::close(socks[0]); 00137 00138 if (writable) 00139 dup2(socks[1], 0); // writable means redirect child stdin 00140 else if (stdin_fd == -1) 00141 ::close(0); 00142 else 00143 dup2(stdin_fd, 0); 00144 if (readable) 00145 dup2(socks[1], 1); // readable means we redirect child stdout 00146 else if (stdout_fd == -1) 00147 ::close(1); 00148 else 00149 dup2(stdout_fd, 1); 00150 if (catch_stderr) 00151 dup2(socks[1], 2); // but catch_stderr does what you think 00152 else if (stderr_fd == -1) 00153 ::close(2); 00154 else 00155 dup2(stderr_fd, 2); 00156 00157 /* never close stdin/stdout/stderr */ 00158 fcntl(0, F_SETFD, 0); 00159 fcntl(1, F_SETFD, 0); 00160 fcntl(2, F_SETFD, 0); 00161 00162 /* drop the O_NONBLOCK from stdin/stdout/stderr, it confuses 00163 * some programs */ 00164 flags = fcntl(0, F_GETFL); 00165 fcntl(0, F_SETFL, flags & ~O_NONBLOCK); 00166 flags = fcntl(1, F_GETFL); 00167 fcntl(1, F_SETFL, flags & ~O_NONBLOCK); 00168 flags = fcntl(2, F_GETFL); 00169 fcntl(2, F_SETFL, flags & ~O_NONBLOCK); 00170 00171 /* If we're not capturing any of these through the socket, it 00172 * means that the child end of the socket will be closed right 00173 * at the execvp, which is bad. If we set the close-on-exec to 00174 * false, the child end of the socket will be closed when the 00175 * child (or sub-) process exits. */ 00176 if (!writable && !readable && !catch_stderr) 00177 fcntl(socks[1], F_SETFD, 0); // never close the socketpair 00178 else 00179 ::close(socks[1]); // has already been duplicated 00180 00181 // this will often fail, but when it does work it is probably 00182 // the Right Thing To Do (tm) 00183 if (!readable && stdout_fd != 1) 00184 { 00185 setsid(); 00186 // Only on some OSes will we find TIOCSCTTY to set the controlling tty. 00187 // On others, we need to use TCSETCTTY, but we are too lazy to implement that. 00188 #ifdef TIOCSCTTY 00189 ioctl(1, TIOCSCTTY, 1); 00190 #else 00191 # ifdef TCSETCTTY 00192 # warning You should implement TCSETCTTY here. Thanks! 00193 # endif 00194 #endif 00195 } 00196 00197 ::close(waitfd); 00198 00199 // now run the program. If it fails, use _exit() so no destructors 00200 // get called and make a mess. 00201 execvp(program, (char * const *)argv); 00202 _exit(242); 00203 } 00204 else if (pid > 0) 00205 { 00206 // parent process. 00207 // now that we've forked, it's okay to close this fd if we fork again. 00208 fcntl(socks[0], F_SETFD, 1); 00209 ::close(socks[1]); 00210 } 00211 else 00212 { 00213 ::close(socks[0]); 00214 ::close(socks[1]); 00215 return; 00216 } 00217 } 00218 00219 00220 // send the child process a signal 00221 void WvPipe::kill(int signum) 00222 { 00223 if (proc.running) 00224 proc.kill(signum); 00225 } 00226 00227 00228 // wait for the child to die 00229 int WvPipe::finish(bool wait_children) 00230 { 00231 shutdown(getwfd(), SHUT_WR); 00232 close(); 00233 while (proc.running) 00234 proc.wait(1000, wait_children); 00235 00236 return proc.estatus; 00237 } 00238 00239 00240 bool WvPipe::child_exited() 00241 { 00242 /* FIXME: bug in WvSubProc? */ 00243 proc.wait(0); 00244 proc.wait(0); 00245 return !proc.running; 00246 } 00247 00248 00249 // if child_exited(), return true if it died because of a signal, or 00250 // false if it died due to a call to exit(). 00251 bool WvPipe::child_killed() const 00252 { 00253 int st = proc.estatus; 00254 assert (WIFEXITED(st) || WIFSIGNALED(st)); 00255 return WIFSIGNALED(st); 00256 } 00257 00258 00259 // return the numeric exit status of the child (if it exited) or the 00260 // signal that killed the child (if it was killed). 00261 int WvPipe::exit_status() 00262 { 00263 /* FIXME: bug in WvSubProc? */ 00264 proc.wait(0); 00265 proc.wait(0); 00266 00267 int st = proc.estatus; 00268 assert (WIFEXITED(st) || WIFSIGNALED(st)); 00269 if (child_killed()) 00270 return WTERMSIG(st); 00271 else 00272 return WEXITSTATUS(st); 00273 } 00274 00275 00276 WvPipe::~WvPipe() 00277 { 00278 close(); 00279 } 00280 00281 00282 // this is necessary when putting, say, sendmail through a WvPipe on the 00283 // globallist so we can forget about it. We call nowrite() so that it'll 00284 // get the EOF and then go away when it's done, but we need to read from it 00285 // for it the WvPipe stop selecting true and get deleted. 00286 void WvPipe::ignore_read(WvStream& s) 00287 { 00288 char buf[512]; 00289 s.read(&buf, sizeof(buf)); 00290 }