00001
00002
00003
00004
00005
00006
00007
00008
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
00021
00022
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
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 seterr(EINVAL);
00110 return;
00111 }
00112
00113 if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks))
00114 {
00115 seterr(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
00127 ::close(socks[0]);
00128
00129 if (writable)
00130 dup2(socks[1], 0);
00131 else if (stdin_fd == -1)
00132 ::close(0);
00133 else
00134 dup2(stdin_fd, 0);
00135 if (readable)
00136 dup2(socks[1], 1);
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);
00143 else if (stderr_fd == -1)
00144 ::close(2);
00145 else
00146 dup2(stderr_fd, 2);
00147
00148
00149 fcntl(0, F_SETFD, 0);
00150 fcntl(1, F_SETFD, 0);
00151 fcntl(2, F_SETFD, 0);
00152
00153
00154
00155 flags = fcntl(0, F_GETFL);
00156 fcntl(0, F_SETFL, flags & ~O_NONBLOCK);
00157 flags = fcntl(1, F_GETFL);
00158 fcntl(1, F_SETFL, flags & ~O_NONBLOCK);
00159 flags = fcntl(2, F_GETFL);
00160 fcntl(2, F_SETFL, flags & ~O_NONBLOCK);
00161
00162
00163
00164
00165
00166
00167 if (!writable && !readable && !catch_stderr)
00168 fcntl(socks[1], F_SETFD, 0);
00169 else
00170 ::close(socks[1]);
00171
00172
00173
00174 if (!readable && stdout_fd != 1)
00175 {
00176 setsid();
00177
00178
00179 #ifdef TIOCSCTTY
00180 ioctl(1, TIOCSCTTY, 1);
00181 #else
00182 # ifdef TCSETCTTY
00183 # warning You should implement TCSETCTTY here. Thanks!
00184 # endif
00185 #endif
00186 }
00187
00188 ::close(waitfd);
00189
00190
00191
00192 execvp(program, (char * const *)argv);
00193 _exit(242);
00194 }
00195 else if (pid > 0)
00196 {
00197
00198
00199 fcntl(socks[0], F_SETFD, 1);
00200 ::close(socks[1]);
00201 }
00202 else
00203 {
00204 ::close(socks[0]);
00205 ::close(socks[1]);
00206 return;
00207 }
00208 }
00209
00210
00211
00212 void WvPipe::kill(int signum)
00213 {
00214 if (proc.running)
00215 proc.kill(signum);
00216 }
00217
00218
00219
00220 int WvPipe::finish(bool wait_children)
00221 {
00222 shutdown(getwfd(), SHUT_WR);
00223 close();
00224 while (proc.running)
00225 proc.wait(1000, wait_children);
00226
00227 return proc.estatus;
00228 }
00229
00230
00231 bool WvPipe::child_exited()
00232 {
00233
00234 proc.wait(0);
00235 proc.wait(0);
00236 return !proc.running;
00237 }
00238
00239
00240
00241
00242 bool WvPipe::child_killed() const
00243 {
00244 int st = proc.estatus;
00245 assert (WIFEXITED(st) || WIFSIGNALED(st));
00246 return WIFSIGNALED(st);
00247 }
00248
00249
00250
00251
00252 int WvPipe::exit_status()
00253 {
00254
00255 proc.wait(0);
00256 proc.wait(0);
00257
00258 int st = proc.estatus;
00259 assert (WIFEXITED(st) || WIFSIGNALED(st));
00260 if (child_killed())
00261 return WTERMSIG(st);
00262 else
00263 return WEXITSTATUS(st);
00264 }
00265
00266
00267 WvPipe::~WvPipe()
00268 {
00269 close();
00270 }
00271
00272
00273
00274
00275
00276
00277 void WvPipe::ignore_read(WvStream& s, void *userdata)
00278 {
00279 char c;
00280 s.read(&c, 1);
00281 }