1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| /* FUNCTION: interact
* DESCRIPTION: Interact with a child process
* ARGUMENTS: - cmd: command associated with the child process
* - ifd: file descriptor connected to the child's stdin
* - ofd: file descriptor connected to the child's stdout
* - efd: file descriptor connected to the child's stderr
* RETURNS:
* MODIFIES: - cmd: out, outsz, err, errsz
* COMMENTS: ifd, ofd and efd are closed
*/
static void
interact(cmd_t *cmd, int ifd, int ofd, int efd)
{
nfds_t nfds;
struct pollfd fds[3];
rdblock_t *oblock = NULL, *eblock = NULL;
char *in;
size_t olen = 0, elen = 0;
size_t insz;
/* Initialize poll list */
fds[0].fd = ofd;
fds[0].events = POLLIN;
fds[1].fd = efd;
fds[1].events = POLLIN;
if (cmd->insz != 0) {
/* Add ifd to poll list */
fds[2].fd = ifd;
fds[2].events = POLLOUT;
nfds = 3;
/* Initialize current position in input buffer */
in = cmd->in;
insz = cmd->insz;
} else {
close(ifd);
nfds = 2;
}
/* Poll file descriptors */
while (nfds > 0) {
int i;
poll(fds, nfds, -1);
/* See which fds are ready */
for (i = 0; i < nfds; i++) {
if (fds[i].revents) {
ssize_t rc;
if (fds[i].fd == ofd) {
/* Child's stdout has data */
rc = rdblock(ofd, &oblock, &olen);
} else if (fds[i].fd == efd) {
/* Child's stderr has data */
rc = rdblock(efd, &eblock, &elen);
} else {
/* Child's stdin accepts data */
rc = write(ifd, in, insz);
if (rc > 0) {
in += rc;
insz -= rc;
}
}
if (rc <= 0) {
/* Error (rc == -1) or nothing more to
* read/write (rc == 0). Either way,
* close fd and remove it from poll
* list.
*/
close(fds[i].fd);
nfds--;
if (i != nfds) {
fds[i].fd = fds[nfds].fd;
fds[i].events = fds[nfds].events;
}
}
}
}
}
/* Save data read from child */
cmd->out = rdblock2data(oblock, olen);
cmd->outsz = olen;
cmd->err = rdblock2data(eblock, elen);
cmd->errsz = elen;
} |
Partager