#include "forkexecreadwait.h" #include #include #include #include "wait.h" #include "pathexec.h" #include "fd.h" #include "error.h" #include "ndelay.h" #include int forkexecreadwait(stralloc *out, stralloc *out2, char **run) { int pid; int r; int status; int fromchild1[2] = {-1,-1}; int fromchild2[2] = {-1,-1}; struct pollfd p[2]; struct pollfd *x; stralloc *sa = 0; int fd1ok = 1; int fd2ok = 1; int *fdok = 0; long long len, i; if (!stralloc_copys(out,"")) return -1; if (pipe(fromchild1) == -1) return -1; if (pipe(fromchild2) == -1) { close(fromchild2[0]); close(fromchild2[1]); return -1; } pid = fork(); if (pid == -1) { close(fromchild1[0]); close(fromchild1[1]); close(fromchild2[0]); close(fromchild2[1]); return -1; } if (pid == 0) { if (fd_move(1, fromchild1[1]) == -1) _exit(111); if (fd_move(2, fromchild2[1]) == -1) _exit(111); close(fromchild1[0]); close(fromchild2[0]); signal(SIGPIPE,SIG_DFL); pathexec(run); _exit(111); } close(fromchild1[1]); close(fromchild2[1]); if (ndelay_on(fromchild1[0]) == -1) { close(fromchild1[0]); close(fromchild2[0]); return -1; } if (ndelay_on(fromchild2[0]) == -1) { close(fromchild1[0]); close(fromchild2[0]); return -1; } while(fd1ok || fd2ok) { len = 0; x = p; if (fd1ok) { x->fd = fromchild1[0]; x->events = POLLIN; ++len; ++x; } if (fd2ok) { x->fd = fromchild2[0]; x->events = POLLIN; ++len; ++x; } poll(p,len,-1); for (i = 0; i < len; ++i){ if (p[i].revents) { if (p[i].fd == fromchild1[0]) { sa = out; fdok = &fd1ok; } if (p[i].fd == fromchild2[0]) { sa = out2; fdok = &fd2ok; } if (!stralloc_readyplus(sa, 128)) return -1; r = read(p[i].fd, sa->s + sa->len, 128); if (r == -1) { if (errno == error_again) continue; if (errno == error_intr) continue; if (errno == error_wouldblock) continue; *fdok = 0; } if (r == 0) *fdok = 0; if (r > 0) if (sa->len < 5000) sa->len += r; /* XXX: hardcoded limit 5000 B */ } } } close(fromchild1[0]); close(fromchild2[0]); r = wait_pid(&status,pid); if (r == -1) return -1; r = wait_crashed(status); if (r) return -1; r = wait_exitcode(status); if (r) return -1; return 0; }