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 }