Re: PATCH 3/20: domain lifecycle changes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Attached this time...

On Fri, Jun 22, 2007 at 02:40:20AM +0100, Daniel P. Berrange wrote:
> This patch moves the code which deals with starting and stopping of domains
> and networks out of qemud.d and into the main QEMU driver.c file.
> 
>  driver.c   | 1067 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  driver.h   |   14 
>  internal.h |   12 
>  qemud.c    | 1029 ----------------------------------------------------------
>  4 files changed, 1083 insertions(+), 1039 deletions(-)

Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
diff -r a04dbba5004f qemud/driver.c
--- a/qemud/driver.c	Thu Jun 21 12:06:05 2007 -0400
+++ b/qemud/driver.c	Thu Jun 21 16:07:18 2007 -0400
@@ -35,9 +35,16 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/utsname.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <paths.h>
+#include <ctype.h>
+#include <sys/wait.h>
 
 #include <libvirt/virterror.h>
 
+#include "event.h"
 #include "buf.h"
 #include "internal.h"
 #include "driver.h"
@@ -54,6 +61,1066 @@ void qemudReportError(struct qemud_serve
     } else {
         server->errorMessage[0] = '\0';
     }
+}
+
+static void qemudDispatchVMEvent(int fd, int events, void *opaque);
+
+static int qemudSetCloseExec(int fd) {
+    int flags;
+    if ((flags = fcntl(fd, F_GETFD)) < 0)
+        goto error;
+    flags |= FD_CLOEXEC;
+    if ((fcntl(fd, F_SETFD, flags)) < 0)
+        goto error;
+    return 0;
+ error:
+    qemudLog(QEMUD_ERR, "Failed to set close-on-exec file descriptor flag");
+    return -1;
+}
+
+
+static int qemudSetNonBlock(int fd) {
+    int flags;
+    if ((flags = fcntl(fd, F_GETFL)) < 0)
+        goto error;
+    flags |= O_NONBLOCK;
+    if ((fcntl(fd, F_SETFL, flags)) < 0)
+        goto error;
+    return 0;
+ error:
+    qemudLog(QEMUD_ERR, "Failed to set non-blocking file descriptor flag");
+    return -1;
+}
+
+
+void qemudShutdown(struct qemud_server *server) {
+    struct qemud_vm *vm;
+    struct qemud_network *network;
+
+    /* shutdown active VMs */
+    vm = server->vms;
+    while (vm) {
+        struct qemud_vm *next = vm->next;
+        if (qemudIsActiveVM(vm))
+            qemudShutdownVMDaemon(server, vm);
+        vm = next;
+    }
+    
+    /* free inactive VMs */
+    vm = server->vms;
+    while (vm) {
+        struct qemud_vm *next = vm->next;
+        qemudFreeVM(vm);
+        vm = next;
+    }
+    server->vms = NULL;
+    server->nactivevms = 0;
+    server->ninactivevms = 0;
+
+    /* shutdown active networks */
+    network = server->networks;
+    while (network) {
+        struct qemud_network *next = network->next;
+        if (qemudIsActiveNetwork(network))
+            qemudShutdownNetworkDaemon(server, network);
+        network = next;
+    }
+    
+    /* free inactive networks */
+    network = server->networks;
+    while (network) {
+        struct qemud_network *next = network->next;
+        qemudFreeNetwork(network);
+        network = next;
+    }
+    server->networks = NULL;
+    server->nactivenetworks = 0;
+    server->ninactivenetworks = 0;
+}
+
+static int
+qemudExec(struct qemud_server *server, char **argv,
+          int *retpid, int *outfd, int *errfd) {
+    int pid, null;
+    int pipeout[2] = {-1,-1};
+    int pipeerr[2] = {-1,-1};
+
+    if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot open %s : %s",
+                         _PATH_DEVNULL, strerror(errno));
+        goto cleanup;
+    }
+
+    if ((outfd != NULL && pipe(pipeout) < 0) ||
+        (errfd != NULL && pipe(pipeerr) < 0)) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot create pipe : %s",
+                         strerror(errno));
+        goto cleanup;
+    }
+
+    if ((pid = fork()) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot fork child process : %s",
+                         strerror(errno));
+        goto cleanup;
+    }
+
+    if (pid) { /* parent */
+        close(null);
+        if (outfd) {
+            close(pipeout[1]);
+            qemudSetNonBlock(pipeout[0]);
+            qemudSetCloseExec(pipeout[0]);
+            *outfd = pipeout[0];
+        }
+        if (errfd) {
+            close(pipeerr[1]);
+            qemudSetNonBlock(pipeerr[0]);
+            qemudSetCloseExec(pipeerr[0]);
+            *errfd = pipeerr[0];
+        }
+        *retpid = pid;
+        return 0;
+    }
+
+    /* child */
+
+    if (pipeout[0] > 0 && close(pipeout[0]) < 0)
+        _exit(1);
+    if (pipeerr[0] > 0 && close(pipeerr[0]) < 0)
+        _exit(1);
+
+    if (dup2(null, STDIN_FILENO) < 0)
+        _exit(1);
+    if (dup2(pipeout[1] > 0 ? pipeout[1] : null, STDOUT_FILENO) < 0)
+        _exit(1);
+    if (dup2(pipeerr[1] > 0 ? pipeerr[1] : null, STDERR_FILENO) < 0)
+        _exit(1);
+
+    close(null);
+    if (pipeout[1] > 0)
+        close(pipeout[1]);
+    if (pipeerr[1] > 0)
+        close(pipeerr[1]);
+
+    execvp(argv[0], argv);
+
+    _exit(1);
+
+    return 0;
+
+ cleanup:
+    if (pipeerr[0] > 0)
+        close(pipeerr[0]);
+    if (pipeerr[1] > 0)
+        close(pipeerr[1]);
+    if (pipeout[0] > 0)
+        close(pipeout[0]);
+    if (pipeout[1] > 0)
+        close(pipeout[1]);
+    if (null > 0)
+        close(null);
+    return -1;
+}
+
+/* Return -1 for error, 1 to continue reading and 0 for success */
+typedef int qemudHandlerMonitorOutput(struct qemud_server *server,
+                                      struct qemud_vm *vm,
+                                      const char *output,
+                                      int fd);
+
+static int
+qemudReadMonitorOutput(struct qemud_server *server,
+                       struct qemud_vm *vm,
+                       int fd,
+                       char *buf,
+                       int buflen,
+                       qemudHandlerMonitorOutput func,
+                       const char *what)
+{
+#define MONITOR_TIMEOUT 3000
+
+    int got = 0;
+    buf[0] = '\0';
+
+   /* Consume & discard the initial greeting */
+    while (got < (buflen-1)) {
+        int ret;
+
+        ret = read(fd, buf+got, buflen-got-1);
+        if (ret == 0) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "QEMU quit during %s startup\n%s", what, buf);
+            return -1;
+        }
+        if (ret < 0) {
+            struct pollfd pfd = { .fd = fd, .events = POLLIN };
+            if (errno == EINTR)
+                continue;
+
+            if (errno != EAGAIN) {
+                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                                 "Failure while reading %s startup output: %s",
+                                 what, strerror(errno));
+                return -1;
+            }
+
+            ret = poll(&pfd, 1, MONITOR_TIMEOUT);
+            if (ret == 0) {
+                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                                 "Timed out while reading %s startup output", what);
+                return -1;
+            } else if (ret == -1) {
+                if (errno != EINTR) {
+                    qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                                     "Failure while reading %s startup output: %s",
+                                     what, strerror(errno));
+                    return -1;
+                }
+            } else {
+                /* Make sure we continue loop & read any further data
+                   available before dealing with EOF */
+                if (pfd.revents & (POLLIN | POLLHUP))
+                    continue;
+
+                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                                 "Failure while reading %s startup output", what);
+                return -1;
+            }
+        } else {
+            got += ret;
+            buf[got] = '\0';
+            if ((ret = func(server, vm, buf, fd)) != 1)
+                return ret;
+        }
+    }
+
+    qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                     "Out of space while reading %s startup output", what);
+    return -1;
+
+#undef MONITOR_TIMEOUT
+}
+
+static int
+qemudCheckMonitorPrompt(struct qemud_server *server ATTRIBUTE_UNUSED,
+                        struct qemud_vm *vm,
+                        const char *output,
+                        int fd)
+{
+    if (strstr(output, "(qemu) ") == NULL)
+        return 1; /* keep reading */
+
+    vm->monitor = fd;
+
+    return 0;
+}
+
+static int qemudOpenMonitor(struct qemud_server *server, struct qemud_vm *vm, const char *monitor) {
+    int monfd;
+    char buf[1024];
+    int ret = -1;
+
+    if (!(monfd = open(monitor, O_RDWR))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "Unable to open monitor path %s", monitor);
+        return -1;
+    }
+    if (qemudSetCloseExec(monfd) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "Unable to set monitor close-on-exec flag");
+        goto error;
+    }
+    if (qemudSetNonBlock(monfd) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "Unable to put monitor into non-blocking mode");
+        goto error;
+    }
+
+    ret = qemudReadMonitorOutput(server, vm, monfd,
+                                 buf, sizeof(buf),
+                                 qemudCheckMonitorPrompt,
+                                 "monitor");
+ error:
+    close(monfd);
+    return ret;
+}
+
+static int qemudExtractMonitorPath(const char *haystack, char *path, int pathmax) {
+    static const char needle[] = "char device redirected to";
+    char *tmp;
+
+    if (!(tmp = strstr(haystack, needle)))
+        return -1;
+
+    strncpy(path, tmp+sizeof(needle), pathmax-1);
+    path[pathmax-1] = '\0';
+
+    while (*path) {
+        /*
+         * The monitor path ends at first whitespace char
+         * so lets search for it & NULL terminate it there
+         */
+        if (isspace(*path)) {
+            *path = '\0';
+            return 0;
+        }
+        path++;
+    }
+
+    /*
+     * We found a path, but didn't find any whitespace,
+     * so it must be still incomplete - we should at
+     * least see a \n
+     */
+    return -1;
+}
+
+static int
+qemudOpenMonitorPath(struct qemud_server *server,
+                     struct qemud_vm *vm,
+                     const char *output,
+                     int fd ATTRIBUTE_UNUSED)
+{
+    char monitor[PATH_MAX];
+
+    if (qemudExtractMonitorPath(output, monitor, sizeof(monitor)) < 0)
+        return 1; /* keep reading */
+
+    return qemudOpenMonitor(server, vm, monitor);
+}
+
+static int qemudWaitForMonitor(struct qemud_server *server, struct qemud_vm *vm) {
+    char buf[1024]; /* Plenty of space to get startup greeting */
+    int ret = qemudReadMonitorOutput(server, vm, vm->stderr,
+                                     buf, sizeof(buf),
+                                     qemudOpenMonitorPath,
+                                     "console");
+
+    buf[sizeof(buf)-1] = '\0';
+ retry:
+    if (write(vm->logfile, buf, strlen(buf)) < 0) {
+        /* Log, but ignore failures to write logfile for VM */
+        if (errno == EINTR)
+            goto retry;
+        qemudLog(QEMUD_WARN, "Unable to log VM console data: %s",
+                 strerror(errno));
+    }
+
+    return ret;
+}
+
+static int qemudNextFreeVNCPort(struct qemud_server *server ATTRIBUTE_UNUSED) {
+    int i;
+
+    for (i = 5900 ; i < 6000 ; i++) {
+        int fd;
+        int reuse = 1;
+        struct sockaddr_in addr;
+        addr.sin_family = AF_INET;
+        addr.sin_port = htons(i);
+        addr.sin_addr.s_addr = htonl(INADDR_ANY);
+        fd = socket(PF_INET, SOCK_STREAM, 0);
+        if (fd < 0)
+            return -1;
+
+        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&reuse, sizeof(reuse)) < 0) {
+            close(fd);
+            break;
+        }
+
+        if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
+            /* Not in use, lets grab it */
+            close(fd);
+            return i;
+        }
+        close(fd);
+
+        if (errno == EADDRINUSE) {
+            /* In use, try next */
+            continue;
+        }
+        /* Some other bad failure, get out.. */
+        break;
+    }
+    return -1;
+}
+
+int qemudStartVMDaemon(struct qemud_server *server,
+                       struct qemud_vm *vm) {
+    char **argv = NULL, **tmp;
+    int i, ret = -1;
+    char logfile[PATH_MAX];
+
+    if (qemudIsActiveVM(vm)) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "VM is already active");
+        return -1;
+    }
+
+    if (vm->def->vncPort < 0) {
+        int port = qemudNextFreeVNCPort(server);
+        if (port < 0) {
+            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                             "Unable to find an unused VNC port");
+            return -1;
+        }
+        vm->def->vncActivePort = port;
+    } else
+        vm->def->vncActivePort = vm->def->vncPort;
+
+    if ((strlen(server->logDir) + /* path */
+         1 + /* Separator */
+         strlen(vm->def->name) + /* basename */
+         4 + /* suffix .log */
+         1 /* NULL */) > PATH_MAX) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "config file path too long: %s/%s.log",
+                         server->logDir, vm->def->name);
+        return -1;
+    }
+    strcpy(logfile, server->logDir);
+    strcat(logfile, "/");
+    strcat(logfile, vm->def->name);
+    strcat(logfile, ".log");
+
+    if (qemudEnsureDir(server->logDir) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "cannot create log directory %s: %s",
+                         server->logDir, strerror(errno));
+        return -1;
+    }
+
+    if ((vm->logfile = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
+                            S_IRUSR | S_IWUSR)) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to create logfile %s: %s",
+                         logfile, strerror(errno));
+        return -1;
+    }
+
+    if (qemudBuildCommandLine(server, vm, &argv) < 0) {
+        close(vm->logfile);
+        vm->logfile = -1;
+        return -1;
+    }
+
+    tmp = argv;
+    while (*tmp) {
+        if (write(vm->logfile, *tmp, strlen(*tmp)) < 0)
+            qemudLog(QEMUD_WARN, "Unable to write argv to logfile %d: %s",
+                     errno, strerror(errno));
+        if (write(vm->logfile, " ", 1) < 0)
+            qemudLog(QEMUD_WARN, "Unable to write argv to logfile %d: %s",
+                     errno, strerror(errno));
+        tmp++;
+    }
+    if (write(vm->logfile, "\n", 1) < 0)
+        qemudLog(QEMUD_WARN, "Unable to write argv to logfile %d: %s",
+                 errno, strerror(errno));
+
+    if (qemudExec(server, argv, &vm->pid, &vm->stdout, &vm->stderr) == 0) {
+        vm->id = server->nextvmid++;
+        vm->state = QEMUD_STATE_RUNNING;
+
+        server->ninactivevms--;
+        server->nactivevms++;
+
+        virEventAddHandle(vm->stdout,
+                          POLLIN | POLLERR | POLLHUP,
+                          qemudDispatchVMEvent,
+                          server);
+        virEventAddHandle(vm->stderr,
+                          POLLIN | POLLERR | POLLHUP,
+                          qemudDispatchVMEvent,
+                          server);
+
+        ret = 0;
+
+        if (qemudWaitForMonitor(server, vm) < 0) {
+            qemudShutdownVMDaemon(server, vm);
+            ret = -1;
+        }
+    }
+
+    if (vm->tapfds) {
+        for (i = 0; vm->tapfds[i] != -1; i++) {
+            close(vm->tapfds[i]);
+            vm->tapfds[i] = -1;
+        }
+        free(vm->tapfds);
+        vm->tapfds = NULL;
+        vm->ntapfds = 0;
+    }
+  
+    for (i = 0 ; argv[i] ; i++)
+        free(argv[i]);
+    free(argv);
+
+    return ret;
+}
+
+static int qemudVMData(struct qemud_server *server ATTRIBUTE_UNUSED,
+                       struct qemud_vm *vm, int fd) {
+    char buf[4096];
+    if (vm->pid < 0)
+        return 0;
+
+    for (;;) {
+        int ret = read(fd, buf, sizeof(buf)-1);
+        if (ret < 0) {
+            if (errno == EAGAIN)
+                return 0;
+            return -1;
+        }
+        if (ret == 0) {
+            return 0;
+        }
+        buf[ret] = '\0';
+
+    retry:
+        if (write(vm->logfile, buf, ret) < 0) {
+            /* Log, but ignore failures to write logfile for VM */
+            if (errno == EINTR)
+                goto retry;
+            qemudLog(QEMUD_WARN, "Unable to log VM console data: %s",
+                     strerror(errno));
+        }
+    }
+}
+
+
+int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) {
+    if (!qemudIsActiveVM(vm))
+        return 0;
+
+    qemudLog(QEMUD_INFO, "Shutting down VM '%s'", vm->def->name);
+
+    kill(vm->pid, SIGTERM);
+
+    qemudVMData(server, vm, vm->stdout);
+    qemudVMData(server, vm, vm->stderr);
+
+    virEventRemoveHandle(vm->stdout);
+    virEventRemoveHandle(vm->stderr);
+
+    if (close(vm->logfile) < 0)
+        qemudLog(QEMUD_WARN, "Unable to close logfile %d: %s", errno, strerror(errno));
+    close(vm->stdout);
+    close(vm->stderr);
+    if (vm->monitor != -1)
+        close(vm->monitor);
+    vm->logfile = -1;
+    vm->stdout = -1;
+    vm->stderr = -1;
+    vm->monitor = -1;
+
+    if (waitpid(vm->pid, NULL, WNOHANG) != vm->pid) {
+        kill(vm->pid, SIGKILL);
+        if (waitpid(vm->pid, NULL, 0) != vm->pid) {
+            qemudLog(QEMUD_WARN, "Got unexpected pid, damn");
+        }
+    }
+
+    vm->pid = -1;
+    vm->id = -1;
+    vm->state = QEMUD_STATE_STOPPED;
+
+    if (vm->newDef) {
+        qemudFreeVMDef(vm->def);
+        vm->def = vm->newDef;
+        vm->newDef = NULL;
+    }
+
+    server->nactivevms--;
+    server->ninactivevms++;
+
+    return 0;
+}
+
+static int qemudDispatchVMLog(struct qemud_server *server, struct qemud_vm *vm, int fd) {
+    if (qemudVMData(server, vm, fd) < 0)
+        if (qemudShutdownVMDaemon(server, vm) < 0)
+            return -1;
+    return 0;
+}
+
+static int qemudDispatchVMFailure(struct qemud_server *server, struct qemud_vm *vm,
+                                  int fd ATTRIBUTE_UNUSED) {
+    if (qemudShutdownVMDaemon(server, vm) < 0)
+        return -1;
+    return 0;
+}
+
+static int
+qemudBuildDnsmasqArgv(struct qemud_server *server,
+                      struct qemud_network *network,
+                      char ***argv) {
+    int i, len;
+    char buf[PATH_MAX];
+    struct qemud_dhcp_range_def *range;
+
+    len =
+        1 + /* dnsmasq */
+        1 + /* --keep-in-foreground */
+        1 + /* --strict-order */
+        1 + /* --bind-interfaces */
+        2 + /* --pid-file "" */
+        2 + /* --conf-file "" */
+        /*2 + *//* --interface virbr0 */
+        2 + /* --except-interface lo */
+        2 + /* --listen-address 10.0.0.1 */
+        1 + /* --dhcp-leasefile=path */
+        (2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
+        1;  /* NULL */
+
+    if (!(*argv = calloc(len, sizeof(char *))))
+        goto no_memory;
+
+#define APPEND_ARG(v, n, s) do {     \
+        if (!((v)[(n)] = strdup(s))) \
+            goto no_memory;          \
+    } while (0)
+
+    i = 0;
+
+    APPEND_ARG(*argv, i++, "dnsmasq");
+
+    APPEND_ARG(*argv, i++, "--keep-in-foreground");
+    /*
+     * Needed to ensure dnsmasq uses same algorithm for processing
+     * multiple nameserver entries in /etc/resolv.conf as GLibC.
+     */
+    APPEND_ARG(*argv, i++, "--strict-order");
+    APPEND_ARG(*argv, i++, "--bind-interfaces");
+
+    APPEND_ARG(*argv, i++, "--pid-file");
+    APPEND_ARG(*argv, i++, "");
+
+    APPEND_ARG(*argv, i++, "--conf-file");
+    APPEND_ARG(*argv, i++, "");
+
+    /*
+     * XXX does not actually work, due to some kind of
+     * race condition setting up ipv6 addresses on the
+     * interface. A sleep(10) makes it work, but that's
+     * clearly not practical
+     *
+     * APPEND_ARG(*argv, i++, "--interface");
+     * APPEND_ARG(*argv, i++, network->def->bridge);
+     */
+    APPEND_ARG(*argv, i++, "--listen-address");
+    APPEND_ARG(*argv, i++, network->def->ipAddress);
+
+    APPEND_ARG(*argv, i++, "--except-interface");
+    APPEND_ARG(*argv, i++, "lo");
+
+    /*
+     * NB, dnsmasq command line arg bug means we need to
+     * use a single arg '--dhcp-leasefile=path' rather than
+     * two separate args in '--dhcp-leasefile path' style
+     */
+    snprintf(buf, sizeof(buf), "--dhcp-leasefile=%s/lib/libvirt/dhcp-%s.leases",
+             LOCAL_STATE_DIR, network->def->name);
+    APPEND_ARG(*argv, i++, buf);
+
+    range = network->def->ranges;
+    while (range) {
+        snprintf(buf, sizeof(buf), "%s,%s",
+                 range->start, range->end);
+
+        APPEND_ARG(*argv, i++, "--dhcp-range");
+        APPEND_ARG(*argv, i++, buf);
+
+        range = range->next;
+    }
+
+#undef APPEND_ARG
+
+    return 0;
+
+ no_memory:
+    if (argv) {
+        for (i = 0; (*argv)[i]; i++)
+            free((*argv)[i]);
+        free(*argv);
+    }
+    qemudReportError(server, VIR_ERR_NO_MEMORY, "dnsmasq argv");
+    return -1;
+}
+
+
+static int
+dhcpStartDhcpDaemon(struct qemud_server *server,
+                    struct qemud_network *network)
+{
+    char **argv;
+    int ret, i;
+
+    if (network->def->ipAddress[0] == '\0') {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "cannot start dhcp daemon without IP address for server");
+        return -1;
+    }
+
+    argv = NULL;
+    if (qemudBuildDnsmasqArgv(server, network, &argv) < 0)
+        return -1;
+
+    ret = qemudExec(server, argv, &network->dnsmasqPid, NULL, NULL);
+
+    for (i = 0; argv[i]; i++)
+        free(argv[i]);
+    free(argv);
+
+    return ret;
+}
+
+static int
+qemudAddIptablesRules(struct qemud_server *server,
+                      struct qemud_network *network) {
+    int err;
+
+    if (!server->iptables && !(server->iptables = iptablesContextNew())) {
+        qemudReportError(server, VIR_ERR_NO_MEMORY, "iptables support");
+        return 1;
+    }
+
+
+    /* allow DHCP requests through to dnsmasq */
+    if ((err = iptablesAddTcpInput(server->iptables, network->bridge, 67))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow DHCP requests from '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto err1;
+    }
+
+    if ((err = iptablesAddUdpInput(server->iptables, network->bridge, 67))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow DHCP requests from '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto err2;
+    }
+
+    /* allow DNS requests through to dnsmasq */
+    if ((err = iptablesAddTcpInput(server->iptables, network->bridge, 53))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow DNS requests from '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto err3;
+    }
+
+    if ((err = iptablesAddUdpInput(server->iptables, network->bridge, 53))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow DNS requests from '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto err4;
+    }
+
+
+    /* Catch all rules to block forwarding to/from bridges */
+
+    if ((err = iptablesAddForwardRejectOut(server->iptables, network->bridge))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to block outbound traffic from '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto err5;
+    }
+
+    if ((err = iptablesAddForwardRejectIn(server->iptables, network->bridge))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to block inbound traffic to '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto err6;
+    }
+
+    /* Allow traffic between guests on the same bridge */
+    if ((err = iptablesAddForwardAllowCross(server->iptables, network->bridge))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow cross bridge traffic on '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto err7;
+    }
+
+
+    /* The remaining rules are only needed for IP forwarding */
+    if (!network->def->forward)
+        return 1;
+
+    /* allow forwarding packets from the bridge interface */
+    if ((err = iptablesAddForwardAllowOut(server->iptables,
+                                          network->def->network,
+                                          network->bridge,
+                                          network->def->forwardDev))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow forwarding from '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto err8;
+    }
+
+    /* allow forwarding packets to the bridge interface if they are part of an existing connection */
+    if ((err = iptablesAddForwardAllowIn(server->iptables,
+                                         network->def->network,
+                                         network->bridge,
+                                         network->def->forwardDev))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to allow forwarding to '%s' : %s\n",
+                         network->bridge, strerror(err));
+        goto err9;
+    }
+
+    /* enable masquerading */
+    if ((err = iptablesAddForwardMasquerade(server->iptables,
+                                            network->def->network,
+                                            network->def->forwardDev))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to add iptables rule to enable masquerading : %s\n",
+                         strerror(err));
+        goto err10;
+    }
+
+    return 1;
+
+ err10:
+    iptablesRemoveForwardAllowIn(server->iptables,
+                                 network->def->network,
+                                 network->bridge,
+                                 network->def->forwardDev);
+ err9:
+    iptablesRemoveForwardAllowOut(server->iptables,
+                                  network->def->network,
+                                  network->bridge,
+                                  network->def->forwardDev);
+ err8:
+    iptablesRemoveForwardAllowCross(server->iptables,
+                                    network->bridge);
+ err7:
+    iptablesRemoveForwardRejectIn(server->iptables,
+                                  network->bridge);
+ err6:
+    iptablesRemoveForwardRejectOut(server->iptables,
+                                   network->bridge);
+ err5:
+    iptablesRemoveUdpInput(server->iptables, network->bridge, 53);
+ err4:
+    iptablesRemoveTcpInput(server->iptables, network->bridge, 53);
+ err3:
+    iptablesRemoveUdpInput(server->iptables, network->bridge, 67);
+ err2:
+    iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
+ err1:
+    return 0;
+}
+
+static void
+qemudRemoveIptablesRules(struct qemud_server *server,
+                         struct qemud_network *network) {
+    if (network->def->forward) {
+        iptablesRemoveForwardMasquerade(server->iptables,
+                                     network->def->network,
+                                     network->def->forwardDev);
+        iptablesRemoveForwardAllowIn(server->iptables,
+                                   network->def->network,
+                                   network->bridge,
+                                   network->def->forwardDev);
+        iptablesRemoveForwardAllowOut(server->iptables,
+                                      network->def->network,
+                                      network->bridge,
+                                      network->def->forwardDev);
+    }
+    iptablesRemoveForwardAllowCross(server->iptables, network->bridge);
+    iptablesRemoveForwardRejectIn(server->iptables, network->bridge);
+    iptablesRemoveForwardRejectOut(server->iptables, network->bridge);
+    iptablesRemoveUdpInput(server->iptables, network->bridge, 53);
+    iptablesRemoveTcpInput(server->iptables, network->bridge, 53);
+    iptablesRemoveUdpInput(server->iptables, network->bridge, 67);
+    iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
+}
+
+static int
+qemudEnableIpForwarding(void)
+{
+#define PROC_IP_FORWARD "/proc/sys/net/ipv4/ip_forward"
+
+    int fd, ret;
+
+    if ((fd = open(PROC_IP_FORWARD, O_WRONLY|O_TRUNC)) == -1)
+        return 0;
+
+    if (write(fd, "1\n", 2) < 0)
+        ret = 0;
+
+    close (fd);
+
+    return 1;
+
+#undef PROC_IP_FORWARD
+}
+
+int qemudStartNetworkDaemon(struct qemud_server *server,
+                            struct qemud_network *network) {
+    const char *name;
+    int err;
+
+    if (qemudIsActiveNetwork(network)) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "network is already active");
+        return -1;
+    }
+
+    if (!server->brctl && (err = brInit(&server->brctl))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "cannot initialize bridge support: %s", strerror(err));
+        return -1;
+    }
+
+    if (network->def->bridge[0] == '\0' ||
+        strchr(network->def->bridge, '%')) {
+        name = "vnet%d";
+    } else {
+        name = network->def->bridge;
+    }
+
+    if ((err = brAddBridge(server->brctl, name, network->bridge, sizeof(network->bridge)))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "cannot create bridge '%s' : %s", name, strerror(err));
+        return -1;
+    }
+
+    if (network->def->ipAddress[0] &&
+        (err = brSetInetAddress(server->brctl, network->bridge, network->def->ipAddress))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "cannot set IP address on bridge '%s' to '%s' : %s\n",
+                         network->bridge, network->def->ipAddress, strerror(err));
+        goto err_delbr;
+    }
+
+    if (network->def->netmask[0] &&
+        (err = brSetInetNetmask(server->brctl, network->bridge, network->def->netmask))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "cannot set netmask on bridge '%s' to '%s' : %s\n",
+                         network->bridge, network->def->netmask, strerror(err));
+        goto err_delbr;
+    }
+
+    if (network->def->ipAddress[0] &&
+        (err = brSetInterfaceUp(server->brctl, network->bridge, 1))) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to bring the bridge '%s' up : %s\n",
+                         network->bridge, strerror(err));
+        goto err_delbr;
+    }
+
+    if (!qemudAddIptablesRules(server, network))
+        goto err_delbr1;
+
+    if (network->def->forward &&
+        !qemudEnableIpForwarding()) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to enable IP forwarding : %s\n", strerror(err));
+        goto err_delbr2;
+    }
+
+    if (network->def->ranges &&
+        dhcpStartDhcpDaemon(server, network) < 0)
+        goto err_delbr2;
+
+    network->active = 1;
+
+    server->ninactivenetworks--;
+    server->nactivenetworks++;
+
+    return 0;
+
+ err_delbr2:
+    qemudRemoveIptablesRules(server, network);
+
+ err_delbr1:
+    if (network->def->ipAddress[0] &&
+        (err = brSetInterfaceUp(server->brctl, network->bridge, 0))) {
+        qemudLog(QEMUD_WARN, "Failed to bring down bridge '%s' : %s",
+                 network->bridge, strerror(err));
+    }
+
+ err_delbr:
+    if ((err = brDeleteBridge(server->brctl, network->bridge))) {
+        qemudLog(QEMUD_WARN, "Failed to delete bridge '%s' : %s\n",
+                 network->bridge, strerror(err));
+    }
+
+    return -1;
+}
+
+
+int qemudShutdownNetworkDaemon(struct qemud_server *server,
+                               struct qemud_network *network) {
+    int err;
+
+    qemudLog(QEMUD_INFO, "Shutting down network '%s'", network->def->name);
+
+    if (!qemudIsActiveNetwork(network))
+        return 0;
+
+    if (network->dnsmasqPid > 0)
+        kill(network->dnsmasqPid, SIGTERM);
+
+    qemudRemoveIptablesRules(server, network);
+
+    if (network->def->ipAddress[0] &&
+        (err = brSetInterfaceUp(server->brctl, network->bridge, 0))) {
+        qemudLog(QEMUD_WARN, "Failed to bring down bridge '%s' : %s\n",
+                 network->bridge, strerror(err));
+    }
+
+    if ((err = brDeleteBridge(server->brctl, network->bridge))) {
+        qemudLog(QEMUD_WARN, "Failed to delete bridge '%s' : %s\n",
+                 network->bridge, strerror(err));
+    }
+
+    if (network->dnsmasqPid > 0 &&
+        waitpid(network->dnsmasqPid, NULL, WNOHANG) != network->dnsmasqPid) {
+        kill(network->dnsmasqPid, SIGKILL);
+        if (waitpid(network->dnsmasqPid, NULL, 0) != network->dnsmasqPid)
+            qemudLog(QEMUD_WARN, "Got unexpected pid for dnsmasq\n");
+    }
+
+    network->bridge[0] = '\0';
+    network->dnsmasqPid = -1;
+    network->active = 0;
+
+    if (network->newDef) {
+        qemudFreeNetworkDef(network->def);
+        network->def = network->newDef;
+        network->newDef = NULL;
+    }
+
+    server->nactivenetworks--;
+    server->ninactivenetworks++;
+
+    return 0;
+}
+
+
+static void qemudDispatchVMEvent(int fd, int events, void *opaque) {
+    struct qemud_server *server = (struct qemud_server *)opaque;
+    struct qemud_vm *vm = server->vms;
+
+    while (vm) {
+        if (qemudIsActiveVM(vm) &&
+            (vm->stdout == fd ||
+             vm->stderr == fd))
+            break;
+
+        vm = vm->next;
+    }
+
+    if (!vm)
+        return;
+
+    if (events == POLLIN &&
+        qemudDispatchVMLog(server, vm, fd) == 0)
+        return;
+
+    qemudDispatchVMFailure(server, vm, fd);
 }
 
 int qemudMonitorCommand(struct qemud_server *server ATTRIBUTE_UNUSED,
diff -r a04dbba5004f qemud/driver.h
--- a/qemud/driver.h	Thu Jun 21 12:06:05 2007 -0400
+++ b/qemud/driver.h	Thu Jun 21 16:06:14 2007 -0400
@@ -26,6 +26,20 @@
 #define QEMUD_DRIVER_H
 
 #include "internal.h"
+
+int qemudStartVMDaemon(struct qemud_server *server,
+                       struct qemud_vm *vm);
+
+int qemudShutdownVMDaemon(struct qemud_server *server,
+                          struct qemud_vm *vm);
+
+int qemudStartNetworkDaemon(struct qemud_server *server,
+                            struct qemud_network *network);
+
+int qemudShutdownNetworkDaemon(struct qemud_server *server,
+                               struct qemud_network *network);
+
+void qemudShutdown(struct qemud_server *server);
 
 void qemudReportError(struct qemud_server *server,
                       int code, const char *fmt, ...)
diff -r a04dbba5004f qemud/internal.h
--- a/qemud/internal.h	Thu Jun 21 12:06:05 2007 -0400
+++ b/qemud/internal.h	Thu Jun 21 16:06:53 2007 -0400
@@ -357,18 +357,6 @@ struct qemud_server {
     unsigned int shutdown : 1;
 };
 
-int qemudStartVMDaemon(struct qemud_server *server,
-                       struct qemud_vm *vm);
-
-int qemudShutdownVMDaemon(struct qemud_server *server,
-                          struct qemud_vm *vm);
-
-int qemudStartNetworkDaemon(struct qemud_server *server,
-                            struct qemud_network *network);
-
-int qemudShutdownNetworkDaemon(struct qemud_server *server,
-                               struct qemud_network *network);
-
 void qemudLog(int priority, const char *fmt, ...)
     ATTRIBUTE_FORMAT(printf,2,3);
 
diff -r a04dbba5004f qemud/qemud.c
--- a/qemud/qemud.c	Thu Jun 21 12:06:05 2007 -0400
+++ b/qemud/qemud.c	Thu Jun 21 16:07:07 2007 -0400
@@ -46,7 +46,6 @@
 #include <string.h>
 #include <errno.h>
 #include <getopt.h>
-#include <ctype.h>
 #include <assert.h>
 #include <fnmatch.h>
 #include <gnutls/gnutls.h>
@@ -58,9 +57,9 @@
 #include "../src/remote_internal.h"
 #include "../src/conf.h"
 #include "dispatch.h"
-#include "driver.h"
 #include "conf.h"
 #include "iptables.h"
+#include "driver.h"
 #include "event.h"
 
 static int godaemon = 0;        /* -d: Be a daemon */
@@ -111,7 +110,6 @@ static void sig_handler(int sig) {
     errno = origerrno;
 }
 
-static void qemudDispatchVMEvent(int fd, int events, void *opaque);
 static void qemudDispatchClientEvent(int fd, int events, void *opaque);
 static void qemudDispatchServerEvent(int fd, int events, void *opaque);
 static int qemudRegisterClientEvent(struct qemud_server *server,
@@ -197,8 +195,6 @@ static void qemudDispatchSignalEvent(int
                                      void *opaque) {
     struct qemud_server *server = (struct qemud_server *)opaque;
     unsigned char sigc;
-    struct qemud_vm *vm;
-    struct qemud_network *network;
     int ret;
 
     if (read(server->sigread, &sigc, 1) != 1) {
@@ -228,45 +224,7 @@ static void qemudDispatchSignalEvent(int
         qemudLog(QEMUD_WARN, "Shutting down on signal %d", sigc);
 
         if (!remote) {
-            /* shutdown active VMs */
-            vm = server->vms;
-            while (vm) {
-                struct qemud_vm *next = vm->next;
-                if (qemudIsActiveVM(vm))
-                    qemudShutdownVMDaemon(server, vm);
-                vm = next;
-            }
-
-            /* free inactive VMs */
-            vm = server->vms;
-            while (vm) {
-                struct qemud_vm *next = vm->next;
-                qemudFreeVM(vm);
-                vm = next;
-            }
-            server->vms = NULL;
-            server->nactivevms = 0;
-            server->ninactivevms = 0;
-
-            /* shutdown active networks */
-            network = server->networks;
-            while (network) {
-                struct qemud_network *next = network->next;
-                if (qemudIsActiveNetwork(network))
-                    qemudShutdownNetworkDaemon(server, network);
-                network = next;
-            }
-
-            /* free inactive networks */
-            network = server->networks;
-            while (network) {
-                struct qemud_network *next = network->next;
-                qemudFreeNetwork(network);
-                network = next;
-            }
-            server->networks = NULL;
-            server->nactivenetworks = 0;
-            server->ninactivenetworks = 0;
+            qemudShutdown(server);
         }
 
         server->shutdown = 1;
@@ -1112,426 +1070,6 @@ static int qemudDispatchServer(struct qe
 }
 
 
-static int
-qemudExec(struct qemud_server *server, char **argv,
-          int *retpid, int *outfd, int *errfd) {
-    int pid, null;
-    int pipeout[2] = {-1,-1};
-    int pipeerr[2] = {-1,-1};
-
-    if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot open %s : %s",
-                         _PATH_DEVNULL, strerror(errno));
-        goto cleanup;
-    }
-
-    if ((outfd != NULL && pipe(pipeout) < 0) ||
-        (errfd != NULL && pipe(pipeerr) < 0)) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot create pipe : %s",
-                         strerror(errno));
-        goto cleanup;
-    }
-
-    if ((pid = fork()) < 0) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR, "cannot fork child process : %s",
-                         strerror(errno));
-        goto cleanup;
-    }
-
-    if (pid) { /* parent */
-        close(null);
-        if (outfd) {
-            close(pipeout[1]);
-            qemudSetNonBlock(pipeout[0]);
-            qemudSetCloseExec(pipeout[0]);
-            *outfd = pipeout[0];
-        }
-        if (errfd) {
-            close(pipeerr[1]);
-            qemudSetNonBlock(pipeerr[0]);
-            qemudSetCloseExec(pipeerr[0]);
-            *errfd = pipeerr[0];
-        }
-        *retpid = pid;
-        return 0;
-    }
-
-    /* child */
-
-    if (pipeout[0] > 0 && close(pipeout[0]) < 0)
-        _exit(1);
-    if (pipeerr[0] > 0 && close(pipeerr[0]) < 0)
-        _exit(1);
-
-    if (dup2(null, STDIN_FILENO) < 0)
-        _exit(1);
-    if (dup2(pipeout[1] > 0 ? pipeout[1] : null, STDOUT_FILENO) < 0)
-        _exit(1);
-    if (dup2(pipeerr[1] > 0 ? pipeerr[1] : null, STDERR_FILENO) < 0)
-        _exit(1);
-
-    close(null);
-    if (pipeout[1] > 0)
-        close(pipeout[1]);
-    if (pipeerr[1] > 0)
-        close(pipeerr[1]);
-
-    execvp(argv[0], argv);
-
-    _exit(1);
-
-    return 0;
-
- cleanup:
-    if (pipeerr[0] > 0)
-        close(pipeerr[0]);
-    if (pipeerr[1] > 0)
-        close(pipeerr[1]);
-    if (pipeout[0] > 0)
-        close(pipeout[0]);
-    if (pipeout[1] > 0)
-        close(pipeout[1]);
-    if (null > 0)
-        close(null);
-    return -1;
-}
-
-/* Return -1 for error, 1 to continue reading and 0 for success */
-typedef int qemudHandlerMonitorOutput(struct qemud_server *server,
-                                      struct qemud_vm *vm,
-                                      const char *output,
-                                      int fd);
-
-static int
-qemudReadMonitorOutput(struct qemud_server *server,
-                       struct qemud_vm *vm,
-                       int fd,
-                       char *buffer,
-                       int buflen,
-                       qemudHandlerMonitorOutput func,
-                       const char *what)
-{
-#define MONITOR_TIMEOUT 3000
-
-    int got = 0;
-    buffer[0] = '\0';
-
-   /* Consume & discard the initial greeting */
-    while (got < (buflen-1)) {
-        int ret;
-
-        ret = read(fd, buffer+got, buflen-got-1);
-        if (ret == 0) {
-            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                             "QEMU quit during %s startup\n%s", what, buffer);
-            return -1;
-        }
-        if (ret < 0) {
-            struct pollfd pfd = { .fd = fd, .events = POLLIN };
-            if (errno == EINTR)
-                continue;
-
-            if (errno != EAGAIN) {
-                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                                 "Failure while reading %s startup output: %s",
-                                 what, strerror(errno));
-                return -1;
-            }
-
-            ret = poll(&pfd, 1, MONITOR_TIMEOUT);
-            if (ret == 0) {
-                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                                 "Timed out while reading %s startup output", what);
-                return -1;
-            } else if (ret == -1) {
-                if (errno != EINTR) {
-                    qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                                     "Failure while reading %s startup output: %s",
-                                     what, strerror(errno));
-                    return -1;
-                }
-            } else {
-                /* Make sure we continue loop & read any further data
-                   available before dealing with EOF */
-                if (pfd.revents & (POLLIN | POLLHUP))
-                    continue;
-
-                qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                                 "Failure while reading %s startup output", what);
-                return -1;
-            }
-        } else {
-            got += ret;
-            buffer[got] = '\0';
-            if ((ret = func(server, vm, buffer, fd)) != 1)
-                return ret;
-        }
-    }
-
-    qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                     "Out of space while reading %s startup output", what);
-    return -1;
-
-#undef MONITOR_TIMEOUT
-}
-
-static int
-qemudCheckMonitorPrompt(struct qemud_server *server ATTRIBUTE_UNUSED,
-                        struct qemud_vm *vm,
-                        const char *output,
-                        int fd)
-{
-    if (strstr(output, "(qemu) ") == NULL)
-        return 1; /* keep reading */
-
-    vm->monitor = fd;
-
-    return 0;
-}
-
-static int qemudOpenMonitor(struct qemud_server *server, struct qemud_vm *vm, const char *monitor) {
-    int monfd;
-    char buffer[1024];
-    int ret = -1;
-
-    if (!(monfd = open(monitor, O_RDWR))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "Unable to open monitor path %s", monitor);
-        return -1;
-    }
-    if (qemudSetCloseExec(monfd) < 0) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "Unable to set monitor close-on-exec flag");
-        goto error;
-    }
-    if (qemudSetNonBlock(monfd) < 0) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "Unable to put monitor into non-blocking mode");
-        goto error;
-    }
-
-    ret = qemudReadMonitorOutput(server, vm, monfd,
-                                 buffer, sizeof(buffer),
-                                 qemudCheckMonitorPrompt,
-                                 "monitor");
- error:
-    close(monfd);
-    return ret;
-}
-
-static int qemudExtractMonitorPath(const char *haystack, char *path, int pathmax) {
-    static const char needle[] = "char device redirected to";
-    char *tmp;
-
-    if (!(tmp = strstr(haystack, needle)))
-        return -1;
-
-    strncpy(path, tmp+sizeof(needle), pathmax-1);
-    path[pathmax-1] = '\0';
-
-    while (*path) {
-        /*
-         * The monitor path ends at first whitespace char
-         * so lets search for it & NULL terminate it there
-         */
-        if (isspace(*path)) {
-            *path = '\0';
-            return 0;
-        }
-        path++;
-    }
-
-    /*
-     * We found a path, but didn't find any whitespace,
-     * so it must be still incomplete - we should at
-     * least see a \n
-     */
-    return -1;
-}
-
-static int
-qemudOpenMonitorPath(struct qemud_server *server,
-                     struct qemud_vm *vm,
-                     const char *output,
-                     int fd ATTRIBUTE_UNUSED)
-{
-    char monitor[PATH_MAX];
-
-    if (qemudExtractMonitorPath(output, monitor, sizeof(monitor)) < 0)
-        return 1; /* keep reading */
-
-    return qemudOpenMonitor(server, vm, monitor);
-}
-
-static int qemudWaitForMonitor(struct qemud_server *server, struct qemud_vm *vm) {
-    char buffer[1024]; /* Plenty of space to get startup greeting */
-    int ret = qemudReadMonitorOutput(server, vm, vm->stderr,
-                                     buffer, sizeof(buffer),
-                                     qemudOpenMonitorPath,
-                                     "console");
-
-    buffer[sizeof(buffer)-1] = '\0';
- retry:
-    if (write(vm->logfile, buffer, strlen(buffer)) < 0) {
-        /* Log, but ignore failures to write logfile for VM */
-        if (errno == EINTR)
-            goto retry;
-        qemudLog(QEMUD_WARN, "Unable to log VM console data: %s",
-                 strerror(errno));
-    }
-
-    return ret;
-}
-
-static int qemudNextFreeVNCPort(struct qemud_server *server ATTRIBUTE_UNUSED) {
-    int i;
-
-    for (i = 5900 ; i < 6000 ; i++) {
-        int fd;
-        int reuse = 1;
-        struct sockaddr_in addr;
-        addr.sin_family = AF_INET;
-        addr.sin_port = htons(i);
-        addr.sin_addr.s_addr = htonl(INADDR_ANY);
-        fd = socket(PF_INET, SOCK_STREAM, 0);
-        if (fd < 0)
-            return -1;
-
-        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&reuse, sizeof(reuse)) < 0) {
-            close(fd);
-            break;
-        }
-
-        if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
-            /* Not in use, lets grab it */
-            close(fd);
-            return i;
-        }
-        close(fd);
-
-        if (errno == EADDRINUSE) {
-            /* In use, try next */
-            continue;
-        }
-        /* Some other bad failure, get out.. */
-        break;
-    }
-    return -1;
-}
-
-int qemudStartVMDaemon(struct qemud_server *server,
-                       struct qemud_vm *vm) {
-    char **argv = NULL, **tmp;
-    int i, ret = -1;
-    char logfile[PATH_MAX];
-
-    if (qemudIsActiveVM(vm)) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "VM is already active");
-        return -1;
-    }
-
-    if (vm->def->vncPort < 0) {
-        int port = qemudNextFreeVNCPort(server);
-        if (port < 0) {
-            qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                             "Unable to find an unused VNC port");
-            return -1;
-        }
-        vm->def->vncActivePort = port;
-    } else
-        vm->def->vncActivePort = vm->def->vncPort;
-
-    if ((strlen(server->logDir) + /* path */
-         1 + /* Separator */
-         strlen(vm->def->name) + /* basename */
-         4 + /* suffix .log */
-         1 /* NULL */) > PATH_MAX) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "config file path too long: %s/%s.log",
-                         server->logDir, vm->def->name);
-        return -1;
-    }
-    strcpy(logfile, server->logDir);
-    strcat(logfile, "/");
-    strcat(logfile, vm->def->name);
-    strcat(logfile, ".log");
-
-    if (qemudEnsureDir(server->logDir) < 0) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "cannot create log directory %s: %s",
-                         server->logDir, strerror(errno));
-        return -1;
-    }
-
-    if ((vm->logfile = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
-                            S_IRUSR | S_IWUSR)) < 0) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to create logfile %s: %s",
-                         logfile, strerror(errno));
-        return -1;
-    }
-
-    if (qemudBuildCommandLine(server, vm, &argv) < 0) {
-        close(vm->logfile);
-        vm->logfile = -1;
-        return -1;
-    }
-
-    tmp = argv;
-    while (*tmp) {
-        if (write(vm->logfile, *tmp, strlen(*tmp)) < 0)
-            qemudLog(QEMUD_WARN, "Unable to write argv to logfile %d: %s",
-                     errno, strerror(errno));
-        if (write(vm->logfile, " ", 1) < 0)
-            qemudLog(QEMUD_WARN, "Unable to write argv to logfile %d: %s",
-                     errno, strerror(errno));
-        tmp++;
-    }
-    if (write(vm->logfile, "\n", 1) < 0)
-        qemudLog(QEMUD_WARN, "Unable to write argv to logfile %d: %s",
-                 errno, strerror(errno));
-
-    if (qemudExec(server, argv, &vm->pid, &vm->stdout, &vm->stderr) == 0) {
-        vm->id = server->nextvmid++;
-        vm->state = QEMUD_STATE_RUNNING;
-
-        server->ninactivevms--;
-        server->nactivevms++;
-
-        virEventAddHandle(vm->stdout,
-                          POLLIN | POLLERR | POLLHUP,
-                          qemudDispatchVMEvent,
-                          server);
-        virEventAddHandle(vm->stderr,
-                          POLLIN | POLLERR | POLLHUP,
-                          qemudDispatchVMEvent,
-                          server);
-
-        ret = 0;
-
-        if (qemudWaitForMonitor(server, vm) < 0) {
-            qemudShutdownVMDaemon(server, vm);
-            ret = -1;
-        }
-    }
-
-    if (vm->tapfds) {
-        for (i = 0; vm->tapfds[i] != -1; i++) {
-            close(vm->tapfds[i]);
-            vm->tapfds[i] = -1;
-        }
-        free(vm->tapfds);
-        vm->tapfds = NULL;
-        vm->ntapfds = 0;
-    }
-  
-    for (i = 0 ; argv[i] ; i++)
-        free(argv[i]);
-    free(argv);
-
-    return ret;
-}
 
 
 static void qemudDispatchClientFailure(struct qemud_server *server, struct qemud_client *client) {
@@ -1885,569 +1423,6 @@ static void qemudDispatchClientWrite(str
     }
 }
 
-static int qemudVMData(struct qemud_server *server ATTRIBUTE_UNUSED,
-                       struct qemud_vm *vm, int fd) {
-    char buf[4096];
-    if (vm->pid < 0)
-        return 0;
-
-    for (;;) {
-        int ret = read(fd, buf, sizeof(buf)-1);
-        if (ret < 0) {
-            if (errno == EAGAIN)
-                return 0;
-            return -1;
-        }
-        if (ret == 0) {
-            return 0;
-        }
-        buf[ret] = '\0';
-
-    retry:
-        if (write(vm->logfile, buf, ret) < 0) {
-            /* Log, but ignore failures to write logfile for VM */
-            if (errno == EINTR)
-                goto retry;
-            qemudLog(QEMUD_WARN, "Unable to log VM console data: %s",
-                     strerror(errno));
-        }
-    }
-}
-
-
-int qemudShutdownVMDaemon(struct qemud_server *server, struct qemud_vm *vm) {
-    if (!qemudIsActiveVM(vm))
-        return 0;
-
-    qemudLog(QEMUD_INFO, "Shutting down VM '%s'", vm->def->name);
-
-    kill(vm->pid, SIGTERM);
-
-    qemudVMData(server, vm, vm->stdout);
-    qemudVMData(server, vm, vm->stderr);
-
-    virEventRemoveHandle(vm->stdout);
-    virEventRemoveHandle(vm->stderr);
-
-    if (close(vm->logfile) < 0)
-        qemudLog(QEMUD_WARN, "Unable to close logfile %d: %s", errno, strerror(errno));
-    close(vm->stdout);
-    close(vm->stderr);
-    if (vm->monitor != -1)
-        close(vm->monitor);
-    vm->logfile = -1;
-    vm->stdout = -1;
-    vm->stderr = -1;
-    vm->monitor = -1;
-
-    if (waitpid(vm->pid, NULL, WNOHANG) != vm->pid) {
-        kill(vm->pid, SIGKILL);
-        if (waitpid(vm->pid, NULL, 0) != vm->pid) {
-            qemudLog(QEMUD_WARN, "Got unexpected pid, damn");
-        }
-    }
-
-    vm->pid = -1;
-    vm->id = -1;
-    vm->state = QEMUD_STATE_STOPPED;
-
-    if (vm->newDef) {
-        qemudFreeVMDef(vm->def);
-        vm->def = vm->newDef;
-        vm->newDef = NULL;
-    }
-
-    server->nactivevms--;
-    server->ninactivevms++;
-
-    return 0;
-}
-
-static int qemudDispatchVMLog(struct qemud_server *server, struct qemud_vm *vm, int fd) {
-    if (qemudVMData(server, vm, fd) < 0)
-        if (qemudShutdownVMDaemon(server, vm) < 0)
-            return -1;
-    return 0;
-}
-
-static int qemudDispatchVMFailure(struct qemud_server *server, struct qemud_vm *vm,
-                                  int fd ATTRIBUTE_UNUSED) {
-    if (qemudShutdownVMDaemon(server, vm) < 0)
-        return -1;
-    return 0;
-}
-
-static int
-qemudBuildDnsmasqArgv(struct qemud_server *server,
-                      struct qemud_network *network,
-                      char ***argv) {
-    int i, len;
-    char buf[PATH_MAX];
-    struct qemud_dhcp_range_def *range;
-
-    len =
-        1 + /* dnsmasq */
-        1 + /* --keep-in-foreground */
-        1 + /* --strict-order */
-        1 + /* --bind-interfaces */
-        2 + /* --pid-file "" */
-        2 + /* --conf-file "" */
-        /*2 + *//* --interface virbr0 */
-        2 + /* --except-interface lo */
-        2 + /* --listen-address 10.0.0.1 */
-        1 + /* --dhcp-leasefile=path */
-        (2 * network->def->nranges) + /* --dhcp-range 10.0.0.2,10.0.0.254 */
-        1;  /* NULL */
-
-    if (!(*argv = calloc(len, sizeof(char *))))
-        goto no_memory;
-
-#define APPEND_ARG(v, n, s) do {     \
-        if (!((v)[(n)] = strdup(s))) \
-            goto no_memory;          \
-    } while (0)
-
-    i = 0;
-
-    APPEND_ARG(*argv, i++, "dnsmasq");
-
-    APPEND_ARG(*argv, i++, "--keep-in-foreground");
-    /*
-     * Needed to ensure dnsmasq uses same algorithm for processing
-     * multiple nameserver entries in /etc/resolv.conf as GLibC.
-     */
-    APPEND_ARG(*argv, i++, "--strict-order");
-    APPEND_ARG(*argv, i++, "--bind-interfaces");
-
-    APPEND_ARG(*argv, i++, "--pid-file");
-    APPEND_ARG(*argv, i++, "");
-
-    APPEND_ARG(*argv, i++, "--conf-file");
-    APPEND_ARG(*argv, i++, "");
-
-    /*
-     * XXX does not actually work, due to some kind of
-     * race condition setting up ipv6 addresses on the
-     * interface. A sleep(10) makes it work, but that's
-     * clearly not practical
-     *
-     * APPEND_ARG(*argv, i++, "--interface");
-     * APPEND_ARG(*argv, i++, network->def->bridge);
-     */
-    APPEND_ARG(*argv, i++, "--listen-address");
-    APPEND_ARG(*argv, i++, network->def->ipAddress);
-
-    APPEND_ARG(*argv, i++, "--except-interface");
-    APPEND_ARG(*argv, i++, "lo");
-
-    /*
-     * NB, dnsmasq command line arg bug means we need to
-     * use a single arg '--dhcp-leasefile=path' rather than
-     * two separate args in '--dhcp-leasefile path' style
-     */
-    snprintf(buf, sizeof(buf), "--dhcp-leasefile=%s/lib/libvirt/dhcp-%s.leases",
-             LOCAL_STATE_DIR, network->def->name);
-    APPEND_ARG(*argv, i++, buf);
-
-    range = network->def->ranges;
-    while (range) {
-        snprintf(buf, sizeof(buf), "%s,%s",
-                 range->start, range->end);
-
-        APPEND_ARG(*argv, i++, "--dhcp-range");
-        APPEND_ARG(*argv, i++, buf);
-
-        range = range->next;
-    }
-
-#undef APPEND_ARG
-
-    return 0;
-
- no_memory:
-    if (argv) {
-        for (i = 0; (*argv)[i]; i++)
-            free((*argv)[i]);
-        free(*argv);
-    }
-    qemudReportError(server, VIR_ERR_NO_MEMORY, "dnsmasq argv");
-    return -1;
-}
-
-
-static int
-dhcpStartDhcpDaemon(struct qemud_server *server,
-                    struct qemud_network *network)
-{
-    char **argv;
-    int ret, i;
-
-    if (network->def->ipAddress[0] == '\0') {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "cannot start dhcp daemon without IP address for server");
-        return -1;
-    }
-
-    argv = NULL;
-    if (qemudBuildDnsmasqArgv(server, network, &argv) < 0)
-        return -1;
-
-    ret = qemudExec(server, argv, &network->dnsmasqPid, NULL, NULL);
-
-    for (i = 0; argv[i]; i++)
-        free(argv[i]);
-    free(argv);
-
-    return ret;
-}
-
-static int
-qemudAddIptablesRules(struct qemud_server *server,
-                      struct qemud_network *network) {
-    int err;
-
-    if (!server->iptables && !(server->iptables = iptablesContextNew())) {
-        qemudReportError(server, VIR_ERR_NO_MEMORY, "iptables support");
-        return 1;
-    }
-
-
-    /* allow DHCP requests through to dnsmasq */
-    if ((err = iptablesAddTcpInput(server->iptables, network->bridge, 67))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to allow DHCP requests from '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err1;
-    }
-
-    if ((err = iptablesAddUdpInput(server->iptables, network->bridge, 67))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to allow DHCP requests from '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err2;
-    }
-
-    /* allow DNS requests through to dnsmasq */
-    if ((err = iptablesAddTcpInput(server->iptables, network->bridge, 53))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to allow DNS requests from '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err3;
-    }
-
-    if ((err = iptablesAddUdpInput(server->iptables, network->bridge, 53))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to allow DNS requests from '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err4;
-    }
-
-
-    /* Catch all rules to block forwarding to/from bridges */
-
-    if ((err = iptablesAddForwardRejectOut(server->iptables, network->bridge))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to block outbound traffic from '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err5;
-    }
-
-    if ((err = iptablesAddForwardRejectIn(server->iptables, network->bridge))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to block inbound traffic to '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err6;
-    }
-
-    /* Allow traffic between guests on the same bridge */
-    if ((err = iptablesAddForwardAllowCross(server->iptables, network->bridge))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to allow cross bridge traffic on '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err7;
-    }
-
-
-    /* The remaining rules are only needed for IP forwarding */
-    if (!network->def->forward)
-        return 1;
-
-    /* allow forwarding packets from the bridge interface */
-    if ((err = iptablesAddForwardAllowOut(server->iptables,
-                                          network->def->network,
-                                          network->bridge,
-                                          network->def->forwardDev))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to allow forwarding from '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err8;
-    }
-
-    /* allow forwarding packets to the bridge interface if they are part of an existing connection */
-    if ((err = iptablesAddForwardAllowIn(server->iptables,
-                                         network->def->network,
-                                         network->bridge,
-                                         network->def->forwardDev))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to allow forwarding to '%s' : %s\n",
-                         network->bridge, strerror(err));
-        goto err9;
-    }
-
-    /* enable masquerading */
-    if ((err = iptablesAddForwardMasquerade(server->iptables,
-                                            network->def->network,
-                                            network->def->forwardDev))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to add iptables rule to enable masquerading : %s\n",
-                         strerror(err));
-        goto err10;
-    }
-
-    return 1;
-
- err10:
-    iptablesRemoveForwardAllowIn(server->iptables,
-                                 network->def->network,
-                                 network->bridge,
-                                 network->def->forwardDev);
- err9:
-    iptablesRemoveForwardAllowOut(server->iptables,
-                                  network->def->network,
-                                  network->bridge,
-                                  network->def->forwardDev);
- err8:
-    iptablesRemoveForwardAllowCross(server->iptables,
-                                    network->bridge);
- err7:
-    iptablesRemoveForwardRejectIn(server->iptables,
-                                  network->bridge);
- err6:
-    iptablesRemoveForwardRejectOut(server->iptables,
-                                   network->bridge);
- err5:
-    iptablesRemoveUdpInput(server->iptables, network->bridge, 53);
- err4:
-    iptablesRemoveTcpInput(server->iptables, network->bridge, 53);
- err3:
-    iptablesRemoveUdpInput(server->iptables, network->bridge, 67);
- err2:
-    iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
- err1:
-    return 0;
-}
-
-static void
-qemudRemoveIptablesRules(struct qemud_server *server,
-                         struct qemud_network *network) {
-    if (network->def->forward) {
-        iptablesRemoveForwardMasquerade(server->iptables,
-                                     network->def->network,
-                                     network->def->forwardDev);
-        iptablesRemoveForwardAllowIn(server->iptables,
-                                   network->def->network,
-                                   network->bridge,
-                                   network->def->forwardDev);
-        iptablesRemoveForwardAllowOut(server->iptables,
-                                      network->def->network,
-                                      network->bridge,
-                                      network->def->forwardDev);
-    }
-    iptablesRemoveForwardAllowCross(server->iptables, network->bridge);
-    iptablesRemoveForwardRejectIn(server->iptables, network->bridge);
-    iptablesRemoveForwardRejectOut(server->iptables, network->bridge);
-    iptablesRemoveUdpInput(server->iptables, network->bridge, 53);
-    iptablesRemoveTcpInput(server->iptables, network->bridge, 53);
-    iptablesRemoveUdpInput(server->iptables, network->bridge, 67);
-    iptablesRemoveTcpInput(server->iptables, network->bridge, 67);
-}
-
-static int
-qemudEnableIpForwarding(void)
-{
-#define PROC_IP_FORWARD "/proc/sys/net/ipv4/ip_forward"
-
-    int fd, ret;
-
-    if ((fd = open(PROC_IP_FORWARD, O_WRONLY|O_TRUNC)) == -1)
-        return 0;
-
-    if (write(fd, "1\n", 2) < 0)
-        ret = 0;
-
-    close (fd);
-
-    return 1;
-
-#undef PROC_IP_FORWARD
-}
-
-int qemudStartNetworkDaemon(struct qemud_server *server,
-                            struct qemud_network *network) {
-    const char *name;
-    int err;
-
-    if (qemudIsActiveNetwork(network)) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "network is already active");
-        return -1;
-    }
-
-    if (!server->brctl && (err = brInit(&server->brctl))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "cannot initialize bridge support: %s", strerror(err));
-        return -1;
-    }
-
-    if (network->def->bridge[0] == '\0' ||
-        strchr(network->def->bridge, '%')) {
-        name = "vnet%d";
-    } else {
-        name = network->def->bridge;
-    }
-
-    if ((err = brAddBridge(server->brctl, name, network->bridge, sizeof(network->bridge)))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "cannot create bridge '%s' : %s", name, strerror(err));
-        return -1;
-    }
-
-    if (network->def->ipAddress[0] &&
-        (err = brSetInetAddress(server->brctl, network->bridge, network->def->ipAddress))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "cannot set IP address on bridge '%s' to '%s' : %s\n",
-                         network->bridge, network->def->ipAddress, strerror(err));
-        goto err_delbr;
-    }
-
-    if (network->def->netmask[0] &&
-        (err = brSetInetNetmask(server->brctl, network->bridge, network->def->netmask))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "cannot set netmask on bridge '%s' to '%s' : %s\n",
-                         network->bridge, network->def->netmask, strerror(err));
-        goto err_delbr;
-    }
-
-    if (network->def->ipAddress[0] &&
-        (err = brSetInterfaceUp(server->brctl, network->bridge, 1))) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to bring the bridge '%s' up : %s\n",
-                         network->bridge, strerror(err));
-        goto err_delbr;
-    }
-
-    if (!qemudAddIptablesRules(server, network))
-        goto err_delbr1;
-
-    if (network->def->forward &&
-        !qemudEnableIpForwarding()) {
-        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
-                         "failed to enable IP forwarding : %s\n", strerror(err));
-        goto err_delbr2;
-    }
-
-    if (network->def->ranges &&
-        dhcpStartDhcpDaemon(server, network) < 0)
-        goto err_delbr2;
-
-    network->active = 1;
-
-    server->ninactivenetworks--;
-    server->nactivenetworks++;
-
-    return 0;
-
- err_delbr2:
-    qemudRemoveIptablesRules(server, network);
-
- err_delbr1:
-    if (network->def->ipAddress[0] &&
-        (err = brSetInterfaceUp(server->brctl, network->bridge, 0))) {
-        qemudLog(QEMUD_WARN, "Failed to bring down bridge '%s' : %s",
-                 network->bridge, strerror(err));
-    }
-
- err_delbr:
-    if ((err = brDeleteBridge(server->brctl, network->bridge))) {
-        qemudLog(QEMUD_WARN, "Failed to delete bridge '%s' : %s\n",
-                 network->bridge, strerror(err));
-    }
-
-    return -1;
-}
-
-
-int qemudShutdownNetworkDaemon(struct qemud_server *server,
-                               struct qemud_network *network) {
-    int err;
-
-    qemudLog(QEMUD_INFO, "Shutting down network '%s'", network->def->name);
-
-    if (!qemudIsActiveNetwork(network))
-        return 0;
-
-    if (network->dnsmasqPid > 0)
-        kill(network->dnsmasqPid, SIGTERM);
-
-    qemudRemoveIptablesRules(server, network);
-
-    if (network->def->ipAddress[0] &&
-        (err = brSetInterfaceUp(server->brctl, network->bridge, 0))) {
-        qemudLog(QEMUD_WARN, "Failed to bring down bridge '%s' : %s\n",
-                 network->bridge, strerror(err));
-    }
-
-    if ((err = brDeleteBridge(server->brctl, network->bridge))) {
-        qemudLog(QEMUD_WARN, "Failed to delete bridge '%s' : %s\n",
-                 network->bridge, strerror(err));
-    }
-
-    if (network->dnsmasqPid > 0 &&
-        waitpid(network->dnsmasqPid, NULL, WNOHANG) != network->dnsmasqPid) {
-        kill(network->dnsmasqPid, SIGKILL);
-        if (waitpid(network->dnsmasqPid, NULL, 0) != network->dnsmasqPid)
-            qemudLog(QEMUD_WARN, "Got unexpected pid for dnsmasq\n");
-    }
-
-    network->bridge[0] = '\0';
-    network->dnsmasqPid = -1;
-    network->active = 0;
-
-    if (network->newDef) {
-        qemudFreeNetworkDef(network->def);
-        network->def = network->newDef;
-        network->newDef = NULL;
-    }
-
-    server->nactivenetworks--;
-    server->ninactivenetworks++;
-
-    return 0;
-}
-
-
-static void qemudDispatchVMEvent(int fd, int events, void *opaque) {
-    struct qemud_server *server = (struct qemud_server *)opaque;
-    struct qemud_vm *vm = server->vms;
-
-    while (vm) {
-        if (qemudIsActiveVM(vm) &&
-            (vm->stdout == fd ||
-             vm->stderr == fd))
-            break;
-
-        vm = vm->next;
-    }
-
-    if (!vm)
-        return;
-
-    if (events == POLLIN &&
-        qemudDispatchVMLog(server, vm, fd) == 0)
-        return;
-
-    qemudDispatchVMFailure(server, vm, fd);
-}
 
 static void qemudDispatchClientEvent(int fd, int events, void *opaque) {
     struct qemud_server *server = (struct qemud_server *)opaque;

[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]