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 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
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_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
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 ioctl(1, TIOCSCTTY, 1);
00178 }
00179
00180 ::close(waitfd);
00181
00182
00183
00184 execvp(program, (char * const *)argv);
00185 _exit(242);
00186 }
00187 else if (pid > 0)
00188 {
00189
00190
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
00204 void WvPipe::kill(int signum)
00205 {
00206 if (proc.running)
00207 proc.kill(signum);
00208 }
00209
00210
00211
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
00226 proc.wait(0);
00227 proc.wait(0);
00228 return !proc.running;
00229 }
00230
00231
00232
00233
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
00243
00244 int WvPipe::exit_status()
00245 {
00246
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
00266
00267
00268
00269 void WvPipe::ignore_read(WvStream& s, void *userdata)
00270 {
00271 char c;
00272 s.read(&c, 1);
00273 }