diff --git a/src/util/vircommand.c b/src/util/vircommand.c index a3a5780d29..774038e536 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -1820,6 +1820,61 @@ virCommandSetSendBuffer(virCommandPtr cmd, #endif +static int +virCommandSendBuffersFillPollfd(virCommandPtr cmd, + struct pollfd *fds, + int startidx) +{ + size_t i, j; + + for (i = 0, j = 0; i < virCommandGetNumSendBuffers(cmd); i++) { + if (cmd->sendBuffers[i].fd >= 0) { + fds[startidx + j].fd = cmd->sendBuffers[i].fd; + fds[startidx + j].events = POLLOUT; + fds[startidx + j].revents = 0; + j++; + } + } + + return j; +} + + +static int +virCommandSendBuffersHandlePoll(virCommandPtr cmd, + struct pollfd *fds) +{ + size_t i; + ssize_t done; + + for (i = 0; i < virCommandGetNumSendBuffers(cmd); i++) { + if (fds->fd == cmd->sendBuffers[i].fd) + break; + } + if (i == virCommandGetNumSendBuffers(cmd)) + return 0; + + done = write(fds->fd, + cmd->sendBuffers[i].buffer + cmd->sendBuffers[i].offset, + cmd->sendBuffers[i].buflen - cmd->sendBuffers[i].offset); + if (done < 0) { + if (errno == EPIPE) { + VIR_DEBUG("child closed PIPE early, ignoring EPIPE " + "on fd %d", cmd->sendBuffers[i].fd); + VIR_FORCE_CLOSE(cmd->sendBuffers[i].fd); + } else if (errno != EINTR && errno != EAGAIN) { + virReportSystemError(errno, "%s", + _("unable to write to child input")); + return -1; + } + } else { + cmd->sendBuffers[i].offset += done; + if (cmd->sendBuffers[i].offset == cmd->sendBuffers[i].buflen) + VIR_FORCE_CLOSE(cmd->sendBuffers[i].fd); + } + return 0; +} + /** * virCommandSetInputBuffer: * @cmd: the command to modify @@ -2174,7 +2229,7 @@ virCommandProcessIO(virCommandPtr cmd) goto cleanup; ret = -1; - if (VIR_ALLOC_N(fds, 3) < 0) + if (VIR_ALLOC_N(fds, 3 + virCommandGetNumSendBuffers(cmd)) < 0) goto cleanup; for (;;) { @@ -2200,6 +2255,8 @@ virCommandProcessIO(virCommandPtr cmd) nfds++; } + nfds += virCommandSendBuffersFillPollfd(cmd, fds, nfds); + if (nfds == 0) break; @@ -2272,6 +2329,9 @@ virCommandProcessIO(virCommandPtr cmd) if (inoff == inlen) VIR_FORCE_CLOSE(cmd->inpipe); } + } else if (fds[i].revents & (POLLOUT | POLLHUP | POLLERR)) { + if (virCommandSendBuffersHandlePoll(cmd, &fds[i]) < 0) + goto cleanup; } } }