#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <poll.h>
#include "internal.h"
#define NO_LIBVIRT
char *cwd;
FILE *log = fopen(abs_builddir "/commandhelper.log", "w");
int ret = EXIT_FAILURE;
+ int readfds[3] = { STDIN_FILENO, };
+ int numreadfds = 1;
+ struct pollfd fds[3];
+ int numpollfds = 0;
+ char *buffers[3] = {NULL, NULL, NULL};
+ size_t buflen[3] = {0, 0, 0};
+ char c;
if (!log)
return ret;
- for (i = 1; i < argc; i++)
+ for (i = 1; i < argc; i++) {
fprintf(log, "ARG:%s\n", argv[i]);
+ if (STREQ(argv[i - 1], "--readfd") &&
+ sscanf(argv[i], "%u%c", &readfds[numreadfds++], &c) != 1) {
+ printf("Could not parse fd %s\n", argv[i]);
+ goto cleanup;
+ }
+ }
+
origenv = environ;
n = 0;
while (*origenv != NULL) {
fprintf(stderr, "BEGIN STDERR\n");
fflush(stderr);
+ for (i = 0; i < numreadfds; i++) {
+ fds[numpollfds].fd = readfds[i];
+ fds[numpollfds].events = POLLIN;
+ fds[numpollfds].revents = 0;
+ numpollfds++;
+ }
+
for (;;) {
- got = read(STDIN_FILENO, buf, sizeof(buf));
- if (got < 0)
+ unsigned ctr = 0;
+
+ if (poll(fds, numpollfds, -1) < 0) {
+ printf("poll failed: %s\n", strerror(errno));
goto cleanup;
- if (got == 0)
+ }
+
+ for (i = 0; i < numpollfds; i++) {
+ if (fds[i].revents & (POLLIN | POLLHUP | POLLERR)) {
+ fds[i].revents = 0;
+
+ got = read(fds[i].fd, buf, sizeof(buf));
+ if (got < 0)
+ goto cleanup;
+ if (got == 0) {
+ /* do not want to hear from this fd anymore */
+ fds[i].events = 0;
+ } else {
+ buffers[i] = realloc(buffers[i], buflen[i] + got);
+ if (!buf[i]) {
+ fprintf(stdout, "Out of memory!\n");
+ goto cleanup;
+ }
+ memcpy(buffers[i] + buflen[i], buf, got);
+ buflen[i] += got;
+ }
+ }
+ }
+ for (i = 0; i < numpollfds; i++) {
+ if (fds[i].events) {
+ ctr++;
+ break;
+ }
+ }
+ if (ctr == 0)
break;
- if (write(STDOUT_FILENO, buf, got) != got)
+ }
+
+ for (i = 0; i < numpollfds; i++) {
+ if (write(STDOUT_FILENO, buffers[i], buflen[i]) != buflen[i])
goto cleanup;
- if (write(STDERR_FILENO, buf, got) != got)
+ if (write(STDERR_FILENO, buffers[i], buflen[i]) != buflen[i])
goto cleanup;
}
ret = EXIT_SUCCESS;
cleanup:
+ for (i = 0; i < ARRAY_CARDINALITY(buffers); i++)
+ free(buffers[i]);
fclose(log);
free(newenv);
return ret;
return ret;
}
+static int test27(const void *unused ATTRIBUTE_UNUSED)
+{
+ virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
+ int pipe1[2];
+ int pipe2[2];
+ int ret = -1;
+ size_t buflen = 1024 * 128;
+ char *buffer0 = NULL;
+ char *buffer1 = NULL;
+ char *buffer2 = NULL;
+ char *outactual = NULL;
+ char *erractual = NULL;
+ char *outexpect = NULL;
+# define TEST27_OUTEXPECT_TEMP "BEGIN STDOUT\n" \
+ "%s%s%s" \
+ "END STDOUT\n"
+ char *errexpect = NULL;
+# define TEST27_ERREXPECT_TEMP "BEGIN STDERR\n" \
+ "%s%s%s" \
+ "END STDERR\n"
+
+ if (VIR_ALLOC_N(buffer0, buflen) < 0 ||
+ VIR_ALLOC_N(buffer1, buflen) < 0 ||
+ VIR_ALLOC_N(buffer2, buflen) < 0)
+ goto cleanup;
+
+ memset(buffer0, 'H', buflen - 2);
+ buffer0[buflen - 2] = '\n';
+ buffer0[buflen - 1] = 0;
+
+ memset(buffer1, '1', buflen - 2);
+ buffer1[buflen - 2] = '\n';
+ buffer1[buflen - 1] = 0;
+
+ memset(buffer2, '2', buflen - 2);
+ buffer2[buflen - 2] = '\n';
+ buffer2[buflen - 1] = 0;
+
+ if (virAsprintf(&outexpect, TEST27_OUTEXPECT_TEMP,
+ buffer0, buffer1, buffer2) < 0 ||
+ virAsprintf(&errexpect, TEST27_ERREXPECT_TEMP,
+ buffer0, buffer1, buffer2) < 0) {
+ printf("Could not virAsprintf expected output\n");
+ goto cleanup;
+ }
+
+ if (pipe(pipe1) < 0 || pipe(pipe2) < 0) {
+ printf("Could not create pipe: %s\n", strerror(errno));
+ goto cleanup;
+ }
+
+ if (virCommandSetSendBuffer(cmd, pipe1[1],
+ (unsigned char *)buffer1, buflen - 1) < 0 ||
+ virCommandSetSendBuffer(cmd, pipe2[1],
+ (unsigned char *)buffer2, buflen - 1) < 0) {
+ printf("Could not set send buffers\n");
+ goto cleanup;
+ }
+ pipe1[1] = 0;
+ pipe2[1] = 0;
+ buffer1 = NULL;
+ buffer2 = NULL;
+
+ virCommandAddArg(cmd, "--readfd");
+ virCommandAddArgFormat(cmd, "%d", pipe1[0]);
+ virCommandPassFD(cmd, pipe1[0], 0);
+
+ virCommandAddArg(cmd, "--readfd");
+ virCommandAddArgFormat(cmd, "%d", pipe2[0]);
+ virCommandPassFD(cmd, pipe2[0], 0);
+
+ virCommandSetInputBuffer(cmd, buffer0);
+ virCommandSetOutputBuffer(cmd, &outactual);
+ virCommandSetErrorBuffer(cmd, &erractual);
+
+ if (virCommandRun(cmd, NULL) < 0) {
+ printf("Cannot run child %s\n", virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ virCommandFree(cmd);
+
+ if (!outactual || !erractual)
+ goto cleanup;
+
+ if (STRNEQ(outactual, outexpect)) {
+ virTestDifference(stderr, outexpect, outactual);
+ goto cleanup;
+ }
+ if (STRNEQ(erractual, errexpect)) {
+ virTestDifference(stderr, errexpect, erractual);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ VIR_FORCE_CLOSE(pipe1[0]);
+ VIR_FORCE_CLOSE(pipe2[0]);
+ VIR_FORCE_CLOSE(pipe1[1]);
+ VIR_FORCE_CLOSE(pipe2[1]);
+ VIR_FREE(buffer0);
+ VIR_FREE(buffer1);
+ VIR_FREE(buffer2);
+ VIR_FREE(outactual);
+ VIR_FREE(erractual);
+ VIR_FREE(outexpect);
+ VIR_FREE(errexpect);
+
+ return ret;
+}
+
static void virCommandThreadWorker(void *opaque)
{
virCommandTestDataPtr test = opaque;
DO_TEST(test23);
DO_TEST(test25);
DO_TEST(test26);
+ DO_TEST(test27);
virMutexLock(&test->lock);
if (test->running) {