[libvirt] PATCH: 5/5: Make all code use virExec

Daniel P. Berrange berrange at redhat.com
Wed Aug 27 14:22:04 UTC 2008


On Wed, Aug 20, 2008 at 06:40:37PM +0200, Jim Meyering wrote:
> "Daniel P. Berrange" <berrange at redhat.com> wrote:
> > This final patch switches over all places which do fork()/exec() to use the
> > new enhanced virExec() code. A fair amount of code is deleted, but that's
> > not the whole story - the new impl is more robust that most of the existing
> > code we're deleting here.
> 
> Nice clean-up!

I believe I've addressed all the comments you had - its quite a significant
change from the previous patch. I was in fact able to simplify the bridge.c
file even more than I did before.

 bridge.c          |  128 ++++--------------------------------
 proxy_internal.c  |   26 +------
 qemu_conf.c       |  188 +++++++++++++++++++++++-------------------------------
 qemu_conf.h       |    8 +-
 qemu_driver.c     |   15 +---
 remote_internal.c |  101 +++--------------------------
 6 files changed, 125 insertions(+), 341 deletions(-)

Daniel

diff -r c3d345142e1b src/bridge.c
--- a/src/bridge.c	Wed Aug 27 12:45:11 2008 +0100
+++ b/src/bridge.c	Wed Aug 27 14:09:26 2008 +0100
@@ -46,6 +46,7 @@
 
 #include "internal.h"
 #include "memory.h"
+#include "util.h"
 
 #define MAX_BRIDGE_ID 256
 
@@ -596,42 +597,6 @@
     return brGetInetAddr(ctl, ifname, SIOCGIFNETMASK, addr, maxlen);
 }
 
-static int
-brctlSpawn(char * const *argv)
-{
-    pid_t pid, ret;
-    int status;
-    int null = -1;
-
-    if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0)
-        return errno;
-
-    pid = fork();
-    if (pid == -1) {
-        int saved_errno = errno;
-        close(null);
-        return saved_errno;
-    }
-
-    if (pid == 0) { /* child */
-        dup2(null, STDIN_FILENO);
-        dup2(null, STDOUT_FILENO);
-        dup2(null, STDERR_FILENO);
-        close(null);
-
-        execvp(argv[0], argv);
-
-        _exit (1);
-    }
-
-    close(null);
-
-    while ((ret = waitpid(pid, &status, 0) == -1) && errno == EINTR);
-    if (ret == -1)
-        return errno;
-
-    return (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : EINVAL;
-}
 
 /**
  * brSetForwardDelay:
@@ -641,7 +606,7 @@
  *
  * Set the bridge forward delay
  *
- * Returns 0 in case of success or an errno code in case of failure.
+ * Returns 0 in case of success or -1 on failure
  */
 
 int
@@ -649,48 +614,17 @@
                   const char *bridge,
                   int delay)
 {
-    char **argv;
-    int retval = ENOMEM;
-    int n;
     char delayStr[30];
-
-    n = 1 + /* brctl */
-        1 + /* setfd */
-        1 + /* brige name */
-        1; /* value */
+    const char *const progargv[] = {
+        BRCTL, "setfd", bridge, delayStr, NULL
+    };
 
     snprintf(delayStr, sizeof(delayStr), "%d", delay);
 
-    if (VIR_ALLOC_N(argv, n + 1) < 0)
-        goto error;
+    if (virRun(NULL, progargv, NULL) < 0)
+        return -1;
 
-    n = 0;
-
-    if (!(argv[n++] = strdup(BRCTL)))
-        goto error;
-
-    if (!(argv[n++] = strdup("setfd")))
-        goto error;
-
-    if (!(argv[n++] = strdup(bridge)))
-        goto error;
-
-    if (!(argv[n++] = strdup(delayStr)))
-        goto error;
-
-    argv[n++] = NULL;
-
-    retval = brctlSpawn(argv);
-
- error:
-    if (argv) {
-        n = 0;
-        while (argv[n])
-            VIR_FREE(argv[n++]);
-        VIR_FREE(argv);
-    }
-
-    return retval;
+    return 0;
 }
 
 /**
@@ -702,52 +636,22 @@
  * Control whether the bridge participates in the spanning tree protocol,
  * in general don't disable it without good reasons.
  *
- * Returns 0 in case of success or an errno code in case of failure.
+ * Returns 0 in case of success or -1 on failure
  */
 int
 brSetEnableSTP(brControl *ctl ATTRIBUTE_UNUSED,
                const char *bridge,
                int enable)
 {
-    char **argv;
-    int retval = ENOMEM;
-    int n;
+    const char *setting = enable ? "on" : "off";
+    const char *const progargv[] = {
+        BRCTL, "stp", bridge, setting, NULL
+    };
 
-    n = 1 + /* brctl */
-        1 + /* stp */
-        1 + /* brige name */
-        1;  /* value */
+    if (virRun(NULL, progargv, NULL) < 0)
+        return -1;
 
-    if (VIR_ALLOC_N(argv, n + 1) < 0)
-        goto error;
-
-    n = 0;
-
-    if (!(argv[n++] = strdup(BRCTL)))
-        goto error;
-
-    if (!(argv[n++] = strdup("stp")))
-        goto error;
-
-    if (!(argv[n++] = strdup(bridge)))
-        goto error;
-
-    if (!(argv[n++] = strdup(enable ? "on" : "off")))
-        goto error;
-
-    argv[n++] = NULL;
-
-    retval = brctlSpawn(argv);
-
- error:
-    if (argv) {
-        n = 0;
-        while (argv[n])
-            VIR_FREE(argv[n++]);
-        VIR_FREE(argv);
-    }
-
-    return retval;
+    return 0;
 }
 
 #endif /* WITH_QEMU || WITH_LXC */
diff -r c3d345142e1b src/proxy_internal.c
--- a/src/proxy_internal.c	Wed Aug 27 12:45:11 2008 +0100
+++ b/src/proxy_internal.c	Wed Aug 27 14:09:26 2008 +0100
@@ -160,6 +160,7 @@
 {
     const char *proxyPath = virProxyFindServerPath();
     int ret, pid, status;
+    const char *proxyarg[2];
 
     if (!proxyPath) {
         fprintf(stderr, "failed to find libvirt_proxy\n");
@@ -169,27 +170,12 @@
     if (debug)
         fprintf(stderr, "Asking to launch %s\n", proxyPath);
 
-    /* Become a daemon */
-    pid = fork();
-    if (pid == 0) {
-        long open_max;
-        long i;
+    proxyarg[0] = proxyPath;
+    proxyarg[1] = NULL;
 
-        /* don't hold open fd opened from the client of the library */
-        open_max = sysconf (_SC_OPEN_MAX);
-        for (i = 0; i < open_max; i++)
-            fcntl (i, F_SETFD, FD_CLOEXEC);
-
-        setsid();
-        if (fork() == 0) {
-            execl(proxyPath, proxyPath, NULL);
-            fprintf(stderr, _("failed to exec %s\n"), proxyPath);
-        }
-        /*
-         * calling exit() generate troubles for termination handlers
-         */
-        _exit(0);
-    }
+    if (virExec(NULL, proxyarg, NULL, NULL,
+                &pid, -1, NULL, NULL, VIR_EXEC_DAEMON) < 0)
+        fprintf(stderr, "Failed to fork libvirt_proxy\n");
 
     /*
      * do a waitpid on the intermediate process to avoid zombies.
diff -r c3d345142e1b src/qemu_conf.c
--- a/src/qemu_conf.c	Wed Aug 27 12:45:11 2008 +0100
+++ b/src/qemu_conf.c	Wed Aug 27 14:09:26 2008 +0100
@@ -394,124 +394,100 @@
 }
 
 
-int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) {
+int qemudExtractVersionInfo(const char *qemu,
+                            unsigned int *retversion,
+                            unsigned int *retflags) {
+    const char *const qemuarg[] = { qemu, "-help", NULL };
+    const char *const qemuenv[] = { "LC_ALL=C", NULL };
     pid_t child;
-    int newstdout[2];
+    int newstdout = -1;
+    char help[8192]; /* Ought to be enough to hold QEMU help screen */
+    int got = 0, ret = -1, status;
+    unsigned int major, minor, micro;
+    unsigned int version;
+    unsigned int flags = 0;
 
-    if (flags)
-        *flags = 0;
-    if (version)
-        *version = 0;
+    if (retflags)
+        *retflags = 0;
+    if (retversion)
+        *retversion = 0;
 
-    if (pipe(newstdout) < 0) {
+    if (virExec(NULL, qemuarg, qemuenv, NULL,
+                &child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0)
         return -1;
+
+
+    while (got < (sizeof(help)-1)) {
+        int len;
+        if ((len = saferead(newstdout, help+got, sizeof(help)-got-1)) < 0)
+            goto cleanup2;
+        if (!len)
+            break;
+        got += len;
+    }
+    help[got] = '\0';
+
+    if (sscanf(help, "QEMU PC emulator version %u.%u.%u",
+               &major, &minor, &micro) != 3) {
+        goto cleanup2;
     }
 
-    if ((child = fork()) < 0) {
-        close(newstdout[0]);
-        close(newstdout[1]);
-        return -1;
+    version = (major * 1000 * 1000) + (minor * 1000) + micro;
+
+    if (strstr(help, "-no-kqemu"))
+        flags |= QEMUD_CMD_FLAG_KQEMU;
+    if (strstr(help, "-no-reboot"))
+        flags |= QEMUD_CMD_FLAG_NO_REBOOT;
+    if (strstr(help, "-name"))
+        flags |= QEMUD_CMD_FLAG_NAME;
+    if (strstr(help, "-drive"))
+        flags |= QEMUD_CMD_FLAG_DRIVE;
+    if (strstr(help, "boot=on"))
+        flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
+    if (version >= 9000)
+        flags |= QEMUD_CMD_FLAG_VNC_COLON;
+
+
+    if (retversion)
+        *retversion = version;
+    if (retflags)
+        *retflags = flags;
+
+    ret = 0;
+
+    qemudDebug("Version %d %d %d  Cooked version: %d, with flags ? %d",
+               major, minor, micro, version, flags);
+
+cleanup2:
+    if (close(newstdout) < 0)
+        ret = -1;
+
+rewait:
+    if (waitpid(child, &status, 0) != child) {
+        if (errno == EINTR)
+            goto rewait;
+
+        qemudLog(QEMUD_ERR,
+                 _("Unexpected exit status from qemu %d pid %lu"),
+                 WEXITSTATUS(status), (unsigned long)child);
+        ret = -1;
+    }
+    /* Check & log unexpected exit status, but don't fail,
+     * as there's really no need to throw an error if we did
+     * actually read a valid version number above */
+    if (WEXITSTATUS(status) != 0) {
+        qemudLog(QEMUD_WARN,
+                 _("Unexpected exit status '%d', qemu probably failed"),
+                 WEXITSTATUS(status));
     }
 
-    if (child == 0) { /* Kid */
-        /* Just in case QEMU is translated someday we force to C locale.. */
-        const char *const qemuenv[] = { "LANG=C", NULL };
-
-        if (close(STDIN_FILENO) < 0)
-            goto cleanup1;
-        if (close(STDERR_FILENO) < 0)
-            goto cleanup1;
-        if (close(newstdout[0]) < 0)
-            goto cleanup1;
-        if (dup2(newstdout[1], STDOUT_FILENO) < 0)
-            goto cleanup1;
-
-        /* Passing -help, rather than relying on no-args which doesn't
-           always work */
-        execle(qemu, qemu, "-help", (char*)NULL, qemuenv);
-
-    cleanup1:
-        _exit(-1); /* Just in case */
-    } else { /* Parent */
-        char help[8192]; /* Ought to be enough to hold QEMU help screen */
-        int got = 0, ret = -1;
-        int major, minor, micro;
-        int ver;
-
-        if (close(newstdout[1]) < 0)
-            goto cleanup2;
-
-        while (got < (sizeof(help)-1)) {
-            int len;
-            if ((len = read(newstdout[0], help+got, sizeof(help)-got-1)) <= 0) {
-                if (!len)
-                    break;
-                if (errno == EINTR)
-                    continue;
-                goto cleanup2;
-            }
-            got += len;
-        }
-        help[got] = '\0';
-
-        if (sscanf(help, "QEMU PC emulator version %d.%d.%d", &major,&minor, &micro) != 3) {
-            goto cleanup2;
-        }
-
-        ver = (major * 1000 * 1000) + (minor * 1000) + micro;
-        if (version)
-            *version = ver;
-        if (flags) {
-            if (strstr(help, "-no-kqemu"))
-                *flags |= QEMUD_CMD_FLAG_KQEMU;
-            if (strstr(help, "-no-reboot"))
-                *flags |= QEMUD_CMD_FLAG_NO_REBOOT;
-            if (strstr(help, "-name"))
-                *flags |= QEMUD_CMD_FLAG_NAME;
-            if (strstr(help, "-drive"))
-                *flags |= QEMUD_CMD_FLAG_DRIVE;
-            if (strstr(help, "boot=on"))
-                *flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
-            if (ver >= 9000)
-                *flags |= QEMUD_CMD_FLAG_VNC_COLON;
-        }
-        ret = 0;
-
-        qemudDebug("Version %d %d %d  Cooked version: %d, with flags ? %d",
-                   major, minor, micro, *version, *flags);
-
-    cleanup2:
-        if (close(newstdout[0]) < 0)
-            ret = -1;
-
-    rewait:
-        if (waitpid(child, &got, 0) != child) {
-            if (errno == EINTR) {
-                goto rewait;
-            }
-            qemudLog(QEMUD_ERR,
-                     _("Unexpected exit status from qemu %d pid %lu"),
-                     got, (unsigned long)child);
-            ret = -1;
-        }
-        /* Check & log unexpected exit status, but don't fail,
-         * as there's really no need to throw an error if we did
-         * actually read a valid version number above */
-        if (WEXITSTATUS(got) != 0) {
-            qemudLog(QEMUD_WARN,
-                     _("Unexpected exit status '%d', qemu probably failed"),
-                     got);
-        }
-
-        return ret;
-    }
+    return ret;
 }
 
 int qemudExtractVersion(virConnectPtr conn,
                         struct qemud_driver *driver) {
     const char *binary;
     struct stat sb;
-    int ignored;
 
     if (driver->qemuVersion > 0)
         return 0;
@@ -529,7 +505,7 @@
         return -1;
     }
 
-    if (qemudExtractVersionInfo(binary, &driver->qemuVersion, &ignored) < 0) {
+    if (qemudExtractVersionInfo(binary, &driver->qemuVersion, NULL) < 0) {
         return -1;
     }
 
@@ -716,7 +692,7 @@
 int qemudBuildCommandLine(virConnectPtr conn,
                           struct qemud_driver *driver,
                           virDomainObjPtr vm,
-                          int qemuCmdFlags,
+                          unsigned int qemuCmdFlags,
                           const char ***retargv,
                           int **tapfds,
                           int *ntapfds,
diff -r c3d345142e1b src/qemu_conf.h
--- a/src/qemu_conf.h	Wed Aug 27 12:45:11 2008 +0100
+++ b/src/qemu_conf.h	Wed Aug 27 14:09:26 2008 +0100
@@ -49,7 +49,7 @@
 
 /* Main driver state */
 struct qemud_driver {
-    int qemuVersion;
+    unsigned int qemuVersion;
     int nextvmid;
 
     virDomainObjPtr domains;
@@ -86,13 +86,13 @@
 int         qemudExtractVersion         (virConnectPtr conn,
                                          struct qemud_driver *driver);
 int         qemudExtractVersionInfo     (const char *qemu,
-                                         int *version,
-                                         int *flags);
+                                         unsigned int *version,
+                                         unsigned int *flags);
 
 int         qemudBuildCommandLine       (virConnectPtr conn,
                                          struct qemud_driver *driver,
                                          virDomainObjPtr dom,
-                                         int qemuCmdFlags,
+                                         unsigned int qemuCmdFlags,
                                          const char ***argv,
                                          int **tapfds,
                                          int *ntapfds,
diff -r c3d345142e1b src/qemu_driver.c
--- a/src/qemu_driver.c	Wed Aug 27 12:45:11 2008 +0100
+++ b/src/qemu_driver.c	Wed Aug 27 14:09:26 2008 +0100
@@ -312,6 +312,7 @@
 qemudActive(void) {
     virDomainObjPtr dom = qemu_driver->domains;
     virNetworkObjPtr net = qemu_driver->networks;
+
     while (dom) {
         if (virDomainIsActive(dom))
             return 1;
@@ -846,7 +847,7 @@
     struct stat sb;
     int *tapfds = NULL;
     int ntapfds = 0;
-    int qemuCmdFlags;
+    unsigned int qemuCmdFlags;
     fd_set keepfd;
 
     FD_ZERO(&keepfd);
@@ -1509,19 +1510,11 @@
     }
 
 
-    if ((err = brSetForwardDelay(driver->brctl, network->def->bridge, network->def->delay))) {
-        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
-                         _("failed to set bridge forward delay to %ld"),
-                         network->def->delay);
+    if (brSetForwardDelay(driver->brctl, network->def->bridge, network->def->delay) < 0)
         goto err_delbr;
-    }
 
-    if ((err = brSetEnableSTP(driver->brctl, network->def->bridge, network->def->stp ? 1 : 0))) {
-        qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
-                         _("failed to set bridge STP to %s"),
-                         network->def->stp ? "on" : "off");
+    if (brSetEnableSTP(driver->brctl, network->def->bridge, network->def->stp ? 1 : 0) < 0)
         goto err_delbr;
-    }
 
     if (network->def->ipAddress &&
         (err = brSetInetAddress(driver->brctl, network->def->bridge, network->def->ipAddress))) {
diff -r c3d345142e1b src/remote_internal.c
--- a/src/remote_internal.c	Wed Aug 27 12:45:11 2008 +0100
+++ b/src/remote_internal.c	Wed Aug 27 14:09:26 2008 +0100
@@ -72,6 +72,7 @@
 #include "remote_internal.h"
 #include "remote_protocol.h"
 #include "memory.h"
+#include "util.h"
 
 #define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt,__VA_ARGS__)
 #define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
@@ -221,62 +222,17 @@
 remoteForkDaemon(virConnectPtr conn)
 {
     const char *daemonPath = remoteFindDaemonPath();
+    const char *const daemonargs[] = { daemonPath, "--timeout=30", NULL };
     int ret, pid, status;
 
     if (!daemonPath) {
         error(conn, VIR_ERR_INTERNAL_ERROR, _("failed to find libvirtd binary"));
-        return(-1);
-    }
-
-    /* Become a daemon */
-    pid = fork();
-    if (pid == 0) {
-        int stdinfd = -1;
-        int stdoutfd = -1;
-        int i, open_max;
-        if ((stdinfd = open(_PATH_DEVNULL, O_RDONLY)) < 0)
-            goto cleanup;
-        if ((stdoutfd = open(_PATH_DEVNULL, O_WRONLY)) < 0)
-            goto cleanup;
-        if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
-            goto cleanup;
-        if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
-            goto cleanup;
-        if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
-            goto cleanup;
-        if (close(stdinfd) < 0)
-            goto cleanup;
-        stdinfd = -1;
-        if (close(stdoutfd) < 0)
-            goto cleanup;
-        stdoutfd = -1;
-
-        open_max = sysconf (_SC_OPEN_MAX);
-        for (i = 0; i < open_max; i++)
-            if (i != STDIN_FILENO &&
-                i != STDOUT_FILENO &&
-                i != STDERR_FILENO)
-                close(i);
-
-        setsid();
-        if (fork() == 0) {
-            /* Run daemon in auto-shutdown mode, so it goes away when
-               no longer needed by an active guest, or client */
-            execl(daemonPath, daemonPath, "--timeout", "30", NULL);
-        }
-        /*
-         * calling exit() generate troubles for termination handlers
-         */
-        _exit(0);
-
-    cleanup:
-        if (stdoutfd != -1)
-            close(stdoutfd);
-        if (stdinfd != -1)
-            close(stdinfd);
-        _exit(-1);
-    }
-
+        return -1;
+    }
+
+    if (virExec(NULL, daemonargs, NULL, NULL,
+                &pid, -1, NULL, NULL, VIR_EXEC_DAEMON) < 0)
+        return -1;
     /*
      * do a waitpid on the intermediate process to avoid zombies.
      */
@@ -287,7 +243,7 @@
             goto retry_wait;
     }
 
-    return (0);
+    return 0;
 }
 #endif
 
@@ -349,7 +305,7 @@
     char *name = 0, *command = 0, *sockname = 0, *netcat = 0, *username = 0;
     char *port = 0, *authtype = 0;
     int no_verify = 0, no_tty = 0;
-    char **cmd_argv = 0;
+    char **cmd_argv = NULL;
 
     /* Return code from this function, and the private data. */
     int retcode = VIR_DRV_OPEN_ERROR;
@@ -693,40 +649,9 @@
             goto failed;
         }
 
-        pid = fork ();
-        if (pid == -1) {
-            errorf (conn, VIR_ERR_SYSTEM_ERROR,
-                    _("unable to fork external network transport: %s"),
-                    strerror (errno));
-            goto failed;
-        } else if (pid == 0) { /* Child. */
-            close (sv[0]);
-            // Connect socket (sv[1]) to stdin/stdout.
-            close (0);
-            if (dup (sv[1]) == -1) {
-                perror ("dup");
-                _exit(1);
-            }
-            close (1);
-            if (dup (sv[1]) == -1) {
-                perror ("dup");
-                _exit(1);
-            }
-            close (sv[1]);
-
-            // Run the external process.
-            if (!cmd_argv) {
-                if (VIR_ALLOC_N(cmd_argv, 2) < 0) {
-                    perror("malloc");
-                    _exit(1);
-                }
-                cmd_argv[0] = command;
-                cmd_argv[1] = 0;
-            }
-            execvp (command, cmd_argv);
-            perror (command);
-            _exit (1);
-        }
+        if (virExec(conn, (const char**)cmd_argv, NULL, NULL,
+                    &pid, sv[1], &(sv[1]), NULL, VIR_EXEC_NONE) < 0)
+            goto failed;
 
         /* Parent continues here. */
         close (sv[1]);



-- 
|: 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