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, 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
00136 ::close(socks[0]);
00137
00138 if (writable)
00139 dup2(socks[1], 0);
00140 else if (stdin_fd == -1)
00141 ::close(0);
00142 else
00143 dup2(stdin_fd, 0);
00144 if (readable)
00145 dup2(socks[1], 1);
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);
00152 else if (stderr_fd == -1)
00153 ::close(2);
00154 else
00155 dup2(stderr_fd, 2);
00156
00157
00158 fcntl(0, F_SETFD, 0);
00159 fcntl(1, F_SETFD, 0);
00160 fcntl(2, F_SETFD, 0);
00161
00162
00163
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
00172
00173
00174
00175
00176 if (!writable && !readable && !catch_stderr)
00177 fcntl(socks[1], F_SETFD, 0);
00178 else
00179 ::close(socks[1]);
00180
00181
00182
00183 if (!readable && stdout_fd != 1)
00184 {
00185 setsid();
00186
00187
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
00200
00201 execvp(program, (char * const *)argv);
00202 _exit(242);
00203 }
00204 else if (pid > 0)
00205 {
00206
00207
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
00221 void WvPipe::kill(int signum)
00222 {
00223 if (proc.running)
00224 proc.kill(signum);
00225 }
00226
00227
00228
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
00243 proc.wait(0);
00244 proc.wait(0);
00245 return !proc.running;
00246 }
00247
00248
00249
00250
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
00260
00261 int WvPipe::exit_status()
00262 {
00263
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
00283
00284
00285
00286 void WvPipe::ignore_read(WvStream& s)
00287 {
00288 char buf[512];
00289 s.read(&buf, sizeof(buf));
00290 }