]> TLD Linux GIT Repositories - packages/libvirt.git/commitdiff
- from PLD
authorMarcin Krol <hawk@tld-linux.org>
Wed, 8 Oct 2014 07:44:38 +0000 (07:44 +0000)
committerMarcin Krol <hawk@tld-linux.org>
Wed, 8 Oct 2014 07:44:38 +0000 (07:44 +0000)
13 files changed:
bashisms.patch [new file with mode: 0644]
libvirt-guests.init.patch [new file with mode: 0644]
libvirt-lxc.patch [new file with mode: 0644]
libvirt-qemu-acl.patch [new file with mode: 0644]
libvirt-sasl.patch [new file with mode: 0644]
libvirt-udevadm-settle.patch [new file with mode: 0644]
libvirt-xend.patch [new file with mode: 0644]
libvirt.init [new file with mode: 0755]
libvirt.spec [new file with mode: 0644]
libvirt.tmpfiles [new file with mode: 0644]
query-parameters.patch [new file with mode: 0644]
virtlockd.init.patch [new file with mode: 0644]
vserver.patch [new file with mode: 0644]

diff --git a/bashisms.patch b/bashisms.patch
new file mode 100644 (file)
index 0000000..9d7dfc4
--- /dev/null
@@ -0,0 +1,8 @@
+--- libvirt-1.2.3/tools/libvirt-guests.sh.in~  2014-02-26 05:09:50.000000000 +0200
++++ libvirt-1.2.3/tools/libvirt-guests.sh.in   2014-04-05 02:52:16.187741175 +0300
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!/bin/bash
+ # Copyright (C) 2011-2013 Red Hat, Inc.
+ #
diff --git a/libvirt-guests.init.patch b/libvirt-guests.init.patch
new file mode 100644 (file)
index 0000000..da84255
--- /dev/null
@@ -0,0 +1,9 @@
+--- libvirt-1.2.3/./tools/libvirt-guests.init.in~      2012-12-12 04:29:55.000000000 +0200
++++ libvirt-1.2.3/./tools/libvirt-guests.init.in       2014-04-06 12:13:29.091387594 +0300
+@@ -25,3 +25,6 @@
+ #
+ exec @libexecdir@/libvirt-guests.sh "$@"
++
++# next line is here for "service --status-all" to work
++#  status)
diff --git a/libvirt-lxc.patch b/libvirt-lxc.patch
new file mode 100644 (file)
index 0000000..f0d8f7d
--- /dev/null
@@ -0,0 +1,194 @@
+--- libvirt-0.9.13/src/lxc/lxc_controller.c.orig       2012-06-25 09:06:18.000000000 +0200
++++ libvirt-0.9.13/src/lxc/lxc_controller.c    2012-07-08 11:48:06.949684744 +0200
+@@ -44,6 +44,7 @@
+ #include <grp.h>
+ #include <sys/stat.h>
+ #include <time.h>
++#include <sys/time.h>
+ #if HAVE_CAPNG
+ # include <cap-ng.h>
+@@ -558,6 +559,7 @@
+     return ret;
+ }
++static virCgroupPtr domain_cgroup = NULL;
+ /**
+  * lxcSetContainerResources
+@@ -617,10 +619,13 @@
+                              _("Unable to add task %d to cgroup for domain %s"),
+                              getpid(), def->name);
+     }
++    domain_cgroup = cgroup;
++    goto out;
+ cleanup:
+-    virCgroupFree(&driver);
+     virCgroupFree(&cgroup);
++out:
++    virCgroupFree(&driver);
+     return rc;
+ }
+@@ -709,6 +714,63 @@
+ static bool quit = false;
+ static virMutex lock;
+ static int sigpipe[2];
++static pid_t initpid = -1;
++
++static void lxcSignalALRMHandler(int signum ATTRIBUTE_UNUSED)
++{
++    int tasks = 0;
++    char *keypath = NULL;
++    int rc = -1;
++    FILE *fp;
++
++    if (initpid <= 0)
++        return;
++    if (domain_cgroup == NULL)
++        return;
++
++    rc = virCgroupPathOfController(domain_cgroup, -1, "tasks", &keypath);
++    if (rc != 0) {
++        VIR_DEBUG("No path of cgroup tasks");
++        return;
++    }
++
++    if (!(fp = fopen(keypath, "r"))) {
++        VIR_DEBUG("Failed to read %s: %m\n", keypath);
++        return;
++    }
++    while (!feof(fp)) {
++        unsigned long pid_value;
++        if (fscanf(fp, "%lu", &pid_value) != 1) {
++            if (feof(fp))
++                 break;
++            rc = -errno;
++            VIR_DEBUG("Failed to read %s: %m\n", keypath);
++            fclose(fp);
++            return;
++        }
++        tasks++;
++    }
++    fclose(fp);
++    VIR_DEBUG("Tasks left: %d", tasks);
++    /* Kill init if it's the only process left beside container controller process */
++    if (tasks == 2)
++        kill(initpid, SIGKILL);
++}
++
++static void lxcSignalINTHandler(int signum ATTRIBUTE_UNUSED)
++{
++    struct itimerval timer;
++
++    if (initpid <= 0)
++        return;
++    kill(initpid, SIGINT);
++
++    timer.it_interval.tv_sec = 1;
++    timer.it_interval.tv_usec = 0;
++    timer.it_value.tv_sec = 1;
++    timer.it_value.tv_usec = 0;
++    setitimer(ITIMER_REAL, &timer, NULL);
++}
+ static void lxcSignalChildHandler(int signum ATTRIBUTE_UNUSED)
+ {
+@@ -1134,6 +1196,18 @@
+         goto cleanup;
+     }
++    if (signal(SIGINT, lxcSignalINTHandler) == SIG_ERR) {
++        virReportSystemError(errno, "%s",
++                             _("Cannot install signal handler"));
++        goto cleanup;
++    }
++
++    if (signal(SIGALRM, lxcSignalALRMHandler) == SIG_ERR) {
++        virReportSystemError(errno, "%s",
++                             _("Cannot install signal handler"));
++        goto cleanup;
++    }
++
+     VIR_DEBUG("serverFd=%d clientFd=%d",
+               serverFd, clientFd);
+     virResetLastError();
+@@ -1539,6 +1613,7 @@
+         goto cleanup;
+     VIR_FORCE_CLOSE(control[1]);
+     VIR_FORCE_CLOSE(containerhandshake[1]);
++    initpid = container;
+     if (lxcControllerMoveInterfaces(nveths, veths, container) < 0)
+         goto cleanup;
+diff -ur libvirt-0.9.12/src/lxc/lxc_driver.c libvirt-0.9.12-lxc/src/lxc/lxc_driver.c
+--- libvirt-0.9.12/src/lxc/lxc_driver.c        2012-05-02 05:08:53.000000000 +0200
++++ libvirt-0.9.12-lxc/src/lxc/lxc_driver.c    2012-05-16 19:54:48.946901077 +0200
+@@ -3751,6 +3751,58 @@
+ }
+ static int
++lxcDomainShutdown (virDomainPtr dom)
++{
++    lxc_driver_t *driver = dom->conn->privateData;
++    virDomainObjPtr vm;
++    virDomainEventPtr event = NULL;
++    int ret = -1;
++
++    lxcDriverLock(driver);
++    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
++    if (!vm) {
++        char uuidstr[VIR_UUID_STRING_BUFLEN];
++        virUUIDFormat(dom->uuid, uuidstr);
++        lxcError(VIR_ERR_NO_DOMAIN,
++                 _("No domain with matching uuid '%s'"), uuidstr);
++        goto cleanup;
++    }
++
++    if (!virDomainObjIsActive(vm)) {
++        lxcError(VIR_ERR_OPERATION_INVALID,
++                 "%s", _("Domain is not running"));
++        goto cleanup;
++    }
++
++    if (vm->pid <= 0) {
++        lxcError(VIR_ERR_INTERNAL_ERROR,
++                 _("Invalid PID %d for container"), vm->pid);
++        goto cleanup;
++    }
++
++    if (kill(vm->pid, SIGINT) < -1)
++        goto cleanup;
++    ret = 0;
++
++    event = virDomainEventNewFromObj(vm,
++                                     VIR_DOMAIN_EVENT_STOPPED,
++                                     VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
++    virDomainAuditStop(vm, "shutdown");
++    if (!vm->persistent) {
++        virDomainRemoveInactive(&driver->domains, vm);
++        vm = NULL;
++    }
++
++cleanup:
++    if (vm)
++        virDomainObjUnlock(vm);
++    if (event)
++        lxcDomainEventQueue(driver, event);
++    lxcDriverUnlock(driver);
++    return ret;
++}
++
++static int
+ lxcDomainOpenConsole(virDomainPtr dom,
+                       const char *dev_name,
+                       virStreamPtr st,
+@@ -3866,6 +3918,7 @@
+     .domainLookupByName = lxcDomainLookupByName, /* 0.4.2 */
+     .domainSuspend = lxcDomainSuspend, /* 0.7.2 */
+     .domainResume = lxcDomainResume, /* 0.7.2 */
++    .domainShutdown = lxcDomainShutdown, /* PLD */
+     .domainDestroy = lxcDomainDestroy, /* 0.4.4 */
+     .domainDestroyFlags = lxcDomainDestroyFlags, /* 0.9.4 */
+     .domainGetOSType = lxcGetOSType, /* 0.4.2 */
diff --git a/libvirt-qemu-acl.patch b/libvirt-qemu-acl.patch
new file mode 100644 (file)
index 0000000..13fa7ee
--- /dev/null
@@ -0,0 +1,65 @@
+From: Neil Wilson <neil@brightbox.co.uk>
+To: libvir-list@redhat.com
+Date: Mon, 10 Jan 2011 09:52:56 +0000
+Message-ID: <1294653176.3013.16.camel@lenovo-3000-n100>
+
+Hi,
+
+Here's the patch to add basic ACL support to QEMU within libvirt. Like
+SASL it's ignored by RHEL5's default qemu. Newer qemu picks it up as
+expected and you can manipulate the acls using 'virsh'. 
+
+
+diff --git a/src/qemu/qemu.conf b/src/qemu/qemu.conf
+index ba41f80..7ab5eee 100644
+--- a/src/qemu/qemu.conf
++++ b/src/qemu/qemu.conf
+@@ -71,6 +71,15 @@
+ # vnc_sasl = 1
++# Enable the VNC access control lists. When switched on this will
++# initially block all vnc users from accessing the vnc server. To
++# add and remove ids from the ACLs you will need to send the appropriate
++# commands to the qemu monitor as required by your particular version of
++# QEMU. See the QEMU documentation for more details.
++# 
++# vnc_acl = 1
++
++
+ # The default SASL configuration file is located in /etc/sasl/
+ # When running libvirtd unprivileged, it may be desirable to
+ # override the configs in this location. Set this parameter to
+--- libvirt-1.0.6/src/qemu/qemu_command.c.orig 2013-06-16 15:45:37.115181922 +0200
++++ libvirt-1.0.6/src/qemu/qemu_command.c      2013-06-16 15:47:49.335179175 +0200
+@@ -6178,6 +6178,10 @@
+             /* TODO: Support ACLs later */
+         }
++
++        if (cfg->vncACL) 
++           virBufferAddLit(&opt, ",acl");
++
+     }
+     virCommandAddArg(cmd, "-vnc");
+--- libvirt-1.1.3/src/qemu/qemu_conf.c.orig    2013-10-22 20:38:43.522043292 +0200
++++ libvirt-1.1.3/src/qemu/qemu_conf.c 2013-10-22 20:45:19.515360007 +0200
+@@ -357,6 +357,7 @@
+     GET_VALUE_STR("vnc_sasl_dir", cfg->vncSASLdir);
+     GET_VALUE_BOOL("vnc_allow_host_audio", cfg->vncAllowHostAudio);
+     GET_VALUE_BOOL("nographics_allow_host_audio", cfg->nogfxAllowHostAudio);
++    GET_VALUE_LONG("vnc_acl", cfg->vncACL);
+     p = virConfGetValue(conf, "security_driver");
+     if (p && p->type == VIR_CONF_LIST) {
+--- libvirt-1.0.3/src/qemu/qemu_conf.h.orig    2013-03-09 13:10:30.059751685 +0100
++++ libvirt-1.0.3/src/qemu/qemu_conf.h 2013-03-09 13:54:17.296308093 +0100
+@@ -102,6 +102,7 @@
+     bool vncTLS;
+     bool vncTLSx509verify;
+     bool vncSASL;
++    bool vncACL;
+     char *vncTLSx509certdir;
+     char *vncListen;
+     char *vncPassword;
diff --git a/libvirt-sasl.patch b/libvirt-sasl.patch
new file mode 100644 (file)
index 0000000..3e19ce6
--- /dev/null
@@ -0,0 +1,186 @@
+diff -ru libvirt-0.8.8/daemon/libvirtd.conf libvirt-0.8.8-sasl/daemon/libvirtd.conf
+--- libvirt-0.8.8/daemon/libvirtd.conf 2010-12-20 14:35:22.000000000 +0100
++++ libvirt-0.8.8-sasl/daemon/libvirtd.conf    2011-04-28 11:45:47.727741165 +0200
+@@ -111,7 +111,7 @@
+ #          the network providing auth (eg, TLS/x509 certificates)
+ #
+ #  - sasl: use SASL infrastructure. The actual auth scheme is then
+-#          controlled from /etc/sasl2/libvirt.conf. For the TCP
++#          controlled from /etc/sasl/libvirt.conf. For the TCP
+ #          socket only GSSAPI & DIGEST-MD5 mechanisms will be used.
+ #          For non-TCP or TLS sockets,  any scheme is allowed.
+ #
+@@ -142,7 +142,7 @@
+ # If you don't enable SASL, then all TCP traffic is cleartext.
+ # Don't do this outside of a dev/test scenario. For real world
+ # use, always enable SASL and use the GSSAPI or DIGEST-MD5
+-# mechanism in /etc/sasl2/libvirt.conf
++# mechanism in /etc/sasl/libvirt.conf
+ #auth_tcp = "sasl"
+ # Change the authentication scheme for TLS sockets.
+--- libvirt-1.1.3/daemon/Makefile.am.orig      2013-10-22 16:46:45.409294047 +0200
++++ libvirt-1.1.3/daemon/Makefile.am   2013-10-22 20:09:12.185450964 +0200
+@@ -453,13 +453,13 @@
+ # the WITH_LIBVIRTD conditional
+ if WITH_SASL
+ install-data-sasl:
+-      $(MKDIR_P) $(DESTDIR)$(sysconfdir)/sasl2/
++      $(MKDIR_P) $(DESTDIR)$(sysconfdir)/sasl/
+       $(INSTALL_DATA) $(srcdir)/libvirtd.sasl \
+-              $(DESTDIR)$(sysconfdir)/sasl2/libvirt.conf
++              $(DESTDIR)$(sysconfdir)/sasl/libvirt.conf
+ uninstall-data-sasl:
+-      rm -f $(DESTDIR)$(sysconfdir)/sasl2/libvirt.conf
+-      rmdir $(DESTDIR)$(sysconfdir)/sasl2/ || :
++      rm -f $(DESTDIR)$(sysconfdir)/sasl/libvirt.conf
++      rmdir $(DESTDIR)$(sysconfdir)/sasl/ || :
+ else ! WITH_SASL
+ install-data-sasl:
+ uninstall-data-sasl:
+diff -ru libvirt-0.8.8/daemon/test_libvirtd.aug libvirt-0.8.8-sasl/daemon/test_libvirtd.aug
+diff -ru libvirt-0.8.8/docs/auth.html libvirt-0.8.8-sasl/docs/auth.html
+--- libvirt-0.8.8/docs/auth.html       2011-02-17 05:13:12.000000000 +0100
++++ libvirt-0.8.8-sasl/docs/auth.html  2011-04-28 11:45:43.429741167 +0200
+@@ -273,7 +273,7 @@
+ The plain TCP socket of the libvirt daemon defaults to using SASL for authentication.
+ The SASL mechanism configured by default is DIGEST-MD5, which provides a basic
+ username+password style authentication. To enable Kerberos single-sign-on instead,
+-the libvirt SASL configuration file must be changed. This is <code>/etc/sasl2/libvirt.conf</code>.
++the libvirt SASL configuration file must be changed. This is <code>/etc/sasl/libvirt.conf</code>.
+ The <code>mech_list</code> parameter must first be changed to <code>gssapi</code>
+ instead of the default <code>digest-md5</code>. If SASL is enabled on the UNIX
+ and/or TLS sockets, Kerberos will also be used for them. Like DIGEST-MD5, the Kerberos
+diff -ru libvirt-0.8.8/docs/auth.html.in libvirt-0.8.8-sasl/docs/auth.html.in
+--- libvirt-0.8.8/docs/auth.html.in    2010-12-20 14:35:22.000000000 +0100
++++ libvirt-0.8.8-sasl/docs/auth.html.in       2011-04-28 11:45:43.586741167 +0200
+@@ -115,7 +115,7 @@
+ The plain TCP socket of the libvirt daemon defaults to using SASL for authentication.
+ The SASL mechanism configured by default is DIGEST-MD5, which provides a basic
+ username+password style authentication. To enable Kerberos single-sign-on instead,
+-the libvirt SASL configuration file must be changed. This is <code>/etc/sasl2/libvirt.conf</code>.
++the libvirt SASL configuration file must be changed. This is <code>/etc/sasl/libvirt.conf</code>.
+ The <code>mech_list</code> parameter must first be changed to <code>gssapi</code>
+ instead of the default <code>digest-md5</code>. If SASL is enabled on the UNIX
+ and/or TLS sockets, Kerberos will also be used for them. Like DIGEST-MD5, the Kerberos
+diff -ru libvirt-0.8.8/libvirt.spec libvirt-0.8.8-sasl/libvirt.spec
+--- libvirt-0.8.8/libvirt.spec 2011-02-17 05:13:09.000000000 +0100
++++ libvirt-0.8.8-sasl/libvirt.spec    2011-04-28 11:45:43.675741167 +0200
+@@ -933,7 +933,7 @@
+ %dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/
+ %if %{with_sasl}
+-%config(noreplace) %{_sysconfdir}/sasl2/libvirt.conf
++%config(noreplace) %{_sysconfdir}/sasl/libvirt.conf
+ %endif
+ %files devel
+diff -ru libvirt-0.8.8/libvirt.spec.in libvirt-0.8.8-sasl/libvirt.spec.in
+--- libvirt-0.8.8/libvirt.spec.in      2011-02-17 05:10:58.000000000 +0100
++++ libvirt-0.8.8-sasl/libvirt.spec.in 2011-04-28 11:45:43.672741167 +0200
+@@ -933,7 +933,7 @@
+ %dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/
+ %if %{with_sasl}
+-%config(noreplace) %{_sysconfdir}/sasl2/libvirt.conf
++%config(noreplace) %{_sysconfdir}/sasl/libvirt.conf
+ %endif
+ %files devel
+--- libvirt-0.9.13/src/qemu/qemu.conf.orig     2012-05-31 16:23:22.000000000 +0200
++++ libvirt-0.9.13/src/qemu/qemu.conf  2012-07-08 11:37:16.366378718 +0200
+@@ -74,18 +74,18 @@
+ # Examples include vinagre, virt-viewer and virt-manager
+ # itself. UltraVNC, RealVNC, TightVNC do not support this
+ #
+-# It is necessary to configure /etc/sasl2/qemu.conf to choose
++# It is necessary to configure /etc/sasl/qemu.conf to choose
+ # the desired SASL plugin (eg, GSSPI for Kerberos)
+ #
+ #vnc_sasl = 1
+-# The default SASL configuration file is located in /etc/sasl2/
++# The default SASL configuration file is located in /etc/sasl/
+ # When running libvirtd unprivileged, it may be desirable to
+ # override the configs in this location. Set this parameter to
+ # point to the directory, and create a qemu.conf in that location
+ #
+-#vnc_sasl_dir = "/some/directory/sasl2"
++#vnc_sasl_dir = "/some/directory/sasl"
+ # QEMU implements an extension for providing audio over a VNC connection,
+diff -ru libvirt-0.8.8/src/qemu/test_libvirtd_qemu.aug libvirt-0.8.8-sasl/src/qemu/test_libvirtd_qemu.aug
+diff -ru libvirt-0.8.8/tests/confdata/libvirtd.conf libvirt-0.8.8-sasl/tests/confdata/libvirtd.conf
+--- libvirt-0.8.8/tests/confdata/libvirtd.conf 2010-05-27 14:03:22.000000000 +0200
++++ libvirt-0.8.8-sasl/tests/confdata/libvirtd.conf    2011-04-28 11:45:46.878741165 +0200
+@@ -102,7 +102,7 @@
+ #          the network providing auth (eg, TLS/x509 certificates)
+ #
+ #  - sasl: use SASL infrastructure. The actual auth scheme is then
+-#          controlled from /etc/sasl2/libvirt.conf. For the TCP
++#          controlled from /etc/sasl/libvirt.conf. For the TCP
+ #          socket only GSSAPI & DIGEST-MD5 mechanisms will be used.
+ #          For non-TCP or TLS sockets,  any scheme is allowed.
+ #
+@@ -133,7 +133,7 @@
+ # If you don't enable SASL, then all TCP traffic is cleartext.
+ # Don't do this outside of a dev/test scenario. For real world
+ # use, always enable SASL and use the GSSAPI or DIGEST-MD5
+-# mechanism in /etc/sasl2/libvirt.conf
++# mechanism in /etc/sasl/libvirt.conf
+ auth_tcp = "sasl"
+ # Change the authentication scheme for TLS sockets.
+diff -ru libvirt-0.8.8/tests/confdata/libvirtd.out libvirt-0.8.8-sasl/tests/confdata/libvirtd.out
+--- libvirt-0.8.8/tests/confdata/libvirtd.out  2010-05-27 14:03:22.000000000 +0200
++++ libvirt-0.8.8-sasl/tests/confdata/libvirtd.out     2011-04-28 11:45:46.875741165 +0200
+@@ -82,7 +82,7 @@
+ #          the network providing auth (eg, TLS/x509 certificates)
+ #
+ #  - sasl: use SASL infrastructure. The actual auth scheme is then
+-#          controlled from /etc/sasl2/libvirt.conf. For the TCP
++#          controlled from /etc/sasl/libvirt.conf. For the TCP
+ #          socket only GSSAPI & DIGEST-MD5 mechanisms will be used.
+ #          For non-TCP or TLS sockets,  any scheme is allowed.
+ #
+@@ -111,7 +111,7 @@
+ # If you don't enable SASL, then all TCP traffic is cleartext.
+ # Don't do this outside of a dev/test scenario. For real world
+ # use, always enable SASL and use the GSSAPI or DIGEST-MD5
+-# mechanism in /etc/sasl2/libvirt.conf
++# mechanism in /etc/sasl/libvirt.conf
+ auth_tcp = "sasl"
+ # Change the authentication scheme for TLS sockets.
+ #
+--- libvirt-1.2.6/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-sasl.args.orig      2014-07-03 20:04:05.132591762 +0200
++++ libvirt-1.2.6/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-sasl.args   2014-07-03 20:42:03.205829499 +0200
+@@ -1,5 +1,5 @@
+ LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \
+-SASL_CONF_PATH=/root/.sasl2 QEMU_AUDIO_DRV=none \
++SASL_CONF_PATH=/root/.sasl QEMU_AUDIO_DRV=none \
+ /usr/bin/qemu -S -M pc -m 214 \
+ -smp 1 -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb -hda \
+ /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -vnc \
+--- libvirt-1.2.6/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-tls.args.orig       2014-07-03 20:04:05.132591762 +0200
++++ libvirt-1.2.6/tests/qemuxml2argvdata/qemuxml2argv-graphics-vnc-tls.args    2014-07-03 20:42:29.659161721 +0200
+@@ -1,5 +1,5 @@
+ LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test \
+-SASL_CONF_PATH=/root/.sasl2 QEMU_AUDIO_DRV=none \
++SASL_CONF_PATH=/root/.sasl QEMU_AUDIO_DRV=none \
+ /usr/bin/qemu -S -M pc -m 214 \
+ -smp 1 -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -usb -hda \
+ /dev/HostVG/QEMUGuest1 -net none -serial none -parallel none -vnc \
+--- libvirt-1.0.6/tests/qemuxml2argvtest.c.orig        2013-06-16 15:44:25.855183409 +0200
++++ libvirt-1.0.6/tests/qemuxml2argvtest.c     2013-06-16 15:45:12.908515760 +0200
+@@ -614,7 +614,7 @@
+     driver.config->vncSASL = 1;
+     VIR_FREE(driver.config->vncSASLdir);
+-    ignore_value(VIR_STRDUP(driver.config->vncSASLdir, "/root/.sasl2"));
++    ignore_value(VIR_STRDUP(driver.config->vncSASLdir, "/root/.sasl"));
+     DO_TEST("graphics-vnc-sasl", QEMU_CAPS_VNC, QEMU_CAPS_VGA);
+     driver.config->vncTLS = 1;
+     driver.config->vncTLSx509verify = 1;
diff --git a/libvirt-udevadm-settle.patch b/libvirt-udevadm-settle.patch
new file mode 100644 (file)
index 0000000..a645d9f
--- /dev/null
@@ -0,0 +1,12 @@
+diff -urP libvirt-1.1.0.orig/src/util/virutil.c libvirt-1.1.0/src/util/virutil.c
+--- libvirt-1.1.0.orig/src/util/virutil.c      2013-07-01 03:08:36.000000000 +0000
++++ libvirt-1.1.0/src/util/virutil.c   2013-07-22 12:58:14.053179206 +0000
+@@ -1419,7 +1419,7 @@
+ void virFileWaitForDevices(void)
+ {
+ # ifdef UDEVADM
+-    const char *const settleprog[] = { UDEVADM, "settle", NULL };
++    const char *const settleprog[] = { UDEVADM, "settle", "--timeout=10" , NULL };
+ # else
+     const char *const settleprog[] = { UDEVSETTLE, NULL };
+ # endif
diff --git a/libvirt-xend.patch b/libvirt-xend.patch
new file mode 100644 (file)
index 0000000..a6d4d5b
--- /dev/null
@@ -0,0 +1,44 @@
+--- libvirt-1.2.4/src/xen/xen_driver.c.orig    2014-05-25 21:03:34.237326121 +0200
++++ libvirt-1.2.4/src/xen/xen_driver.c 2014-05-25 21:25:26.260632109 +0200
+@@ -320,7 +320,7 @@
+     if (virFileExists("/usr/sbin/xend")) {
+         virCommandPtr cmd;
+-        cmd = virCommandNewArgList("/usr/sbin/xend", "status", NULL);
++        cmd = virCommandNewArgList("/sbin/service", "xend", "status", NULL);
+         if (virCommandRun(cmd, NULL) == 0)
+             ret = true;
+         virCommandFree(cmd);
+--- libvirt-1.2.4/src/libxl/libxl_driver.c.orig        2014-05-25 21:03:34.447326117 +0200
++++ libvirt-1.2.4/src/libxl/libxl_driver.c     2014-05-25 21:28:23.317295096 +0200
+@@ -258,7 +258,7 @@
+     if (virFileExists("/usr/sbin/xend")) {
+         virCommandPtr cmd;
+-        cmd = virCommandNewArgList("/usr/sbin/xend", "status", NULL);
++        cmd = virCommandNewArgList("/sbin/service", "xend", "status", NULL);
+         if (virCommandRun(cmd, NULL) == 0) {
+             VIR_INFO("Legacy xen tool stack seems to be in use, disabling "
+                      "libxenlight driver.");
+--- libvirt-1.2.3/tests/statstest.c.orig       2014-04-04 15:57:05.109436604 +0200
++++ libvirt-1.2.3/tests/statstest.c    2014-04-04 16:00:09.836099420 +0200
+@@ -49,7 +49,7 @@
+     uname(&ut);
+     if (strstr(ut.release, "xen") == NULL)
+         return EXIT_AM_SKIP;
+-    cmd = virCommandNewArgList("/usr/sbin/xend", "status", NULL);
++    cmd = virCommandNewArgList("/sbin/service", "xend", "status", NULL);
+     if (virCommandRun(cmd, NULL) < 0) {
+         virCommandFree(cmd);
+         return EXIT_AM_SKIP;
+--- libvirt-1.2.3/tests/reconnect.c.orig       2014-04-04 15:57:05.109436604 +0200
++++ libvirt-1.2.3/tests/reconnect.c    2014-04-04 16:03:28.892761936 +0200
+@@ -24,7 +24,7 @@
+     uname(&ut);
+     if (strstr(ut.release, "xen") == NULL)
+         return EXIT_AM_SKIP;
+-    cmd = virCommandNewArgList("/usr/sbin/xend", "status", NULL);
++    cmd = virCommandNewArgList("/sbin/service", "xend", "status", NULL);
+     if (virCommandRun(cmd, NULL) < 0) {
+         virCommandFree(cmd);
+         return EXIT_AM_SKIP;
diff --git a/libvirt.init b/libvirt.init
new file mode 100755 (executable)
index 0000000..42c9d64
--- /dev/null
@@ -0,0 +1,101 @@
+#!/bin/sh
+# libvirtd:   guest and virtual network management daemon
+#
+# chkconfig: 345 97 03
+# description:  This is a daemon for managing guest instances
+#               and libvirt virtual networks
+#               See http://libvirt.org
+#
+# processname: libvirtd
+#
+
+LIBVIRTD_CONFIG=
+LIBVIRTD_ARGS=
+
+LIBVIRTD_CONFIG_ARGS=
+if [ -n "$LIBVIRTD_CONFIG" ]; then
+       LIBVIRTD_CONFIG_ARGS="--config $LIBVIRTD_CONFIG"
+fi
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+# Source config
+if [ -f /etc/sysconfig/libvirtd ] ; then
+       . /etc/sysconfig/libvirtd
+fi
+
+start() {
+       if [ -f /var/lock/subsys/libvirtd ]; then
+               msg_already_running "libvirtd"
+               return
+       fi
+
+       umask 077
+       msg_starting "libvirtd"
+       daemon /usr/sbin/libvirtd --daemon $LIBVIRTD_CONFIG_ARGS $LIBVIRTD_ARGS
+       RETVAL=$?
+       [ $RETVAL -eq 0 ] && touch /var/lock/subsys/libvirtd
+}
+
+stop() {
+       if [ ! -f /var/lock/subsys/libvirtd ]; then
+               msg_not_running "libvirtd"
+               return
+       fi
+
+       msg_stopping "libvirtd"
+       killproc libvirtd
+       rm -f /var/lock/subsys/libvirtd
+}
+
+reload() {
+       if [ ! -f /var/lock/subsys/libvirtd ]; then
+               msg_not_running "libvirtd"
+               RETVAL=7
+               return
+       fi
+
+       msg_reloading libvirtd
+       killproc libvirtd -HUP
+       RETVAL=$?
+}
+
+condrestart() {
+       if [ ! -f /var/lock/subsys/libvirtd ]; then
+               msg_not_running "libvirtd"
+               RETVAL=$1
+               return
+       fi
+
+       stop
+       start
+}
+
+RETVAL=0
+case "$1" in
+  start)
+       start
+       ;;
+  stop)
+       stop
+       ;;
+  restart)
+       stop
+       start
+       ;;
+  try-restart)
+       condrestart 0
+       ;;
+  reload|force-reload)
+       reload
+       ;;
+  status)
+       status libvirtd
+       ;;
+  *)
+       msg_usage "$0 {start|stop|restart|try-restart|reload|force-reload|status}"
+       exit 3
+esac
+
+exit $RETVAL
diff --git a/libvirt.spec b/libvirt.spec
new file mode 100644 (file)
index 0000000..c434dd1
--- /dev/null
@@ -0,0 +1,802 @@
+#
+# TODO:
+# - seems that lxc patch is not needed anymore, verify that before removing
+# - pldize virtlockd.init
+#
+# Conditional build:
+%bcond_without ceph            # RADOS BD (Ceph) storage support
+%bcond_without esx             # VMware ESX support
+%bcond_without glusterfs       # GlusterFS storage support
+%bcond_without hyperv          # Hyper-V support
+%bcond_without libxl           # libxenlight support
+%bcond_without lxc             # LXC support
+%bcond_without netcf           # host interfaces support
+%bcond_without openvz          # OpenVZ support
+%bcond_without phyp            # PHYP support
+%bcond_without polkit          # PolicyKit support
+%bcond_without qemu            # Qemu support
+%bcond_without sanlock         # sanlock storage lock manager
+%bcond_without systemtap       # systemtap/dtrace probes
+%bcond_without uml             # UML support
+%bcond_without vbox            # VirtualBox support
+%bcond_without vmware          # VMware Workstation/Player support
+%bcond_with    vserver         # Support for Linux-VServer guests
+%bcond_without xenapi          # Xen API (Citrix XenServer) support
+%bcond_without xen             # Xen support
+%bcond_without static_libs     # static libraries build
+
+# qemu available only on x86 and ppc
+%ifnarch %{ix86} %{x8664} ppc
+%undefine      with_qemu
+%endif
+# Xen is available only on x86 and ia64
+%ifnarch %{ix86} %{x8664} ia64
+%undefine      with_xen
+%endif
+
+Summary:       Toolkit to interact with virtualization capabilities
+Summary(pl.UTF-8):     NarzÄ™dzia współpracujÄ…ce z funkcjami wirtualizacji
+Name:          libvirt
+Version:       1.2.8
+Release:       1
+License:       LGPL v2.1+
+Group:         Libraries
+Source0:       ftp://ftp.libvirt.org/libvirt/%{name}-%{version}.tar.gz
+# Source0-md5: 75114991290f7c8f01dd5223431b9c00
+Source1:       %{name}.init
+Source2:       %{name}.tmpfiles
+Patch0:                %{name}-sasl.patch
+Patch1:                %{name}-lxc.patch
+Patch2:                %{name}-qemu-acl.patch
+Patch3:                %{name}-xend.patch
+Patch4:                virtlockd.init.patch
+Patch5:                %{name}-udevadm-settle.patch
+Patch6:                vserver.patch
+Patch7:                bashisms.patch
+Patch8:                libvirt-guests.init.patch
+URL:           http://www.libvirt.org/
+BuildRequires: audit-libs-devel
+BuildRequires: augeas-devel
+BuildRequires: autoconf >= 2.50
+BuildRequires: automake
+BuildRequires: avahi-devel >= 0.6.0
+%{?with_ceph:BuildRequires:    ceph-devel}
+BuildRequires: curl-devel >= 7.18.0
+BuildRequires: cyrus-sasl-devel
+BuildRequires: dbus-devel >= 1.0.0
+BuildRequires: device-mapper-devel >= 1.0.0
+BuildRequires: gawk
+BuildRequires: gettext-devel >= 0.17
+%{?with_glusterfs:BuildRequires:       glusterfs-devel >= 3.4.1}
+BuildRequires: gnutls-devel >= 1.0.25
+BuildRequires: libapparmor-devel
+BuildRequires: libblkid-devel >= 2.17
+BuildRequires: libcap-ng-devel >= 0.4.0
+BuildRequires: libfuse-devel >= 2.8.6
+BuildRequires: libgcrypt-devel
+BuildRequires: libnl-devel >= 3.2
+BuildRequires: libpcap-devel >= 1.0.0
+BuildRequires: libselinux-devel >= 2.0.82
+BuildRequires: libssh2-devel >= 1.3
+BuildRequires: libtool
+%{?with_xenapi:BuildRequires:  libxenserver-devel}
+BuildRequires: libxml2-devel >= 1:2.6.0
+BuildRequires: libxslt-devel
+BuildRequires: ncurses-devel
+%{?with_netcf:BuildRequires:   netcf-devel >= 0.2.0}
+BuildRequires: numactl-devel
+BuildRequires: openldap-devel
+BuildRequires: openwsman-devel >= 2.2.3
+BuildRequires: parted-devel >= 1.8.0
+BuildRequires: pkgconfig
+BuildRequires: polkit
+%{?with_polkit:BuildRequires:  polkit-devel >= 0.90}
+BuildRequires: readline-devel
+BuildRequires: rpmbuild(macros) >= 1.627
+%{?with_sanlock:BuildRequires: sanlock-devel >= 0.8}
+BuildRequires: systemd-devel
+%{?with_systemtap:BuildRequires:       systemtap-sdt-devel}
+BuildRequires: udev-devel >= 1:145
+%{?with_xen:BuildRequires:     xen-devel >= 4.2}
+# For disk driver
+BuildRequires: xorg-lib-libpciaccess-devel >= 0.10.0
+BuildRequires: yajl-devel
+Requires:      curl-libs >= 7.18.0
+Requires:      device-mapper >= 1.0.0
+Requires:      libcap-ng >= 0.4.0
+Requires:      libnl >= 3.2
+Requires:      libpcap >= 1.0.0
+Requires:      libselinux >= 2.0.82
+Requires:      libssh2 >= 1.3
+Requires:      libxml2 >= 1:2.6.0
+Requires:      openwsman-libs >= 2.2.3
+Obsoletes:     libvirt-daemon-esx
+Obsoletes:     libvirt-daemon-hyperv
+Obsoletes:     libvirt-daemon-openvz
+Obsoletes:     libvirt-daemon-phyp
+Obsoletes:     libvirt-daemon-vbox
+Obsoletes:     libvirt-daemon-vmware
+BuildRoot:     %{tmpdir}/%{name}-%{version}-root-%(id -u -n)
+
+%description
+Libvirt is a C toolkit to interact with the virtualization
+capabilities of recent versions of Linux.
+
+Virtualization of the Linux Operating System means the ability to run
+multiple instances of Operating Systems concurently on a single
+hardware system where the basic resources are driven by a Linux
+instance. The library aim at providing long term stable C API
+initially for the Xen paravirtualization but should be able to
+integrate other virtualization mechanisms if needed.
+
+This package contains the base libraries and configuration file.
+
+%description -l pl.UTF-8
+Libvirt to zestaw narzÄ™dzi w C do współpracy z funkcjami wirtualizacji
+obecnych wersji Linuksa.
+
+Wirtualizacja w systemie operacyjnym Linux oznacza możliwość
+jednoczesnego uruchamiania wielu instancji systemu operacyjnego na
+pojedynczym systemie sprzÄ™towym, którego podstawowe zasoby sÄ…
+zarzÄ…dzane przez instancjÄ™ Linuksa. Celem biblioteki jest zapewnienie
+dÅ‚ugotrwale stabilnego API C, poczÄ…tkowo do parawirtualizacji Xen, ale
+dajÄ…cej siÄ™ zintegrować w razie potrzeby z innymi mechanizmami
+wirtualizacji.
+
+Ten pakiet zawiera podstawowe biblioteki oraz plik konfiguracyjny.
+
+%package devel
+Summary:       Development files for programs using libvirt
+Summary(pl.UTF-8):     Pliki programistyczne do programów wykorzystujÄ…cych libvirt
+Group:         Development/Libraries
+Requires:      %{name} = %{version}-%{release}
+Requires:      audit-libs-devel
+Requires:      curl-devel >= 7.18.0
+Requires:      dbus-devel >= 1.0.0
+Requires:      device-mapper-devel >= 1.0.0
+Requires:      gnutls-devel >= 1.0.25
+Requires:      libapparmor-devel
+Requires:      libcap-ng-devel >= 0.4.0
+Requires:      libgcrypt-devel
+Requires:      libnl-devel >= 3.2
+Requires:      libpcap-devel >= 1.0.0
+Requires:      libselinux-devel >= 2.0.82
+Requires:      libxml2-devel >= 1:2.6.0
+Requires:      numactl-devel
+Requires:      openwsman-devel >= 2.2.3
+%{?with_xen:Requires:  xen-devel >= 4.2}
+Requires:      yajl-devel
+
+%description devel
+Libvirt is a C toolkit to interact with the virtualization
+capabilities of recent versions of Linux.
+
+This package contains the header files needed for developing programs
+using the libvirt library.
+
+%description devel -l pl.UTF-8
+Libvirt to zestaw narzÄ™dzi w C do współpracy z funkcjami wirtualizacji
+obecnych wersji Linuksa.
+
+Ten pakiet zawiera pliki nagłówkowe potrzebne do tworzenia programów
+wykorzystujÄ…cych bibliotekÄ™ libvirt.
+
+%package static
+Summary:       Development static libraries for programs using libvirt
+Summary(pl.UTF-8):     Statyczne biblioteki programistyczne do programów wykorzystujÄ…cych libvirt
+Group:         Development/Libraries
+Requires:      %{name}-devel = %{version}-%{release}
+
+%description static
+Libvirt is a C toolkit to interact with the virtualization
+capabilities of recent versions of Linux.
+
+This package contains the static libraries for developing programs
+using the libvirt library.
+
+%description static -l pl.UTF-8
+Libvirt to zestaw narzÄ™dzi w C do współpracy z funkcjami wirtualizacji
+obecnych wersji Linuksa.
+
+Ten pakiet zawiera biblioteki statyczne do tworzenia programów
+wykorzystujÄ…cych bibliotekÄ™ libvirt.
+
+%package lock-sanlock
+Summary:       Sanlock lock manager plugin for libvirt
+Summary(pl.UTF-8):     ZarzÄ…dca blokad sanlock dla biblioteki libvirt
+Group:         Libraries
+Requires:      %{name}-daemon = %{version}-%{release}
+
+%description lock-sanlock
+Sanlock lock manager plugin for libvirt.
+
+%description lock-sanlock -l pl.UTF-8
+ZarzÄ…dca blokad sanlock dla biblioteki libvirt.
+
+%package daemon
+Summary:       Server side daemon and supporting files for libvirt library
+Summary(pl.UTF-8):     Demon dziaÅ‚ajÄ…cy po stronie serwera oraz pliki wspierajÄ…ce dla biblioteki libvirt
+Group:         Applications/System
+Requires:      %{name} = %{version}-%{release}
+Requires:      avahi-libs >= 0.6.0
+Requires:      iproute2
+Requires:      libblkid >= 2.17
+%{?with_netcf:Requires:        netcf >= 0.2.0}
+Requires:      parted-libs >= 1.8.0
+Requires:      rc-scripts
+# Needed for probing the power management features of the host.
+Requires:      pm-utils
+Requires:      systemd-units >= 37-0.10
+Requires:      udev-libs >= 1:145
+Requires:      util-linux
+Requires:      virtual(module-tools)
+Requires:      xorg-lib-libpciaccess >= 0.10.0
+Requires(post):        systemd-units
+Requires(post,preun):  /sbin/chkconfig
+Requires(postun):      systemd-units
+Requires(preun):       systemd-units
+Suggests:      bridge-utils
+Suggests:      cyrus-sasl
+Suggests:      cyrus-sasl-digest-md5
+Suggests:      dmidecode
+Suggests:      dnsmasq >= 2.41
+Suggests:      ebtables
+Suggests:      gawk
+Suggests:      glusterfs-client >= 2.0.1
+Suggests:      iptables
+Suggests:      iptables
+Suggests:      libcgroup
+Suggests:      lvm2
+Suggests:      numad
+Suggests:      open-iscsi
+Suggests:      parted >= 1.8.0
+Suggests:      polkit >= 0.93
+#Suggests:     radvd
+Suggests:      scrub
+#Suggests:     sheepdog
+Provides:      libvirt(hypervisor)
+
+%description daemon
+Server side daemon required to manage the virtualization capabilities
+of recent versions of Linux. Requires a hypervisor specific sub-RPM
+for specific drivers.
+
+%description daemon -l pl.UTF-8
+Demon dziaÅ‚ajÄ…cy po stronie serwera wymagany do zarzÄ…dzania funkcjami
+wirtualizacji nowych wersji Linuksa. Wymaga podpakietu specyficznego
+dla hipernadzorcy.
+
+%package daemon-libxl
+Summary:       Server side driver required to run XEN guests (xenlight)
+Summary(pl.UTF-8):     Sterownik wymagany po stronie serwera do uruchamiania goÅ›ci XEN (xenlight)
+Group:         Libraries
+Requires:      %{name}-daemon = %{version}-%{release}
+Requires:      /usr/sbin/qcow-create
+Requires:      xen
+Provides:      libvirt(hypervisor)
+
+%description daemon-libxl
+Server side driver required to manage the virtualization capabilities
+of XEN via xenlight interface.
+
+%description daemon-libxl -l pl.UTF-8
+Sterownik wymagany po stronie serwera do zarzÄ…dzania funkcjami
+wirtualizacji XEN poprzez interfejs xenlight.
+
+%package daemon-lxc
+Summary:       Server side driver required to run LXC guests
+Summary(pl.UTF-8):     Sterownik wymagany po stronie serwera do uruchamiania goÅ›ci LXC
+Group:         Libraries
+Requires:      %{name}-daemon = %{version}-%{release}
+Requires:      libfuse >= 2.8.6
+Provides:      libvirt(hypervisor)
+
+%description daemon-lxc
+Server side driver required to manage the virtualization capabilities
+of LXC.
+
+%description daemon-lxc -l pl.UTF-8
+Sterownik wymagany po stronie serwera do zarzÄ…dzania funkcjami
+wirtualizacji LXC.
+
+%package daemon-qemu
+Summary:       Server side driver required to run QEMU guests
+Summary(pl.UTF-8):     Sterownik wymagany po stronie serwera do uruchamiania goÅ›ci QEMU
+Group:         Libraries
+Requires:      %{name}-daemon = %{version}-%{release}
+Requires:      /usr/bin/qemu-img
+Requires:      bzip2
+Requires:      gzip
+Requires:      lzop
+Requires:      qemu
+Requires:      xz
+Provides:      libvirt(hypervisor)
+
+%description daemon-qemu
+Server side driver required to manage the virtualization capabilities
+of the QEMU emulators.
+
+%description daemon-qemu -l pl.UTF-8
+Sterownik wymagany po stronie serwera do zarzÄ…dzania funkcjami
+wirtualizacji emulatora QEMU.
+
+%package daemon-uml
+Summary:       Server side driver required to run UML guests
+Summary(pl.UTF-8):     Sterownik wymagany po stronie serwera do uruchamiania goÅ›ci UML
+Group:         Libraries
+Requires:      %{name}-daemon = %{version}-%{release}
+Provides:      libvirt(hypervisor)
+
+%description daemon-uml
+Server side driver required to manage the virtualization capabilities
+of UML.
+
+%description daemon-uml -l pl.UTF-8
+Sterownik wymagany po stronie serwera do zarzÄ…dzania funkcjami
+wirtualizacji UML.
+
+%package daemon-xen
+Summary:       Server side driver required to run XEN guests
+Summary(pl.UTF-8):     Sterownik wymagany po stronie serwera do uruchamiania goÅ›ci XEN
+Group:         Libraries
+Requires:      %{name}-daemon = %{version}-%{release}
+Requires:      /usr/sbin/qcow-create
+Requires:      xen
+Requires:      xen-xend
+Provides:      libvirt(hypervisor)
+
+%description daemon-xen
+Server side driver required to manage the virtualization capabilities
+of XEN.
+
+%description daemon-xen -l pl.UTF-8
+Sterownik wymagany po stronie serwera do zarzÄ…dzania funkcjami
+wirtualizacji XEN.
+
+%package client
+Summary:       Client side utilities of the libvirt library
+Summary(pl.UTF-8):     NarzÄ™dzia klienckie do biblioteki libvirt
+Group:         Applications/System
+Requires:      %{name} = %{version}-%{release}
+Requires:      gettext >= 0.18.1.1-6
+Requires:      gnutls >= 1.0.25
+Requires:      netcat-openbsd
+Requires:      rc-scripts
+Requires(post):        systemd-units
+Requires(post,preun):  /sbin/chkconfig
+Requires(postun):      systemd-units
+Requires(preun):       systemd-units
+
+%description client
+Client binaries needed to access to the virtualization capabilities of
+recent versions of Linux (and other OSes).
+
+%description client -l pl.UTF-8
+Programy klienckie potrzebne do funkcji wirtualizacji nowych wersji
+Linuksa (oraz innych systemów operacyjnych).
+
+%package utils
+Summary:       Tools to interact with virtualization capabilities (metapackage)
+Summary(pl.UTF-8):     NarzÄ™dzia do współpracy z funkcjami wirtualizacyjnymi (metapakiet)
+Group:         Applications/System
+Requires:      %{name}-client = %{version}-%{release}
+Requires:      %{name}-daemon = %{version}-%{release}
+%{?with_libxl:Requires:        %{name}-daemon-libxl = %{version}-%{release}}
+Requires:      %{name}-daemon-lxc = %{version}-%{release}
+Requires:      %{name}-daemon-qemu = %{version}-%{release}
+Requires:      %{name}-daemon-uml = %{version}-%{release}
+Requires:      %{name}-daemon-xen = %{version}-%{release}
+
+%description utils
+Libvirt is a C toolkit to interact with the virtualization
+capabilities of recent versions of Linux.
+
+This is metapackage gathering all tools for the libvirt library.
+
+%description utils -l pl.UTF-8
+Libvirt to zestaw narzÄ™dzi w C do współpracy z funkcjami wirtualizacji
+obecnych wersji Linuksa.
+
+To jest metapakiet zbierajÄ…cy wszystkie narzÄ™dzia przeznaczone dla
+biblioteki libvirt.
+
+%package -n systemtap-libvirt
+Summary:       systemtap/dtrace probes for libvirt
+Summary(pl.UTF-8):     Sondy systemtap/dtrace dla libvirt
+Group:         Development/Tools
+Requires:      %{name} = %{version}-%{release}
+Requires:      systemtap-client
+
+%description -n systemtap-libvirt
+systemtap/dtrace probes for libvirt.
+
+%description -n systemtap-libvirt -l pl.UTF-8
+Sondy systemtap/dtrace dla libvirt.
+
+%prep
+%setup -q
+%patch0 -p1
+# TODO
+#patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%{?with_vserver:%patch6 -p1}
+%patch7 -p1
+%patch8 -p1
+
+%build
+%{__libtoolize}
+%{__aclocal} -I m4
+%{__autoconf}
+%{__autoheader}
+%{__automake}
+
+%configure \
+       PVCREATE=/sbin/pvcreate \
+       VGCREATE=/sbin/vgcreate \
+       LVCREATE=/sbin/lvcreate \
+       PVREMOVE=/sbin/pvremove \
+       VGREMOVE=/sbin/vgremove \
+       LVREMOVE=/sbin/lvremove \
+       VGCHANGE=/sbin/vgchange \
+       LVCHANGE=/sbin/lvchange \
+         VGSCAN=/sbin/vgscan   \
+            PVS=/sbin/pvs      \
+            VGS=/sbin/vgs      \
+            LVS=/sbin/lvs      \
+             TC=/sbin/tc \
+          BRCTL=/sbin/brctl    \
+       ISCSIADM=/sbin/iscsiadm \
+       SHOWMOUNT=/usr/sbin/showmount \
+       MOUNT=/bin/mount \
+       UMOUNT=/bin/umount \
+       MKFS=/sbin/mkfs \
+       SHOWMOUNT=/usr/sbin/showmount \
+       IPTABLES_PATH=/usr/sbin/iptables \
+       IP6TABLES_PATH=/usr/sbin/ip6tables \
+       EBTABLES_PATH=/usr/sbin/ebtables \
+       ISCSIADM=/sbin/iscsiadm \
+       DNSMASQ=/usr/sbin/dnsmasq \
+       RADVD=/usr/sbin/radvd \
+       UDEVADM=/sbin/udevadm \
+       MODPROBE=/sbin/modprobe \
+       SCRUB=/usr/bin/scrub \
+       OVSVSCTL=/usr/bin/ovs-vsctl \
+       NUMAD=/usr/bin/numad \
+       COLLIE=/usr/sbin/collie \
+       --disable-silent-rules \
+       %{?with_static_libs:--enable-static} \
+       --with-html-dir=%{_gtkdocdir} \
+       --with-html-subdir=%{name} \
+       --with-init-script=systemd+redhat \
+       --with-packager="PLD-Linux" \
+       --with-packager-version="%{name}-%{version}-%{release}.%{_target_cpu}" \
+       --with-qemu-user=qemu \
+       --with-qemu-group=qemu \
+       --with-storage-disk \
+       --with-storage-fs \
+       --with-storage-gluster%{!?with_glusterfs:=no} \
+       --with-storage-iscsi \
+       --with-storage-lvm \
+       --with-storage-mpath \
+       --with-storage-rbd%{!?with_ceph:=no} \
+       --with-storage-scsi \
+       --with-storage-sheepdog \
+       --with-apparmor \
+       --with-audit \
+       --with-avahi \
+       %{__with_without systemtap dtrace} \
+       %{__with_without esx} \
+       --with-driver-modules \
+       --without-hal \
+       %{__with_without hyperv} \
+       --with-blkid \
+       --with-ssh2 \
+       %{__with_without libxl} \
+       %{__with_without lxc} \
+       --with-macvtap \
+       %{__with_without netcf} \
+       --with-numactl \
+       --with-numad \
+       %{__with_without openvz} \
+       %{__with_without phyp} \
+       %{__with_without polkit} \
+       %{__with_without qemu} \
+       %{__with_without sanlock} \
+       --with-sasl \
+       --with-selinux \
+       --with-udev \
+       %{__with_without uml} \
+       %{__with_without vbox vbox %{_libdir}/VirtualBox} \
+       --with-virtualport \
+       %{__with_without vmware} \
+       %{__with_without xen} \
+       %{__with_without xenapi} \
+       --with-yajl \
+       --x-libraries=%{_libdir}
+
+%{__make} \
+       AWK=gawk
+
+%install
+rm -rf $RPM_BUILD_ROOT
+install -d $RPM_BUILD_ROOT/etc/{sysconfig,rc.d/init.d} \
+       $RPM_BUILD_ROOT%{systemdtmpfilesdir}
+
+%{__make} install \
+       DEVHELP_DIR=%{_gtkdocdir}/%{name}/devhelp \
+       SYSTEMD_UNIT_DIR=%{systemdunitdir} \
+       DESTDIR=$RPM_BUILD_ROOT
+
+install %{SOURCE1} $RPM_BUILD_ROOT/etc/rc.d/init.d/libvirtd
+install %{SOURCE2} $RPM_BUILD_ROOT%{systemdtmpfilesdir}/%{name}.conf
+
+%{__rm} $RPM_BUILD_ROOT%{_libdir}/*.la
+%{__rm} $RPM_BUILD_ROOT%{_libdir}/libvirt/connection-driver/*.la \
+       %{?with_static_libs:$RPM_BUILD_ROOT%{_libdir}/libvirt/connection-driver/*.a}
+
+%if %{with sanlock}
+%{__rm} $RPM_BUILD_ROOT%{_libdir}/libvirt/lock-driver/*.la \
+       %{?with_static_libs:$RPM_BUILD_ROOT%{_libdir}/libvirt/lock-driver/*.a}
+%endif
+
+%{__mv} $RPM_BUILD_ROOT%{_localedir}/{eu_ES,eu}
+# duplicate of vi, just one less message translated
+%{__rm} -r $RPM_BUILD_ROOT%{_localedir}/vi_VN
+
+%find_lang %{name}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post  -p /sbin/ldconfig
+%postun        -p /sbin/ldconfig
+
+%post daemon
+/sbin/chkconfig --add libvirtd
+%service libvirtd restart
+%systemd_post libvirtd.service
+
+%preun daemon
+if [ "$1" = "0" ]; then
+       %service -q libvirtd stop
+       /sbin/chkconfig --del libvirtd
+fi
+%systemd_preun libvirtd.service
+
+%postun daemon
+%systemd_reload
+
+%post client
+/sbin/chkconfig --add libvirt-guests
+%service -n libvirt-guests restart
+NORESTART=1
+%systemd_post libvirt-guests.service
+
+%preun client
+%systemd_preun libvirt-guests.service
+if [ "$1" = "0" ]; then
+       %service -q libvirt-guests stop
+       /sbin/chkconfig --del libvirt-guests
+fi
+
+%postun client
+%systemd_reload
+
+%files -f %{name}.lang
+%defattr(644,root,root,755)
+%doc ChangeLog README TODO NEWS
+%dir %{_sysconfdir}/libvirt
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/libvirt.conf
+%attr(755,root,root) %{_libdir}/libvirt.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libvirt.so.0
+%if %{with lxc}
+%attr(755,root,root) %{_libdir}/libvirt-lxc.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libvirt-lxc.so.0
+%endif
+%if %{with qemu}
+%attr(755,root,root) %{_libdir}/libvirt-qemu.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libvirt-qemu.so.0
+%endif
+
+%dir %{_libdir}/libvirt
+%dir %{_datadir}/libvirt
+%{_datadir}/libvirt/libvirtLogo.png
+
+%files devel
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libvirt.so
+%{?with_lxc:%attr(755,root,root) %{_libdir}/libvirt-lxc.so}
+%{?with_qemu:%attr(755,root,root) %{_libdir}/libvirt-qemu.so}
+%{_datadir}/%{name}/api
+%{_gtkdocdir}/%{name}
+%{_includedir}/%{name}
+%{_pkgconfigdir}/libvirt.pc
+%{?with_lxc:%{_pkgconfigdir}/libvirt-lxc.pc}
+%{?with_qemu:%{_pkgconfigdir}/libvirt-qemu.pc}
+
+%files static
+%defattr(644,root,root,755)
+%{_libdir}/libvirt.a
+%{?with_lxc:%{_libdir}/libvirt-lxc.a}
+%{?with_qemu:%{_libdir}/libvirt-qemu.a}
+
+%if %{with sanlock}
+%files lock-sanlock
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_sbindir}/virt-sanlock-cleanup
+%attr(755,root,root) %{_libdir}/libvirt_sanlock_helper
+%attr(755,root,root) %{_libdir}/libvirt/lock-driver/sanlock.so
+%{_datadir}/augeas/lenses/libvirt_sanlock.aug
+%{_datadir}/augeas/lenses/tests/test_libvirt_sanlock.aug
+%dir /var/lib/libvirt/sanlock
+%{_mandir}/man8/virt-sanlock-cleanup.8*
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/qemu-sanlock.conf
+%endif
+
+%files daemon
+%defattr(644,root,root,755)
+%doc docs/*.xml
+%dir %attr(700,root,root) %{_sysconfdir}/libvirt/nwfilter
+%dir %attr(700,root,root) %{_sysconfdir}/libvirt/qemu
+%dir %attr(700,root,root) %{_sysconfdir}/libvirt/qemu/networks
+%dir %attr(700,root,root) %{_sysconfdir}/libvirt/qemu/networks/autostart
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/libvirtd.conf
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/qemu-lockd.conf
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/virtlockd.conf
+%config(noreplace,missingok) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/qemu/networks/default.xml
+%config(noreplace,missingok) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/qemu/networks/autostart/default.xml
+%config(noreplace,missingok) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/nwfilter/*.xml
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/sasl/libvirt.conf
+%config(noreplace) %verify(not md5 mtime size) /etc/sysconfig/libvirtd
+%config(noreplace) %verify(not md5 mtime size) /etc/sysconfig/virtlockd
+%attr(754,root,root) /etc/rc.d/init.d/libvirtd
+%attr(754,root,root) /etc/rc.d/init.d/virtlockd
+%{systemdunitdir}/libvirtd.service
+%{systemdunitdir}/libvirtd.socket
+%{systemdunitdir}/virtlockd.service
+%{systemdunitdir}/virtlockd.socket
+%config(noreplace) %verify(not md5 mtime size) /usr/lib/sysctl.d/libvirtd.conf
+%config(noreplace) %verify(not md5 mtime size) /etc/logrotate.d/libvirtd
+%attr(755,root,root) %{_libdir}/libvirt_iohelper
+%attr(755,root,root) %{_libdir}/libvirt_parthelper
+%attr(755,root,root) %{_libdir}/virt-aa-helper
+%attr(755,root,root) %{_sbindir}/libvirtd
+%attr(755,root,root) %{_sbindir}/virtlockd
+%{_datadir}/augeas/lenses/libvirtd.aug
+%{_datadir}/augeas/lenses/libvirt_lockd.aug
+%{_datadir}/augeas/lenses/virtlockd.aug
+%{_datadir}/augeas/lenses/tests/test_libvirtd.aug
+%{_datadir}/augeas/lenses/tests/test_libvirt_lockd.aug
+%{_datadir}/augeas/lenses/tests/test_virtlockd.aug
+%if %{with polkit}
+%{_datadir}/polkit-1/actions/org.libvirt.api.policy
+%{_datadir}/polkit-1/actions/org.libvirt.unix.policy
+%endif
+%{_mandir}/man8/libvirtd.8*
+%{_mandir}/man8/virtlockd.8*
+%dir /var/lib/libvirt
+%dir /var/lib/libvirt/dnsmasq
+%attr(711,root,root) %dir /var/lib/libvirt/boot
+%attr(700,root,root) %dir /var/lib/libvirt/network
+%attr(711,root,root) %dir /var/lib/libvirt/images
+%attr(711,root,root) %dir /var/lib/libvirt/filesystems
+%attr(700,root,root) %dir /var/log/libvirt
+%attr(711,root,root) %dir /var/cache/libvirt
+%dir /var/run/libvirt
+%dir /var/run/libvirt/network
+%{systemdtmpfilesdir}/%{name}.conf
+%attr(755,root,root) %{_libexecdir}/libvirt_leaseshelper
+%dir %{_libdir}/libvirt/connection-driver
+%{_datadir}/libvirt/cpu_map.xml
+%{?with_netcf:%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_interface.so}
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_network.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_nodedev.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_nwfilter.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_secret.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_storage.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_vbox.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_vbox_network.so
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_vbox_storage.so
+%dir %{_libdir}/libvirt/lock-driver
+%attr(755,root,root) %{_libdir}/libvirt/lock-driver/lockd.so
+
+%if %{with libxl}
+%files daemon-libxl
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_libxl.so
+%attr(700,root,root) %dir /var/lib/libvirt/libxl
+%attr(700,root,root) %dir /var/run/libvirt/libxl
+%attr(700,root,root) %dir /var/log/libvirt/libxl
+%endif
+
+%if %{with lxc}
+%files daemon-lxc
+%defattr(644,root,root,755)
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/lxc.conf
+%config(noreplace) %verify(not md5 mtime size) /etc/logrotate.d/libvirtd.lxc
+%attr(700,root,root) %dir /var/lib/libvirt/lxc
+%attr(700,root,root) %dir /var/run/libvirt/lxc
+%attr(700,root,root) %dir /var/log/libvirt/lxc
+%{_datadir}/augeas/lenses/libvirtd_lxc.aug
+%{_datadir}/augeas/lenses/tests/test_libvirtd_lxc.aug
+%attr(755,root,root) %{_libdir}/libvirt_lxc
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_lxc.so
+%endif
+
+%if %{with qemu}
+%files daemon-qemu
+%defattr(644,root,root,755)
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/qemu.conf
+%config(noreplace) %verify(not md5 mtime size) /etc/logrotate.d/libvirtd.qemu
+%attr(750,qemu,qemu) %dir /var/cache/libvirt/qemu
+%attr(750,qemu,qemu) %dir /var/lib/libvirt/qemu
+%attr(700,root,root) %dir /var/log/libvirt/qemu
+%attr(700,root,root) %dir /var/run/libvirt/qemu
+%{_datadir}/augeas/lenses/libvirtd_qemu.aug
+%{_datadir}/augeas/lenses/tests/test_libvirtd_qemu.aug
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_qemu.so
+%endif
+
+%if %{with uml}
+%files daemon-uml
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_uml.so
+%config(noreplace) %verify(not md5 mtime size) /etc/logrotate.d/libvirtd.uml
+%attr(700,root,root) %dir /var/lib/libvirt/uml
+%attr(700,root,root) %dir /var/run/libvirt/uml
+%attr(700,root,root) %dir /var/log/libvirt/uml
+%endif
+
+%if %{with xen}
+%files daemon-xen
+%defattr(644,root,root,755)
+%attr(755,root,root) %{_libdir}/libvirt/connection-driver/libvirt_driver_xen.so
+%endif
+
+%files client
+%defattr(644,root,root,755)
+%config(noreplace) %verify(not md5 mtime size) /etc/sysconfig/libvirt-guests
+%attr(754,root,root) /etc/rc.d/init.d/libvirt-guests
+%{systemdunitdir}/libvirt-guests.service
+%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/libvirt/virt-login-shell.conf
+%attr(755,root,root) %{_bindir}/virsh
+%attr(755,root,root) %{_bindir}/virt-host-validate
+%attr(4755,root,root) %{_bindir}/virt-login-shell
+%attr(755,root,root) %{_bindir}/virt-xml-validate
+%attr(755,root,root) %{_bindir}/virt-pki-validate
+%attr(754,root,root) %{_libexecdir}/libvirt-guests.sh
+%{_mandir}/man1/virsh.1*
+%{_mandir}/man1/virt-host-validate.1*
+%{_mandir}/man1/virt-login-shell.1*
+%{_mandir}/man1/virt-xml-validate.1*
+%{_mandir}/man1/virt-pki-validate.1*
+%dir %{_datadir}/libvirt/schemas
+%{_datadir}/libvirt/schemas/basictypes.rng
+%{_datadir}/libvirt/schemas/capability.rng
+%{_datadir}/libvirt/schemas/domain.rng
+%{_datadir}/libvirt/schemas/domaincaps.rng
+%{_datadir}/libvirt/schemas/domaincommon.rng
+%{_datadir}/libvirt/schemas/domainsnapshot.rng
+%{_datadir}/libvirt/schemas/interface.rng
+%{_datadir}/libvirt/schemas/network.rng
+%{_datadir}/libvirt/schemas/networkcommon.rng
+%{_datadir}/libvirt/schemas/nodedev.rng
+%{_datadir}/libvirt/schemas/nwfilter.rng
+%{_datadir}/libvirt/schemas/secret.rng
+%{_datadir}/libvirt/schemas/storagecommon.rng
+%{_datadir}/libvirt/schemas/storagepool.rng
+%{_datadir}/libvirt/schemas/storagevol.rng
+
+%files utils
+%defattr(644,root,root,755)
+
+%if %{with systemtap}
+%files -n systemtap-libvirt
+%defattr(644,root,root,755)
+%{_datadir}/systemtap/tapset/libvirt_functions.stp
+%{_datadir}/systemtap/tapset/libvirt_probes.stp
+%{_datadir}/systemtap/tapset/libvirt_qemu_probes.stp
+%endif
diff --git a/libvirt.tmpfiles b/libvirt.tmpfiles
new file mode 100644 (file)
index 0000000..f6b97c4
--- /dev/null
@@ -0,0 +1,3 @@
+d /var/run/libvirt 0755 root root -
+d /var/run/libvirt/lxc 0700 root root -
+d /var/run/libvirt/qemu 0700 root root -
diff --git a/query-parameters.patch b/query-parameters.patch
new file mode 100644 (file)
index 0000000..04f15c7
--- /dev/null
@@ -0,0 +1,180 @@
+From 70c07e01dee24df0a1591d65799b66a8e89a3bd6 Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+Date: Mon, 26 Mar 2012 11:23:45 +0100
+Subject: [PATCH] Fix and test round-trip of query parameters
+
+When qparams support was dropped in commit bc1ff160, we forgot
+to add tests to ensure that viruri can do the same round trip
+handling of a URI. This round trip was broken, due to use
+of the old 'query' field of xmlUriPtr, instead of the new
+'query_raw'
+
+Also, we forgot to report an OOM error.
+
+* tests/viruritest.c (mymain): Add tests based on just-deleted
+qparamtest.
+(testURIParse): Allow difference in input and expected output.
+* src/util/viruri.c (virURIFormat): Add missing error. Use
+  query_raw, instead of query for xmlUriPtr object.
+---
+ src/util/viruri.c  |    8 ++++-
+ tests/viruritest.c |   78 +++++++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 72 insertions(+), 14 deletions(-)
+
+diff --git a/src/util/viruri.c b/src/util/viruri.c
+index 7cca977..2c6de51 100644
+--- a/src/util/viruri.c
++++ b/src/util/viruri.c
+@@ -243,15 +243,21 @@ virURIFormat(virURIPtr uri)
+     xmluri.server = uri->server;
+     xmluri.port = uri->port;
+     xmluri.path = uri->path;
++#ifdef HAVE_XMLURI_QUERY_RAW
++    xmluri.query_raw = uri->query;
++#else
+     xmluri.query = uri->query;
++#endif
+     xmluri.fragment = uri->fragment;
+     /* First check: does it make sense to do anything */
+     if (xmluri.server != NULL &&
+         strchr(xmluri.server, ':') != NULL) {
+-        if (virAsprintf(&tmpserver, "[%s]", xmluri.server) < 0)
++        if (virAsprintf(&tmpserver, "[%s]", xmluri.server) < 0) {
++            virReportOOMError();
+             return NULL;
++        }
+         xmluri.server = tmpserver;
+     }
+diff --git a/tests/viruritest.c b/tests/viruritest.c
+index 9504a3b..d97e9c7 100644
+--- a/tests/viruritest.c
++++ b/tests/viruritest.c
+@@ -35,6 +35,7 @@
+ struct URIParseData {
+     const char *uri;
++    const char *uri_out;
+     const char *scheme;
+     const char *server;
+     int port;
+@@ -49,21 +50,12 @@ static int testURIParse(const void *args)
+     int ret = -1;
+     virURIPtr uri = NULL;
+     const struct URIParseData *data = args;
+-    char *uristr;
++    char *uristr = NULL;
+     size_t i;
+     if (!(uri = virURIParse(data->uri)))
+         goto cleanup;
+-    if (!(uristr = virURIFormat(uri)))
+-        goto cleanup;
+-
+-    if (!STREQ(uristr, data->uri)) {
+-        VIR_DEBUG("URI did not roundtrip, expect '%s', actual '%s'",
+-                  data->uri, uristr);
+-        goto cleanup;
+-    }
+-
+     if (!STREQ(uri->scheme, data->scheme)) {
+         VIR_DEBUG("Expected scheme '%s', actual '%s'",
+                   data->scheme, uri->scheme);
+@@ -123,6 +115,18 @@ static int testURIParse(const void *args)
+         goto cleanup;
+     }
++    VIR_FREE(uri->query);
++    uri->query = virURIFormatParams(uri);
++
++    if (!(uristr = virURIFormat(uri)))
++        goto cleanup;
++
++    if (!STREQ(uristr, data->uri_out)) {
++        VIR_DEBUG("URI did not roundtrip, expect '%s', actual '%s'",
++                  data->uri_out, uristr);
++        goto cleanup;
++    }
++
+     ret = 0;
+ cleanup:
+     VIR_FREE(uristr);
+@@ -138,14 +142,22 @@ mymain(void)
+     signal(SIGPIPE, SIG_IGN);
+-#define TEST_PARSE(uri, scheme, server, port, path, query, fragment, params) \
++#define TEST_FULL(uri, uri_out, scheme, server, port, path, query,      \
++                  fragment, params)                                     \
+     do  {                                                               \
+         const struct URIParseData data = {                              \
+-            uri, scheme, server, port, path, query, fragment, params    \
++            uri, (uri_out) ? (uri_out) : (uri), scheme, server, port,   \
++            path, query, fragment, params                               \
+         };                                                              \
+-        if (virtTestRun("Test IPv6 " # uri,  1, testURIParse, &data) < 0) \
++        if (virtTestRun("Test URI " # uri,  1, testURIParse, &data) < 0) \
+             ret = -1;                                                   \
+     } while (0)
++#define TEST_PARSE(uri, scheme, server, port, path, query, fragment, params) \
++    TEST_FULL(uri, NULL, scheme, server, port, path, query, fragment, params)
++#define TEST_PARAMS(query_in, query_out, params)                        \
++    TEST_FULL("test://example.com/?" query_in,                          \
++              *query_out ? "test://example.com/?" query_out : NULL,     \
++              "test", "example.com", 0, "/", query_in, NULL, params)
+     virURIParam params[] = {
+         { (char*)"name", (char*)"value" },
+@@ -159,6 +171,46 @@ mymain(void)
+     TEST_PARSE("test://[::1]:123/system", "test", "::1", 123, "/system", NULL, NULL, NULL);
+     TEST_PARSE("test://[2001:41c8:1:4fd4::2]:123/system", "test", "2001:41c8:1:4fd4::2", 123, "/system", NULL, NULL, NULL);
++    virURIParam params1[] = {
++        { (char*)"foo", (char*)"one" },
++        { (char*)"bar", (char*)"two" },
++        { NULL, NULL },
++    };
++    virURIParam params2[] = {
++        { (char*)"foo", (char*)"one" },
++        { (char*)"foo", (char*)"two" },
++        { NULL, NULL },
++    };
++    virURIParam params3[] = {
++        { (char*)"foo", (char*)"&one" },
++        { (char*)"bar", (char*)"&two" },
++        { NULL, NULL },
++    };
++    virURIParam params4[] = {
++        { (char*)"foo", (char*)"" },
++        { NULL, NULL },
++    };
++    virURIParam params5[] = {
++        { (char*)"foo", (char*)"one two" },
++        { NULL, NULL },
++    };
++    virURIParam params6[] = {
++        { (char*)"foo", (char*)"one" },
++        { NULL, NULL },
++    };
++
++    TEST_PARAMS("foo=one&bar=two", "", params1);
++    TEST_PARAMS("foo=one&foo=two", "", params2);
++    TEST_PARAMS("foo=one&&foo=two", "foo=one&foo=two", params2);
++    TEST_PARAMS("foo=one;foo=two", "foo=one&foo=two", params2);
++    TEST_PARAMS("foo=%26one&bar=%26two", "", params3);
++    TEST_PARAMS("foo", "foo=", params4);
++    TEST_PARAMS("foo=", "", params4);
++    TEST_PARAMS("foo=&", "foo=", params4);
++    TEST_PARAMS("foo=&&", "foo=", params4);
++    TEST_PARAMS("foo=one%20two", "", params5);
++    TEST_PARAMS("=bogus&foo=one", "foo=one", params6);
++
+     return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ }
+-- 
+1.7.1
+
diff --git a/virtlockd.init.patch b/virtlockd.init.patch
new file mode 100644 (file)
index 0000000..f3bdadd
--- /dev/null
@@ -0,0 +1,8 @@
+--- libvirt-1.0.4/src/locking/virtlockd.init.in~       2013-01-17 08:01:39.000000000 +0200
++++ libvirt-1.0.4/src/locking/virtlockd.init.in        2013-04-26 22:51:35.454895048 +0300
+@@ -1,4 +1,4 @@
+-#!/bin/sh
++#!/bin/bash
+ # the following is the LSB init header see
+ # http://www.linux-foundation.org/spec//booksets/LSB-Core-generic/LSB-Core-generic.html#INITSCRCOMCONV
diff --git a/vserver.patch b/vserver.patch
new file mode 100644 (file)
index 0000000..42c4fe2
--- /dev/null
@@ -0,0 +1,2744 @@
+https://www.redhat.com/archives/libvir-list/2008-January/msg00097.html
+
+From: "Daniel Hokka Zakrisson" <daniel hozac com>
+To: libvir-list redhat com
+Subject: [Libvir] [PATCH] Linux-VServer support
+Date: Wed, 9 Jan 2008 22:51:20 +0100 (CET)
+
+This patch implements support for Linux-VServer guests. It is currently
+missing vcpu and console support, and the necessary virsh code to support
+it, but is otherwise pretty feature complete.
+
+This is an XML dump from one of my guests:
+<domain type='vserver' id='40010'>
+  <name>lenny</name>
+  <uuid>19e12957-261a-5a06-d6d0-89917d6d439f</uuid>
+  <memory>2048000</memory>
+  <os>
+    <hostname>lenny.test</hostname>
+    <type arch='i686'>vserver</type>
+  </os>
+  <devices>
+    <interface type='ethernet'>
+      <ip prefix='24' interface='dummy0' address='192.168.20.4' />
+    </interface>
+    <interface type='ethernet'>
+      <ip prefix='24' interface='dummy0' type='range' address='192.168.32.100' address2='192.168.32.200'/>
+    </interface>
+    <disk type='directory' device='directory'>
+      <source directory='/vservers/lenny' type='auto' options='defaults'/>
+      <target directory='/'/>
+    </disk>
+    <disk type='directory' device='directory'>
+      <source directory='/srv' type='ext3' options='bind,ro'/>
+      <target directory='/srv'/>
+    </disk>
+    <disk type='block' device='directory'>
+       <source dev='/dev/mapper/test' type='ext3' options='defaults'/>
+       <target directory='/mnt'/>
+    </disk>
+  </devices>
+</domain>
+
+-- 
+Daniel Hokka Zakrisson
+--- libvirt-1.2.3/configure.ac~        2014-04-06 12:21:22.000000000 +0300
++++ libvirt-1.2.3/configure.ac 2014-04-06 12:22:55.249258975 +0300
+@@ -546,6 +546,10 @@
+   [AS_HELP_STRING([--with-parallels],
+     [add Parallels Cloud Server support @<:@default=check@:>@])])
+ m4_divert_text([DEFAULTS], [with_parallels=check])
++AC_ARG_WITH([vserver],
++  [AS_HELP_STRING([--with-vserver],
++    [add Linux-VServer support @<:@default=check@:>@])])
++m4_divert_text([DEFAULTS], [with_vserver=check])
+ AC_ARG_WITH([test],
+   [AS_HELP_STRING([--with-test],
+     [add test driver support @<:@default=yes@:>@])])
+@@ -991,6 +991,39 @@
+   fi
+ fi
++if test "$with_vserver" = "yes" ; then
++    AC_CHECK_LIB(vserver, [vc_rlimit_stat],, [with_vserver=no])
++    AC_CHECK_TYPES([xid_t, nid_t, tag_t])
++    AC_CHECK_HEADER(vserver.h,, [with_vserver=no], [AC_INCLUDES_DEFAULT()
++#ifndef HAVE_XID_T
++typedef unsigned int xid_t;
++#endif
++#ifndef HAVE_NID_T
++typedef unsigned int nid_t;
++#endif
++#ifndef HAVE_TAG_T
++typedef unsigned int tag_t;
++#endif])
++
++    AC_MSG_CHECKING([for vserver configuration directory])
++    VSERVER_CONF_DIR=`env PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" \
++        vserver-info - SYSINFO | sed -n 's/^.*cfg-Directory:.//p'`
++    AC_MSG_RESULT([$VSERVER_CONF_DIR])
++    AC_DEFINE_UNQUOTED([VSERVER_CONF_DIR], ["$VSERVER_CONF_DIR"],
++        [The default path to the Linux-VServer configuration files])
++
++    AC_MSG_CHECKING([for the vserver program])
++    PROG_VSERVER=`env PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" \
++        which vserver 2> /dev/null` || with_vserver=no
++    AC_MSG_RESULT([$PROG_VSERVER])
++    AC_DEFINE_UNQUOTED([PROG_VSERVER], ["$PROG_VSERVER"],
++        [The path to the vserver program])
++
++    if test "$with_vserver" = "yes" ; then
++        LIBVIRT_FEATURES="$LIBVIRT_FEATURES -DWITH_VSERVER"
++    fi
++fi
++
+ dnl
+ dnl check for kernel headers required by src/bridge.c
+@@ -2759,6 +2759,7 @@
+ AC_MSG_NOTICE([      ESX: $with_esx])
+ AC_MSG_NOTICE([  Hyper-V: $with_hyperv])
+ AC_MSG_NOTICE([Parallels: $with_parallels])
++AC_MSG_NOTICE([  VServer: $with_vserver])
+ LIBVIRT_DRIVER_RESULT_BHYVE
+ AC_MSG_NOTICE([     Test: $with_test])
+ AC_MSG_NOTICE([   Remote: $with_remote])
+--- libvirt-1.1.1/include/libvirt/virterror.h~ 2013-07-24 03:23:07.000000000 +0300
++++ libvirt-1.1.1/include/libvirt/virterror.h  2013-09-01 00:07:44.097192613 +0300
+@@ -121,6 +121,8 @@
+     VIR_FROM_ACCESS = 55,       /* Error from access control manager */
+     VIR_FROM_SYSTEMD = 56,      /* Error from systemd code */
++    VIR_FROM_VSERVER = 57,      /* Error from Linux-VServer driver */
++
+ # ifdef VIR_ENUM_SENTINELS
+     VIR_ERR_DOMAIN_LAST
+ # endif
+--- libvirt-1.2.3/src/driver.h~        2014-03-27 12:35:00.000000000 +0200
++++ libvirt-1.2.3/src/driver.h 2014-04-06 12:25:03.124800629 +0300
+@@ -48,6 +48,7 @@
+     VIR_DRV_HYPERV = 15,
+     VIR_DRV_PARALLELS = 16,
+     VIR_DRV_BHYVE = 17,
++    VIR_DRV_VSERVER = 18,
+ } virDrvNo;
+--- libvirt-1.1.1/src/libvirt.c~       2013-09-01 00:20:50.000000000 +0300
++++ libvirt-1.1.1/src/libvirt.c        2013-09-01 00:21:02.812830784 +0300
+@@ -94,6 +94,9 @@
+ #ifdef WITH_PARALLELS
+ # include "parallels/parallels_driver.h"
+ #endif
++#ifdef WITH_VSERVER
++# include "server/vserver_driver.h"
++#endif
+ #define VIR_FROM_THIS VIR_FROM_NONE
+@@ -479,6 +482,10 @@
+     if (parallelsRegister() == -1)
+         goto error;
+ #endif
++#ifdef WITH_VSERVER
++    if (verversRegister() == -1)
++        goto error;
++#endif
+ #ifdef WITH_REMOTE
+     if (remoteRegister() == -1)
+         goto error;
+--- libvirt-1.1.1/src/Makefile.am~     2013-07-30 10:21:31.000000000 +0300
++++ libvirt-1.1.1/src/Makefile.am      2013-09-01 00:11:19.080124997 +0300
+@@ -467,6 +467,7 @@
+       $(NWFILTER_DRIVER_SOURCES) \
+       $(OPENVZ_DRIVER_SOURCES) \
+       $(PARALLELS_DRIVER_SOURCES) \
++      $(VSERVER_DRIVER_SOURCES) \
+       $(PHYP_DRIVER_SOURCES) \
+       $(QEMU_DRIVER_SOURCES) \
+       $(REMOTE_DRIVER_SOURCES) \
+@@ -727,6 +728,12 @@
+               parallels/parallels_storage.c           \
+               parallels/parallels_network.c
++VSERVER_DRIVER_SOURCES =                                      \
++              vserver/vserver_driver.h                        \
++              vserver/vserver_driver.c                        \
++              vserver/vserver_conf.h                          \
++              vserver/vserver_conf.c
++
+ NETWORK_DRIVER_SOURCES =                                      \
+               network/bridge_driver.h network/bridge_driver.c
+--- libvirt-1.2.3/src/util/virerror.c~ 2014-03-27 12:35:01.000000000 +0200
++++ libvirt-1.2.3/src/util/virerror.c  2014-04-06 12:25:58.523869047 +0300
+@@ -127,6 +127,7 @@
+               "Access Manager", /* 55 */
+               "Systemd",
++              "Vserver",
+               "Bhyve",
+               "Crypto",
+     )
+--- libvirt-0.4.0.orig/src/vserver/vserver_conf.c      1970-01-01 01:00:00.000000000 +0100
++++ libvirt-0.4.0.vserver/src/vserver/vserver_conf.c   2008-01-09 08:52:11.000000000 +0100
+@@ -0,0 +1,751 @@
++/*
++ * Configuration handling for Linux-VServer guests
++ *
++ * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
++ *
++ * 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
++ *
++ * Author: Daniel Hokka Zakrisson <daniel hozac com>
++ */
++
++#ifdef WITH_VSERVER
++
++#define _GNU_SOURCE
++
++#ifdef HAVE_CONFIG_H
++#  include <config.h>
++#endif
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <fcntl.h>
++#include <dirent.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <arpa/inet.h>
++#include <net/if.h>
++#include <sys/stat.h>
++#include <ctype.h>
++
++#include <libvirt/virterror.h>
++
++#define IN_VSERVER 1
++#include "internal.h"
++#include "vserver_driver.h"
++#include "vserver_conf.h"
++#include "uuid.h"
++
++static int
++readStr(char *dst, size_t len, const char *name, const char *setting)
++{
++    char file[strlen(name) + strlen(setting) + 2];
++    int fd;
++    ssize_t bytes;
++    char *p;
++
++    sprintf(file, "%s/%s", name, setting);
++
++    /* a non-existant file is not a failure */
++    *dst = '\0';
++    if ((fd = open(file, O_RDONLY)) == -1)
++        return 1;
++
++    if ((bytes = read(fd, dst, len - 1)) == -1) {
++        close(fd);
++        return -1;
++    }
++    close(fd);
++
++    dst[bytes] = '\0';
++
++    if ((p = strchr(dst, '\n')) != NULL)
++        *p = '\0';
++
++    return 0;
++}
++
++static int
++readLong(void *v_dst, const char *name, const char *setting)
++{
++    char buf[128], *endptr;
++    int ret;
++    long *dst = v_dst;
++
++    ret = readStr(buf, sizeof(buf), name, setting);
++    if (ret)
++        return ret;
++
++    *dst = strtol(buf, &endptr, 0);
++    if (endptr && *endptr != '\0')
++        return -1;
++
++    return 0;
++}
++
++static int
++readInt(void *v_dst, const char *name, const char *setting)
++{
++    long val;
++    int *dst = v_dst;
++    int ret;
++
++    ret = readLong(&val, name, setting);
++    if (ret)
++        return ret;
++
++    *dst = (int) val;
++
++    return 0;
++}
++
++static int
++readBool(char *dst, const char *name, const char *setting)
++{
++    char file[strlen(name) + strlen(setting) + 2];
++
++    sprintf(file, "%s/%s", name, setting);
++
++    *dst = access(file, F_OK) != -1;
++
++    return 0;
++}
++
++int
++vserverWriteToConfig(struct vserver_guest *guest, const char *filename,
++                     const char *format, ...)
++{
++    char path[strlen(guest->path) + 1 + strlen(filename) + 1];
++    va_list va;
++    char value[1024];
++    int fd;
++    ssize_t len, off, ret;
++    char *dir;
++
++    sprintf(path, "%s/%s", guest->path, filename);
++
++    /* ensure the directory exists */
++    dir = strrchr(path, '/');
++    *dir = '\0';
++    if (mkdir(path, 0755) && errno != EEXIST)
++        return -1;
++    *dir = '/';
++
++    va_start(va, format);
++    if (strcmp(format, "%b") == 0) {
++        /* bool, this is a special case */
++        if (va_arg(va, int)) {
++            *value = '\0';
++            len = 0;
++        }
++        else {
++            if (unlink(path) == -1 && errno != ENOENT)
++                return -1;
++            else
++                return 0;
++        }
++    }
++    else
++        len = vsnprintf(value, sizeof(value), format, va);
++    va_end(va);
++
++    fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, 0644);
++    if (fd == -1)
++        return -1;
++
++    for (off = 0; off < len; off += ret) {
++        ret = write(fd, value + off, len - off);
++        if (ret == -1) {
++            close(fd);
++            return -1;
++        }
++    }
++
++    if (close(fd) == -1)
++        return -1;
++    return 0;
++}
++
++#define WRITE(...)  if (vserverWriteToConfig(guest, __VA_ARGS__) == -1)    \
++                        return -1
++#define WRITE_SCHED_VAL(sched, file, mask, format, value)           \
++    if ((sched)->set_mask & mask) {                                 \
++        WRITE(file, format, value);                                 \
++    }
++#define WRITE_SCHED(dir, sched)                                     \
++    do {                                                            \
++        WRITE_SCHED_VAL(sched, dir "/fill-rate",                    \
++                        VC_VXSM_FILL_RATE, "%u\n",                  \
++                        (sched)->fill_rate);                        \
++        WRITE_SCHED_VAL(sched, dir "/interval",                     \
++                        VC_VXSM_INTERVAL, "%u\n",                   \
++                        (sched)->interval);                         \
++        WRITE_SCHED_VAL(sched, dir "/fill-rate2",                   \
++                        VC_VXSM_FILL_RATE2, "%u\n",                 \
++                        (sched)->fill_rate2);                       \
++        WRITE_SCHED_VAL(sched, dir "/interval2",                    \
++                        VC_VXSM_INTERVAL2, "%u\n",                  \
++                        (sched)->interval2);                        \
++        WRITE_SCHED_VAL(sched, dir "/tokens-min",                   \
++                        VC_VXSM_TOKENS_MIN, "%u\n",                 \
++                        (sched)->tokens_min);                       \
++        WRITE_SCHED_VAL(sched, dir "/tokens-max",                   \
++                        VC_VXSM_TOKENS_MAX, "%u\n",                 \
++                        (sched)->tokens_max);                       \
++        WRITE_SCHED_VAL(sched, dir "/priority-bias",                \
++                        VC_VXSM_PRIO_BIAS, "%u\n",                  \
++                        (sched)->priority_bias);                    \
++        WRITE(dir "/idle-time", "%b",                               \
++              (sched)->set_mask & VC_VXSM_IDLE_TIME);               \
++    } while (0)
++#define WRITE_IP(filename, v4var, v6var)                            \
++            strcpy(file, filename);                                 \
++            switch (type) {                                         \
++            case VC_NXA_TYPE_IPV4:                                  \
++                inet_ntop(AF_INET, (v4var), buf, sizeof(buf));      \
++                break;                                              \
++            case VC_NXA_TYPE_IPV6:                                  \
++                inet_ntop(AF_INET6, (v6var), buf, sizeof(buf));     \
++                break;                                              \
++            }                                                       \
++            WRITE(dir, "%s\n", buf);
++
++static int
++writeInterfaces(struct vserver_guest *guest)
++{
++    char name[strlen(guest->path) + sizeof("/interfaces/XXXXXX/prefix")],
++         *dir, *file;
++    char buf[128];
++    struct vserver_ip *ip;
++    unsigned int i;
++
++    snprintf(name, sizeof(name), "%s/interfaces", guest->path);
++    if (vserverRunCommand(0, "rm", "-fr", name, NULL) != 0)
++        return -1;
++    if (mkdir(name, 0755) == -1)
++        return -1;
++
++    dir = name + strlen(guest->path) + 1;
++    for (ip = guest->ips, i = 0; ip; ip = ip->next, i++) {
++        uint16_t type;
++
++        /* Yeah right... */
++        if (i > 999999) {
++            errno = EOVERFLOW;
++            return -1;
++        }
++
++        file = dir;
++        file += snprintf(dir, sizeof(name) - (dir - name), "interfaces/%u", i);
++        if (mkdir(name, 0755) == -1)
++            return -1;
++
++        type = ip->addr.vna_type & (VC_NXA_TYPE_IPV4|VC_NXA_TYPE_IPV6);
++
++        strcpy(file, "/prefix");
++        WRITE(dir, "%u\n", ip->addr.vna_prefix);
++
++        if (*ip->interface) {
++            strcpy(file, "/dev");
++            WRITE(dir, "%s\n", ip->interface);
++        }
++        else {
++            strcpy(file, "/nodev");
++            WRITE(dir, "%b", 1);
++        }
++
++        WRITE_IP("/ip", &ip->addr.vna_v4_ip, &ip->addr.vna_v6_ip);
++        if (ip->addr.vna_type & VC_NXA_TYPE_RANGE) {
++            WRITE_IP("/ip2", &ip->addr.vna_v4_ip2, &ip->addr.vna_v6_ip2);
++        }
++        if (ip->addr.vna_type & (VC_NXA_TYPE_RANGE|VC_NXA_TYPE_MASK)) {
++            WRITE_IP("/mask", &ip->addr.vna_v4_mask, &ip->addr.vna_v6_mask);
++        }
++    }
++    return 0;
++}
++
++static int
++writeFstab(struct vserver_guest *guest)
++{
++    FILE *fp;
++    struct vserver_fstab *ent;
++    char file[strlen(guest->path) + sizeof("/fstab")];
++
++    sprintf(file, "%s/fstab", guest->path);
++    fp = fopen(file, "w");
++    if (fp == NULL)
++        return -1;
++
++    for (ent = guest->fstab; ent; ent = ent->next) {
++        if (!(ent->flags & VSERVER_FSTAB_OUTPUT))
++            continue;
++        fprintf(fp, "%s\t%s\t%s\t%s\t%s\n", ent->source, ent->target,
++                ent->fstype, ent->options, (ent->rest ? ent->rest : ""));
++    }
++
++    if (fclose(fp) == -1)
++        return -1;
++
++    return 0;
++}
++
++int
++vserverWriteGuestToConfig(struct vserver_guest *guest)
++{
++    char buf[128];
++
++    WRITE("context", "%u\n", guest->xid);
++    WRITE("name", "%s\n", guest->name);
++    virUUIDFormat(guest->uuid, buf);
++    WRITE("uuid", "%s\n", buf);
++    if (*guest->uts.hostname)
++        WRITE("uts/nodename", "%s\n", guest->uts.hostname);
++    if (*guest->uts.machine)
++        WRITE("uts/machine", "%s\n", guest->uts.machine);
++    if (*guest->uts.release)
++        WRITE("uts/release", "%s\n", guest->uts.release);
++    if (*guest->uts.version)
++        WRITE("uts/version", "%s\n", guest->uts.version);
++    if (guest->rss_hard > 0)
++        WRITE("rlimits/rss.hard", "%lu\n", guest->rss_hard);
++    WRITE("apps/init/mark", (guest->autostart ? "default\n" : "\n"));
++    WRITE_SCHED("sched", &guest->sched);
++
++    if (writeInterfaces(guest) == -1)
++        return -1;
++
++    if (writeFstab(guest) == -1)
++        return -1;
++
++    return 0;
++}
++#undef WRITE_IP
++#undef WRITE_SCHED
++#undef WRITE_SCHED_VAL
++#undef WRITE
++
++static int
++parseInterfaces(struct vserver_guest *guest, const char *directory)
++{
++    DIR *interfaces;
++    struct dirent *interface;
++    struct vserver_ip *ip = NULL;
++    char ipath[256], *subdir;
++    size_t spare;
++    char s_ip[48], s_prefix[4], s_mask[48], s_dev[32], s_ip2[48];
++
++    subdir = ipath;
++    subdir += snprintf(ipath, sizeof(ipath), "%s/%s", guest->name, directory);
++    spare = sizeof(ipath) - (subdir - ipath);
++
++    interfaces = opendir(ipath);
++    if (!interfaces)
++        return 0;
++
++    while ((interface = readdir(interfaces)) != NULL) {
++        if (*interface->d_name == '.')
++            continue;
++        /* would overflow */
++        if (strlen(interface->d_name) + sizeof("//disabled") > spare)
++            continue;
++
++        snprintf(subdir, spare, "/%s/disabled", interface->d_name);
++        if (access(ipath, F_OK) != -1)
++            continue;
++
++        snprintf(subdir, spare, "/%s", interface->d_name);
++        *s_mask = '\0';
++        *s_prefix = '\0';
++        if (readStr(s_ip, sizeof(s_ip), ipath, "ip") == 0 &&
++            (readStr(s_prefix, sizeof(s_prefix), ipath, "prefix") == 0 ||
++             readStr(s_mask, sizeof(s_mask), ipath, "mask") == 0)) {
++            if (readStr(s_dev, sizeof(s_dev), ipath, "dev") != 0)
++                *s_dev = '\0';
++            if (readStr(s_ip2, sizeof(s_ip2), ipath, "ip2") != 0)
++                *s_ip2 = '\0';
++        }
++        else
++            continue;
++
++        if (!ip)
++            guest->ips = ip = calloc(1, sizeof(*ip));
++        else {
++            ip->next = calloc(1, sizeof(*ip));
++            ip = ip->next;
++        }
++        if (!ip)
++            goto cleanup;
++
++        strcpy(ip->interface, s_dev);
++
++        if (inet_pton(AF_INET6, s_ip, &ip->addr.vna_v6_ip) > 0)
++            ip->addr.vna_type = VC_NXA_TYPE_IPV6;
++        else if (inet_pton(AF_INET, s_ip, &ip->addr.vna_v4_ip) > 0)
++            ip->addr.vna_type = VC_NXA_TYPE_IPV4;
++        else
++            goto cleanup;
++
++        if (ip->addr.vna_type == VC_NXA_TYPE_IPV6) {
++            if (*s_mask) {
++                if (inet_pton(AF_INET6, s_mask, &ip->addr.vna_v6_mask) <= 0)
++                    goto cleanup;
++            }
++            if (*s_ip2) {
++                if (inet_pton(AF_INET6, s_ip2, &ip->addr.vna_v6_ip2) <= 0)
++                    goto cleanup;
++                ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
++            }
++            else
++                ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
++        }
++        else if (ip->addr.vna_type == VC_NXA_TYPE_IPV4) {
++            if (*s_mask) {
++                if (inet_pton(AF_INET, s_mask, &ip->addr.vna_v4_mask) <= 0)
++                    goto cleanup;
++            }
++            if (*s_ip2) {
++                if (inet_pton(AF_INET, s_ip2, &ip->addr.vna_v4_ip2) <= 0)
++                    goto cleanup;
++                ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
++            }
++            else
++                ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
++        }
++
++        if (*s_prefix) {
++            char *endptr;
++            ip->addr.vna_prefix = strtoul(s_prefix, &endptr, 0);
++            if (*endptr != '\n' && *endptr)
++                goto cleanup;
++        }
++    }
++
++    closedir(interfaces);
++    return 0;
++
++cleanup:
++    closedir(interfaces);
++    return -1;
++}
++
++static inline char *
++endOfField(char *start)
++{
++    char *end;
++    for (end = start; *(end - 1) != '\\' &&
++                      !isspace(*end) &&
++                      *end != '\0'; end++)
++        ;
++    return end;
++}
++
++static inline char *
++startOfField(char *end)
++{
++    char *start;
++    for (start = end + 1; isspace(*start) &&
++                          *start != '\0'; start++)
++        ;
++    return start;
++}
++
++static const struct {
++    int mode;
++    const char *type;
++} source_types[] = {
++    { S_IFBLK, "block" },
++    { S_IFREG, "file" },
++    { S_IFDIR, "directory" },
++};
++
++const char *
++vserverFindSourceType(const char *source)
++{
++    struct stat st;
++    int mode, i;
++    if (stat(source, &st) == -1)
++        mode = -1;
++    else
++        mode = st.st_mode & S_IFMT;
++    for (i = 0; i < (sizeof(source_types) / sizeof(*source_types)); i++) {
++        if (mode == source_types[i].mode)
++            return source_types[i].type;
++    }
++    return NULL;
++}
++
++static int
++parseFstab(struct vserver_guest *guest, const char *filename)
++{
++    FILE *fp;
++    char buf[256], *start, *end;
++    struct vserver_fstab *ent = NULL;
++    char path[strlen(guest->name) + 2 + strlen(filename)];
++
++    sprintf(path, "%s/%s", guest->name, filename);
++    if ((fp = fopen(path, "r")) == NULL)
++        return 0;
++
++    while (fgets(buf, sizeof(buf), fp) != NULL) {
++        if (!ent)
++            guest->fstab = ent = calloc(1, sizeof(*ent));
++        else {
++            ent->next = calloc(1, sizeof(*ent));
++            ent = ent->next;
++        }
++        if (!ent)
++            goto err;
++
++        start = buf;
++        end = endOfField(start);
++        *end = '\0';
++        ent->source = strdup(start);
++        ent->source_type = vserverFindSourceType(start);
++
++        ent->flags |= VSERVER_FSTAB_OUTPUT;
++        if (ent->source_type)
++            ent->flags |= VSERVER_FSTAB_SHOW;
++
++        start = startOfField(end);
++        end = endOfField(start);
++        *end = '\0';
++        ent->target = strdup(start);
++
++        start = startOfField(end);
++        end = endOfField(start);
++        *end = '\0';
++        ent->fstype = strdup(start);
++
++        start = startOfField(end);
++        end = endOfField(start);
++        if (*end != '\0') {
++            char *ptr;
++            ent->rest = strdup(end + 1);
++            ptr = strchr(ent->rest, '\n');
++            if (ptr)
++                *ptr = '\0';
++        }
++        else
++            ent->rest = NULL;
++        *end = '\0';
++        ent->options = strdup(start);
++
++        if (!ent->source || !ent->target || !ent->fstype || !ent->options)
++            goto err;
++    }
++
++    fclose(fp);
++    return 0;
++
++err:
++    fclose(fp);
++    return -1;
++}
++
++virDrvOpenStatus
++vserverInitializeDriver(virConnectPtr conn, struct vserver_driver *driver,
++                        const char *path)
++{
++    struct vserver_guest *guest = NULL;
++    DIR *dp = NULL;
++    struct dirent *de;
++    int cwd;
++    const char *conf_dir = (*path ? path : VSERVER_CONF_DIR);
++
++    if (driver->initialized == 1)
++        return VIR_DRV_OPEN_SUCCESS;
++
++    driver->guests = NULL;
++    driver->inactive_guests = driver->active_guests = 0;
++
++    cwd = open(".", O_RDONLY);
++    if (cwd == -1 ||
++        chdir(conf_dir) == -1 ||
++        (dp = opendir(".")) == NULL) {
++        vserverError(conn, NULL, NULL, VIR_ERR_OPEN_FAILED, conf_dir);
++        goto error;
++    }
++
++    while ((de = readdir(dp)) != NULL) {
++        char uuidstr[VIR_UUID_STRING_BUFLEN + 1];
++        char mark[32];
++        char tmp;
++
++        if (*de->d_name == '.')
++            continue;
++
++        if (driver->guests == NULL)
++            driver->guests = guest = calloc(1, sizeof(struct vserver_guest));
++        else {
++            guest->next = calloc(1, sizeof(struct vserver_guest));
++            guest = guest->next;
++        }
++
++        if (!guest) {
++            vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
++                         "vserver_guest");
++            goto error;
++        }
++
++        guest->path = calloc(strlen(conf_dir) + 1 + strlen(de->d_name) + 1, sizeof(char));
++        if (!guest->path)
++            goto nomem;
++        sprintf(guest->path, "%s/%s", conf_dir, de->d_name);
++
++#define CHECK(x)                                                            \
++    if ((x) == -1) {                                                        \
++        goto parseerror;                                                    \
++    }
++#define DO_SCHED(type, var, file, bit)                                      \
++    do {                                                                    \
++        int ret;                                                            \
++        CHECK(ret = read ## type((var), de->d_name, (file)));               \
++        if (ret == 0)                                                       \
++            guest->sched.set_mask |= (bit);                                 \
++    } while (0)
++
++        /* Parse simple values */
++        CHECK(readInt(&guest->xid, de->d_name, "context"));
++        CHECK(readStr(guest->name, sizeof(guest->name), de->d_name, "name"));
++        CHECK(readStr(guest->uts.hostname, sizeof(guest->uts.hostname), de->d_name,
++                      "uts/nodename"));
++        CHECK(readStr(guest->uts.machine, sizeof(guest->uts.machine), de->d_name,
++                      "uts/machine"));
++        CHECK(readStr(guest->uts.release, sizeof(guest->uts.release), de->d_name,
++                      "uts/release"));
++        CHECK(readStr(guest->uts.version, sizeof(guest->uts.version), de->d_name,
++                      "uts/version"));
++        CHECK(readStr(mark, sizeof(mark), de->d_name, "apps/init/mark"));
++
++        DO_SCHED(Int, &guest->sched.fill_rate,     "sched/fill-rate",
++                 VC_VXSM_FILL_RATE);
++        DO_SCHED(Int, &guest->sched.interval,      "sched/interval",
++                 VC_VXSM_INTERVAL);
++        DO_SCHED(Int, &guest->sched.fill_rate2,    "sched/fill-rate2",
++                 VC_VXSM_FILL_RATE2);
++        DO_SCHED(Int, &guest->sched.interval2,     "sched/interval2",
++                 VC_VXSM_INTERVAL2);
++        DO_SCHED(Int, &guest->sched.tokens_min,    "sched/tokens-min",
++                 VC_VXSM_TOKENS_MIN);
++        DO_SCHED(Int, &guest->sched.tokens_max,    "sched/tokens-max",
++                 VC_VXSM_TOKENS_MAX);
++        DO_SCHED(Int, &guest->sched.priority_bias, "sched/priority-bias",
++                 VC_VXSM_PRIO_BIAS);
++        if (readBool(&tmp, de->d_name, "sched/idle-time") == 0) {
++            if (tmp)
++                guest->sched.set_mask |= VC_VXSM_IDLE_TIME;
++        }
++
++        CHECK(readLong(&guest->rss_hard, de->d_name, "rlimits/rss.hard"));
++
++        /* Generate a UUID if one doesn't already exist */
++        switch (readStr(uuidstr, sizeof(uuidstr), de->d_name, "uuid")) {
++        case 1:
++            CHECK(virUUIDGenerate(guest->uuid));
++            virUUIDFormat(guest->uuid, uuidstr);
++            CHECK(vserverWriteToConfig(guest, "uuid", "%s\n", uuidstr));
++            break;
++        case 0:
++            CHECK(virUUIDParse(uuidstr, guest->uuid));
++            break;
++        case -1:
++            goto parseerror;
++        }
++
++        /* Parse interfaces */
++        if (parseInterfaces(guest, "interfaces") == -1)
++            goto parseerror;
++
++        /* Parse fstab */
++        if (parseFstab(guest, "fstab") == -1)
++            goto parseerror;
++
++        /* Make sure the guest has the / directory in the disk output */
++        do {
++            struct vserver_fstab *ent;
++            int has_root = 0;
++            for (ent = guest->fstab; ent; ent = ent->next) {
++                if (strcmp(ent->target, "/") == 0) {
++                    has_root = 1;
++                    break;
++                }
++            }
++            if (!has_root) {
++                char vdir[strlen(de->d_name) + sizeof("/vdir")];
++
++                ent = calloc(1, sizeof(*ent));
++                if (!ent)
++                    goto nomem;
++
++                sprintf(vdir, "%s/vdir", de->d_name);
++                ent->source = realpath(vdir, NULL);
++
++                ent->flags = VSERVER_FSTAB_SHOW;
++                ent->source_type = vserverFindSourceType("/");
++                ent->target = strdup("/");
++                ent->fstype = strdup("auto");
++                ent->options = strdup("defaults");
++                if (!ent->source || !ent->target || !ent->fstype || !ent->options)
++                    goto nomem;
++                ent->next = guest->fstab;
++                guest->fstab = ent;
++            }
++        } while (0);
++#undef DO_SCHED
++#undef CHECK
++
++        if (STREQ(mark, "default"))
++            guest->autostart = 1;
++        if (vserverContextIsRunning(guest->path)) {
++            struct vc_ctx_flags flags;
++            if (vc_get_cflags(guest->xid, &flags) == 0 &&
++                (flags.flagword & VC_VXF_SCHED_PAUSE))
++                guest->status = VIR_DOMAIN_PAUSED;
++            else
++                guest->status = VIR_DOMAIN_RUNNING;
++            driver->active_guests++;
++        }
++        else {
++            guest->status = VIR_DOMAIN_SHUTOFF;
++            driver->inactive_guests++;
++        }
++    }
++
++    closedir(dp);
++    if (fchdir(cwd) == -1 || close(cwd) == -1) {
++        /* do nothing, we succeeded with everything else... */
++    }
++    driver->initialized = 1;
++
++    return VIR_DRV_OPEN_SUCCESS;
++
++nomem:
++    vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
++    goto error;
++parseerror:
++    vserverError(conn, NULL, NULL, VIR_ERR_PARSE_FAILED, de->d_name);
++error:
++    if (dp)
++        closedir(dp);
++
++    if (fchdir(cwd) == -1 || close(cwd) == -1) {
++        /* we're already failing, nothing to do */
++    }
++    return VIR_DRV_OPEN_ERROR;
++}
++
++#endif
+--- libvirt-0.4.0.orig/src/vserver/vserver_conf.h      1970-01-01 01:00:00.000000000 +0100
++++ libvirt-0.4.0.vserver/src/vserver/vserver_conf.h   2008-01-05 02:10:20.000000000 +0100
+@@ -0,0 +1,36 @@
++/*
++ * Configuration handling for Linux-VServer guests
++ *
++ * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
++ *
++ * 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
++ *
++ * Author: Daniel Hokka Zakrisson <daniel hozac com>
++ */
++
++#ifdef WITH_VSERVER
++
++/* Kind of a hack */
++#ifdef IN_VSERVER
++int vserverWriteToConfig(struct vserver_guest *guest, const char *filename,
++                         const char *format, ...);
++int vserverWriteGuestToConfig(struct vserver_guest *guest);
++virDrvOpenStatus vserverInitializeDriver(virConnectPtr conn,
++                                         struct vserver_driver *driver,
++                                         const char *path);
++const char *vserverFindSourceType(const char *source);
++#endif
++
++#endif
+diff -Nurp libvirt-0.4.0.orig/src/vserver_driver.c libvirt-0.4.0.vserver/src/vserver_driver.c
+--- libvirt-0.4.0.orig/src/vserver_driver.c    1970-01-01 01:00:00.000000000 +0100
++++ libvirt-0.4.0.vserver/src/vserver_driver.c 2008-01-09 22:43:23.000000000 +0100
+@@ -0,0 +1,1625 @@
++/*
++ * Core driver for managing Linux-VServer guests
++ *
++ * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
++ *
++ * 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
++ *
++ * Author: Daniel Hokka Zakrisson <daniel hozac com>
++ */
++
++#ifdef WITH_VSERVER
++
++#define _GNU_SOURCE
++
++#ifdef HAVE_CONFIG_H
++#  include <config.h>
++#endif
++
++#include <stdio.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <string.h>
++#include <fcntl.h>
++#include <dirent.h>
++#include <sys/wait.h>
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <arpa/inet.h>
++#include <net/if.h>
++#include <sys/syscall.h>
++
++#include <libxml/uri.h>
++#include <libxml/xpath.h>
++#include <libxml/tree.h>
++
++#include <libvirt/virterror.h>
++
++#define IN_VSERVER 1
++#include "internal.h"
++#include "vserver_driver.h"
++#include "vserver_conf.h"
++#include "buf.h"
++#include "uuid.h"
++#include "xml.h"
++#include "nodeinfo.h"
++
++#define GET_DOMAIN(dom, ret)                                            \
++    struct vserver_driver *driver = (struct vserver_driver *)           \
++                                    (dom)->conn->privateData;           \
++    struct vserver_guest *guest = getGuestByUUID(driver, (dom)->uuid);  \
++                                                                        \
++    if (!guest) {                                                       \
++        vserverError((dom)->conn, (dom), NULL, VIR_ERR_INVALID_ARG,     \
++                     __FUNCTION__);                                     \
++        return (ret);                                                   \
++    }
++
++#ifndef MNT_DETACH
++#  define MNT_DETACH    0x00000002
++#endif
++
++static int PAGE_SHIFT_TO_KIBI = 2;
++
++static inline int sys_umount(const char *path, int flags)
++{
++    return syscall(__NR_umount2, path, flags);
++}
++
++static inline struct vserver_guest *
++getGuestByID(struct vserver_driver *driver,
++             int id)
++{
++    struct vserver_guest *res;
++    for (res = driver->guests; res; res = res->next) {
++        if (res->xid == id)
++            break;
++    }
++    return res;
++}
++
++static inline struct vserver_guest *
++getGuestByUUID(struct vserver_driver *driver,
++               const unsigned char *uuid)
++{
++    struct vserver_guest *res;
++    for (res = driver->guests; res; res = res->next) {
++        if (memcmp(res->uuid, uuid, VIR_UUID_BUFLEN) == 0)
++            break;
++    }
++    return res;
++}
++
++static inline struct vserver_guest *
++getGuestByName(struct vserver_driver *driver,
++               const char *name)
++{
++    struct vserver_guest *res;
++    for (res = driver->guests; res; res = res->next) {
++        if (STREQ(res->name, name))
++            break;
++    }
++    return res;
++}
++
++void
++vserverError(virConnectPtr con,
++             virDomainPtr dom,
++             virNetworkPtr net,
++             virErrorNumber error,
++             const char *info)
++{
++    const char *errmsg;
++
++    if (error == VIR_ERR_OK)
++        return;
++
++    errmsg = __virErrorMsg(error, info);
++    __virRaiseError(con, dom, net, VIR_FROM_VSERVER, error, VIR_ERR_ERROR,
++                    errmsg, info, NULL, 0, 0, errmsg, info, 0);
++}
++
++/* like execl, but uses /dev/null and handles forking/waiting/etc. */
++int
++vserverRunCommand(int do_daemon, const char *cmd, ...)
++{
++    pid_t pid;
++    va_list va;
++    char **argv;
++    int i, argc;
++    sighandler_t sigchld;
++    int ret;
++
++    va_start(va, cmd);
++    argc = 15;
++    argv = calloc(argc, sizeof(*argv));
++    argv[0] = (char *) cmd;
++    for (i = 1; (argv[i] = va_arg(va, char *)) != NULL; i++) {
++        if (i == argc-1) {
++            argc += 5;
++            argv = realloc(argv, sizeof(*argv) * argc);
++        }
++    }
++
++    va_end(va);
++
++    /* XXX: This is bad, since another child could die
++     *      between here and where we restore it */
++    sigchld = signal(SIGCHLD, SIG_DFL);
++    if ((pid = fork()) == 0) {
++        int fd;
++        if (do_daemon) {
++            pid_t not_a_zombie;
++
++            if (setsid() == -1)
++                goto error;
++
++            not_a_zombie = fork();
++            if (not_a_zombie == -1)
++                goto error;
++            else if (not_a_zombie > 0)
++                _exit(0);
++        }
++        if ((fd = open("/dev/null", O_RDWR)) == -1)
++            goto error;
++        if (dup2(fd, 0) == -1 || dup2(fd, 1) == -1 || dup2(fd, 2) == -1)
++            goto error;
++        if (fd > 2 && close(fd) == -1)
++            goto error;
++        execvp(cmd, argv);
++    error:
++        _exit(1);
++    }
++    else if (pid == -1) {
++        ret =  -1;
++    }
++    else {
++        int status;
++        if (waitpid(pid, &status, 0) == -1)
++            ret = -1;
++        else if (WEXITSTATUS(status) != 0)
++            ret = 1;
++        else
++            ret = 0;
++    }
++
++    signal(SIGCHLD, sigchld);
++    return ret;
++}
++
++int
++vserverContextIsRunning(const char *path)
++{
++    return vc_getVserverCtx(path, vcCFG_AUTO, false, 0, vcCTX_XID) != VC_NOCTX;
++}
++
++static void
++vserverSetPagesize(void)
++{
++    long page_size = sysconf(_SC_PAGESIZE);
++    PAGE_SHIFT_TO_KIBI = page_size / 1024;
++}
++
++static virDrvOpenStatus
++vserverOpen(virConnectPtr conn, xmlURIPtr uri,
++            virConnectAuthPtr auth ATTRIBUTE_UNUSED,
++            int flags ATTRIBUTE_UNUSED)
++{
++    virDrvOpenStatus ret;
++    struct vserver_driver *driver;
++
++    if (!uri)
++        return VIR_DRV_OPEN_DECLINED;
++
++    if (getuid() != 0)
++        return VIR_DRV_OPEN_DECLINED;
++
++    if (!uri->scheme || STRNEQ(uri->scheme, "vserver"))
++        return VIR_DRV_OPEN_DECLINED;
++
++    if (uri->server)
++        return VIR_DRV_OPEN_DECLINED;
++
++    /* nothing else supported right now */
++    if (strncmp(uri->path, "/system", 7) != 0)
++        return VIR_DRV_OPEN_DECLINED;
++
++    /* make sure it's a Linux-VServer kernel */
++    if (vc_get_version() == -1)
++        return VIR_DRV_OPEN_DECLINED;
++
++    if (!conn->privateData)
++        conn->privateData = calloc(1, sizeof(struct vserver_driver));
++
++    ret = vserverInitializeDriver(conn, conn->privateData, uri->path + 7);
++    if (ret == VIR_DRV_OPEN_SUCCESS) {
++        driver = conn->privateData;
++        driver->uri = xmlSaveUri(uri);
++    }
++    else {
++        free(conn->privateData);
++    }
++
++    vserverSetPagesize();
++
++    return ret;
++}
++
++static void
++freeFstab(struct vserver_fstab *ent)
++{
++    free(ent->source);
++    free(ent->target);
++    free(ent->fstype);
++    free(ent->options);
++    free(ent);
++}
++
++static void
++freeGuest(struct vserver_guest *guest)
++{
++    struct vserver_ip *ip, *pip = NULL;
++    struct vserver_fstab *ent, *pent = NULL;
++    for (ip = guest->ips; ip; ip = ip->next) {
++        if (pip)
++            free(pip);
++        pip = ip;
++    }
++    if (pip)
++        free(pip);
++    for (ent = guest->fstab; ent; ent = ent->next) {
++        if (pent)
++            freeFstab(pent);
++        pent = ent;
++    }
++    if (pent)
++        freeFstab(pent);
++    free(guest->path);
++    free(guest);
++}
++
++static int
++vserverClose(virConnectPtr conn)
++{
++    struct vserver_driver *driver = conn->privateData;
++    struct vserver_guest *guest, *pguest;
++
++    if (!driver || !driver->initialized)
++        return 0;
++
++    for (guest = driver->guests, pguest = NULL; guest; guest = guest->next) {
++        if (pguest)
++            freeGuest(pguest);
++        pguest = guest;
++    }
++    if (pguest)
++        freeGuest(pguest);
++
++    xmlFree(driver->uri);
++    free(driver);
++    conn->privateData = NULL;
++
++    return 0;
++}
++
++static const char *
++vserverGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
++{
++    return "Linux-VServer";
++}
++
++static int
++vserverGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
++{
++    *version = 1;
++    return 0;
++}
++
++static char *
++vserverGetHostname(virConnectPtr conn)
++{
++    char *ret;
++
++    ret = calloc(VSERVER_UTS_MAX + 1, sizeof(char));
++    if (!ret) {
++        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "gethostname");
++        return NULL;
++    }
++
++    if (gethostname(ret, VSERVER_UTS_MAX) == -1) {
++        free(ret);
++        vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, strerror(errno));
++        return NULL;
++    }
++
++    return ret;
++}
++
++static char *
++vserverGetURI(virConnectPtr conn)
++{
++    struct vserver_driver *driver = conn->privateData;
++    return (char *) xmlStrdup(driver->uri);
++}
++
++static int
++vserverNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
++{
++    return virNodeInfoPopulate(conn, nodeinfo);
++}
++
++static int
++vserverListDomains(virConnectPtr conn, int *ids, int nids)
++{
++    struct vserver_driver *driver = conn->privateData;
++    struct vserver_guest *guest;
++    int i;
++
++    for (guest = driver->guests, i = 0; guest && i < nids;
++         guest = guest->next) {
++        if (guest->status != VIR_DOMAIN_SHUTOFF)
++            ids[i++] = guest->xid;
++    }
++
++    return i;
++}
++
++static int
++vserverNumOfDomains(virConnectPtr conn)
++{
++    struct vserver_driver *driver = conn->privateData;
++
++    return driver->active_guests;
++}
++
++static virDomainPtr
++vserverDomainLookupByID(virConnectPtr conn, int id)
++{
++    struct vserver_driver *driver = conn->privateData;
++    struct vserver_guest *guest;
++    virDomainPtr domain;
++
++    if ((guest = getGuestByID(driver, id)) == NULL) {
++        vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
++                     _("No domain by that ID found"));
++        return NULL;
++    }
++
++    domain = virGetDomain(conn, guest->name, guest->uuid);
++    if (!domain) {
++        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
++        return NULL;
++    }
++
++    if (vserverIsRunning(guest))
++        domain->id = guest->xid;
++
++    return domain;
++}
++
++static virDomainPtr
++vserverDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
++{
++    struct vserver_driver *driver = conn->privateData;
++    struct vserver_guest *guest;
++    virDomainPtr domain;
++
++    if ((guest = getGuestByUUID(driver, uuid)) == NULL) {
++        vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
++                     _("No domain by that UUID found"));
++        return NULL;
++    }
++
++    domain = virGetDomain(conn, guest->name, guest->uuid);
++    if (!domain) {
++        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
++        return NULL;
++    }
++
++    if (vserverIsRunning(guest))
++        domain->id = guest->xid;
++
++    return domain;
++}
++
++static virDomainPtr
++vserverDomainLookupByName(virConnectPtr conn, const char *name)
++{
++    struct vserver_driver *driver = conn->privateData;
++    struct vserver_guest *guest;
++    virDomainPtr domain;
++
++    if ((guest = getGuestByName(driver, name)) == NULL) {
++        vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
++                     _("No domain by that name found"));
++        return NULL;
++    }
++
++    domain = virGetDomain(conn, guest->name, guest->uuid);
++    if (!domain) {
++        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
++        return NULL;
++    }
++
++    if (vserverIsRunning(guest))
++        domain->id = guest->xid;
++
++    return domain;
++}
++
++static int
++vserverDomainSuspend(virDomainPtr domain)
++{
++    struct vc_ctx_flags flags = {
++        .flagword = VC_VXF_SCHED_PAUSE,
++        .mask = VC_VXF_SCHED_PAUSE,
++    };
++    GET_DOMAIN(domain, -1);
++
++    if (guest->status == VIR_DOMAIN_PAUSED)
++        return 0;
++    if (guest->status != VIR_DOMAIN_RUNNING) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_OPERATION_FAILED,
++                     _("domain is not running"));
++        return -1;
++    }
++
++    if (vc_set_cflags(guest->xid, &flags) == -1) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                     strerror(errno));
++        return -1;
++    }
++    guest->status = VIR_DOMAIN_PAUSED;
++
++    return 0;
++}
++
++static int
++vserverDomainResume(virDomainPtr domain)
++{
++    struct vc_ctx_flags flags = {
++        .flagword = 0,
++        .mask = VC_VXF_SCHED_PAUSE,
++    };
++    GET_DOMAIN(domain, -1);
++
++    if (guest->status == VIR_DOMAIN_RUNNING)
++        return 0;
++    if (guest->status != VIR_DOMAIN_PAUSED) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_OPERATION_FAILED,
++                     _("domain is not running"));
++        return -1;
++    }
++
++    if (vc_set_cflags(guest->xid, &flags) == -1) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                     strerror(errno));
++        return -1;
++    }
++    guest->status = VIR_DOMAIN_RUNNING;
++
++    return 0;
++}
++
++static int
++vserverDomainShutdown(virDomainPtr domain)
++{
++    GET_DOMAIN(domain, -1);
++
++    if (vserverRunCommand(1, PROG_VSERVER, guest->path, "stop", NULL) != 0) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                     "vserver stop");
++        return -1;
++    }
++
++    driver->active_guests--;
++    guest->status = VIR_DOMAIN_SHUTOFF;
++    driver->inactive_guests++;
++    return 0;
++}
++
++static int
++vserverDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
++{
++    GET_DOMAIN(domain, -1);
++
++    if (vserverRunCommand(1, PROG_VSERVER, guest->path, "restart", NULL) != 0) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                     "vserver restart");
++        return -1;
++    }
++
++    guest->status = VIR_DOMAIN_RUNNING;
++    return 0;
++}
++
++static int
++vserverDomainDestroy(virDomainPtr domain)
++{
++    GET_DOMAIN(domain, -1);
++
++    if (vserverDomainShutdown(domain) == -1)
++        return -1;
++
++    virFreeDomain(domain->conn, domain);
++
++    return 0;
++}
++
++static char *
++vserverDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
++{
++    return strdup("Linux");
++}
++
++static unsigned long
++vserverDomainGetMaxMemory(virDomainPtr domain)
++{
++    GET_DOMAIN(domain, (unsigned long) -1);
++
++    return guest->rss_hard << PAGE_SHIFT_TO_KIBI;
++}
++
++static int
++vserverDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
++{
++    struct vc_rlimit limit = {
++        .min = 0,
++    };
++    GET_DOMAIN(domain, -1);
++
++    guest->rss_hard = memory >> PAGE_SHIFT_TO_KIBI;
++    limit.soft = limit.hard = guest->rss_hard;
++    if (vserverIsRunning(guest) &&
++        vc_set_rlimit(guest->xid, RLIMIT_RSS, &limit) == -1) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR, strerror(errno));
++        return -1;
++    }
++
++    if (vserverWriteToConfig(guest, "rlimits/rss.hard", "%lu\n", guest->rss_hard) == -1) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                     strerror(errno));
++        return -1;
++    }
++
++    return 0;
++}
++
++static int
++vserverDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
++{
++    struct vc_sched_info sinfo = { .user_msec = 0, .sys_msec = 0 };
++    struct vc_rlimit_stat rss_stat = { .value = 0 };
++    GET_DOMAIN(domain, -1);
++
++    if (vserverIsRunning(guest)) {
++        if (vc_sched_info(guest->xid, &sinfo) == -1) {
++            vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                         strerror(errno));
++            return -1;
++        }
++        if (vc_rlimit_stat(guest->xid, RLIMIT_RSS, &rss_stat) == -1) {
++            vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                         strerror(errno));
++            return -1;
++        }
++    }
++
++    info->state = guest->status;
++    info->maxMem = guest->rss_hard << PAGE_SHIFT_TO_KIBI;
++    info->nrVirtCpu = -1;
++    info->memory = rss_stat.value;
++    info->cpuTime = (sinfo.user_msec + sinfo.sys_msec) * 1000000ULL;
++
++    return 0;
++}
++
++static char *
++vserverDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
++{
++    virBufferPtr buf;
++    char uuid[VIR_UUID_STRING_BUFLEN + 1];
++    struct vserver_ip *ip;
++    GET_DOMAIN(domain, NULL);
++
++    buf = virBufferNew(4096);
++    if (!buf)
++        goto no_memory;
++
++    virUUIDFormat(guest->uuid, uuid);
++    if (virBufferVSprintf(buf,
++"<domain type='vserver' id='%d'>\n"
++"  <name>%s</name>\n"
++"  <uuid>%s</uuid>\n"
++                             , guest->xid, guest->name, uuid
++                             ) < 0)
++        goto no_memory;
++    if (guest->rss_hard > 0)
++        if (virBufferVSprintf(buf, "  <memory>%lu</memory>\n",
++                              guest->rss_hard << PAGE_SHIFT_TO_KIBI) < 0)
++            goto no_memory;
++
++    if (virBufferVSprintf(buf, "  <os>\n"
++                               "    <hostname>%s</hostname>\n"
++                               , guest->uts.hostname) < 0)
++        goto no_memory;
++    if (virBufferVSprintf(buf, "    <type") < 0)
++        goto no_memory;
++    if (*guest->uts.machine)
++        if (virBufferVSprintf(buf, " arch='%s'", guest->uts.machine) < 0)
++            goto no_memory;
++    if (virBufferVSprintf(buf, ">vserver</type>\n") < 0)
++        goto no_memory;
++    if (*guest->uts.release)
++        if (virBufferVSprintf(buf, "    <release>%s</release>\n",
++                              guest->uts.release) < 0)
++            goto no_memory;
++    if (*guest->uts.version)
++        if (virBufferVSprintf(buf, "    <version>%s</version>\n",
++                              guest->uts.version) < 0)
++            goto no_memory;
++    if (virBufferVSprintf(buf, "  </os>\n"
++                               "  <devices>\n") < 0)
++        goto no_memory;
++
++    for (ip = guest->ips; ip; ip = ip->next) {
++        char addrbuf[128];
++        if (virBufferVSprintf(buf, "    <interface type='ethernet'>\n"
++                                   "      <ip prefix='%d'", ip->addr.vna_prefix) < 0)
++            goto no_memory;
++        if (*ip->interface)
++            if (virBufferVSprintf(buf, " interface='%s'", ip->interface) < 0)
++                goto no_memory;
++
++        switch (ip->addr.vna_type & (VC_NXA_TYPE_IPV4|VC_NXA_TYPE_IPV6)) {
++            case VC_NXA_TYPE_IPV4:
++                inet_ntop(AF_INET, &ip->addr.vna_v4_ip, addrbuf, sizeof(addrbuf));
++                if (virBufferVSprintf(buf, " address='%s'", addrbuf) < 0)
++                    goto no_memory;
++                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_RANGE)) {
++                    inet_ntop(AF_INET, &ip->addr.vna_v4_ip2, addrbuf, sizeof(addrbuf));
++                    if (virBufferVSprintf(buf, " address2='%s' type='range'", addrbuf) < 0)
++                        goto no_memory;
++                }
++                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_MASK)) {
++                    if (virBufferVSprintf(buf, " type='mask'") < 0)
++                        goto no_memory;
++                }
++                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_RANGE) ||
++                    ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_MASK)) {
++                    inet_ntop(AF_INET, &ip->addr.vna_v4_mask, addrbuf, sizeof(addrbuf));
++                    if (virBufferVSprintf(buf, " mask='%s'", addrbuf) < 0)
++                        goto no_memory;
++                }
++                break;
++
++            case VC_NXA_TYPE_IPV6:
++                inet_ntop(AF_INET6, &ip->addr.vna_v6_ip, addrbuf, sizeof(addrbuf));
++                if (virBufferVSprintf(buf, " address='%s'", addrbuf) < 0)
++                    goto no_memory;
++                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_RANGE)) {
++                    inet_ntop(AF_INET6, &ip->addr.vna_v6_ip2, addrbuf, sizeof(addrbuf));
++                    if (virBufferVSprintf(buf, " address2='%s' type='range'", addrbuf) < 0)
++                        goto no_memory;
++                }
++                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_MASK)) {
++                    if (virBufferVSprintf(buf, " type='mask'") < 0)
++                        goto no_memory;
++                }
++                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_RANGE) ||
++                    ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_MASK)) {
++                    inet_ntop(AF_INET6, &ip->addr.vna_v6_mask, addrbuf, sizeof(addrbuf));
++                    if (virBufferVSprintf(buf, " mask='%s'", addrbuf) < 0)
++                        goto no_memory;
++                }
++                break;
++        }
++
++        if (virBufferVSprintf(buf, " />\n"
++                                   "    </interface>\n") < 0)
++            goto no_memory;
++    }
++
++    if (guest->fstab) {
++        struct vserver_fstab *ent;
++        for (ent = guest->fstab; ent; ent = ent->next) {
++            /* Skip things like proc */
++            if (!(ent->flags & VSERVER_FSTAB_SHOW))
++                continue;
++            if (virBufferVSprintf(buf, "    <disk type='%s' device='directory'>\n"
++                                       "      <source %s='%s' type='%s' options='%s'/>\n"
++                                       "      <target directory='%s'/>\n"
++                                       "    </disk>\n",
++                                  ent->source_type,
++                                  (strcmp(ent->source_type, "block") == 0 ?
++                                   "dev" : ent->source_type),
++                                  ent->source,
++                                  ent->fstype,
++                                  ent->options,
++                                  ent->target) < 0)
++                goto no_memory;
++        }
++    }
++
++    if (virBufferVSprintf(buf, "  </devices>\n"
++                               "</domain>\n") < 0)
++        goto no_memory;
++
++    return virBufferContentAndFree(buf);
++
++no_memory:
++    if (buf)
++        virBufferFree(buf);
++    vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY,
++                 "xml");
++    return NULL;
++}
++
++static int
++vserverParseIP(struct vserver_ip *ip, xmlNodePtr node)
++{
++    xmlChar *value;
++    char *endptr;
++
++    value = xmlGetProp(node, BAD_CAST "address");
++    if (!value)
++        goto err;
++    if (inet_pton(AF_INET6, (char *) value, &ip->addr.vna_v6_ip) > 0)
++        ip->addr.vna_type = VC_NXA_TYPE_IPV6;
++    else if (inet_pton(AF_INET, (char *) value, &ip->addr.vna_v4_ip) > 0)
++        ip->addr.vna_type = VC_NXA_TYPE_IPV4;
++    else
++        goto err;
++
++    value = xmlGetProp(node, BAD_CAST "prefix");
++    if (!value)
++        goto err;
++    ip->addr.vna_prefix = strtol((char *) value, &endptr, 0);
++    if (*endptr)
++        goto err;
++    xmlFree(value);
++
++    value = xmlGetProp(node, BAD_CAST "type");
++    if (!value)
++        ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
++    else {
++        if (xmlStrcasecmp(value, BAD_CAST "address") == 0)
++            ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
++        else if (xmlStrcasecmp(value, BAD_CAST "mask") == 0)
++            ip->addr.vna_type |= VC_NXA_TYPE_MASK;
++        else if (xmlStrcasecmp(value, BAD_CAST "range") == 0)
++            ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
++        else
++            goto err;
++        xmlFree(value);
++    }
++
++    value = xmlGetProp(node, BAD_CAST "interface");
++    if (value) {
++        strncpy(ip->interface, (char *) value, IFNAMSIZ);
++        xmlFree(value);
++    }
++
++    return 0;
++
++err:
++    if (value)
++        xmlFree(value);
++    return -1;
++}
++
++static const char *
++diskTypeToAttr(const char *type)
++{
++    return (strcmp(type, "block") == 0 ? "dev" : type);
++}
++
++static int
++vserverParseDisk(struct vserver_fstab *ent, xmlNodePtr node)
++{
++    xmlChar *type = NULL, *value = NULL;
++    xmlNodePtr iter, source = NULL, target = NULL;
++
++    for (iter = node->children; iter && (!source || !target); iter = iter->next) {
++        if (iter->type != XML_ELEMENT_NODE)
++            continue;
++        if (xmlStrEqual(iter->name, BAD_CAST "source"))
++            source = iter;
++        else if (xmlStrEqual(iter->name, BAD_CAST "target"))
++            target = iter;
++    }
++    if (!target || !source)
++        goto err;
++
++    value = xmlGetProp(node, BAD_CAST "device");
++    if (!value || !xmlStrEqual(value, BAD_CAST "directory"))
++        goto err;
++    xmlFree(value);
++
++    ent->target = (char *) xmlGetProp(target, BAD_CAST "directory");
++    if (!value)
++        goto err;
++
++    type = xmlGetProp(node, BAD_CAST "type");
++    if (!type)
++        goto err;
++    ent->source = (char *) xmlGetProp(source, BAD_CAST diskTypeToAttr((char *) type));
++    xmlFree(type);
++    if (!ent->source)
++        goto err;
++
++    ent->source_type = vserverFindSourceType(ent->source);
++    if (!ent->source_type)
++        goto err;
++
++    ent->fstype = (char *) xmlGetProp(source, BAD_CAST "type");
++    if (!ent->fstype)
++        ent->fstype = strdup("auto");
++
++    ent->options = (char *) xmlGetProp(source, BAD_CAST "options");
++    if (!ent->options) {
++        if (strcmp(ent->source_type, "file") == 0)
++            ent->options = strdup("defaults,loop");
++        else
++            ent->options = strdup("defaults");
++    }
++
++    ent->flags = VSERVER_FSTAB_SHOW | VSERVER_FSTAB_OUTPUT;
++
++    return 0;
++
++err:
++    if (ent->fstype)
++        xmlFree(ent->fstype);
++    if (ent->source)
++        xmlFree(ent->source);
++    if (ent->target)
++        xmlFree(ent->target);
++    if (value)
++        xmlFree(value);
++    return -1;
++}
++
++static int
++vserverParseXML(struct vserver_guest *guest, xmlDocPtr doc)
++{
++    xmlNodePtr root;
++    xmlXPathContextPtr xpath = NULL;
++    xmlXPathObjectPtr obj;
++    char *str;
++    long l_tmp;
++
++    /* FIXME: This could use some better error reporting... */
++    root = xmlDocGetRootElement(doc);
++    if (!root || !xmlStrEqual(root->name, BAD_CAST "domain"))
++        goto err;
++
++    xpath = xmlXPathNewContext(doc);
++    if (!xpath)
++        goto err;
++
++    if (virXPathLong("string(/domain[1]/@id)", xpath, &l_tmp) != 0)
++        goto err;
++    guest->xid = (int) l_tmp;
++
++    str = virXPathString("string(/domain/name[1])", xpath);
++    if (!str)
++        goto err;
++    strncpy(guest->name, str, VSERVER_NAME_MAX - 1);
++
++    str = virXPathString("string(/domain/uuid[1])", xpath);
++    if (!str) {
++        if (virUUIDGenerate(guest->uuid) != 0)
++            goto err;
++    }
++    else if (virUUIDParse(str, guest->uuid) < 0)
++        goto err;
++
++    guest->rss_hard = 0;
++    if (virXPathLong("string(/domain/memory[1])", xpath, (long *) &guest->rss_hard) == -2)
++        goto err;
++    guest->rss_hard >>= PAGE_SHIFT_TO_KIBI;
++
++    str = virXPathString("string(/domain/os[1]/hostname[1])", xpath);
++    if (str)
++        strncpy(guest->uts.hostname, str, VSERVER_UTS_MAX - 1);
++
++    str = virXPathString("string(/domain/os[1]/type[1]/@arch)", xpath);
++    if (str)
++        strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
++
++    str = virXPathString("string(/domain/os[1]/release[1])", xpath);
++    if (str)
++        strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
++
++    str = virXPathString("string(/domain/os[1]/version[1])", xpath);
++    if (str)
++        strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
++
++    str = virXPathString("string(/domain/container/initstyle[1]/@type)", xpath);
++    guest->initstyle = VSERVER_INIT_SYSV;
++    if (str) {
++        if (strcmp(str, "plain") == 0)
++            guest->initstyle = VSERVER_INIT_PLAIN;
++        else if (strcmp(str, "gentoo") == 0)
++            guest->initstyle = VSERVER_INIT_GENTOO;
++        else if (strcmp(str, "minit") == 0)
++            guest->initstyle = VSERVER_INIT_MINIT;
++        else if (strcmp(str, "sysv") == 0)
++            guest->initstyle = VSERVER_INIT_SYSV;
++    }
++
++    obj = xmlXPathEval(BAD_CAST "/domain/devices[1]/interface/ip", xpath);
++    if (obj != NULL && obj->type == XPATH_NODESET && obj->nodesetval != NULL &&
++        obj->nodesetval->nodeNr > 0) {
++        int i;
++        struct vserver_ip *ip = NULL;
++
++        for (i = 0; i < obj->nodesetval->nodeNr; i++) {
++            if (ip == NULL)
++                guest->ips = ip = calloc(1, sizeof(*ip));
++            else {
++                ip->next = calloc(1, sizeof(*ip));
++                ip = ip->next;
++            }
++
++            if (vserverParseIP(ip, obj->nodesetval->nodeTab[i]) == -1)
++                goto nodeset_err;
++        }
++    }
++    if (obj)
++        xmlXPathFreeObject(obj);
++
++    obj = xmlXPathEval(BAD_CAST "/domain/devices[1]/disk", xpath);
++    if (obj != NULL && obj->type == XPATH_NODESET && obj->nodesetval != NULL &&
++        obj->nodesetval->nodeNr > 0) {
++        int i;
++        struct vserver_fstab *ent = NULL;
++
++        for (i = 0; i < obj->nodesetval->nodeNr; i++) {
++            if (ent == NULL)
++                guest->fstab = ent = calloc(1, sizeof(*ent));
++            else {
++                ent->next = calloc(1, sizeof(*ent));
++                ent = ent->next;
++            }
++
++            if (vserverParseDisk(ent, obj->nodesetval->nodeTab[i]) == -1)
++                goto nodeset_err;
++        }
++    }
++    if (obj)
++        xmlXPathFreeObject(obj);
++
++    xmlXPathFreeContext(xpath);
++    xpath = NULL;
++
++    return 0;
++
++nodeset_err:
++    xmlXPathFreeObject(obj);
++err:
++    if (xpath)
++        xmlXPathFreeContext(xpath);
++    return -1;
++}
++
++static virDomainPtr
++vserverDomainDefineXML(virConnectPtr conn, const char *xml)
++{
++    struct vserver_driver *driver = conn->privateData;
++    struct vserver_guest *guest, *tail;
++    virDomainPtr domain;
++    xmlDocPtr doc;
++    char buf[128];
++
++    if ((guest = calloc(1, sizeof(struct vserver_guest))) == NULL) {
++        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "vserver_guest");
++        return NULL;
++    }
++
++    if ((doc = xmlReadDoc(BAD_CAST xml, "domain.xml", NULL,
++                          XML_PARSE_NOENT | XML_PARSE_NONET |
++                          XML_PARSE_NOWARNING | XML_PARSE_NOERROR)) == NULL) {
++        vserverError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
++        free(guest);
++        return NULL;
++    }
++
++    if (vserverParseXML(guest, doc) == -1) {
++        vserverError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
++        xmlFreeDoc(doc);
++        free(guest);
++        return NULL;
++    }
++
++    xmlFreeDoc(doc);
++
++    guest->path = calloc(sizeof(VSERVER_CONF_DIR "/") + strlen(guest->name), sizeof(char));
++    sprintf(guest->path, VSERVER_CONF_DIR "/%s", guest->name);
++    guest->status = VIR_DOMAIN_SHUTOFF;
++    if (vserverRunCommand(0, PROG_VSERVER, guest->name, "build", "-m",
++                   "skeleton", "--confdir", guest->path, NULL) != 0) {
++        vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, "vserver build");
++        free(guest);
++        return NULL;
++    }
++    virUUIDFormat(guest->uuid, buf);
++    if (vserverWriteGuestToConfig(guest) == -1) {
++        vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, "vserverWriteToConfig");
++        free(guest);
++        return NULL;
++    }
++
++    /* add it to the list */
++    for (tail = driver->guests; tail && tail->next; tail = tail->next)
++        ;
++    if (!tail)
++        driver->guests = guest;
++    else
++        tail->next = guest;
++
++    driver->inactive_guests++;
++
++    domain = virGetDomain(conn, guest->name, guest->uuid);
++    if (!domain)
++        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
++
++    return domain;
++}
++
++static int
++vserverListDefinedDomains(virConnectPtr conn, char **const names,
++                          int maxnames)
++{
++    struct vserver_driver *driver = conn->privateData;
++    struct vserver_guest *guest;
++    int i = 0;
++
++    for (guest = driver->guests; guest && i < maxnames; guest = guest->next) {
++        if (guest->status == VIR_DOMAIN_SHUTOFF) {
++            if ((names[i++] = strdup(guest->name)) == NULL) {
++                vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "names");
++                return -1;
++            }
++        }
++    }
++
++    return i;
++}
++
++static int
++vserverNumOfDefinedDomains(virConnectPtr conn)
++{
++    struct vserver_driver *driver = conn->privateData;
++
++    return driver->inactive_guests;
++}
++
++static int
++vserverDomainCreate(virDomainPtr domain)
++{
++    GET_DOMAIN(domain, -1);
++
++    if (vserverRunCommand(1, PROG_VSERVER, guest->path, "start", NULL) != 0) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                     "vserver start");
++        return -1;
++    }
++
++    driver->inactive_guests--;
++    guest->status = VIR_DOMAIN_RUNNING;
++    driver->active_guests++;
++    return 0;
++}
++
++static virDomainPtr
++vserverDomainCreateLinux(virConnectPtr conn, const char *xml,
++                         unsigned int flags ATTRIBUTE_UNUSED)
++{
++    virDomainPtr domain;
++
++    domain = vserverDomainDefineXML(conn, xml);
++    if (!domain)
++        return NULL;
++
++    if (vserverDomainCreate(domain) == -1)
++        return NULL;
++
++    return domain;
++}
++
++static int
++vserverDomainUndefine(virDomainPtr domain)
++{
++    struct vserver_guest *prev;
++    GET_DOMAIN(domain, -1);
++
++    for (prev = driver->guests; prev; prev = prev->next) {
++        if (prev->next == guest)
++            break;
++    }
++    if (!prev) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
++                     _("domain not found"));
++        return -1;
++    }
++    if (vserverIsRunning(guest)) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG,
++                     _("domain is running"));
++        return -1;
++    }
++
++    driver->inactive_guests--;
++    prev->next = guest->next;
++    /* XXX: deletes the domain's contents as well */
++    vserverRunCommand(0, PROG_VSERVER, "--silent", guest->path, "delete", NULL);
++    free(guest);
++
++    return 0;
++}
++
++static int
++doMount(int do_umount, struct vserver_guest *guest, struct vserver_fstab *ent)
++{
++    pid_t child;
++    int status;
++
++    if ((child = fork()) == 0) {
++        if (vc_enter_namespace(guest->xid, CLONE_NEWNS|CLONE_FS) == -1)
++            _exit(errno);
++        if (do_umount) {
++            if (sys_umount(ent->target, MNT_DETACH) == -1)
++                _exit(errno);
++        }
++        else {
++            char target[strlen(guest->path) + sizeof("/vdir/") + strlen(ent->target)];
++            sprintf(target, "%s/vdir/%s", guest->path, ent->target);
++            if (vserverRunCommand(0, "mount", "-t", ent->fstype, "-n", "-o",
++                                  ent->options, ent->source, target, NULL))
++                _exit(errno);
++        }
++        _exit(0);
++    }
++    else if (child == -1)
++        return -1;
++    else {
++        if (waitpid(child, &status, 0) == -1)
++            return -1;
++        if (WEXITSTATUS(status) != 0) {
++            errno = WEXITSTATUS(status);
++            return -1;
++        }
++    }
++
++    return 0;
++}
++
++static int
++vserverDomainHandleDevice(virDomainPtr domain, const char *xml, int attach)
++{
++    xmlDocPtr doc;
++    xmlNodePtr node;
++    GET_DOMAIN(domain, -1);
++
++    if ((doc = xmlReadDoc(BAD_CAST xml, "device.xml", NULL,
++                          XML_PARSE_NOENT | XML_PARSE_NONET |
++                          XML_PARSE_NOWARNING | XML_PARSE_NOERROR)) == NULL) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR, _("device"));
++        return -1;
++    }
++
++    node = xmlDocGetRootElement(doc);
++    if (node == NULL) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
++                     _("missing root element"));
++        return -1;
++    }
++
++    if (xmlStrEqual(node->name, BAD_CAST "interface")) {
++        xmlNodePtr child;
++        struct vserver_ip *ip;
++
++        for (child = node->children; child; child = child->next) {
++            if (child->type != XML_ELEMENT_NODE)
++                continue;
++
++            /* This should be an only child, but who knows. */
++            if (xmlStrEqual(child->name, BAD_CAST "ip"))
++                break;
++        }
++        if (!child) {
++            vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
++                         _("no <ip> element found"));
++            return -1;
++        }
++
++        ip = calloc(1, sizeof(*ip));
++        if (vserverParseIP(ip, child) == -1) {
++            vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
++                         _("parsing IP failed"));
++            return -1;
++        }
++
++        if (attach) {
++            list_add_tail(guest->ips, ip);
++            if (vserverIsRunning(guest)) {
++                if (vc_net_add(guest->xid, &ip->addr) == -1) {
++                    vserverError(domain->conn, domain, NULL,
++                                 VIR_ERR_SYSTEM_ERROR, strerror(errno));
++                    return -1;
++                }
++            }
++        }
++
++        else /* detach */ {
++            struct vserver_ip *i, *p = NULL;
++            for (i = guest->ips; i; i = i->next) {
++                if (strcmp(ip->interface, i->interface) == 0 &&
++                    memcmp(&ip->addr, &i->addr, sizeof(ip->addr)) == 0)
++                    break;
++                p = i;
++            }
++            if (i) {
++                if (p)
++                    p->next = i->next;
++                else
++                    guest->ips = i->next;
++                if (vserverIsRunning(guest)) {
++                    /* Not a lot of kernels support this, so don't fail. */
++                    vc_net_remove(guest->xid, &ip->addr);
++                }
++                free(i);
++            }
++            free(ip);
++        }
++    }
++    else if (xmlStrEqual(node->name, BAD_CAST "disk")) {
++        struct vserver_fstab *ent = calloc(1, sizeof(*ent));
++        if (!ent) {
++            vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY, NULL);
++            return -1;
++        }
++
++        if (vserverParseDisk(ent, node) == -1) {
++            vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR, "disk");
++            return -1;
++        }
++
++        if (attach) {
++            list_add_tail(guest->fstab, ent);
++            if (vserverIsRunning(guest)) {
++                if (doMount(0, guest, ent) == -1) {
++                    vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                                 strerror(errno));
++                    return -1;
++                }
++            }
++        }
++
++        else /* detach */ {
++            struct vserver_fstab *i, *p = NULL;
++            for (i = guest->fstab; i; i = i->next) {
++                /* These are the fields we care about */
++                if (strcmp(ent->source, i->source) == 0 &&
++                    strcmp(ent->target, i->target) == 0 &&
++                    strcmp(ent->source_type, i->source_type) == 0)
++                    break;
++                p = i;
++            }
++            if (i) {
++                if (p)
++                    p->next = i->next;
++                else
++                    guest->fstab = i->next;
++                if (vserverIsRunning(guest)) {
++                    if (doMount(1, guest, ent) == -1) {
++                        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                                     strerror(errno));
++                        return -1;
++                    }
++                }
++                freeFstab(i);
++            }
++            freeFstab(ent);
++        }
++    }
++    else {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
++                     _("unknown device type"));
++        return -1;
++    }
++
++    /* Both fstab and interfaces need a lot of writing, so write the whole thing */
++    if (vserverWriteGuestToConfig(guest) == -1) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_WRITE_FAILED, guest->name);
++        return -1;
++    }
++
++    xmlFreeDoc(doc);
++
++    return 0;
++}
++
++static int
++vserverDomainAttachDevice(virDomainPtr domain, const char *xml)
++{
++    return vserverDomainHandleDevice(domain, xml, 1);
++}
++
++static int
++vserverDomainDetachDevice(virDomainPtr domain, const char *xml)
++{
++    return vserverDomainHandleDevice(domain, xml, 0);
++}
++
++static int
++vserverDomainGetAutostart(virDomainPtr domain, int *autostart)
++{
++    GET_DOMAIN(domain, -1);
++
++    *autostart = guest->autostart;
++    return 0;
++}
++
++static int
++vserverDomainSetAutostart(virDomainPtr domain, int autostart)
++{
++    GET_DOMAIN(domain, -1);
++
++    if (vserverWriteToConfig(guest, "apps/init/mark",
++                      (autostart ? "default\n" : "\n")) == -1) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_WRITE_FAILED,
++                     "apps/init/mark");
++        return -1;
++    }
++    guest->autostart = autostart;
++    return 0;
++}
++
++static const struct {
++    unsigned int id;
++    const char *field;
++    int type;
++} sched_fields[] = {
++    { VC_VXSM_FILL_RATE,  "fill_rate1",   VIR_DOMAIN_SCHED_FIELD_UINT },
++    { VC_VXSM_INTERVAL,   "interval1",    VIR_DOMAIN_SCHED_FIELD_UINT },
++    { VC_VXSM_FILL_RATE2, "fill_rate2",   VIR_DOMAIN_SCHED_FIELD_UINT },
++    { VC_VXSM_INTERVAL2,  "interval2",    VIR_DOMAIN_SCHED_FIELD_UINT },
++    { VC_VXSM_TOKENS_MIN, "tokens_min",   VIR_DOMAIN_SCHED_FIELD_UINT },
++    { VC_VXSM_TOKENS_MAX, "tokens_max",   VIR_DOMAIN_SCHED_FIELD_UINT },
++    { VC_VXSM_PRIO_BIAS,  "prio_bias",    VIR_DOMAIN_SCHED_FIELD_INT  },
++    { VC_VXSM_IDLE_TIME,  "idle_time",    VIR_DOMAIN_SCHED_FIELD_BOOLEAN },
++    { 0, NULL, 0 }
++};
++
++static char *
++vserverDomainGetSchedulerType(virDomainPtr domain, int *nparams)
++{
++    char *ret;
++    int i;
++    GET_DOMAIN(domain, NULL);
++
++    ret = strdup(guest->sched.set_mask & VC_VXSM_IDLE_TIME ? "fair" : "hard");
++    if (!ret) {
++        vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY,
++                     _("scheduler"));
++        return NULL;
++    }
++
++    *nparams = 0;
++    for (i = 0; sched_fields[i].field != NULL; i++) {
++        /* only returns fields which are set */
++        if (guest->sched.set_mask & sched_fields[i].id)
++            (*nparams)++;
++    }
++
++    return ret;
++}
++
++static int
++vserverDomainGetSchedulerParams(virDomainPtr domain,
++                                virSchedParameterPtr params,
++                                int *nparams)
++{
++    int i, j;
++    GET_DOMAIN(domain, -1);
++
++    for (i = 0, j = 0; sched_fields[i].field != NULL && i < *nparams; i++) {
++        /* skip unset fields */
++        if (!(guest->sched.set_mask & sched_fields[i].id))
++            continue;
++
++        params[j].type = sched_fields[i].type;
++        strncpy(params[j].field, sched_fields[i].field, sizeof(params[j].field) - 1);
++        switch (sched_fields[i].id) {
++            case VC_VXSM_FILL_RATE:
++                params[j].value.ui = guest->sched.fill_rate;
++                break;
++            case VC_VXSM_INTERVAL:
++                params[j].value.ui = guest->sched.interval;
++                break;
++            case VC_VXSM_FILL_RATE2:
++                params[j].value.ui = guest->sched.fill_rate2;
++                break;
++            case VC_VXSM_INTERVAL2:
++                params[j].value.ui = guest->sched.interval2;
++                break;
++            case VC_VXSM_TOKENS_MIN:
++                params[j].value.ui = guest->sched.tokens_min;
++                break;
++            case VC_VXSM_TOKENS_MAX:
++                params[j].value.ui = guest->sched.tokens_max;
++                break;
++            case VC_VXSM_PRIO_BIAS:
++                params[j].value.i = guest->sched.priority_bias;
++                break;
++            case VC_VXSM_IDLE_TIME:
++                params[j].value.b = guest->sched.set_mask & VC_VXSM_IDLE_TIME;
++                break;
++        }
++        j++;
++    }
++    *nparams = j;
++
++    return 0;
++}
++
++static int
++vserverDomainSetSchedulerParams(virDomainPtr domain,
++                                virSchedParameterPtr params,
++                                int nparams)
++{
++    int i, j, cret;
++    GET_DOMAIN(domain, -1);
++
++    for (i = 0; i < nparams; i++) {
++        for (j = 0; sched_fields[j].field != NULL; j++) {
++            if (STREQ(sched_fields[j].field, params[i].field))
++                break;
++        }
++        if (sched_fields[j].field == NULL) {
++            vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "field");
++            return -1;
++        }
++        if (sched_fields[j].type != params[i].type) {
++            vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "type");
++            return -1;
++        }
++        switch (sched_fields[j].id) {
++            case VC_VXSM_FILL_RATE:
++                guest->sched.fill_rate = params[i].value.ui;
++                cret = vserverWriteToConfig(guest, "sched/fill-rate", "%u\n",
++                                     params[i].value.ui);
++                break;
++            case VC_VXSM_INTERVAL:
++                guest->sched.interval = params[i].value.ui;
++                cret = vserverWriteToConfig(guest, "sched/interval", "%u\n",
++                                     params[i].value.ui);
++                break;
++            case VC_VXSM_FILL_RATE2:
++                guest->sched.fill_rate2 = params[i].value.ui;
++                cret = vserverWriteToConfig(guest, "sched/fill-rate2", "%u\n",
++                                     params[i].value.ui);
++                break;
++            case VC_VXSM_INTERVAL2:
++                guest->sched.interval2 = params[i].value.ui;
++                cret = vserverWriteToConfig(guest, "sched/interval2", "%u\n",
++                                     params[i].value.ui);
++                break;
++            case VC_VXSM_TOKENS_MIN:
++                guest->sched.tokens_min = params[i].value.ui;
++                cret = vserverWriteToConfig(guest, "sched/tokens-min", "%u\n",
++                                     params[i].value.ui);
++                break;
++            case VC_VXSM_TOKENS_MAX:
++                guest->sched.tokens_max = params[i].value.ui;
++                cret = vserverWriteToConfig(guest, "sched/tokens-max", "%u\n",
++                                     params[i].value.ui);
++                break;
++            case VC_VXSM_PRIO_BIAS:
++                guest->sched.priority_bias = params[i].value.i;
++                cret = vserverWriteToConfig(guest, "sched/prio-bias", "%d\n",
++                                     params[i].value.i);
++                break;
++            case VC_VXSM_IDLE_TIME:
++                cret = vserverWriteToConfig(guest, "sched/idle-time", "%b",
++                                     params[i].value.b);
++                break;
++            default:
++                vserverError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
++                             "Unknown scheduler parameter");
++                return -1;
++        }
++        if (cret == -1) {
++            vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
++                         "vserverWriteToConfig");
++            return -1;
++        }
++        guest->sched.set_mask |= sched_fields[j].id;
++    }
++
++    return 0;
++}
++
++
++virDriver vserverDriver = {
++    VIR_DRV_VSERVER,
++    "Linux-VServer",
++    LIBVIR_VERSION_NUMBER,
++    vserverOpen,
++    vserverClose,
++    NULL,   /* supports_feature */
++    vserverGetType,
++    vserverGetVersion,
++    vserverGetHostname,
++    vserverGetURI,
++    NULL,   /* getMaxVcpus */
++    vserverNodeGetInfo,
++    NULL,   /* getCapabilties */
++    vserverListDomains,
++    vserverNumOfDomains,
++    vserverDomainCreateLinux,
++    vserverDomainLookupByID,
++    vserverDomainLookupByUUID,
++    vserverDomainLookupByName,
++    vserverDomainSuspend,
++    vserverDomainResume,
++    vserverDomainShutdown,
++    vserverDomainReboot,
++    vserverDomainDestroy,
++    vserverDomainGetOSType,
++    vserverDomainGetMaxMemory,
++    vserverDomainSetMaxMemory,
++    NULL,   /* domainSetMemory */
++    vserverDomainGetInfo,
++    NULL,   /* domainSave */
++    NULL,   /* domainRestore */
++    NULL,   /* domainCoreDump */
++    NULL,   /* domainSetVcpus */
++    NULL,   /* domainPinVcpu */
++    NULL,   /* domainGetVcpus */
++    NULL,   /* domainGetMaxVcpus */
++    vserverDomainDumpXML,
++    vserverListDefinedDomains,
++    vserverNumOfDefinedDomains,
++    vserverDomainCreate,
++    vserverDomainDefineXML,
++    vserverDomainUndefine,
++    vserverDomainAttachDevice,
++    vserverDomainDetachDevice,
++    vserverDomainGetAutostart,
++    vserverDomainSetAutostart,
++    vserverDomainGetSchedulerType,
++    vserverDomainGetSchedulerParams,
++    vserverDomainSetSchedulerParams,
++    NULL,   /* domainMigratePrepare  */
++    NULL,   /* domainMigratePerform */
++    NULL,   /* domainMigrateFinish */
++    NULL,   /* domainBlockStats */
++    NULL,   /* domainInterfaceStats */
++    NULL,   /* nodeGetCellsFreeMemory */
++    NULL,   /* getFreeMemory */
++};
++
++int vserverRegister(void)
++{
++    if (virRegisterDriver(&vserverDriver) < 0)
++        return -1;
++    return 0;
++}
++
++#endif
+--- libvirt-0.4.0.orig/src/vserver/vserver_driver.h    1970-01-01 01:00:00.000000000 +0100
++++ libvirt-0.4.0.vserver/src/vserver/vserver_driver.h 2008-01-09 19:14:08.000000000 +0100
+@@ -0,0 +1,137 @@
++/*
++ * Core driver for managing Linux-VServer guests
++ *
++ * Copyright (C) 2007 Daniel Hokka Zakrisson
++ *
++ * 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
++ *
++ * Author: Daniel Hokka Zakrisson <daniel hozac com>
++ */
++
++#ifdef WITH_VSERVER
++
++/* Kind of a hack */
++#ifdef IN_VSERVER
++#ifndef HAVE_XID_T
++typedef unsigned int xid_t;
++#endif
++#ifndef HAVE_NID_T
++typedef unsigned int nid_t;
++#endif
++#ifndef HAVE_TAG_T
++typedef unsigned int tag_t;
++#endif
++#include <vserver.h>
++
++#define VSERVER_NAME_MAX                  64
++#define VSERVER_UTS_MAX             255
++
++enum vserver_initstyle {
++    VSERVER_INIT_NONE,
++    VSERVER_INIT_SYSV,
++    VSERVER_INIT_PLAIN,
++    VSERVER_INIT_GENTOO,
++    VSERVER_INIT_MINIT,
++};
++
++struct vserver_ip {
++    char interface[IFNAMSIZ+1];
++    struct vc_net_addr addr;
++    struct vserver_ip *next;
++};
++
++enum fstab_flags {
++    VSERVER_FSTAB_SHOW=1,
++    VSERVER_FSTAB_OUTPUT=2,
++};
++struct vserver_fstab {
++    char *source;
++    const char *source_type;
++    char *target;
++    char *fstype;
++    char *options;
++    char *rest;
++    int flags;
++    struct vserver_fstab *next;
++};
++
++struct vserver_guest {
++    xid_t xid;
++    char name[VSERVER_NAME_MAX];
++    unsigned char uuid[VIR_UUID_BUFLEN];
++    char *path;
++
++    struct {
++        char hostname[VSERVER_UTS_MAX];
++        char machine[VSERVER_UTS_MAX];
++        char release[VSERVER_UTS_MAX];
++        char version[VSERVER_UTS_MAX];
++    } uts;
++
++    struct vserver_ip *ips;
++
++    struct vc_set_sched sched;
++    unsigned long rss_hard;
++
++    char autostart;
++    enum vserver_initstyle initstyle;
++
++    int status;
++
++    struct vserver_fstab *fstab;
++
++    struct vserver_guest *next;
++};
++
++struct vserver_driver {
++    struct vserver_guest *guests;
++    xmlChar *uri;
++    unsigned int active_guests;
++    unsigned int inactive_guests;
++    unsigned int initialized : 1;
++};
++
++
++#define list_add_tail(list, elem)                               \
++    do {                                                        \
++        __typeof__(list) iter;                                  \
++        if (list) {                                             \
++            for (iter = list; iter->next; iter = iter->next)    \
++                ;                                               \
++            iter->next = elem;                                  \
++        }                                                       \
++        else                                                    \
++            list = elem;                                        \
++    } while (0)
++
++static inline int
++vserverIsRunning(struct vserver_guest *guest) {
++    if (guest->status == VIR_DOMAIN_RUNNING || guest->status == VIR_DOMAIN_PAUSED)
++        return 1;
++    else
++        return 0;
++}
++
++
++int vserverContextIsRunning(const char *path);
++int vserverRunCommand(int do_daemon, const char *cmd, ...);
++void vserverError(virConnectPtr con, virDomainPtr dom, virNetworkPtr net,
++                  virErrorNumber error, const char *info);
++#endif
++
++
++extern int vserverRegister(void);
++
++#endif