[libvirt] PATCH: 3/4: Introduce libvirt_lxc binary

Daniel P. Berrange berrange at redhat.com
Wed Aug 13 14:22:43 UTC 2008


This patch is the important one, switching from an I/O controller which
is simply fork'd off libvirtd, to a properly execable libvirt_lxc
binary.

The libvirtd LXC driver writes the config it wants to launch with to 
/var/run/libvirt/lxc/NAME.log and invokves

    libvirt_lxc --name NAME

This then loads the config and spawns the container. It also expects a
'--console FD' arg to provide a file descriptor for the master PTY to
use for the container's stdin/out/err.  Currently this is compulsory
but we can make it optional in future and have the container stdin/out/err
plumbe straight to the libvirt_lxc process' existing stdin/out/err. This
would allow launching containers standalone. 

If networking is configured, then we also pass '--veth NAME' for each
configured interface specifying the name of the veth that will be moved
into the container's namespace.

The libvirt_lxc process writes a PID file to /var/run/libvirt/lxc/NAME.pid
and opens a UNIX socket in the same dir - this is how libvirtd discovers
when the container dies.

 a/src/lxc_controller.h |   41 ------
 src/Makefile.am        |   26 +++
 src/domain_conf.c      |    6 
 src/lxc_conf.c         |    8 -
 src/lxc_conf.h         |    4 
 src/lxc_controller.c   |  320 +++++++++++++++++++++++++++++++------------------
 src/lxc_driver.c       |  191 +++++++++++++++++++----------
 7 files changed, 366 insertions(+), 230 deletions(-)

Daniel

diff -r 1cf789924625 src/Makefile.am
--- a/src/Makefile.am	Tue Aug 12 22:21:48 2008 +0100
+++ b/src/Makefile.am	Tue Aug 12 22:22:37 2008 +0100
@@ -88,8 +88,13 @@
 LXC_DRIVER_SOURCES =						\
 		lxc_conf.c lxc_conf.h				\
 		lxc_container.c lxc_container.h			\
-		lxc_controller.c lxc_controller.h		\
 		lxc_driver.c lxc_driver.h			\
+		veth.c veth.h
+
+LXC_CONTROLLER_SOURCES =					\
+		lxc_conf.c lxc_conf.h				\
+		lxc_container.c lxc_container.h			\
+		lxc_controller.c				\
 		veth.c veth.h
 
 OPENVZ_DRIVER_SOURCES =						\
@@ -272,9 +277,11 @@
 	rm -f $@
 	mv $@-tmp $@
 
+libexec_PROGRAMS =
+
 if WITH_STORAGE_DISK
 if WITH_LIBVIRTD
-libexec_PROGRAMS = libvirt_parthelper
+libexec_PROGRAMS += libvirt_parthelper
 
 libvirt_parthelper_SOURCES = $(STORAGE_HELPER_DISK_SOURCES)
 libvirt_parthelper_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS)
@@ -284,6 +291,21 @@
 endif
 EXTRA_DIST += $(STORAGE_HELPER_DISK_SOURCES)
 
+
+if WITH_LXC
+if WITH_LIBVIRTD
+libexec_PROGRAMS += libvirt_lxc
+
+libvirt_lxc_SOURCES =						\
+		$(LXC_CONTROLLER_SOURCES)			\
+		$(GENERIC_LIB_SOURCES) 				\
+		$(DOMAIN_CONF_SOURCES)
+libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS)
+libvirt_lxc_LDADD = $(LIBXML_LIBS) ../gnulib/lib/libgnu.la
+libvirt_lxc_CFLAGS =  $(LIBPARTED_CFLAGS)
+endif
+endif
+EXTRA_DIST += $(LXC_CONTROLLER_SOURCES)
 
 # Create the /var/cache/libvirt directory when installing.
 install-exec-local:
diff -r 1cf789924625 src/domain_conf.c
--- a/src/domain_conf.c	Tue Aug 12 22:21:48 2008 +0100
+++ b/src/domain_conf.c	Tue Aug 12 22:22:37 2008 +0100
@@ -1109,13 +1109,11 @@
         break;
 
     case VIR_DOMAIN_CHR_TYPE_PTY:
-        /* @path attribute is an output only property - pty is auto-allocted */
-        break;
-
     case VIR_DOMAIN_CHR_TYPE_DEV:
     case VIR_DOMAIN_CHR_TYPE_FILE:
     case VIR_DOMAIN_CHR_TYPE_PIPE:
-        if (path == NULL) {
+        if (path == NULL &&
+            def->type != VIR_DOMAIN_CHR_TYPE_PTY) {
             virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
                                  "%s", _("Missing source path attribute for char device"));
             goto error;
diff -r 1cf789924625 src/lxc_conf.c
--- a/src/lxc_conf.c	Tue Aug 12 22:21:48 2008 +0100
+++ b/src/lxc_conf.c	Tue Aug 12 22:22:37 2008 +0100
@@ -71,7 +71,7 @@
                                          "exe",
                                          utsname.machine,
                                          sizeof(int) == 4 ? 32 : 8,
-                                         NULL,
+                                         BINDIR "/libvirt_lxc",
                                          NULL,
                                          0,
                                          NULL)) == NULL)
@@ -94,11 +94,11 @@
 int lxcLoadDriverConfig(lxc_driver_t *driver)
 {
     /* Set the container configuration directory */
-    if ((driver->configDir = strdup(SYSCONF_DIR "/libvirt/lxc")) == NULL)
+    if ((driver->configDir = strdup(LXC_CONFIG_DIR)) == NULL)
         goto no_memory;
-    if ((driver->stateDir = strdup(LOCAL_STATE_DIR "/run/libvirt/lxc")) == NULL)
+    if ((driver->stateDir = strdup(LXC_STATE_DIR)) == NULL)
         goto no_memory;
-    if ((driver->logDir = strdup(LOCAL_STATE_DIR "/log/libvirt/lxc")) == NULL)
+    if ((driver->logDir = strdup(LXC_LOG_DIR)) == NULL)
         goto no_memory;
 
     return 0;
diff -r 1cf789924625 src/lxc_conf.h
--- a/src/lxc_conf.h	Tue Aug 12 22:21:48 2008 +0100
+++ b/src/lxc_conf.h	Tue Aug 12 22:22:37 2008 +0100
@@ -30,6 +30,10 @@
 #include "domain_conf.h"
 #include "capabilities.h"
 
+#define LXC_CONFIG_DIR SYSCONF_DIR "/libvirt/lxc"
+#define LXC_STATE_DIR LOCAL_STATE_DIR "/run/libvirt/lxc"
+#define LXC_LOG_DIR LOCAL_STATE_DIR "/log/libvirt/lxc"
+
 typedef struct __lxc_driver lxc_driver_t;
 struct __lxc_driver {
     virCapsPtr caps;
diff -r 1cf789924625 src/lxc_controller.c
--- a/src/lxc_controller.c	Tue Aug 12 22:21:48 2008 +0100
+++ b/src/lxc_controller.c	Tue Aug 12 22:22:37 2008 +0100
@@ -23,22 +23,22 @@
 
 #include <config.h>
 
-#ifdef WITH_LXC
-
 #include <sys/epoll.h>
 #include <sys/wait.h>
 #include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
 #include <unistd.h>
 #include <paths.h>
 #include <fcntl.h>
 #include <signal.h>
+#include <getopt.h>
 
 #include "internal.h"
 #include "util.h"
 
 #include "lxc_conf.h"
 #include "lxc_container.h"
-#include "lxc_controller.h"
 #include "veth.h"
 #include "memory.h"
 #include "util.h"
@@ -47,6 +47,56 @@
 #define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
 #define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
 
+int debugFlag = 0;
+
+static char*lxcMonitorPath(virDomainDefPtr def)
+{
+    char *sockpath;
+    if (asprintf(&sockpath, "%s/%s.sock",
+                 LXC_STATE_DIR, def->name) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
+        return NULL;
+    }
+    return sockpath;
+}
+
+static int lxcMonitorServer(const char *sockpath)
+{
+    int fd;
+    struct sockaddr_un addr;
+
+    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("failed to create server socket %s: %s"),
+                 sockpath, strerror(errno));
+        goto error;
+    }
+
+    unlink(sockpath);
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
+
+    if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("failed to bind server socket %s: %s"),
+                 sockpath, strerror(errno));
+        goto error;
+    }
+    if (listen(fd, 30 /* backlog */ ) < 0) {
+        lxcError(NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("failed to listen server socket %s: %s"),
+                 sockpath, strerror(errno));
+        goto error;
+    }
+
+    return fd;
+
+error:
+    if (fd != -1)
+        close(fd);
+    return -1;
+}
 
 /**
  * lxcFdForward:
@@ -305,8 +355,7 @@
 
 
 static int
-lxcControllerRun(const char *stateDir,
-                 virDomainDefPtr def,
+lxcControllerRun(virDomainDefPtr def,
                  unsigned int nveths,
                  char **veths,
                  int monitor,
@@ -359,148 +408,187 @@
     if (containerPty != -1)
         close(containerPty);
 
-    kill(container, SIGTERM);
-    waitpid(container, NULL, 0);
-    lxcControllerCleanupInterfaces(nveths, veths);
-    virFileDeletePid(stateDir, def->name);
+    if (container > 1) {
+        kill(container, SIGTERM);
+        waitpid(container, NULL, 0);
+    }
     return rc;
 }
 
 
-int lxcControllerStart(const char *stateDir,
-                       virDomainDefPtr def,
-                       unsigned int nveths,
-                       char **veths,
-                       int monitor,
-                       int appPty,
-                       int logfd)
+int main(int argc, char *argv[])
 {
     pid_t pid;
-    int rc;
-    int status, null;
-    int open_max, i;
+    int rc = 1;
     int client;
-    struct sigaction sig_action;
+    char *name = NULL;
+    int nveths = 0;
+    char **veths = NULL;
+    int monitor = -1;
+    int appPty = -1;
+    int bg = 0;
+    virCapsPtr caps = NULL;
+    virDomainDefPtr def = NULL;
+    int nnets = 0;
+    virDomainNetDefPtr nets = NULL;
+    char *configFile = NULL;
+    char *sockpath = NULL;
+    const struct option const options[] = {
+        { "background", 0, NULL, 'b' },
+        { "name",   1, NULL, 'n' },
+        { "veth",   1, NULL, 'v' },
+        { "console", 1, NULL, 'c' },
+        { "help", 0, NULL, 'h' },
+        { 0, 0, 0, 0 },
+    };
 
-    if ((pid = fork()) < 0)
-        return -1;
+    while (1) {
+        int c;
 
-    if (pid > 0) {
-        /* Original caller waits for first child to exit */
-        while (1) {
-            rc = waitpid(pid, &status, 0);
-            if (rc < 0) {
-                if (errno == EINTR)
-                    continue;
-                return -1;
+        c = getopt_long(argc, argv, "dn:v:m:c:h",
+                       options, NULL);
+
+        if (c == -1)
+            break;
+
+        switch (c) {
+        case 'b':
+            bg = 1;
+            break;
+
+        case 'n':
+            if ((name = strdup(optarg)) == NULL) {
+                fprintf(stderr, "%s", strerror(errno));
+                goto cleanup;
             }
-            if (rc != pid) {
-                fprintf(stderr,
-                        _("Unexpected pid %d != %d from waitpid\n"),
-                        rc, pid);
-                return -1;
+            break;
+
+        case 'v':
+            if (VIR_REALLOC_N(veths, nveths+1) < 0) {
+                fprintf(stderr, "cannot allocate veths %s", strerror(errno));
+                goto cleanup;
             }
-            if (WIFEXITED(status) &&
-                WEXITSTATUS(status) == 0)
-                return 0;
-            else {
-                fprintf(stderr,
-                        _("Unexpected status %d from pid %d\n"),
-                        status, pid);
-                return -1;
+            if ((veths[nveths++] = strdup(optarg)) == NULL) {
+                fprintf(stderr, "cannot allocate veth name %s", strerror(errno));
+                goto cleanup;
             }
+            break;
+
+        case 'c':
+            if (virStrToLong_i(optarg, NULL, 10, &appPty) < 0) {
+                fprintf(stderr, "malformed --console argument '%s'", optarg);
+                goto cleanup;
+            }
+            break;
+
+        case 'h':
+        case '?':
+            fprintf(stderr, "\n");
+            fprintf(stderr, "syntax: %s [OPTIONS]\n", argv[0]);
+            fprintf(stderr, "\n");
+            fprintf(stderr, "Options\n");
+            fprintf(stderr, "\n");
+            fprintf(stderr, "  -b, --background\n");
+            fprintf(stderr, "  -n NAME, --name NAME\n");
+            fprintf(stderr, "  -c FD, --console FD\n");
+            fprintf(stderr, "  -v VETH, --veth VETH\n");
+            fprintf(stderr, "  -h, --help\n");
+            fprintf(stderr, "\n");
+            goto cleanup;
         }
     }
 
-    /* First child is running here */
 
-    /* Clobber all libvirtd's signal handlers so they
-     * don't affect us
-     */
-    sig_action.sa_handler = SIG_DFL;
-    sig_action.sa_flags = 0;
-    sigemptyset(&sig_action.sa_mask);
-
-    sigaction(SIGHUP, &sig_action, NULL);
-    sigaction(SIGINT, &sig_action, NULL);
-    sigaction(SIGQUIT, &sig_action, NULL);
-    sigaction(SIGTERM, &sig_action, NULL);
-    sigaction(SIGCHLD, &sig_action, NULL);
-
-    sig_action.sa_handler = SIG_IGN;
-    sigaction(SIGPIPE, &sig_action, NULL);
-
-
-    /* Don't hold onto any cwd we inherit from libvirtd either */
-    if (chdir("/") < 0) {
-        fprintf(stderr, _("Unable to change to root dir: %s\n"),
-                strerror(errno));
-        _exit(-1);
+    if (name == NULL) {
+        fprintf(stderr, "%s: missing --name argument for configuration\n", argv[0]);
+        goto cleanup;
     }
 
-    if (setsid() < 0) {
-        fprintf(stderr, _("Unable to become session leader: %s\n"),
-                strerror(errno));
-        _exit(-1);
+    if (appPty < 0) {
+        fprintf(stderr, "%s: missing --console argument for container PTY\n", argv[0]);
+        goto cleanup;
     }
 
-    if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0) {
-        fprintf(stderr, _("Unable to open %s: %s\n"),
-                _PATH_DEVNULL, strerror(errno));
-        _exit(-1);
+    if (getuid() && 0) {
+        fprintf(stderr, "%s: must be run as the 'root' user\n", argv[0]);
+        goto cleanup;
     }
 
-    open_max = sysconf (_SC_OPEN_MAX);
-    for (i = 0; i < open_max; i++)
-        if (i != appPty &&
-            i != monitor &&
-            i != logfd &&
-            i != null)
-            close(i);
+    if ((caps = lxcCapsInit()) == NULL)
+        goto cleanup;
 
-    if (dup2(null, STDIN_FILENO) < 0 ||
-        dup2(logfd, STDOUT_FILENO) < 0 ||
-        dup2(logfd, STDERR_FILENO) < 0) {
-        fprintf(stderr, _("Unable to redirect stdio: %s\n"),
-                strerror(errno));
-        _exit(-1);
+    if ((configFile = virDomainConfigFile(NULL,
+                                          LXC_STATE_DIR,
+                                          name)) == NULL)
+        goto cleanup;
+
+    if ((def = virDomainDefParseFile(NULL, caps, configFile)) == NULL)
+        goto cleanup;
+
+    nets = def->nets;
+    while (nets) {
+        nnets++;
+        nets = nets->next;
+    }
+    if (nnets != nveths) {
+        fprintf(stderr, "%s: expecting %d veths, but got %d\n",
+                argv[0], nnets, nveths);
+        goto cleanup;
     }
 
-    close(null);
-    close(logfd);
+    if ((sockpath = lxcMonitorPath(def)) == NULL)
+        goto cleanup;
 
-    /* Now fork the real controller process */
-    if ((pid = fork()) < 0) {
-        fprintf(stderr, _("Unable to fork controller: %s\n"),
-                strerror(errno));
-        _exit(-1);
+    if ((monitor = lxcMonitorServer(sockpath)) < 0)
+        goto cleanup;
+
+    if (bg) {
+        if ((pid = fork()) < 0)
+            goto cleanup;
+
+        if (pid > 0) {
+            if ((rc = virFileWritePid(LXC_STATE_DIR, name, pid)) != 0) {
+                fprintf(stderr, _("Unable to write pid file: %s\n"),
+                        strerror(rc));
+                _exit(1);
+            }
+
+            /* First child now exits, allowing original caller
+             * (ie libvirtd's LXC driver to complete their
+             * waitpid & continue */
+            _exit(0);
+        }
+
+        /* Don't hold onto any cwd we inherit from libvirtd either */
+        if (chdir("/") < 0) {
+            fprintf(stderr, _("Unable to change to root dir: %s\n"),
+                    strerror(errno));
+            goto cleanup;
+        }
+
+        if (setsid() < 0) {
+            fprintf(stderr, _("Unable to become session leader: %s\n"),
+                    strerror(errno));
+            goto cleanup;
+        }
     }
 
-    if (pid > 0) {
-        if ((rc = virFileWritePid(stateDir, def->name, pid)) != 0) {
-            fprintf(stderr, _("Unable to write pid file: %s\n"),
-                    strerror(rc));
-            _exit(-1);
-        }
-        /* First child now exits, allowing originall caller to
-         * complete their waitpid & continue */
-        _exit(0);
+    /* Accept initial client which is the libvirtd daemon */
+    if ((client = accept(monitor, NULL, 0)) < 0) {
+        fprintf(stderr, _("Failed connection from LXC driver: %s\n"),
+                strerror(errno));
+        goto cleanup;
     }
 
-    /* This is real controller running finally... */
+    rc = lxcControllerRun(def, nveths, veths, monitor, client, appPty);
 
-    /* Accept initial client which is the libvirtd daemon */
-    if ((client = accept(monitor, NULL, 0))) {
-        fprintf(stderr, _("Failed connection from LXC driver: %s\n"),
-                strerror(errno));
-        _exit(-1);
-    }
 
-    /* Controlling libvirtd LXC driver now knows
-       what our PID is, and is able to cleanup after
-       us from now on */
-    _exit(lxcControllerRun(stateDir, def, nveths, veths, monitor, client, appPty));
+cleanup:
+    virFileDeletePid(LXC_STATE_DIR, def->name);
+    lxcControllerCleanupInterfaces(nveths, veths);
+    unlink(sockpath);
+    VIR_FREE(sockpath);
+
+    return rc;
 }
 
-
-#endif
diff -r 1cf789924625 src/lxc_controller.h
--- a/src/lxc_controller.h	Tue Aug 12 22:21:48 2008 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-/*
- * Copyright IBM Corp. 2008
- *
- * lxc_controller.h: linux container process controller
- *
- * Authors:
- *  David L. Leskovec <dlesko at linux.vnet.ibm.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef LXC_CONTROLLER_H
-#define LXC_CONTROLLER_H
-
-#ifdef WITH_LXC
-
-#include "lxc_conf.h"
-
-int lxcControllerStart(const char *stateDir,
-                       virDomainDefPtr def,
-                       unsigned int nveths,
-                       char **veths,
-                       int monitor,
-                       int appPty,
-                       int logfd);
-
-#endif /* WITH_LXC */
-
-#endif /* LXC_CONTROLLER_H */
diff -r 1cf789924625 src/lxc_driver.c
--- a/src/lxc_driver.c	Tue Aug 12 22:21:48 2008 +0100
+++ b/src/lxc_driver.c	Tue Aug 12 22:22:37 2008 +0100
@@ -38,7 +38,6 @@
 #include "lxc_conf.h"
 #include "lxc_container.h"
 #include "lxc_driver.h"
-#include "lxc_controller.h"
 #include "memory.h"
 #include "util.h"
 #include "bridge.h"
@@ -398,6 +397,7 @@
     close(vm->monitor);
 
     virFileDeletePid(driver->stateDir, vm->def->name);
+    virDomainDeleteConfig(conn, driver->stateDir, NULL, vm);
 
     vm->state = VIR_DOMAIN_SHUTOFF;
     vm->pid = -1;
@@ -507,55 +507,6 @@
     return rc;
 }
 
-static int lxcMonitorServer(virConnectPtr conn,
-                            lxc_driver_t * driver,
-                            virDomainObjPtr vm)
-{
-    char *sockpath = NULL;
-    int fd;
-    struct sockaddr_un addr;
-
-    if (asprintf(&sockpath, "%s/%s.sock",
-                 driver->stateDir, vm->def->name) < 0) {
-        lxcError(conn, NULL, VIR_ERR_NO_MEMORY, NULL);
-        return -1;
-    }
-
-    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
-        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
-                 _("failed to create server socket: %s"),
-                 strerror(errno));
-        goto error;
-    }
-
-    unlink(sockpath);
-    memset(&addr, 0, sizeof(addr));
-    addr.sun_family = AF_UNIX;
-    strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
-
-    if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
-                 _("failed to bind server socket: %s"),
-                 strerror(errno));
-        goto error;
-    }
-    if (listen(fd, 30 /* backlog */ ) < 0) {
-        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
-                 _("failed to listen server socket: %s"),
-                 strerror(errno));
-        goto error;
-        return (-1);
-    }
-
-    VIR_FREE(sockpath);
-    return fd;
-
-error:
-    VIR_FREE(sockpath);
-    if (fd != -1)
-        close(fd);
-    return -1;
-}
 
 static int lxcMonitorClient(virConnectPtr conn,
                             lxc_driver_t * driver,
@@ -608,6 +559,12 @@
     if (signum == 0)
         signum = SIGINT;
 
+    if (vm->pid <= 0) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("invalid PID %d for container"), vm->pid);
+        return -1;
+    }
+
     if (kill(vm->pid, signum) < 0) {
         if (errno != ESRCH) {
             lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
@@ -644,6 +601,102 @@
 }
 
 
+static int lxcControllerStart(virConnectPtr conn,
+                              virDomainObjPtr vm,
+                              int nveths,
+                              char **veths,
+                              int appPty,
+                              int logfd)
+{
+    int i;
+    int rc;
+    int ret = -1;
+    int largc = 0, larga = 0;
+    const char **largv = NULL;
+    pid_t child;
+    int status;
+
+#define ADD_ARG_SPACE                                                   \
+    do { \
+        if (largc == larga) {                                           \
+            larga += 10;                                                \
+            if (VIR_REALLOC_N(largv, larga) < 0)                        \
+                goto no_memory;                                         \
+        }                                                               \
+    } while (0)
+
+#define ADD_ARG(thisarg)                                                \
+    do {                                                                \
+        ADD_ARG_SPACE;                                                  \
+        largv[largc++] = thisarg;                                       \
+    } while (0)
+
+#define ADD_ARG_LIT(thisarg)                                            \
+    do {                                                                \
+        ADD_ARG_SPACE;                                                  \
+        if ((largv[largc++] = strdup(thisarg)) == NULL)                 \
+            goto no_memory;                                             \
+    } while (0)
+
+    ADD_ARG_LIT(vm->def->emulator);
+    ADD_ARG_LIT("--name");
+    ADD_ARG_LIT(vm->def->name);
+    ADD_ARG_LIT("--console");
+    ADD_ARG_LIT("0");  /* Passing console master PTY as FD 0 */
+    ADD_ARG_LIT("--background");
+
+    for (i = 0 ; i < nveths ; i++) {
+        ADD_ARG_LIT("--veth");
+        ADD_ARG_LIT(veths[i]);
+    }
+
+    ADD_ARG(NULL);
+
+    vm->stdin_fd = appPty; /* Passing console master PTY as FD 0 */
+    vm->stdout_fd = vm->stderr_fd = logfd;
+
+    if (virExec(conn, largv, NULL, &child,
+                vm->stdin_fd, &vm->stdout_fd, &vm->stderr_fd,
+                VIR_EXEC_NONE) < 0)
+        goto cleanup;
+
+    /* We now wait for the process to exit - the controller
+     * will fork() itself into the background - waiting for
+     * it to exit thus guarentees it has written its pidfile
+     */
+    while ((rc = waitpid(child, &status, 0) == -1) && errno == EINTR);
+    if (rc == -1) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("cannot wait for '%s': %s"),
+                 largv[0], strerror(errno));
+        goto cleanup;
+    }
+
+    if (!(WIFEXITED(status) && WEXITSTATUS(status) == 0)) {
+        lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
+                 _("container '%s' unexpectedly shutdown during startup"),
+                 largv[0]);
+        goto cleanup;
+    }
+
+#undef ADD_ARG
+#undef ADD_ARG_LIT
+#undef ADD_ARG_SPACE
+
+    ret = 0;
+
+cleanup:
+    for (i = 0 ; i < largc ; i++)
+        VIR_FREE(largv[i]);
+
+    return ret;
+
+no_memory:
+    lxcError(conn, NULL, VIR_ERR_NO_MEMORY, NULL);
+    goto cleanup;
+}
+
+
 /**
  * lxcVmStart:
  * @conn: pointer to connection
@@ -660,7 +713,6 @@
 {
     int rc = -1;
     unsigned int i;
-    int monitor;
     int parentTty;
     char *parentTtyPath = NULL;
     char *logfile = NULL;
@@ -681,9 +733,6 @@
         return -1;
     }
 
-    if ((monitor = lxcMonitorServer(conn, driver, vm)) < 0)
-        goto cleanup;
-
     /* open parent tty */
     if (virFileOpenTty(&parentTty, &parentTtyPath, 1) < 0) {
         lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
@@ -702,6 +751,12 @@
     if (lxcSetupInterfaces(conn, vm->def, &nveths, &veths) != 0)
         goto cleanup;
 
+    /* Persist the live configuration now we have veth & tty info */
+    if (virDomainSaveConfig(conn, driver->stateDir, vm->def) < 0) {
+        rc = -1;
+        goto cleanup;
+    }
+
     if ((logfd = open(logfile, O_WRONLY | O_TRUNC | O_CREAT,
              S_IRUSR|S_IWUSR)) < 0) {
         lxcError(conn, NULL, VIR_ERR_INTERNAL_ERROR,
@@ -710,14 +765,11 @@
         goto cleanup;
     }
 
-    if (lxcControllerStart(driver->stateDir,
-                           vm->def, nveths, veths,
-                           monitor, parentTty, logfd) < 0)
+    if (lxcControllerStart(conn,
+                           vm,
+                           nveths, veths,
+                           parentTty, logfd) < 0)
         goto cleanup;
-    /* Close the server side of the monitor, now owned
-     * by the controller process */
-    close(monitor);
-    monitor = -1;
 
     /* Connect to the controller as a client *first* because
      * this will block until the child has written their
@@ -753,8 +805,6 @@
             vethDelete(veths[i]);
         VIR_FREE(veths[i]);
     }
-    if (monitor != -1)
-        close(monitor);
     if (rc != 0 && vm->monitor != -1) {
         close(vm->monitor);
         vm->monitor = -1;
@@ -951,6 +1001,8 @@
 
     vm = lxc_driver->domains;
     while (vm) {
+        char *config = NULL;
+        virDomainDefPtr tmp;
         int rc;
         if ((vm->monitor = lxcMonitorClient(NULL, lxc_driver, vm)) < 0) {
             vm = vm->next;
@@ -963,6 +1015,19 @@
             vm->monitor = -1;
             vm = vm->next;
             continue;
+        }
+
+        if ((config = virDomainConfigFile(NULL,
+                                          lxc_driver->stateDir,
+                                          vm->def->name)) == NULL)
+            continue;
+
+        /* Try and load the live config */
+        tmp = virDomainDefParseFile(NULL, lxc_driver->caps, config);
+        VIR_FREE(config);
+        if (tmp) {
+            vm->newDef = vm->def;
+            vm->def = tmp;
         }
 
         if (vm->pid != 0) {

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