[libvirt] PATCH: 3/5: Allow FD for stdout/err to be passed in

Daniel P. Berrange berrange at redhat.com
Wed Aug 13 09:14:48 UTC 2008


The contract for virExec() currently allows the caller to pass in a NULL
for stdout/err parameters in which case the child will be connected to
/dev/null, or they can pass in a pointer to an int, in which case the
child will be connected to a pair of pipes, and the read end of the pipe
is returned to the caller.

The LXC driver will require a 3rd option - we want to pass in a existing
file handler connected to a logfile. So this patch extends the semantics
of these two parameters. If the stderr/out params are non-NULL, but are
initialized to -1, then a pipe will be allocated. If they are >= 0, then
they are assumed to be existing FDs to dup onto the child's stdout/err.

This change neccessitated updating all existing callers of virExec to
make sure they initialize the parameters to -1 to maintain existing
behaviour.


 openvz_driver.c |    4 -
 qemu_driver.c   |    2 
 util.c          |  120 ++++++++++++++++++++++++++++++++------------------------
 3 files changed, 73 insertions(+), 53 deletions(-)


Daniel

diff -r 100b059a8488 src/openvz_driver.c
--- a/src/openvz_driver.c	Tue Aug 12 22:12:38 2008 +0100
+++ b/src/openvz_driver.c	Tue Aug 12 22:12:42 2008 +0100
@@ -736,7 +736,7 @@
 
 static int openvzListDomains(virConnectPtr conn, int *ids, int nids) {
     int got = 0;
-    int veid, pid, outfd, errfd;
+    int veid, pid, outfd = -1, errfd = -1;
     int ret;
     char buf[32];
     char *endptr;
@@ -772,7 +772,7 @@
 static int openvzListDefinedDomains(virConnectPtr conn,
                             char **const names, int nnames) {
     int got = 0;
-    int veid, pid, outfd, errfd, ret;
+    int veid, pid, outfd = -1, errfd = -1, ret;
     char vpsname[OPENVZ_NAME_MAX];
     char buf[32];
     char *endptr;
diff -r 100b059a8488 src/qemu_driver.c
--- a/src/qemu_driver.c	Tue Aug 12 22:12:38 2008 +0100
+++ b/src/qemu_driver.c	Tue Aug 12 22:12:42 2008 +0100
@@ -948,6 +948,8 @@
     if (safewrite(vm->logfile, "\n", 1) < 0)
         qemudLog(QEMUD_WARN, _("Unable to write argv to logfile %d: %s\n"),
                  errno, strerror(errno));
+
+    vm->stdout_fd = vm->stderr_fd = -1;
 
     ret = virExecNonBlock(conn, argv, &vm->pid,
                           vm->stdin_fd, &vm->stdout_fd, &vm->stderr_fd);
diff -r 100b059a8488 src/util.c
--- a/src/util.c	Tue Aug 12 22:12:38 2008 +0100
+++ b/src/util.c	Tue Aug 12 22:12:42 2008 +0100
@@ -110,6 +110,7 @@
     int pid, null, i;
     int pipeout[2] = {-1,-1};
     int pipeerr[2] = {-1,-1};
+    int childout = -1, childerr = -1;
     sigset_t oldmask, newmask;
     struct sigaction sig_action;
 
@@ -132,39 +133,66 @@
         goto cleanup;
     }
 
-    if ((outfd != NULL && pipe(pipeout) < 0) ||
-        (errfd != NULL && pipe(pipeerr) < 0)) {
-        ReportError(conn, VIR_ERR_INTERNAL_ERROR,
-                    _("cannot create pipe: %s"), strerror(errno));
-        goto cleanup;
+    if (outfd != NULL) {
+        if (*outfd == -1) {
+            if (pipe(pipeout) < 0) {
+                ReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                            _("cannot create pipe: %s"), strerror(errno));
+                goto cleanup;
+            }
+
+            if (non_block &&
+                virSetNonBlock(pipeout[0]) == -1) {
+                ReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                            _("Failed to set non-blocking file descriptor flag"));
+                goto cleanup;
+            }
+
+            if (virSetCloseExec(pipeout[0]) == -1) {
+                ReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                            _("Failed to set close-on-exec file descriptor flag"));
+                goto cleanup;
+            }
+
+            childout = pipeout[1];
+        } else {
+            childout = *outfd;
+        }
+#ifndef ENABLE_DEBUG
+    } else {
+        childout = null;
+#endif
     }
 
-    if (outfd) {
-        if(non_block &&
-           virSetNonBlock(pipeout[0]) == -1) {
-            ReportError(conn, VIR_ERR_INTERNAL_ERROR,
-                        _("Failed to set non-blocking file descriptor flag"));
-            goto cleanup;
+    if (errfd != NULL) {
+        if (*errfd == -1) {
+            if (pipe(pipeerr) < 0) {
+                ReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                            _("cannot create pipe: %s"), strerror(errno));
+                goto cleanup;
+            }
+
+            if (non_block &&
+                virSetNonBlock(pipeerr[0]) == -1) {
+                ReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                            _("Failed to set non-blocking file descriptor flag"));
+                goto cleanup;
+            }
+
+            if (virSetCloseExec(pipeerr[0]) == -1) {
+                ReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                            _("Failed to set close-on-exec file descriptor flag"));
+                goto cleanup;
+            }
+
+            childerr = pipeerr[1];
+        } else {
+            childerr = *errfd;
         }
-
-        if(virSetCloseExec(pipeout[0]) == -1) {
-            ReportError(conn, VIR_ERR_INTERNAL_ERROR,
-                        _("Failed to set close-on-exec file descriptor flag"));
-            goto cleanup;
-        }
-    }
-    if (errfd) {
-        if(non_block &&
-           virSetNonBlock(pipeerr[0]) == -1) {
-            ReportError(conn, VIR_ERR_INTERNAL_ERROR,
-                        _("Failed to set non-blocking file descriptor flag"));
-            goto cleanup;
-        }
-        if(virSetCloseExec(pipeerr[0]) == -1) {
-            ReportError(conn, VIR_ERR_INTERNAL_ERROR,
-                        _("Failed to set close-on-exec file descriptor flag"));
-            goto cleanup;
-        }
+#ifndef ENABLE_DEBUG
+    } else {
+        childerr = null;
+#endif
     }
 
     if ((pid = fork()) < 0) {
@@ -175,11 +203,11 @@
 
     if (pid) { /* parent */
         close(null);
-        if (outfd) {
+        if (outfd && *outfd == -1) {
             close(pipeout[1]);
             *outfd = pipeout[0];
         }
-        if (errfd) {
+        if (errfd && *errfd == -1) {
             close(pipeerr[1]);
             *errfd = pipeerr[0];
         }
@@ -242,35 +270,25 @@
                     _("failed to setup stdin file handle: %s"), strerror(errno));
         _exit(1);
     }
-#ifndef ENABLE_DEBUG
-    if (dup2(pipeout[1] > 0 ? pipeout[1] : null, STDOUT_FILENO) < 0) {
+    if (childout > 0 &&
+        dup2(childout, STDOUT_FILENO) < 0) {
         ReportError(conn, VIR_ERR_INTERNAL_ERROR,
                     _("failed to setup stdout file handle: %s"), strerror(errno));
         _exit(1);
     }
-    if (dup2(pipeerr[1] > 0 ? pipeerr[1] : null, STDERR_FILENO) < 0) {
+    if (childerr > 0 &&
+        dup2(childerr, STDERR_FILENO) < 0) {
         ReportError(conn, VIR_ERR_INTERNAL_ERROR,
                     _("failed to setup stderr file handle: %s"), strerror(errno));
         _exit(1);
     }
-#else /* ENABLE_DEBUG */
-    if (pipeout[1] > 0 && dup2(pipeout[1], STDOUT_FILENO) < 0) {
-        ReportError(conn, VIR_ERR_INTERNAL_ERROR,
-                    _("failed to setup stderr file handle: %s"), strerror(errno));
-        _exit(1);
-    }
-    if (pipeerr[1] > 0 && dup2(pipeerr[1], STDERR_FILENO) < 0) {
-        ReportError(conn, VIR_ERR_INTERNAL_ERROR,
-                    _("failed to setup stdout file handle: %s"), strerror(errno));
-        _exit(1);
-    }
-#endif /* ENABLE_DEBUG */
 
     close(null);
-    if (pipeout[1] > 0)
-        close(pipeout[1]);
-    if (pipeerr[1] > 0)
-        close(pipeerr[1]);
+    if (childout > 0)
+        close(childout);
+    if (childerr > 0 &&
+        childerr != childout)
+        close(childerr);
 
     execvp(argv[0], (char **) argv);
 


-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list