From 1718358acaea43778ae6ad6656e62efe07a92f75 Mon Sep 17 00:00:00 2001 From: Marcin Krol Date: Wed, 8 Oct 2014 07:44:38 +0000 Subject: [PATCH] - from PLD --- bashisms.patch | 8 + libvirt-guests.init.patch | 9 + libvirt-lxc.patch | 194 +++ libvirt-qemu-acl.patch | 65 + libvirt-sasl.patch | 186 +++ libvirt-udevadm-settle.patch | 12 + libvirt-xend.patch | 44 + libvirt.init | 101 ++ libvirt.spec | 802 ++++++++++ libvirt.tmpfiles | 3 + query-parameters.patch | 180 +++ virtlockd.init.patch | 8 + vserver.patch | 2744 ++++++++++++++++++++++++++++++++++ 13 files changed, 4356 insertions(+) create mode 100644 bashisms.patch create mode 100644 libvirt-guests.init.patch create mode 100644 libvirt-lxc.patch create mode 100644 libvirt-qemu-acl.patch create mode 100644 libvirt-sasl.patch create mode 100644 libvirt-udevadm-settle.patch create mode 100644 libvirt-xend.patch create mode 100755 libvirt.init create mode 100644 libvirt.spec create mode 100644 libvirt.tmpfiles create mode 100644 query-parameters.patch create mode 100644 virtlockd.init.patch create mode 100644 vserver.patch diff --git a/bashisms.patch b/bashisms.patch new file mode 100644 index 0000000..9d7dfc4 --- /dev/null +++ b/bashisms.patch @@ -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 index 0000000..da84255 --- /dev/null +++ b/libvirt-guests.init.patch @@ -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 index 0000000..f0d8f7d --- /dev/null +++ b/libvirt-lxc.patch @@ -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 + #include + #include ++#include + + #if HAVE_CAPNG + # include +@@ -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 index 0000000..13fa7ee --- /dev/null +++ b/libvirt-qemu-acl.patch @@ -0,0 +1,65 @@ +From: Neil Wilson +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 index 0000000..3e19ce6 --- /dev/null +++ b/libvirt-sasl.patch @@ -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 /etc/sasl2/libvirt.conf. ++the libvirt SASL configuration file must be changed. This is /etc/sasl/libvirt.conf. + The mech_list parameter must first be changed to gssapi + instead of the default digest-md5. 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 /etc/sasl2/libvirt.conf. ++the libvirt SASL configuration file must be changed. This is /etc/sasl/libvirt.conf. + The mech_list parameter must first be changed to gssapi + instead of the default digest-md5. 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 index 0000000..a645d9f --- /dev/null +++ b/libvirt-udevadm-settle.patch @@ -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 index 0000000..a6d4d5b --- /dev/null +++ b/libvirt-xend.patch @@ -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 index 0000000..42c9d64 --- /dev/null +++ b/libvirt.init @@ -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 index 0000000..c434dd1 --- /dev/null +++ b/libvirt.spec @@ -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 index 0000000..f6b97c4 --- /dev/null +++ b/libvirt.tmpfiles @@ -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 index 0000000..04f15c7 --- /dev/null +++ b/query-parameters.patch @@ -0,0 +1,180 @@ +From 70c07e01dee24df0a1591d65799b66a8e89a3bd6 Mon Sep 17 00:00:00 2001 +From: Eric Blake +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 index 0000000..f3bdadd --- /dev/null +++ b/virtlockd.init.patch @@ -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 index 0000000..42c4fe2 --- /dev/null +++ b/vserver.patch @@ -0,0 +1,2744 @@ +https://www.redhat.com/archives/libvir-list/2008-January/msg00097.html + +From: "Daniel Hokka Zakrisson" +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: + + lenny + 19e12957-261a-5a06-d6d0-89917d6d439f + 2048000 + + lenny.test + vserver + + + + + + + + + + + + + + + + + + + + + + + +-- +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 ++ */ ++ ++#ifdef WITH_VSERVER ++ ++#define _GNU_SOURCE ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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 ++ */ ++ ++#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 ++ */ ++ ++#ifdef WITH_VSERVER ++ ++#define _GNU_SOURCE ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#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, ++"\n" ++" %s\n" ++" %s\n" ++ , guest->xid, guest->name, uuid ++ ) < 0) ++ goto no_memory; ++ if (guest->rss_hard > 0) ++ if (virBufferVSprintf(buf, " %lu\n", ++ guest->rss_hard << PAGE_SHIFT_TO_KIBI) < 0) ++ goto no_memory; ++ ++ if (virBufferVSprintf(buf, " \n" ++ " %s\n" ++ , guest->uts.hostname) < 0) ++ goto no_memory; ++ if (virBufferVSprintf(buf, " uts.machine) ++ if (virBufferVSprintf(buf, " arch='%s'", guest->uts.machine) < 0) ++ goto no_memory; ++ if (virBufferVSprintf(buf, ">vserver\n") < 0) ++ goto no_memory; ++ if (*guest->uts.release) ++ if (virBufferVSprintf(buf, " %s\n", ++ guest->uts.release) < 0) ++ goto no_memory; ++ if (*guest->uts.version) ++ if (virBufferVSprintf(buf, " %s\n", ++ guest->uts.version) < 0) ++ goto no_memory; ++ if (virBufferVSprintf(buf, " \n" ++ " \n") < 0) ++ goto no_memory; ++ ++ for (ip = guest->ips; ip; ip = ip->next) { ++ char addrbuf[128]; ++ if (virBufferVSprintf(buf, " \n" ++ " 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" ++ " \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, " \n" ++ " \n" ++ " \n" ++ " \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, " \n" ++ "\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 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 ++ */ ++ ++#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 ++ ++#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 -- 2.44.0