00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "wvpipe.h"
00011 #include "wvsplitstream.h"
00012 #include <fcntl.h>
00013 #include <sys/types.h>
00014 #include <sys/socket.h>
00015 #include <signal.h>
00016 #include <sys/wait.h>
00017 #include <errno.h>
00018 #include <sys/ioctl.h>
00019 #include <assert.h>
00020
00021
00022
00023
00024 WvPipe::WvPipe(const char *program, const char * const *argv,
00025 bool writable, bool readable, bool catch_stderr,
00026 int stdin_fd, int stdout_fd, int stderr_fd)
00027 {
00028 setup(program, argv, writable, readable, catch_stderr,
00029 stdin_fd, stdout_fd, stderr_fd);
00030 }
00031
00032
00033 WvPipe::WvPipe(const char *program, const char * const *argv,
00034 bool writable, bool readable, bool catch_stderr,
00035 WvStream *stdin_str, WvStream *stdout_str,
00036 WvStream *stderr_str)
00037 {
00038 int fd0 = 0, fd1 = 1, fd2 = 2;
00039 if (stdin_str)
00040 fd0 = stdin_str->getrfd();
00041 if (stdout_str)
00042 fd1 = stdout_str->getwfd();
00043 if (stderr_str)
00044 fd2 = stderr_str->getwfd();
00045 setup(program, argv, writable, readable, catch_stderr, fd0, fd1, fd2);
00046 }
00047
00048
00049 WvPipe::WvPipe(const char *program, const char **argv,
00050 bool writable, bool readable, bool catch_stderr,
00051 WvSplitStream *stdio_str)
00052 {
00053 if (stdio_str)
00054 {
00055 int rfd = stdio_str->getrfd(), wfd = stdio_str->getwfd();
00056 setup(program, argv, writable, readable, catch_stderr,
00057 rfd, wfd, wfd);
00058 }
00059 else
00060 setup(program, argv, writable, readable, catch_stderr, 0, 1, 2);
00061 }
00062
00063
00064 void WvPipe::setup(const char *program, const char * const *argv,
00065 bool writable, bool readable, bool catch_stderr,
00066 int stdin_fd, int stdout_fd, int stderr_fd)
00067 {
00068 int socks[2];
00069
00070 pid = 0;
00071 estatus = -1;
00072
00073 if (!program || !argv)
00074 {
00075 errnum = EINVAL;
00076 return;
00077 }
00078
00079 if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks))
00080 {
00081 errnum = errno;
00082 return;
00083 }
00084
00085
00086
00087 pid = fork();
00088 if (pid < 0)
00089 {
00090 pid = 0;
00091 errnum = errno;
00092 ::close(socks[0]);
00093 ::close(socks[1]);
00094 return;
00095 }
00096
00097 if (!pid)
00098 {
00099 ::close(socks[0]);
00100
00101 if (writable)
00102 dup2(socks[1], 0);
00103 else if (stdin_fd == -1)
00104 ::close(0);
00105 else
00106 dup2(stdin_fd, 0);
00107 if (readable)
00108 dup2(socks[1], 1);
00109 else if (stdout_fd == -1)
00110 ::close(1);
00111 else
00112 dup2(stdout_fd, 1);
00113 if (catch_stderr)
00114 dup2(socks[1], 2);
00115 else if (stderr_fd == -1)
00116 ::close(2);
00117 else
00118 dup2(stderr_fd, 2);
00119
00120 fcntl(0, F_SETFD, 0);
00121 fcntl(1, F_SETFD, 0);
00122 fcntl(2, F_SETFD, 0);
00123
00124
00125
00126
00127
00128
00129 if(!writable && !readable && !catch_stderr)
00130 fcntl(socks[1], F_SETFD, 0);
00131
00132
00133
00134 if (!readable && stdout_fd != 1)
00135 {
00136 setsid();
00137 ioctl(1, TIOCSCTTY, 1);
00138 }
00139
00140
00141
00142 execvp(program, (char * const *)argv);
00143 _exit(242);
00144 }
00145
00146
00147
00148
00149 fcntl(socks[0], F_SETFL, O_RDWR|O_NONBLOCK);
00150
00151 rwfd = socks[0];
00152 ::close(socks[1]);
00153 }
00154
00155
00156
00157 void WvPipe::kill(int signum)
00158 {
00159 if (pid)
00160 ::kill(pid, signum);
00161 }
00162
00163
00164
00165 int WvPipe::finish()
00166 {
00167 while (!child_exited())
00168 usleep(100*1000);
00169
00170 return exit_status();
00171 }
00172
00173
00174
00175
00176
00177 bool WvPipe::child_exited()
00178 {
00179 int status;
00180 pid_t dead_pid;
00181
00182 if (!pid) return true;
00183
00184 dead_pid = waitpid(pid, &status, WNOHANG);
00185 if (dead_pid != pid)
00186 return false;
00187 estatus = status;
00188 pid = 0;
00189 return true;
00190 }
00191
00192
00193
00194
00195 bool WvPipe::child_killed() const
00196 {
00197 int st = estatus;
00198 assert (WIFEXITED(st) || WIFSIGNALED(st));
00199 return WIFSIGNALED(st);
00200 }
00201
00202
00203
00204
00205 int WvPipe::exit_status() const
00206 {
00207 int st = estatus;
00208 assert (WIFEXITED(st) || WIFSIGNALED(st));
00209 if (child_killed())
00210 return WTERMSIG(st);
00211 else
00212 return WEXITSTATUS(st);
00213 }
00214
00215
00216
00217 WvPipe::~WvPipe()
00218 {
00219 int status, count;
00220 pid_t dead_pid;
00221
00222 close();
00223
00224 if (!pid) return;
00225
00226 dead_pid = waitpid(pid, &status, WNOHANG);
00227 if (dead_pid == 0)
00228 {
00229 kill(SIGTERM);
00230
00231 for (count = 20; count > 0; count--)
00232 {
00233 dead_pid = waitpid(pid, &status, WNOHANG);
00234 if (dead_pid == pid)
00235 break;
00236 usleep(100 * 1000);
00237 }
00238
00239 if (dead_pid == 0)
00240 {
00241 kill(SIGKILL);
00242 waitpid(pid, &status, 0);
00243 }
00244 }
00245 }