+++ /dev/null
-https://www.redhat.com/archives/libvir-list/2008-January/msg00097.html
-
-From: "Daniel Hokka Zakrisson" <daniel hozac com>
-To: libvir-list redhat com
-Subject: [Libvir] [PATCH] Linux-VServer support
-Date: Wed, 9 Jan 2008 22:51:20 +0100 (CET)
-
-This patch implements support for Linux-VServer guests. It is currently
-missing vcpu and console support, and the necessary virsh code to support
-it, but is otherwise pretty feature complete.
-
-This is an XML dump from one of my guests:
-<domain type='vserver' id='40010'>
- <name>lenny</name>
- <uuid>19e12957-261a-5a06-d6d0-89917d6d439f</uuid>
- <memory>2048000</memory>
- <os>
- <hostname>lenny.test</hostname>
- <type arch='i686'>vserver</type>
- </os>
- <devices>
- <interface type='ethernet'>
- <ip prefix='24' interface='dummy0' address='192.168.20.4' />
- </interface>
- <interface type='ethernet'>
- <ip prefix='24' interface='dummy0' type='range' address='192.168.32.100' address2='192.168.32.200'/>
- </interface>
- <disk type='directory' device='directory'>
- <source directory='/vservers/lenny' type='auto' options='defaults'/>
- <target directory='/'/>
- </disk>
- <disk type='directory' device='directory'>
- <source directory='/srv' type='ext3' options='bind,ro'/>
- <target directory='/srv'/>
- </disk>
- <disk type='block' device='directory'>
- <source dev='/dev/mapper/test' type='ext3' options='defaults'/>
- <target directory='/mnt'/>
- </disk>
- </devices>
-</domain>
-
---
-Daniel Hokka Zakrisson
---- libvirt-1.2.3/configure.ac~ 2014-04-06 12:21:22.000000000 +0300
-+++ libvirt-1.2.3/configure.ac 2014-04-06 12:22:55.249258975 +0300
-@@ -546,6 +546,10 @@
- [AS_HELP_STRING([--with-parallels],
- [add Parallels Cloud Server support @<:@default=check@:>@])])
- m4_divert_text([DEFAULTS], [with_parallels=check])
-+AC_ARG_WITH([vserver],
-+ [AS_HELP_STRING([--with-vserver],
-+ [add Linux-VServer support @<:@default=check@:>@])])
-+m4_divert_text([DEFAULTS], [with_vserver=check])
- AC_ARG_WITH([test],
- [AS_HELP_STRING([--with-test],
- [add test driver support @<:@default=yes@:>@])])
-@@ -991,6 +991,39 @@
- fi
- fi
-
-+if test "$with_vserver" = "yes" ; then
-+ AC_CHECK_LIB(vserver, [vc_rlimit_stat],, [with_vserver=no])
-+ AC_CHECK_TYPES([xid_t, nid_t, tag_t])
-+ AC_CHECK_HEADER(vserver.h,, [with_vserver=no], [AC_INCLUDES_DEFAULT()
-+#ifndef HAVE_XID_T
-+typedef unsigned int xid_t;
-+#endif
-+#ifndef HAVE_NID_T
-+typedef unsigned int nid_t;
-+#endif
-+#ifndef HAVE_TAG_T
-+typedef unsigned int tag_t;
-+#endif])
-+
-+ AC_MSG_CHECKING([for vserver configuration directory])
-+ VSERVER_CONF_DIR=`env PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" \
-+ vserver-info - SYSINFO | sed -n 's/^.*cfg-Directory:.//p'`
-+ AC_MSG_RESULT([$VSERVER_CONF_DIR])
-+ AC_DEFINE_UNQUOTED([VSERVER_CONF_DIR], ["$VSERVER_CONF_DIR"],
-+ [The default path to the Linux-VServer configuration files])
-+
-+ AC_MSG_CHECKING([for the vserver program])
-+ PROG_VSERVER=`env PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" \
-+ which vserver 2> /dev/null` || with_vserver=no
-+ AC_MSG_RESULT([$PROG_VSERVER])
-+ AC_DEFINE_UNQUOTED([PROG_VSERVER], ["$PROG_VSERVER"],
-+ [The path to the vserver program])
-+
-+ if test "$with_vserver" = "yes" ; then
-+ LIBVIRT_FEATURES="$LIBVIRT_FEATURES -DWITH_VSERVER"
-+ fi
-+fi
-+
-
- dnl
- dnl check for kernel headers required by src/bridge.c
-@@ -2759,6 +2759,7 @@
- AC_MSG_NOTICE([ ESX: $with_esx])
- AC_MSG_NOTICE([ Hyper-V: $with_hyperv])
- AC_MSG_NOTICE([Parallels: $with_parallels])
-+AC_MSG_NOTICE([ VServer: $with_vserver])
- LIBVIRT_DRIVER_RESULT_BHYVE
- AC_MSG_NOTICE([ Test: $with_test])
- AC_MSG_NOTICE([ Remote: $with_remote])
---- libvirt-1.1.1/include/libvirt/virterror.h~ 2013-07-24 03:23:07.000000000 +0300
-+++ libvirt-1.1.1/include/libvirt/virterror.h 2013-09-01 00:07:44.097192613 +0300
-@@ -121,6 +121,8 @@
- VIR_FROM_ACCESS = 55, /* Error from access control manager */
- VIR_FROM_SYSTEMD = 56, /* Error from systemd code */
-
-+ VIR_FROM_VSERVER = 57, /* Error from Linux-VServer driver */
-+
- # ifdef VIR_ENUM_SENTINELS
- VIR_ERR_DOMAIN_LAST
- # endif
---- libvirt-1.2.3/src/driver.h~ 2014-03-27 12:35:00.000000000 +0200
-+++ libvirt-1.2.3/src/driver.h 2014-04-06 12:25:03.124800629 +0300
-@@ -48,6 +48,7 @@
- VIR_DRV_HYPERV = 15,
- VIR_DRV_PARALLELS = 16,
- VIR_DRV_BHYVE = 17,
-+ VIR_DRV_VSERVER = 18,
- } virDrvNo;
-
-
---- libvirt-1.1.1/src/libvirt.c~ 2013-09-01 00:20:50.000000000 +0300
-+++ libvirt-1.1.1/src/libvirt.c 2013-09-01 00:21:02.812830784 +0300
-@@ -94,6 +94,9 @@
- #ifdef WITH_PARALLELS
- # include "parallels/parallels_driver.h"
- #endif
-+#ifdef WITH_VSERVER
-+# include "server/vserver_driver.h"
-+#endif
-
- #define VIR_FROM_THIS VIR_FROM_NONE
-
-@@ -479,6 +482,10 @@
- if (parallelsRegister() == -1)
- goto error;
- #endif
-+#ifdef WITH_VSERVER
-+ if (verversRegister() == -1)
-+ goto error;
-+#endif
- #ifdef WITH_REMOTE
- if (remoteRegister() == -1)
- goto error;
---- libvirt-1.1.1/src/Makefile.am~ 2013-07-30 10:21:31.000000000 +0300
-+++ libvirt-1.1.1/src/Makefile.am 2013-09-01 00:11:19.080124997 +0300
-@@ -467,6 +467,7 @@
- $(NWFILTER_DRIVER_SOURCES) \
- $(OPENVZ_DRIVER_SOURCES) \
- $(PARALLELS_DRIVER_SOURCES) \
-+ $(VSERVER_DRIVER_SOURCES) \
- $(PHYP_DRIVER_SOURCES) \
- $(QEMU_DRIVER_SOURCES) \
- $(REMOTE_DRIVER_SOURCES) \
-@@ -727,6 +728,12 @@
- parallels/parallels_storage.c \
- parallels/parallels_network.c
-
-+VSERVER_DRIVER_SOURCES = \
-+ vserver/vserver_driver.h \
-+ vserver/vserver_driver.c \
-+ vserver/vserver_conf.h \
-+ vserver/vserver_conf.c
-+
- NETWORK_DRIVER_SOURCES = \
- network/bridge_driver.h network/bridge_driver.c
-
---- libvirt-1.2.3/src/util/virerror.c~ 2014-03-27 12:35:01.000000000 +0200
-+++ libvirt-1.2.3/src/util/virerror.c 2014-04-06 12:25:58.523869047 +0300
-@@ -127,6 +127,7 @@
-
- "Access Manager", /* 55 */
- "Systemd",
-+ "Vserver",
- "Bhyve",
- "Crypto",
- )
---- libvirt-0.4.0.orig/src/vserver/vserver_conf.c 1970-01-01 01:00:00.000000000 +0100
-+++ libvirt-0.4.0.vserver/src/vserver/vserver_conf.c 2008-01-09 08:52:11.000000000 +0100
-@@ -0,0 +1,751 @@
-+/*
-+ * Configuration handling for Linux-VServer guests
-+ *
-+ * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
-+ *
-+ * This library is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ * Author: Daniel Hokka Zakrisson <daniel hozac com>
-+ */
-+
-+#ifdef WITH_VSERVER
-+
-+#define _GNU_SOURCE
-+
-+#ifdef HAVE_CONFIG_H
-+# include <config.h>
-+#endif
-+
-+#include <stdio.h>
-+#include <unistd.h>
-+#include <stdlib.h>
-+#include <fcntl.h>
-+#include <dirent.h>
-+#include <errno.h>
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <arpa/inet.h>
-+#include <net/if.h>
-+#include <sys/stat.h>
-+#include <ctype.h>
-+
-+#include <libvirt/virterror.h>
-+
-+#define IN_VSERVER 1
-+#include "internal.h"
-+#include "vserver_driver.h"
-+#include "vserver_conf.h"
-+#include "uuid.h"
-+
-+static int
-+readStr(char *dst, size_t len, const char *name, const char *setting)
-+{
-+ char file[strlen(name) + strlen(setting) + 2];
-+ int fd;
-+ ssize_t bytes;
-+ char *p;
-+
-+ sprintf(file, "%s/%s", name, setting);
-+
-+ /* a non-existant file is not a failure */
-+ *dst = '\0';
-+ if ((fd = open(file, O_RDONLY)) == -1)
-+ return 1;
-+
-+ if ((bytes = read(fd, dst, len - 1)) == -1) {
-+ close(fd);
-+ return -1;
-+ }
-+ close(fd);
-+
-+ dst[bytes] = '\0';
-+
-+ if ((p = strchr(dst, '\n')) != NULL)
-+ *p = '\0';
-+
-+ return 0;
-+}
-+
-+static int
-+readLong(void *v_dst, const char *name, const char *setting)
-+{
-+ char buf[128], *endptr;
-+ int ret;
-+ long *dst = v_dst;
-+
-+ ret = readStr(buf, sizeof(buf), name, setting);
-+ if (ret)
-+ return ret;
-+
-+ *dst = strtol(buf, &endptr, 0);
-+ if (endptr && *endptr != '\0')
-+ return -1;
-+
-+ return 0;
-+}
-+
-+static int
-+readInt(void *v_dst, const char *name, const char *setting)
-+{
-+ long val;
-+ int *dst = v_dst;
-+ int ret;
-+
-+ ret = readLong(&val, name, setting);
-+ if (ret)
-+ return ret;
-+
-+ *dst = (int) val;
-+
-+ return 0;
-+}
-+
-+static int
-+readBool(char *dst, const char *name, const char *setting)
-+{
-+ char file[strlen(name) + strlen(setting) + 2];
-+
-+ sprintf(file, "%s/%s", name, setting);
-+
-+ *dst = access(file, F_OK) != -1;
-+
-+ return 0;
-+}
-+
-+int
-+vserverWriteToConfig(struct vserver_guest *guest, const char *filename,
-+ const char *format, ...)
-+{
-+ char path[strlen(guest->path) + 1 + strlen(filename) + 1];
-+ va_list va;
-+ char value[1024];
-+ int fd;
-+ ssize_t len, off, ret;
-+ char *dir;
-+
-+ sprintf(path, "%s/%s", guest->path, filename);
-+
-+ /* ensure the directory exists */
-+ dir = strrchr(path, '/');
-+ *dir = '\0';
-+ if (mkdir(path, 0755) && errno != EEXIST)
-+ return -1;
-+ *dir = '/';
-+
-+ va_start(va, format);
-+ if (strcmp(format, "%b") == 0) {
-+ /* bool, this is a special case */
-+ if (va_arg(va, int)) {
-+ *value = '\0';
-+ len = 0;
-+ }
-+ else {
-+ if (unlink(path) == -1 && errno != ENOENT)
-+ return -1;
-+ else
-+ return 0;
-+ }
-+ }
-+ else
-+ len = vsnprintf(value, sizeof(value), format, va);
-+ va_end(va);
-+
-+ fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, 0644);
-+ if (fd == -1)
-+ return -1;
-+
-+ for (off = 0; off < len; off += ret) {
-+ ret = write(fd, value + off, len - off);
-+ if (ret == -1) {
-+ close(fd);
-+ return -1;
-+ }
-+ }
-+
-+ if (close(fd) == -1)
-+ return -1;
-+ return 0;
-+}
-+
-+#define WRITE(...) if (vserverWriteToConfig(guest, __VA_ARGS__) == -1) \
-+ return -1
-+#define WRITE_SCHED_VAL(sched, file, mask, format, value) \
-+ if ((sched)->set_mask & mask) { \
-+ WRITE(file, format, value); \
-+ }
-+#define WRITE_SCHED(dir, sched) \
-+ do { \
-+ WRITE_SCHED_VAL(sched, dir "/fill-rate", \
-+ VC_VXSM_FILL_RATE, "%u\n", \
-+ (sched)->fill_rate); \
-+ WRITE_SCHED_VAL(sched, dir "/interval", \
-+ VC_VXSM_INTERVAL, "%u\n", \
-+ (sched)->interval); \
-+ WRITE_SCHED_VAL(sched, dir "/fill-rate2", \
-+ VC_VXSM_FILL_RATE2, "%u\n", \
-+ (sched)->fill_rate2); \
-+ WRITE_SCHED_VAL(sched, dir "/interval2", \
-+ VC_VXSM_INTERVAL2, "%u\n", \
-+ (sched)->interval2); \
-+ WRITE_SCHED_VAL(sched, dir "/tokens-min", \
-+ VC_VXSM_TOKENS_MIN, "%u\n", \
-+ (sched)->tokens_min); \
-+ WRITE_SCHED_VAL(sched, dir "/tokens-max", \
-+ VC_VXSM_TOKENS_MAX, "%u\n", \
-+ (sched)->tokens_max); \
-+ WRITE_SCHED_VAL(sched, dir "/priority-bias", \
-+ VC_VXSM_PRIO_BIAS, "%u\n", \
-+ (sched)->priority_bias); \
-+ WRITE(dir "/idle-time", "%b", \
-+ (sched)->set_mask & VC_VXSM_IDLE_TIME); \
-+ } while (0)
-+#define WRITE_IP(filename, v4var, v6var) \
-+ strcpy(file, filename); \
-+ switch (type) { \
-+ case VC_NXA_TYPE_IPV4: \
-+ inet_ntop(AF_INET, (v4var), buf, sizeof(buf)); \
-+ break; \
-+ case VC_NXA_TYPE_IPV6: \
-+ inet_ntop(AF_INET6, (v6var), buf, sizeof(buf)); \
-+ break; \
-+ } \
-+ WRITE(dir, "%s\n", buf);
-+
-+static int
-+writeInterfaces(struct vserver_guest *guest)
-+{
-+ char name[strlen(guest->path) + sizeof("/interfaces/XXXXXX/prefix")],
-+ *dir, *file;
-+ char buf[128];
-+ struct vserver_ip *ip;
-+ unsigned int i;
-+
-+ snprintf(name, sizeof(name), "%s/interfaces", guest->path);
-+ if (vserverRunCommand(0, "rm", "-fr", name, NULL) != 0)
-+ return -1;
-+ if (mkdir(name, 0755) == -1)
-+ return -1;
-+
-+ dir = name + strlen(guest->path) + 1;
-+ for (ip = guest->ips, i = 0; ip; ip = ip->next, i++) {
-+ uint16_t type;
-+
-+ /* Yeah right... */
-+ if (i > 999999) {
-+ errno = EOVERFLOW;
-+ return -1;
-+ }
-+
-+ file = dir;
-+ file += snprintf(dir, sizeof(name) - (dir - name), "interfaces/%u", i);
-+ if (mkdir(name, 0755) == -1)
-+ return -1;
-+
-+ type = ip->addr.vna_type & (VC_NXA_TYPE_IPV4|VC_NXA_TYPE_IPV6);
-+
-+ strcpy(file, "/prefix");
-+ WRITE(dir, "%u\n", ip->addr.vna_prefix);
-+
-+ if (*ip->interface) {
-+ strcpy(file, "/dev");
-+ WRITE(dir, "%s\n", ip->interface);
-+ }
-+ else {
-+ strcpy(file, "/nodev");
-+ WRITE(dir, "%b", 1);
-+ }
-+
-+ WRITE_IP("/ip", &ip->addr.vna_v4_ip, &ip->addr.vna_v6_ip);
-+ if (ip->addr.vna_type & VC_NXA_TYPE_RANGE) {
-+ WRITE_IP("/ip2", &ip->addr.vna_v4_ip2, &ip->addr.vna_v6_ip2);
-+ }
-+ if (ip->addr.vna_type & (VC_NXA_TYPE_RANGE|VC_NXA_TYPE_MASK)) {
-+ WRITE_IP("/mask", &ip->addr.vna_v4_mask, &ip->addr.vna_v6_mask);
-+ }
-+ }
-+ return 0;
-+}
-+
-+static int
-+writeFstab(struct vserver_guest *guest)
-+{
-+ FILE *fp;
-+ struct vserver_fstab *ent;
-+ char file[strlen(guest->path) + sizeof("/fstab")];
-+
-+ sprintf(file, "%s/fstab", guest->path);
-+ fp = fopen(file, "w");
-+ if (fp == NULL)
-+ return -1;
-+
-+ for (ent = guest->fstab; ent; ent = ent->next) {
-+ if (!(ent->flags & VSERVER_FSTAB_OUTPUT))
-+ continue;
-+ fprintf(fp, "%s\t%s\t%s\t%s\t%s\n", ent->source, ent->target,
-+ ent->fstype, ent->options, (ent->rest ? ent->rest : ""));
-+ }
-+
-+ if (fclose(fp) == -1)
-+ return -1;
-+
-+ return 0;
-+}
-+
-+int
-+vserverWriteGuestToConfig(struct vserver_guest *guest)
-+{
-+ char buf[128];
-+
-+ WRITE("context", "%u\n", guest->xid);
-+ WRITE("name", "%s\n", guest->name);
-+ virUUIDFormat(guest->uuid, buf);
-+ WRITE("uuid", "%s\n", buf);
-+ if (*guest->uts.hostname)
-+ WRITE("uts/nodename", "%s\n", guest->uts.hostname);
-+ if (*guest->uts.machine)
-+ WRITE("uts/machine", "%s\n", guest->uts.machine);
-+ if (*guest->uts.release)
-+ WRITE("uts/release", "%s\n", guest->uts.release);
-+ if (*guest->uts.version)
-+ WRITE("uts/version", "%s\n", guest->uts.version);
-+ if (guest->rss_hard > 0)
-+ WRITE("rlimits/rss.hard", "%lu\n", guest->rss_hard);
-+ WRITE("apps/init/mark", (guest->autostart ? "default\n" : "\n"));
-+ WRITE_SCHED("sched", &guest->sched);
-+
-+ if (writeInterfaces(guest) == -1)
-+ return -1;
-+
-+ if (writeFstab(guest) == -1)
-+ return -1;
-+
-+ return 0;
-+}
-+#undef WRITE_IP
-+#undef WRITE_SCHED
-+#undef WRITE_SCHED_VAL
-+#undef WRITE
-+
-+static int
-+parseInterfaces(struct vserver_guest *guest, const char *directory)
-+{
-+ DIR *interfaces;
-+ struct dirent *interface;
-+ struct vserver_ip *ip = NULL;
-+ char ipath[256], *subdir;
-+ size_t spare;
-+ char s_ip[48], s_prefix[4], s_mask[48], s_dev[32], s_ip2[48];
-+
-+ subdir = ipath;
-+ subdir += snprintf(ipath, sizeof(ipath), "%s/%s", guest->name, directory);
-+ spare = sizeof(ipath) - (subdir - ipath);
-+
-+ interfaces = opendir(ipath);
-+ if (!interfaces)
-+ return 0;
-+
-+ while ((interface = readdir(interfaces)) != NULL) {
-+ if (*interface->d_name == '.')
-+ continue;
-+ /* would overflow */
-+ if (strlen(interface->d_name) + sizeof("//disabled") > spare)
-+ continue;
-+
-+ snprintf(subdir, spare, "/%s/disabled", interface->d_name);
-+ if (access(ipath, F_OK) != -1)
-+ continue;
-+
-+ snprintf(subdir, spare, "/%s", interface->d_name);
-+ *s_mask = '\0';
-+ *s_prefix = '\0';
-+ if (readStr(s_ip, sizeof(s_ip), ipath, "ip") == 0 &&
-+ (readStr(s_prefix, sizeof(s_prefix), ipath, "prefix") == 0 ||
-+ readStr(s_mask, sizeof(s_mask), ipath, "mask") == 0)) {
-+ if (readStr(s_dev, sizeof(s_dev), ipath, "dev") != 0)
-+ *s_dev = '\0';
-+ if (readStr(s_ip2, sizeof(s_ip2), ipath, "ip2") != 0)
-+ *s_ip2 = '\0';
-+ }
-+ else
-+ continue;
-+
-+ if (!ip)
-+ guest->ips = ip = calloc(1, sizeof(*ip));
-+ else {
-+ ip->next = calloc(1, sizeof(*ip));
-+ ip = ip->next;
-+ }
-+ if (!ip)
-+ goto cleanup;
-+
-+ strcpy(ip->interface, s_dev);
-+
-+ if (inet_pton(AF_INET6, s_ip, &ip->addr.vna_v6_ip) > 0)
-+ ip->addr.vna_type = VC_NXA_TYPE_IPV6;
-+ else if (inet_pton(AF_INET, s_ip, &ip->addr.vna_v4_ip) > 0)
-+ ip->addr.vna_type = VC_NXA_TYPE_IPV4;
-+ else
-+ goto cleanup;
-+
-+ if (ip->addr.vna_type == VC_NXA_TYPE_IPV6) {
-+ if (*s_mask) {
-+ if (inet_pton(AF_INET6, s_mask, &ip->addr.vna_v6_mask) <= 0)
-+ goto cleanup;
-+ }
-+ if (*s_ip2) {
-+ if (inet_pton(AF_INET6, s_ip2, &ip->addr.vna_v6_ip2) <= 0)
-+ goto cleanup;
-+ ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
-+ }
-+ else
-+ ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
-+ }
-+ else if (ip->addr.vna_type == VC_NXA_TYPE_IPV4) {
-+ if (*s_mask) {
-+ if (inet_pton(AF_INET, s_mask, &ip->addr.vna_v4_mask) <= 0)
-+ goto cleanup;
-+ }
-+ if (*s_ip2) {
-+ if (inet_pton(AF_INET, s_ip2, &ip->addr.vna_v4_ip2) <= 0)
-+ goto cleanup;
-+ ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
-+ }
-+ else
-+ ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
-+ }
-+
-+ if (*s_prefix) {
-+ char *endptr;
-+ ip->addr.vna_prefix = strtoul(s_prefix, &endptr, 0);
-+ if (*endptr != '\n' && *endptr)
-+ goto cleanup;
-+ }
-+ }
-+
-+ closedir(interfaces);
-+ return 0;
-+
-+cleanup:
-+ closedir(interfaces);
-+ return -1;
-+}
-+
-+static inline char *
-+endOfField(char *start)
-+{
-+ char *end;
-+ for (end = start; *(end - 1) != '\\' &&
-+ !isspace(*end) &&
-+ *end != '\0'; end++)
-+ ;
-+ return end;
-+}
-+
-+static inline char *
-+startOfField(char *end)
-+{
-+ char *start;
-+ for (start = end + 1; isspace(*start) &&
-+ *start != '\0'; start++)
-+ ;
-+ return start;
-+}
-+
-+static const struct {
-+ int mode;
-+ const char *type;
-+} source_types[] = {
-+ { S_IFBLK, "block" },
-+ { S_IFREG, "file" },
-+ { S_IFDIR, "directory" },
-+};
-+
-+const char *
-+vserverFindSourceType(const char *source)
-+{
-+ struct stat st;
-+ int mode, i;
-+ if (stat(source, &st) == -1)
-+ mode = -1;
-+ else
-+ mode = st.st_mode & S_IFMT;
-+ for (i = 0; i < (sizeof(source_types) / sizeof(*source_types)); i++) {
-+ if (mode == source_types[i].mode)
-+ return source_types[i].type;
-+ }
-+ return NULL;
-+}
-+
-+static int
-+parseFstab(struct vserver_guest *guest, const char *filename)
-+{
-+ FILE *fp;
-+ char buf[256], *start, *end;
-+ struct vserver_fstab *ent = NULL;
-+ char path[strlen(guest->name) + 2 + strlen(filename)];
-+
-+ sprintf(path, "%s/%s", guest->name, filename);
-+ if ((fp = fopen(path, "r")) == NULL)
-+ return 0;
-+
-+ while (fgets(buf, sizeof(buf), fp) != NULL) {
-+ if (!ent)
-+ guest->fstab = ent = calloc(1, sizeof(*ent));
-+ else {
-+ ent->next = calloc(1, sizeof(*ent));
-+ ent = ent->next;
-+ }
-+ if (!ent)
-+ goto err;
-+
-+ start = buf;
-+ end = endOfField(start);
-+ *end = '\0';
-+ ent->source = strdup(start);
-+ ent->source_type = vserverFindSourceType(start);
-+
-+ ent->flags |= VSERVER_FSTAB_OUTPUT;
-+ if (ent->source_type)
-+ ent->flags |= VSERVER_FSTAB_SHOW;
-+
-+ start = startOfField(end);
-+ end = endOfField(start);
-+ *end = '\0';
-+ ent->target = strdup(start);
-+
-+ start = startOfField(end);
-+ end = endOfField(start);
-+ *end = '\0';
-+ ent->fstype = strdup(start);
-+
-+ start = startOfField(end);
-+ end = endOfField(start);
-+ if (*end != '\0') {
-+ char *ptr;
-+ ent->rest = strdup(end + 1);
-+ ptr = strchr(ent->rest, '\n');
-+ if (ptr)
-+ *ptr = '\0';
-+ }
-+ else
-+ ent->rest = NULL;
-+ *end = '\0';
-+ ent->options = strdup(start);
-+
-+ if (!ent->source || !ent->target || !ent->fstype || !ent->options)
-+ goto err;
-+ }
-+
-+ fclose(fp);
-+ return 0;
-+
-+err:
-+ fclose(fp);
-+ return -1;
-+}
-+
-+virDrvOpenStatus
-+vserverInitializeDriver(virConnectPtr conn, struct vserver_driver *driver,
-+ const char *path)
-+{
-+ struct vserver_guest *guest = NULL;
-+ DIR *dp = NULL;
-+ struct dirent *de;
-+ int cwd;
-+ const char *conf_dir = (*path ? path : VSERVER_CONF_DIR);
-+
-+ if (driver->initialized == 1)
-+ return VIR_DRV_OPEN_SUCCESS;
-+
-+ driver->guests = NULL;
-+ driver->inactive_guests = driver->active_guests = 0;
-+
-+ cwd = open(".", O_RDONLY);
-+ if (cwd == -1 ||
-+ chdir(conf_dir) == -1 ||
-+ (dp = opendir(".")) == NULL) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_OPEN_FAILED, conf_dir);
-+ goto error;
-+ }
-+
-+ while ((de = readdir(dp)) != NULL) {
-+ char uuidstr[VIR_UUID_STRING_BUFLEN + 1];
-+ char mark[32];
-+ char tmp;
-+
-+ if (*de->d_name == '.')
-+ continue;
-+
-+ if (driver->guests == NULL)
-+ driver->guests = guest = calloc(1, sizeof(struct vserver_guest));
-+ else {
-+ guest->next = calloc(1, sizeof(struct vserver_guest));
-+ guest = guest->next;
-+ }
-+
-+ if (!guest) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
-+ "vserver_guest");
-+ goto error;
-+ }
-+
-+ guest->path = calloc(strlen(conf_dir) + 1 + strlen(de->d_name) + 1, sizeof(char));
-+ if (!guest->path)
-+ goto nomem;
-+ sprintf(guest->path, "%s/%s", conf_dir, de->d_name);
-+
-+#define CHECK(x) \
-+ if ((x) == -1) { \
-+ goto parseerror; \
-+ }
-+#define DO_SCHED(type, var, file, bit) \
-+ do { \
-+ int ret; \
-+ CHECK(ret = read ## type((var), de->d_name, (file))); \
-+ if (ret == 0) \
-+ guest->sched.set_mask |= (bit); \
-+ } while (0)
-+
-+ /* Parse simple values */
-+ CHECK(readInt(&guest->xid, de->d_name, "context"));
-+ CHECK(readStr(guest->name, sizeof(guest->name), de->d_name, "name"));
-+ CHECK(readStr(guest->uts.hostname, sizeof(guest->uts.hostname), de->d_name,
-+ "uts/nodename"));
-+ CHECK(readStr(guest->uts.machine, sizeof(guest->uts.machine), de->d_name,
-+ "uts/machine"));
-+ CHECK(readStr(guest->uts.release, sizeof(guest->uts.release), de->d_name,
-+ "uts/release"));
-+ CHECK(readStr(guest->uts.version, sizeof(guest->uts.version), de->d_name,
-+ "uts/version"));
-+ CHECK(readStr(mark, sizeof(mark), de->d_name, "apps/init/mark"));
-+
-+ DO_SCHED(Int, &guest->sched.fill_rate, "sched/fill-rate",
-+ VC_VXSM_FILL_RATE);
-+ DO_SCHED(Int, &guest->sched.interval, "sched/interval",
-+ VC_VXSM_INTERVAL);
-+ DO_SCHED(Int, &guest->sched.fill_rate2, "sched/fill-rate2",
-+ VC_VXSM_FILL_RATE2);
-+ DO_SCHED(Int, &guest->sched.interval2, "sched/interval2",
-+ VC_VXSM_INTERVAL2);
-+ DO_SCHED(Int, &guest->sched.tokens_min, "sched/tokens-min",
-+ VC_VXSM_TOKENS_MIN);
-+ DO_SCHED(Int, &guest->sched.tokens_max, "sched/tokens-max",
-+ VC_VXSM_TOKENS_MAX);
-+ DO_SCHED(Int, &guest->sched.priority_bias, "sched/priority-bias",
-+ VC_VXSM_PRIO_BIAS);
-+ if (readBool(&tmp, de->d_name, "sched/idle-time") == 0) {
-+ if (tmp)
-+ guest->sched.set_mask |= VC_VXSM_IDLE_TIME;
-+ }
-+
-+ CHECK(readLong(&guest->rss_hard, de->d_name, "rlimits/rss.hard"));
-+
-+ /* Generate a UUID if one doesn't already exist */
-+ switch (readStr(uuidstr, sizeof(uuidstr), de->d_name, "uuid")) {
-+ case 1:
-+ CHECK(virUUIDGenerate(guest->uuid));
-+ virUUIDFormat(guest->uuid, uuidstr);
-+ CHECK(vserverWriteToConfig(guest, "uuid", "%s\n", uuidstr));
-+ break;
-+ case 0:
-+ CHECK(virUUIDParse(uuidstr, guest->uuid));
-+ break;
-+ case -1:
-+ goto parseerror;
-+ }
-+
-+ /* Parse interfaces */
-+ if (parseInterfaces(guest, "interfaces") == -1)
-+ goto parseerror;
-+
-+ /* Parse fstab */
-+ if (parseFstab(guest, "fstab") == -1)
-+ goto parseerror;
-+
-+ /* Make sure the guest has the / directory in the disk output */
-+ do {
-+ struct vserver_fstab *ent;
-+ int has_root = 0;
-+ for (ent = guest->fstab; ent; ent = ent->next) {
-+ if (strcmp(ent->target, "/") == 0) {
-+ has_root = 1;
-+ break;
-+ }
-+ }
-+ if (!has_root) {
-+ char vdir[strlen(de->d_name) + sizeof("/vdir")];
-+
-+ ent = calloc(1, sizeof(*ent));
-+ if (!ent)
-+ goto nomem;
-+
-+ sprintf(vdir, "%s/vdir", de->d_name);
-+ ent->source = realpath(vdir, NULL);
-+
-+ ent->flags = VSERVER_FSTAB_SHOW;
-+ ent->source_type = vserverFindSourceType("/");
-+ ent->target = strdup("/");
-+ ent->fstype = strdup("auto");
-+ ent->options = strdup("defaults");
-+ if (!ent->source || !ent->target || !ent->fstype || !ent->options)
-+ goto nomem;
-+ ent->next = guest->fstab;
-+ guest->fstab = ent;
-+ }
-+ } while (0);
-+#undef DO_SCHED
-+#undef CHECK
-+
-+ if (STREQ(mark, "default"))
-+ guest->autostart = 1;
-+ if (vserverContextIsRunning(guest->path)) {
-+ struct vc_ctx_flags flags;
-+ if (vc_get_cflags(guest->xid, &flags) == 0 &&
-+ (flags.flagword & VC_VXF_SCHED_PAUSE))
-+ guest->status = VIR_DOMAIN_PAUSED;
-+ else
-+ guest->status = VIR_DOMAIN_RUNNING;
-+ driver->active_guests++;
-+ }
-+ else {
-+ guest->status = VIR_DOMAIN_SHUTOFF;
-+ driver->inactive_guests++;
-+ }
-+ }
-+
-+ closedir(dp);
-+ if (fchdir(cwd) == -1 || close(cwd) == -1) {
-+ /* do nothing, we succeeded with everything else... */
-+ }
-+ driver->initialized = 1;
-+
-+ return VIR_DRV_OPEN_SUCCESS;
-+
-+nomem:
-+ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
-+ goto error;
-+parseerror:
-+ vserverError(conn, NULL, NULL, VIR_ERR_PARSE_FAILED, de->d_name);
-+error:
-+ if (dp)
-+ closedir(dp);
-+
-+ if (fchdir(cwd) == -1 || close(cwd) == -1) {
-+ /* we're already failing, nothing to do */
-+ }
-+ return VIR_DRV_OPEN_ERROR;
-+}
-+
-+#endif
---- libvirt-0.4.0.orig/src/vserver/vserver_conf.h 1970-01-01 01:00:00.000000000 +0100
-+++ libvirt-0.4.0.vserver/src/vserver/vserver_conf.h 2008-01-05 02:10:20.000000000 +0100
-@@ -0,0 +1,36 @@
-+/*
-+ * Configuration handling for Linux-VServer guests
-+ *
-+ * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
-+ *
-+ * This library is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ * Author: Daniel Hokka Zakrisson <daniel hozac com>
-+ */
-+
-+#ifdef WITH_VSERVER
-+
-+/* Kind of a hack */
-+#ifdef IN_VSERVER
-+int vserverWriteToConfig(struct vserver_guest *guest, const char *filename,
-+ const char *format, ...);
-+int vserverWriteGuestToConfig(struct vserver_guest *guest);
-+virDrvOpenStatus vserverInitializeDriver(virConnectPtr conn,
-+ struct vserver_driver *driver,
-+ const char *path);
-+const char *vserverFindSourceType(const char *source);
-+#endif
-+
-+#endif
-diff -Nurp libvirt-0.4.0.orig/src/vserver_driver.c libvirt-0.4.0.vserver/src/vserver_driver.c
---- libvirt-0.4.0.orig/src/vserver_driver.c 1970-01-01 01:00:00.000000000 +0100
-+++ libvirt-0.4.0.vserver/src/vserver_driver.c 2008-01-09 22:43:23.000000000 +0100
-@@ -0,0 +1,1625 @@
-+/*
-+ * Core driver for managing Linux-VServer guests
-+ *
-+ * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
-+ *
-+ * This library is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ * Author: Daniel Hokka Zakrisson <daniel hozac com>
-+ */
-+
-+#ifdef WITH_VSERVER
-+
-+#define _GNU_SOURCE
-+
-+#ifdef HAVE_CONFIG_H
-+# include <config.h>
-+#endif
-+
-+#include <stdio.h>
-+#include <unistd.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <fcntl.h>
-+#include <dirent.h>
-+#include <sys/wait.h>
-+#include <errno.h>
-+#include <sys/types.h>
-+#include <sys/socket.h>
-+#include <arpa/inet.h>
-+#include <net/if.h>
-+#include <sys/syscall.h>
-+
-+#include <libxml/uri.h>
-+#include <libxml/xpath.h>
-+#include <libxml/tree.h>
-+
-+#include <libvirt/virterror.h>
-+
-+#define IN_VSERVER 1
-+#include "internal.h"
-+#include "vserver_driver.h"
-+#include "vserver_conf.h"
-+#include "buf.h"
-+#include "uuid.h"
-+#include "xml.h"
-+#include "nodeinfo.h"
-+
-+#define GET_DOMAIN(dom, ret) \
-+ struct vserver_driver *driver = (struct vserver_driver *) \
-+ (dom)->conn->privateData; \
-+ struct vserver_guest *guest = getGuestByUUID(driver, (dom)->uuid); \
-+ \
-+ if (!guest) { \
-+ vserverError((dom)->conn, (dom), NULL, VIR_ERR_INVALID_ARG, \
-+ __FUNCTION__); \
-+ return (ret); \
-+ }
-+
-+#ifndef MNT_DETACH
-+# define MNT_DETACH 0x00000002
-+#endif
-+
-+static int PAGE_SHIFT_TO_KIBI = 2;
-+
-+static inline int sys_umount(const char *path, int flags)
-+{
-+ return syscall(__NR_umount2, path, flags);
-+}
-+
-+static inline struct vserver_guest *
-+getGuestByID(struct vserver_driver *driver,
-+ int id)
-+{
-+ struct vserver_guest *res;
-+ for (res = driver->guests; res; res = res->next) {
-+ if (res->xid == id)
-+ break;
-+ }
-+ return res;
-+}
-+
-+static inline struct vserver_guest *
-+getGuestByUUID(struct vserver_driver *driver,
-+ const unsigned char *uuid)
-+{
-+ struct vserver_guest *res;
-+ for (res = driver->guests; res; res = res->next) {
-+ if (memcmp(res->uuid, uuid, VIR_UUID_BUFLEN) == 0)
-+ break;
-+ }
-+ return res;
-+}
-+
-+static inline struct vserver_guest *
-+getGuestByName(struct vserver_driver *driver,
-+ const char *name)
-+{
-+ struct vserver_guest *res;
-+ for (res = driver->guests; res; res = res->next) {
-+ if (STREQ(res->name, name))
-+ break;
-+ }
-+ return res;
-+}
-+
-+void
-+vserverError(virConnectPtr con,
-+ virDomainPtr dom,
-+ virNetworkPtr net,
-+ virErrorNumber error,
-+ const char *info)
-+{
-+ const char *errmsg;
-+
-+ if (error == VIR_ERR_OK)
-+ return;
-+
-+ errmsg = __virErrorMsg(error, info);
-+ __virRaiseError(con, dom, net, VIR_FROM_VSERVER, error, VIR_ERR_ERROR,
-+ errmsg, info, NULL, 0, 0, errmsg, info, 0);
-+}
-+
-+/* like execl, but uses /dev/null and handles forking/waiting/etc. */
-+int
-+vserverRunCommand(int do_daemon, const char *cmd, ...)
-+{
-+ pid_t pid;
-+ va_list va;
-+ char **argv;
-+ int i, argc;
-+ sighandler_t sigchld;
-+ int ret;
-+
-+ va_start(va, cmd);
-+ argc = 15;
-+ argv = calloc(argc, sizeof(*argv));
-+ argv[0] = (char *) cmd;
-+ for (i = 1; (argv[i] = va_arg(va, char *)) != NULL; i++) {
-+ if (i == argc-1) {
-+ argc += 5;
-+ argv = realloc(argv, sizeof(*argv) * argc);
-+ }
-+ }
-+
-+ va_end(va);
-+
-+ /* XXX: This is bad, since another child could die
-+ * between here and where we restore it */
-+ sigchld = signal(SIGCHLD, SIG_DFL);
-+ if ((pid = fork()) == 0) {
-+ int fd;
-+ if (do_daemon) {
-+ pid_t not_a_zombie;
-+
-+ if (setsid() == -1)
-+ goto error;
-+
-+ not_a_zombie = fork();
-+ if (not_a_zombie == -1)
-+ goto error;
-+ else if (not_a_zombie > 0)
-+ _exit(0);
-+ }
-+ if ((fd = open("/dev/null", O_RDWR)) == -1)
-+ goto error;
-+ if (dup2(fd, 0) == -1 || dup2(fd, 1) == -1 || dup2(fd, 2) == -1)
-+ goto error;
-+ if (fd > 2 && close(fd) == -1)
-+ goto error;
-+ execvp(cmd, argv);
-+ error:
-+ _exit(1);
-+ }
-+ else if (pid == -1) {
-+ ret = -1;
-+ }
-+ else {
-+ int status;
-+ if (waitpid(pid, &status, 0) == -1)
-+ ret = -1;
-+ else if (WEXITSTATUS(status) != 0)
-+ ret = 1;
-+ else
-+ ret = 0;
-+ }
-+
-+ signal(SIGCHLD, sigchld);
-+ return ret;
-+}
-+
-+int
-+vserverContextIsRunning(const char *path)
-+{
-+ return vc_getVserverCtx(path, vcCFG_AUTO, false, 0, vcCTX_XID) != VC_NOCTX;
-+}
-+
-+static void
-+vserverSetPagesize(void)
-+{
-+ long page_size = sysconf(_SC_PAGESIZE);
-+ PAGE_SHIFT_TO_KIBI = page_size / 1024;
-+}
-+
-+static virDrvOpenStatus
-+vserverOpen(virConnectPtr conn, xmlURIPtr uri,
-+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
-+ int flags ATTRIBUTE_UNUSED)
-+{
-+ virDrvOpenStatus ret;
-+ struct vserver_driver *driver;
-+
-+ if (!uri)
-+ return VIR_DRV_OPEN_DECLINED;
-+
-+ if (getuid() != 0)
-+ return VIR_DRV_OPEN_DECLINED;
-+
-+ if (!uri->scheme || STRNEQ(uri->scheme, "vserver"))
-+ return VIR_DRV_OPEN_DECLINED;
-+
-+ if (uri->server)
-+ return VIR_DRV_OPEN_DECLINED;
-+
-+ /* nothing else supported right now */
-+ if (strncmp(uri->path, "/system", 7) != 0)
-+ return VIR_DRV_OPEN_DECLINED;
-+
-+ /* make sure it's a Linux-VServer kernel */
-+ if (vc_get_version() == -1)
-+ return VIR_DRV_OPEN_DECLINED;
-+
-+ if (!conn->privateData)
-+ conn->privateData = calloc(1, sizeof(struct vserver_driver));
-+
-+ ret = vserverInitializeDriver(conn, conn->privateData, uri->path + 7);
-+ if (ret == VIR_DRV_OPEN_SUCCESS) {
-+ driver = conn->privateData;
-+ driver->uri = xmlSaveUri(uri);
-+ }
-+ else {
-+ free(conn->privateData);
-+ }
-+
-+ vserverSetPagesize();
-+
-+ return ret;
-+}
-+
-+static void
-+freeFstab(struct vserver_fstab *ent)
-+{
-+ free(ent->source);
-+ free(ent->target);
-+ free(ent->fstype);
-+ free(ent->options);
-+ free(ent);
-+}
-+
-+static void
-+freeGuest(struct vserver_guest *guest)
-+{
-+ struct vserver_ip *ip, *pip = NULL;
-+ struct vserver_fstab *ent, *pent = NULL;
-+ for (ip = guest->ips; ip; ip = ip->next) {
-+ if (pip)
-+ free(pip);
-+ pip = ip;
-+ }
-+ if (pip)
-+ free(pip);
-+ for (ent = guest->fstab; ent; ent = ent->next) {
-+ if (pent)
-+ freeFstab(pent);
-+ pent = ent;
-+ }
-+ if (pent)
-+ freeFstab(pent);
-+ free(guest->path);
-+ free(guest);
-+}
-+
-+static int
-+vserverClose(virConnectPtr conn)
-+{
-+ struct vserver_driver *driver = conn->privateData;
-+ struct vserver_guest *guest, *pguest;
-+
-+ if (!driver || !driver->initialized)
-+ return 0;
-+
-+ for (guest = driver->guests, pguest = NULL; guest; guest = guest->next) {
-+ if (pguest)
-+ freeGuest(pguest);
-+ pguest = guest;
-+ }
-+ if (pguest)
-+ freeGuest(pguest);
-+
-+ xmlFree(driver->uri);
-+ free(driver);
-+ conn->privateData = NULL;
-+
-+ return 0;
-+}
-+
-+static const char *
-+vserverGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
-+{
-+ return "Linux-VServer";
-+}
-+
-+static int
-+vserverGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
-+{
-+ *version = 1;
-+ return 0;
-+}
-+
-+static char *
-+vserverGetHostname(virConnectPtr conn)
-+{
-+ char *ret;
-+
-+ ret = calloc(VSERVER_UTS_MAX + 1, sizeof(char));
-+ if (!ret) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "gethostname");
-+ return NULL;
-+ }
-+
-+ if (gethostname(ret, VSERVER_UTS_MAX) == -1) {
-+ free(ret);
-+ vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, strerror(errno));
-+ return NULL;
-+ }
-+
-+ return ret;
-+}
-+
-+static char *
-+vserverGetURI(virConnectPtr conn)
-+{
-+ struct vserver_driver *driver = conn->privateData;
-+ return (char *) xmlStrdup(driver->uri);
-+}
-+
-+static int
-+vserverNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
-+{
-+ return virNodeInfoPopulate(conn, nodeinfo);
-+}
-+
-+static int
-+vserverListDomains(virConnectPtr conn, int *ids, int nids)
-+{
-+ struct vserver_driver *driver = conn->privateData;
-+ struct vserver_guest *guest;
-+ int i;
-+
-+ for (guest = driver->guests, i = 0; guest && i < nids;
-+ guest = guest->next) {
-+ if (guest->status != VIR_DOMAIN_SHUTOFF)
-+ ids[i++] = guest->xid;
-+ }
-+
-+ return i;
-+}
-+
-+static int
-+vserverNumOfDomains(virConnectPtr conn)
-+{
-+ struct vserver_driver *driver = conn->privateData;
-+
-+ return driver->active_guests;
-+}
-+
-+static virDomainPtr
-+vserverDomainLookupByID(virConnectPtr conn, int id)
-+{
-+ struct vserver_driver *driver = conn->privateData;
-+ struct vserver_guest *guest;
-+ virDomainPtr domain;
-+
-+ if ((guest = getGuestByID(driver, id)) == NULL) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
-+ _("No domain by that ID found"));
-+ return NULL;
-+ }
-+
-+ domain = virGetDomain(conn, guest->name, guest->uuid);
-+ if (!domain) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
-+ return NULL;
-+ }
-+
-+ if (vserverIsRunning(guest))
-+ domain->id = guest->xid;
-+
-+ return domain;
-+}
-+
-+static virDomainPtr
-+vserverDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
-+{
-+ struct vserver_driver *driver = conn->privateData;
-+ struct vserver_guest *guest;
-+ virDomainPtr domain;
-+
-+ if ((guest = getGuestByUUID(driver, uuid)) == NULL) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
-+ _("No domain by that UUID found"));
-+ return NULL;
-+ }
-+
-+ domain = virGetDomain(conn, guest->name, guest->uuid);
-+ if (!domain) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
-+ return NULL;
-+ }
-+
-+ if (vserverIsRunning(guest))
-+ domain->id = guest->xid;
-+
-+ return domain;
-+}
-+
-+static virDomainPtr
-+vserverDomainLookupByName(virConnectPtr conn, const char *name)
-+{
-+ struct vserver_driver *driver = conn->privateData;
-+ struct vserver_guest *guest;
-+ virDomainPtr domain;
-+
-+ if ((guest = getGuestByName(driver, name)) == NULL) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
-+ _("No domain by that name found"));
-+ return NULL;
-+ }
-+
-+ domain = virGetDomain(conn, guest->name, guest->uuid);
-+ if (!domain) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
-+ return NULL;
-+ }
-+
-+ if (vserverIsRunning(guest))
-+ domain->id = guest->xid;
-+
-+ return domain;
-+}
-+
-+static int
-+vserverDomainSuspend(virDomainPtr domain)
-+{
-+ struct vc_ctx_flags flags = {
-+ .flagword = VC_VXF_SCHED_PAUSE,
-+ .mask = VC_VXF_SCHED_PAUSE,
-+ };
-+ GET_DOMAIN(domain, -1);
-+
-+ if (guest->status == VIR_DOMAIN_PAUSED)
-+ return 0;
-+ if (guest->status != VIR_DOMAIN_RUNNING) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_OPERATION_FAILED,
-+ _("domain is not running"));
-+ return -1;
-+ }
-+
-+ if (vc_set_cflags(guest->xid, &flags) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ strerror(errno));
-+ return -1;
-+ }
-+ guest->status = VIR_DOMAIN_PAUSED;
-+
-+ return 0;
-+}
-+
-+static int
-+vserverDomainResume(virDomainPtr domain)
-+{
-+ struct vc_ctx_flags flags = {
-+ .flagword = 0,
-+ .mask = VC_VXF_SCHED_PAUSE,
-+ };
-+ GET_DOMAIN(domain, -1);
-+
-+ if (guest->status == VIR_DOMAIN_RUNNING)
-+ return 0;
-+ if (guest->status != VIR_DOMAIN_PAUSED) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_OPERATION_FAILED,
-+ _("domain is not running"));
-+ return -1;
-+ }
-+
-+ if (vc_set_cflags(guest->xid, &flags) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ strerror(errno));
-+ return -1;
-+ }
-+ guest->status = VIR_DOMAIN_RUNNING;
-+
-+ return 0;
-+}
-+
-+static int
-+vserverDomainShutdown(virDomainPtr domain)
-+{
-+ GET_DOMAIN(domain, -1);
-+
-+ if (vserverRunCommand(1, PROG_VSERVER, guest->path, "stop", NULL) != 0) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ "vserver stop");
-+ return -1;
-+ }
-+
-+ driver->active_guests--;
-+ guest->status = VIR_DOMAIN_SHUTOFF;
-+ driver->inactive_guests++;
-+ return 0;
-+}
-+
-+static int
-+vserverDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
-+{
-+ GET_DOMAIN(domain, -1);
-+
-+ if (vserverRunCommand(1, PROG_VSERVER, guest->path, "restart", NULL) != 0) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ "vserver restart");
-+ return -1;
-+ }
-+
-+ guest->status = VIR_DOMAIN_RUNNING;
-+ return 0;
-+}
-+
-+static int
-+vserverDomainDestroy(virDomainPtr domain)
-+{
-+ GET_DOMAIN(domain, -1);
-+
-+ if (vserverDomainShutdown(domain) == -1)
-+ return -1;
-+
-+ virFreeDomain(domain->conn, domain);
-+
-+ return 0;
-+}
-+
-+static char *
-+vserverDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
-+{
-+ return strdup("Linux");
-+}
-+
-+static unsigned long
-+vserverDomainGetMaxMemory(virDomainPtr domain)
-+{
-+ GET_DOMAIN(domain, (unsigned long) -1);
-+
-+ return guest->rss_hard << PAGE_SHIFT_TO_KIBI;
-+}
-+
-+static int
-+vserverDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
-+{
-+ struct vc_rlimit limit = {
-+ .min = 0,
-+ };
-+ GET_DOMAIN(domain, -1);
-+
-+ guest->rss_hard = memory >> PAGE_SHIFT_TO_KIBI;
-+ limit.soft = limit.hard = guest->rss_hard;
-+ if (vserverIsRunning(guest) &&
-+ vc_set_rlimit(guest->xid, RLIMIT_RSS, &limit) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR, strerror(errno));
-+ return -1;
-+ }
-+
-+ if (vserverWriteToConfig(guest, "rlimits/rss.hard", "%lu\n", guest->rss_hard) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ strerror(errno));
-+ return -1;
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+vserverDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
-+{
-+ struct vc_sched_info sinfo = { .user_msec = 0, .sys_msec = 0 };
-+ struct vc_rlimit_stat rss_stat = { .value = 0 };
-+ GET_DOMAIN(domain, -1);
-+
-+ if (vserverIsRunning(guest)) {
-+ if (vc_sched_info(guest->xid, &sinfo) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ strerror(errno));
-+ return -1;
-+ }
-+ if (vc_rlimit_stat(guest->xid, RLIMIT_RSS, &rss_stat) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ strerror(errno));
-+ return -1;
-+ }
-+ }
-+
-+ info->state = guest->status;
-+ info->maxMem = guest->rss_hard << PAGE_SHIFT_TO_KIBI;
-+ info->nrVirtCpu = -1;
-+ info->memory = rss_stat.value;
-+ info->cpuTime = (sinfo.user_msec + sinfo.sys_msec) * 1000000ULL;
-+
-+ return 0;
-+}
-+
-+static char *
-+vserverDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
-+{
-+ virBufferPtr buf;
-+ char uuid[VIR_UUID_STRING_BUFLEN + 1];
-+ struct vserver_ip *ip;
-+ GET_DOMAIN(domain, NULL);
-+
-+ buf = virBufferNew(4096);
-+ if (!buf)
-+ goto no_memory;
-+
-+ virUUIDFormat(guest->uuid, uuid);
-+ if (virBufferVSprintf(buf,
-+"<domain type='vserver' id='%d'>\n"
-+" <name>%s</name>\n"
-+" <uuid>%s</uuid>\n"
-+ , guest->xid, guest->name, uuid
-+ ) < 0)
-+ goto no_memory;
-+ if (guest->rss_hard > 0)
-+ if (virBufferVSprintf(buf, " <memory>%lu</memory>\n",
-+ guest->rss_hard << PAGE_SHIFT_TO_KIBI) < 0)
-+ goto no_memory;
-+
-+ if (virBufferVSprintf(buf, " <os>\n"
-+ " <hostname>%s</hostname>\n"
-+ , guest->uts.hostname) < 0)
-+ goto no_memory;
-+ if (virBufferVSprintf(buf, " <type") < 0)
-+ goto no_memory;
-+ if (*guest->uts.machine)
-+ if (virBufferVSprintf(buf, " arch='%s'", guest->uts.machine) < 0)
-+ goto no_memory;
-+ if (virBufferVSprintf(buf, ">vserver</type>\n") < 0)
-+ goto no_memory;
-+ if (*guest->uts.release)
-+ if (virBufferVSprintf(buf, " <release>%s</release>\n",
-+ guest->uts.release) < 0)
-+ goto no_memory;
-+ if (*guest->uts.version)
-+ if (virBufferVSprintf(buf, " <version>%s</version>\n",
-+ guest->uts.version) < 0)
-+ goto no_memory;
-+ if (virBufferVSprintf(buf, " </os>\n"
-+ " <devices>\n") < 0)
-+ goto no_memory;
-+
-+ for (ip = guest->ips; ip; ip = ip->next) {
-+ char addrbuf[128];
-+ if (virBufferVSprintf(buf, " <interface type='ethernet'>\n"
-+ " <ip prefix='%d'", ip->addr.vna_prefix) < 0)
-+ goto no_memory;
-+ if (*ip->interface)
-+ if (virBufferVSprintf(buf, " interface='%s'", ip->interface) < 0)
-+ goto no_memory;
-+
-+ switch (ip->addr.vna_type & (VC_NXA_TYPE_IPV4|VC_NXA_TYPE_IPV6)) {
-+ case VC_NXA_TYPE_IPV4:
-+ inet_ntop(AF_INET, &ip->addr.vna_v4_ip, addrbuf, sizeof(addrbuf));
-+ if (virBufferVSprintf(buf, " address='%s'", addrbuf) < 0)
-+ goto no_memory;
-+ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_RANGE)) {
-+ inet_ntop(AF_INET, &ip->addr.vna_v4_ip2, addrbuf, sizeof(addrbuf));
-+ if (virBufferVSprintf(buf, " address2='%s' type='range'", addrbuf) < 0)
-+ goto no_memory;
-+ }
-+ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_MASK)) {
-+ if (virBufferVSprintf(buf, " type='mask'") < 0)
-+ goto no_memory;
-+ }
-+ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_RANGE) ||
-+ ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_MASK)) {
-+ inet_ntop(AF_INET, &ip->addr.vna_v4_mask, addrbuf, sizeof(addrbuf));
-+ if (virBufferVSprintf(buf, " mask='%s'", addrbuf) < 0)
-+ goto no_memory;
-+ }
-+ break;
-+
-+ case VC_NXA_TYPE_IPV6:
-+ inet_ntop(AF_INET6, &ip->addr.vna_v6_ip, addrbuf, sizeof(addrbuf));
-+ if (virBufferVSprintf(buf, " address='%s'", addrbuf) < 0)
-+ goto no_memory;
-+ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_RANGE)) {
-+ inet_ntop(AF_INET6, &ip->addr.vna_v6_ip2, addrbuf, sizeof(addrbuf));
-+ if (virBufferVSprintf(buf, " address2='%s' type='range'", addrbuf) < 0)
-+ goto no_memory;
-+ }
-+ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_MASK)) {
-+ if (virBufferVSprintf(buf, " type='mask'") < 0)
-+ goto no_memory;
-+ }
-+ if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_RANGE) ||
-+ ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_MASK)) {
-+ inet_ntop(AF_INET6, &ip->addr.vna_v6_mask, addrbuf, sizeof(addrbuf));
-+ if (virBufferVSprintf(buf, " mask='%s'", addrbuf) < 0)
-+ goto no_memory;
-+ }
-+ break;
-+ }
-+
-+ if (virBufferVSprintf(buf, " />\n"
-+ " </interface>\n") < 0)
-+ goto no_memory;
-+ }
-+
-+ if (guest->fstab) {
-+ struct vserver_fstab *ent;
-+ for (ent = guest->fstab; ent; ent = ent->next) {
-+ /* Skip things like proc */
-+ if (!(ent->flags & VSERVER_FSTAB_SHOW))
-+ continue;
-+ if (virBufferVSprintf(buf, " <disk type='%s' device='directory'>\n"
-+ " <source %s='%s' type='%s' options='%s'/>\n"
-+ " <target directory='%s'/>\n"
-+ " </disk>\n",
-+ ent->source_type,
-+ (strcmp(ent->source_type, "block") == 0 ?
-+ "dev" : ent->source_type),
-+ ent->source,
-+ ent->fstype,
-+ ent->options,
-+ ent->target) < 0)
-+ goto no_memory;
-+ }
-+ }
-+
-+ if (virBufferVSprintf(buf, " </devices>\n"
-+ "</domain>\n") < 0)
-+ goto no_memory;
-+
-+ return virBufferContentAndFree(buf);
-+
-+no_memory:
-+ if (buf)
-+ virBufferFree(buf);
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY,
-+ "xml");
-+ return NULL;
-+}
-+
-+static int
-+vserverParseIP(struct vserver_ip *ip, xmlNodePtr node)
-+{
-+ xmlChar *value;
-+ char *endptr;
-+
-+ value = xmlGetProp(node, BAD_CAST "address");
-+ if (!value)
-+ goto err;
-+ if (inet_pton(AF_INET6, (char *) value, &ip->addr.vna_v6_ip) > 0)
-+ ip->addr.vna_type = VC_NXA_TYPE_IPV6;
-+ else if (inet_pton(AF_INET, (char *) value, &ip->addr.vna_v4_ip) > 0)
-+ ip->addr.vna_type = VC_NXA_TYPE_IPV4;
-+ else
-+ goto err;
-+
-+ value = xmlGetProp(node, BAD_CAST "prefix");
-+ if (!value)
-+ goto err;
-+ ip->addr.vna_prefix = strtol((char *) value, &endptr, 0);
-+ if (*endptr)
-+ goto err;
-+ xmlFree(value);
-+
-+ value = xmlGetProp(node, BAD_CAST "type");
-+ if (!value)
-+ ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
-+ else {
-+ if (xmlStrcasecmp(value, BAD_CAST "address") == 0)
-+ ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
-+ else if (xmlStrcasecmp(value, BAD_CAST "mask") == 0)
-+ ip->addr.vna_type |= VC_NXA_TYPE_MASK;
-+ else if (xmlStrcasecmp(value, BAD_CAST "range") == 0)
-+ ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
-+ else
-+ goto err;
-+ xmlFree(value);
-+ }
-+
-+ value = xmlGetProp(node, BAD_CAST "interface");
-+ if (value) {
-+ strncpy(ip->interface, (char *) value, IFNAMSIZ);
-+ xmlFree(value);
-+ }
-+
-+ return 0;
-+
-+err:
-+ if (value)
-+ xmlFree(value);
-+ return -1;
-+}
-+
-+static const char *
-+diskTypeToAttr(const char *type)
-+{
-+ return (strcmp(type, "block") == 0 ? "dev" : type);
-+}
-+
-+static int
-+vserverParseDisk(struct vserver_fstab *ent, xmlNodePtr node)
-+{
-+ xmlChar *type = NULL, *value = NULL;
-+ xmlNodePtr iter, source = NULL, target = NULL;
-+
-+ for (iter = node->children; iter && (!source || !target); iter = iter->next) {
-+ if (iter->type != XML_ELEMENT_NODE)
-+ continue;
-+ if (xmlStrEqual(iter->name, BAD_CAST "source"))
-+ source = iter;
-+ else if (xmlStrEqual(iter->name, BAD_CAST "target"))
-+ target = iter;
-+ }
-+ if (!target || !source)
-+ goto err;
-+
-+ value = xmlGetProp(node, BAD_CAST "device");
-+ if (!value || !xmlStrEqual(value, BAD_CAST "directory"))
-+ goto err;
-+ xmlFree(value);
-+
-+ ent->target = (char *) xmlGetProp(target, BAD_CAST "directory");
-+ if (!value)
-+ goto err;
-+
-+ type = xmlGetProp(node, BAD_CAST "type");
-+ if (!type)
-+ goto err;
-+ ent->source = (char *) xmlGetProp(source, BAD_CAST diskTypeToAttr((char *) type));
-+ xmlFree(type);
-+ if (!ent->source)
-+ goto err;
-+
-+ ent->source_type = vserverFindSourceType(ent->source);
-+ if (!ent->source_type)
-+ goto err;
-+
-+ ent->fstype = (char *) xmlGetProp(source, BAD_CAST "type");
-+ if (!ent->fstype)
-+ ent->fstype = strdup("auto");
-+
-+ ent->options = (char *) xmlGetProp(source, BAD_CAST "options");
-+ if (!ent->options) {
-+ if (strcmp(ent->source_type, "file") == 0)
-+ ent->options = strdup("defaults,loop");
-+ else
-+ ent->options = strdup("defaults");
-+ }
-+
-+ ent->flags = VSERVER_FSTAB_SHOW | VSERVER_FSTAB_OUTPUT;
-+
-+ return 0;
-+
-+err:
-+ if (ent->fstype)
-+ xmlFree(ent->fstype);
-+ if (ent->source)
-+ xmlFree(ent->source);
-+ if (ent->target)
-+ xmlFree(ent->target);
-+ if (value)
-+ xmlFree(value);
-+ return -1;
-+}
-+
-+static int
-+vserverParseXML(struct vserver_guest *guest, xmlDocPtr doc)
-+{
-+ xmlNodePtr root;
-+ xmlXPathContextPtr xpath = NULL;
-+ xmlXPathObjectPtr obj;
-+ char *str;
-+ long l_tmp;
-+
-+ /* FIXME: This could use some better error reporting... */
-+ root = xmlDocGetRootElement(doc);
-+ if (!root || !xmlStrEqual(root->name, BAD_CAST "domain"))
-+ goto err;
-+
-+ xpath = xmlXPathNewContext(doc);
-+ if (!xpath)
-+ goto err;
-+
-+ if (virXPathLong("string(/domain[1]/@id)", xpath, &l_tmp) != 0)
-+ goto err;
-+ guest->xid = (int) l_tmp;
-+
-+ str = virXPathString("string(/domain/name[1])", xpath);
-+ if (!str)
-+ goto err;
-+ strncpy(guest->name, str, VSERVER_NAME_MAX - 1);
-+
-+ str = virXPathString("string(/domain/uuid[1])", xpath);
-+ if (!str) {
-+ if (virUUIDGenerate(guest->uuid) != 0)
-+ goto err;
-+ }
-+ else if (virUUIDParse(str, guest->uuid) < 0)
-+ goto err;
-+
-+ guest->rss_hard = 0;
-+ if (virXPathLong("string(/domain/memory[1])", xpath, (long *) &guest->rss_hard) == -2)
-+ goto err;
-+ guest->rss_hard >>= PAGE_SHIFT_TO_KIBI;
-+
-+ str = virXPathString("string(/domain/os[1]/hostname[1])", xpath);
-+ if (str)
-+ strncpy(guest->uts.hostname, str, VSERVER_UTS_MAX - 1);
-+
-+ str = virXPathString("string(/domain/os[1]/type[1]/@arch)", xpath);
-+ if (str)
-+ strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
-+
-+ str = virXPathString("string(/domain/os[1]/release[1])", xpath);
-+ if (str)
-+ strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
-+
-+ str = virXPathString("string(/domain/os[1]/version[1])", xpath);
-+ if (str)
-+ strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
-+
-+ str = virXPathString("string(/domain/container/initstyle[1]/@type)", xpath);
-+ guest->initstyle = VSERVER_INIT_SYSV;
-+ if (str) {
-+ if (strcmp(str, "plain") == 0)
-+ guest->initstyle = VSERVER_INIT_PLAIN;
-+ else if (strcmp(str, "gentoo") == 0)
-+ guest->initstyle = VSERVER_INIT_GENTOO;
-+ else if (strcmp(str, "minit") == 0)
-+ guest->initstyle = VSERVER_INIT_MINIT;
-+ else if (strcmp(str, "sysv") == 0)
-+ guest->initstyle = VSERVER_INIT_SYSV;
-+ }
-+
-+ obj = xmlXPathEval(BAD_CAST "/domain/devices[1]/interface/ip", xpath);
-+ if (obj != NULL && obj->type == XPATH_NODESET && obj->nodesetval != NULL &&
-+ obj->nodesetval->nodeNr > 0) {
-+ int i;
-+ struct vserver_ip *ip = NULL;
-+
-+ for (i = 0; i < obj->nodesetval->nodeNr; i++) {
-+ if (ip == NULL)
-+ guest->ips = ip = calloc(1, sizeof(*ip));
-+ else {
-+ ip->next = calloc(1, sizeof(*ip));
-+ ip = ip->next;
-+ }
-+
-+ if (vserverParseIP(ip, obj->nodesetval->nodeTab[i]) == -1)
-+ goto nodeset_err;
-+ }
-+ }
-+ if (obj)
-+ xmlXPathFreeObject(obj);
-+
-+ obj = xmlXPathEval(BAD_CAST "/domain/devices[1]/disk", xpath);
-+ if (obj != NULL && obj->type == XPATH_NODESET && obj->nodesetval != NULL &&
-+ obj->nodesetval->nodeNr > 0) {
-+ int i;
-+ struct vserver_fstab *ent = NULL;
-+
-+ for (i = 0; i < obj->nodesetval->nodeNr; i++) {
-+ if (ent == NULL)
-+ guest->fstab = ent = calloc(1, sizeof(*ent));
-+ else {
-+ ent->next = calloc(1, sizeof(*ent));
-+ ent = ent->next;
-+ }
-+
-+ if (vserverParseDisk(ent, obj->nodesetval->nodeTab[i]) == -1)
-+ goto nodeset_err;
-+ }
-+ }
-+ if (obj)
-+ xmlXPathFreeObject(obj);
-+
-+ xmlXPathFreeContext(xpath);
-+ xpath = NULL;
-+
-+ return 0;
-+
-+nodeset_err:
-+ xmlXPathFreeObject(obj);
-+err:
-+ if (xpath)
-+ xmlXPathFreeContext(xpath);
-+ return -1;
-+}
-+
-+static virDomainPtr
-+vserverDomainDefineXML(virConnectPtr conn, const char *xml)
-+{
-+ struct vserver_driver *driver = conn->privateData;
-+ struct vserver_guest *guest, *tail;
-+ virDomainPtr domain;
-+ xmlDocPtr doc;
-+ char buf[128];
-+
-+ if ((guest = calloc(1, sizeof(struct vserver_guest))) == NULL) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "vserver_guest");
-+ return NULL;
-+ }
-+
-+ if ((doc = xmlReadDoc(BAD_CAST xml, "domain.xml", NULL,
-+ XML_PARSE_NOENT | XML_PARSE_NONET |
-+ XML_PARSE_NOWARNING | XML_PARSE_NOERROR)) == NULL) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
-+ free(guest);
-+ return NULL;
-+ }
-+
-+ if (vserverParseXML(guest, doc) == -1) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
-+ xmlFreeDoc(doc);
-+ free(guest);
-+ return NULL;
-+ }
-+
-+ xmlFreeDoc(doc);
-+
-+ guest->path = calloc(sizeof(VSERVER_CONF_DIR "/") + strlen(guest->name), sizeof(char));
-+ sprintf(guest->path, VSERVER_CONF_DIR "/%s", guest->name);
-+ guest->status = VIR_DOMAIN_SHUTOFF;
-+ if (vserverRunCommand(0, PROG_VSERVER, guest->name, "build", "-m",
-+ "skeleton", "--confdir", guest->path, NULL) != 0) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, "vserver build");
-+ free(guest);
-+ return NULL;
-+ }
-+ virUUIDFormat(guest->uuid, buf);
-+ if (vserverWriteGuestToConfig(guest) == -1) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, "vserverWriteToConfig");
-+ free(guest);
-+ return NULL;
-+ }
-+
-+ /* add it to the list */
-+ for (tail = driver->guests; tail && tail->next; tail = tail->next)
-+ ;
-+ if (!tail)
-+ driver->guests = guest;
-+ else
-+ tail->next = guest;
-+
-+ driver->inactive_guests++;
-+
-+ domain = virGetDomain(conn, guest->name, guest->uuid);
-+ if (!domain)
-+ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
-+
-+ return domain;
-+}
-+
-+static int
-+vserverListDefinedDomains(virConnectPtr conn, char **const names,
-+ int maxnames)
-+{
-+ struct vserver_driver *driver = conn->privateData;
-+ struct vserver_guest *guest;
-+ int i = 0;
-+
-+ for (guest = driver->guests; guest && i < maxnames; guest = guest->next) {
-+ if (guest->status == VIR_DOMAIN_SHUTOFF) {
-+ if ((names[i++] = strdup(guest->name)) == NULL) {
-+ vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "names");
-+ return -1;
-+ }
-+ }
-+ }
-+
-+ return i;
-+}
-+
-+static int
-+vserverNumOfDefinedDomains(virConnectPtr conn)
-+{
-+ struct vserver_driver *driver = conn->privateData;
-+
-+ return driver->inactive_guests;
-+}
-+
-+static int
-+vserverDomainCreate(virDomainPtr domain)
-+{
-+ GET_DOMAIN(domain, -1);
-+
-+ if (vserverRunCommand(1, PROG_VSERVER, guest->path, "start", NULL) != 0) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ "vserver start");
-+ return -1;
-+ }
-+
-+ driver->inactive_guests--;
-+ guest->status = VIR_DOMAIN_RUNNING;
-+ driver->active_guests++;
-+ return 0;
-+}
-+
-+static virDomainPtr
-+vserverDomainCreateLinux(virConnectPtr conn, const char *xml,
-+ unsigned int flags ATTRIBUTE_UNUSED)
-+{
-+ virDomainPtr domain;
-+
-+ domain = vserverDomainDefineXML(conn, xml);
-+ if (!domain)
-+ return NULL;
-+
-+ if (vserverDomainCreate(domain) == -1)
-+ return NULL;
-+
-+ return domain;
-+}
-+
-+static int
-+vserverDomainUndefine(virDomainPtr domain)
-+{
-+ struct vserver_guest *prev;
-+ GET_DOMAIN(domain, -1);
-+
-+ for (prev = driver->guests; prev; prev = prev->next) {
-+ if (prev->next == guest)
-+ break;
-+ }
-+ if (!prev) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
-+ _("domain not found"));
-+ return -1;
-+ }
-+ if (vserverIsRunning(guest)) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG,
-+ _("domain is running"));
-+ return -1;
-+ }
-+
-+ driver->inactive_guests--;
-+ prev->next = guest->next;
-+ /* XXX: deletes the domain's contents as well */
-+ vserverRunCommand(0, PROG_VSERVER, "--silent", guest->path, "delete", NULL);
-+ free(guest);
-+
-+ return 0;
-+}
-+
-+static int
-+doMount(int do_umount, struct vserver_guest *guest, struct vserver_fstab *ent)
-+{
-+ pid_t child;
-+ int status;
-+
-+ if ((child = fork()) == 0) {
-+ if (vc_enter_namespace(guest->xid, CLONE_NEWNS|CLONE_FS) == -1)
-+ _exit(errno);
-+ if (do_umount) {
-+ if (sys_umount(ent->target, MNT_DETACH) == -1)
-+ _exit(errno);
-+ }
-+ else {
-+ char target[strlen(guest->path) + sizeof("/vdir/") + strlen(ent->target)];
-+ sprintf(target, "%s/vdir/%s", guest->path, ent->target);
-+ if (vserverRunCommand(0, "mount", "-t", ent->fstype, "-n", "-o",
-+ ent->options, ent->source, target, NULL))
-+ _exit(errno);
-+ }
-+ _exit(0);
-+ }
-+ else if (child == -1)
-+ return -1;
-+ else {
-+ if (waitpid(child, &status, 0) == -1)
-+ return -1;
-+ if (WEXITSTATUS(status) != 0) {
-+ errno = WEXITSTATUS(status);
-+ return -1;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+vserverDomainHandleDevice(virDomainPtr domain, const char *xml, int attach)
-+{
-+ xmlDocPtr doc;
-+ xmlNodePtr node;
-+ GET_DOMAIN(domain, -1);
-+
-+ if ((doc = xmlReadDoc(BAD_CAST xml, "device.xml", NULL,
-+ XML_PARSE_NOENT | XML_PARSE_NONET |
-+ XML_PARSE_NOWARNING | XML_PARSE_NOERROR)) == NULL) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR, _("device"));
-+ return -1;
-+ }
-+
-+ node = xmlDocGetRootElement(doc);
-+ if (node == NULL) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
-+ _("missing root element"));
-+ return -1;
-+ }
-+
-+ if (xmlStrEqual(node->name, BAD_CAST "interface")) {
-+ xmlNodePtr child;
-+ struct vserver_ip *ip;
-+
-+ for (child = node->children; child; child = child->next) {
-+ if (child->type != XML_ELEMENT_NODE)
-+ continue;
-+
-+ /* This should be an only child, but who knows. */
-+ if (xmlStrEqual(child->name, BAD_CAST "ip"))
-+ break;
-+ }
-+ if (!child) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
-+ _("no <ip> element found"));
-+ return -1;
-+ }
-+
-+ ip = calloc(1, sizeof(*ip));
-+ if (vserverParseIP(ip, child) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
-+ _("parsing IP failed"));
-+ return -1;
-+ }
-+
-+ if (attach) {
-+ list_add_tail(guest->ips, ip);
-+ if (vserverIsRunning(guest)) {
-+ if (vc_net_add(guest->xid, &ip->addr) == -1) {
-+ vserverError(domain->conn, domain, NULL,
-+ VIR_ERR_SYSTEM_ERROR, strerror(errno));
-+ return -1;
-+ }
-+ }
-+ }
-+
-+ else /* detach */ {
-+ struct vserver_ip *i, *p = NULL;
-+ for (i = guest->ips; i; i = i->next) {
-+ if (strcmp(ip->interface, i->interface) == 0 &&
-+ memcmp(&ip->addr, &i->addr, sizeof(ip->addr)) == 0)
-+ break;
-+ p = i;
-+ }
-+ if (i) {
-+ if (p)
-+ p->next = i->next;
-+ else
-+ guest->ips = i->next;
-+ if (vserverIsRunning(guest)) {
-+ /* Not a lot of kernels support this, so don't fail. */
-+ vc_net_remove(guest->xid, &ip->addr);
-+ }
-+ free(i);
-+ }
-+ free(ip);
-+ }
-+ }
-+ else if (xmlStrEqual(node->name, BAD_CAST "disk")) {
-+ struct vserver_fstab *ent = calloc(1, sizeof(*ent));
-+ if (!ent) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY, NULL);
-+ return -1;
-+ }
-+
-+ if (vserverParseDisk(ent, node) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR, "disk");
-+ return -1;
-+ }
-+
-+ if (attach) {
-+ list_add_tail(guest->fstab, ent);
-+ if (vserverIsRunning(guest)) {
-+ if (doMount(0, guest, ent) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ strerror(errno));
-+ return -1;
-+ }
-+ }
-+ }
-+
-+ else /* detach */ {
-+ struct vserver_fstab *i, *p = NULL;
-+ for (i = guest->fstab; i; i = i->next) {
-+ /* These are the fields we care about */
-+ if (strcmp(ent->source, i->source) == 0 &&
-+ strcmp(ent->target, i->target) == 0 &&
-+ strcmp(ent->source_type, i->source_type) == 0)
-+ break;
-+ p = i;
-+ }
-+ if (i) {
-+ if (p)
-+ p->next = i->next;
-+ else
-+ guest->fstab = i->next;
-+ if (vserverIsRunning(guest)) {
-+ if (doMount(1, guest, ent) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ strerror(errno));
-+ return -1;
-+ }
-+ }
-+ freeFstab(i);
-+ }
-+ freeFstab(ent);
-+ }
-+ }
-+ else {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
-+ _("unknown device type"));
-+ return -1;
-+ }
-+
-+ /* Both fstab and interfaces need a lot of writing, so write the whole thing */
-+ if (vserverWriteGuestToConfig(guest) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_WRITE_FAILED, guest->name);
-+ return -1;
-+ }
-+
-+ xmlFreeDoc(doc);
-+
-+ return 0;
-+}
-+
-+static int
-+vserverDomainAttachDevice(virDomainPtr domain, const char *xml)
-+{
-+ return vserverDomainHandleDevice(domain, xml, 1);
-+}
-+
-+static int
-+vserverDomainDetachDevice(virDomainPtr domain, const char *xml)
-+{
-+ return vserverDomainHandleDevice(domain, xml, 0);
-+}
-+
-+static int
-+vserverDomainGetAutostart(virDomainPtr domain, int *autostart)
-+{
-+ GET_DOMAIN(domain, -1);
-+
-+ *autostart = guest->autostart;
-+ return 0;
-+}
-+
-+static int
-+vserverDomainSetAutostart(virDomainPtr domain, int autostart)
-+{
-+ GET_DOMAIN(domain, -1);
-+
-+ if (vserverWriteToConfig(guest, "apps/init/mark",
-+ (autostart ? "default\n" : "\n")) == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_WRITE_FAILED,
-+ "apps/init/mark");
-+ return -1;
-+ }
-+ guest->autostart = autostart;
-+ return 0;
-+}
-+
-+static const struct {
-+ unsigned int id;
-+ const char *field;
-+ int type;
-+} sched_fields[] = {
-+ { VC_VXSM_FILL_RATE, "fill_rate1", VIR_DOMAIN_SCHED_FIELD_UINT },
-+ { VC_VXSM_INTERVAL, "interval1", VIR_DOMAIN_SCHED_FIELD_UINT },
-+ { VC_VXSM_FILL_RATE2, "fill_rate2", VIR_DOMAIN_SCHED_FIELD_UINT },
-+ { VC_VXSM_INTERVAL2, "interval2", VIR_DOMAIN_SCHED_FIELD_UINT },
-+ { VC_VXSM_TOKENS_MIN, "tokens_min", VIR_DOMAIN_SCHED_FIELD_UINT },
-+ { VC_VXSM_TOKENS_MAX, "tokens_max", VIR_DOMAIN_SCHED_FIELD_UINT },
-+ { VC_VXSM_PRIO_BIAS, "prio_bias", VIR_DOMAIN_SCHED_FIELD_INT },
-+ { VC_VXSM_IDLE_TIME, "idle_time", VIR_DOMAIN_SCHED_FIELD_BOOLEAN },
-+ { 0, NULL, 0 }
-+};
-+
-+static char *
-+vserverDomainGetSchedulerType(virDomainPtr domain, int *nparams)
-+{
-+ char *ret;
-+ int i;
-+ GET_DOMAIN(domain, NULL);
-+
-+ ret = strdup(guest->sched.set_mask & VC_VXSM_IDLE_TIME ? "fair" : "hard");
-+ if (!ret) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY,
-+ _("scheduler"));
-+ return NULL;
-+ }
-+
-+ *nparams = 0;
-+ for (i = 0; sched_fields[i].field != NULL; i++) {
-+ /* only returns fields which are set */
-+ if (guest->sched.set_mask & sched_fields[i].id)
-+ (*nparams)++;
-+ }
-+
-+ return ret;
-+}
-+
-+static int
-+vserverDomainGetSchedulerParams(virDomainPtr domain,
-+ virSchedParameterPtr params,
-+ int *nparams)
-+{
-+ int i, j;
-+ GET_DOMAIN(domain, -1);
-+
-+ for (i = 0, j = 0; sched_fields[i].field != NULL && i < *nparams; i++) {
-+ /* skip unset fields */
-+ if (!(guest->sched.set_mask & sched_fields[i].id))
-+ continue;
-+
-+ params[j].type = sched_fields[i].type;
-+ strncpy(params[j].field, sched_fields[i].field, sizeof(params[j].field) - 1);
-+ switch (sched_fields[i].id) {
-+ case VC_VXSM_FILL_RATE:
-+ params[j].value.ui = guest->sched.fill_rate;
-+ break;
-+ case VC_VXSM_INTERVAL:
-+ params[j].value.ui = guest->sched.interval;
-+ break;
-+ case VC_VXSM_FILL_RATE2:
-+ params[j].value.ui = guest->sched.fill_rate2;
-+ break;
-+ case VC_VXSM_INTERVAL2:
-+ params[j].value.ui = guest->sched.interval2;
-+ break;
-+ case VC_VXSM_TOKENS_MIN:
-+ params[j].value.ui = guest->sched.tokens_min;
-+ break;
-+ case VC_VXSM_TOKENS_MAX:
-+ params[j].value.ui = guest->sched.tokens_max;
-+ break;
-+ case VC_VXSM_PRIO_BIAS:
-+ params[j].value.i = guest->sched.priority_bias;
-+ break;
-+ case VC_VXSM_IDLE_TIME:
-+ params[j].value.b = guest->sched.set_mask & VC_VXSM_IDLE_TIME;
-+ break;
-+ }
-+ j++;
-+ }
-+ *nparams = j;
-+
-+ return 0;
-+}
-+
-+static int
-+vserverDomainSetSchedulerParams(virDomainPtr domain,
-+ virSchedParameterPtr params,
-+ int nparams)
-+{
-+ int i, j, cret;
-+ GET_DOMAIN(domain, -1);
-+
-+ for (i = 0; i < nparams; i++) {
-+ for (j = 0; sched_fields[j].field != NULL; j++) {
-+ if (STREQ(sched_fields[j].field, params[i].field))
-+ break;
-+ }
-+ if (sched_fields[j].field == NULL) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "field");
-+ return -1;
-+ }
-+ if (sched_fields[j].type != params[i].type) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "type");
-+ return -1;
-+ }
-+ switch (sched_fields[j].id) {
-+ case VC_VXSM_FILL_RATE:
-+ guest->sched.fill_rate = params[i].value.ui;
-+ cret = vserverWriteToConfig(guest, "sched/fill-rate", "%u\n",
-+ params[i].value.ui);
-+ break;
-+ case VC_VXSM_INTERVAL:
-+ guest->sched.interval = params[i].value.ui;
-+ cret = vserverWriteToConfig(guest, "sched/interval", "%u\n",
-+ params[i].value.ui);
-+ break;
-+ case VC_VXSM_FILL_RATE2:
-+ guest->sched.fill_rate2 = params[i].value.ui;
-+ cret = vserverWriteToConfig(guest, "sched/fill-rate2", "%u\n",
-+ params[i].value.ui);
-+ break;
-+ case VC_VXSM_INTERVAL2:
-+ guest->sched.interval2 = params[i].value.ui;
-+ cret = vserverWriteToConfig(guest, "sched/interval2", "%u\n",
-+ params[i].value.ui);
-+ break;
-+ case VC_VXSM_TOKENS_MIN:
-+ guest->sched.tokens_min = params[i].value.ui;
-+ cret = vserverWriteToConfig(guest, "sched/tokens-min", "%u\n",
-+ params[i].value.ui);
-+ break;
-+ case VC_VXSM_TOKENS_MAX:
-+ guest->sched.tokens_max = params[i].value.ui;
-+ cret = vserverWriteToConfig(guest, "sched/tokens-max", "%u\n",
-+ params[i].value.ui);
-+ break;
-+ case VC_VXSM_PRIO_BIAS:
-+ guest->sched.priority_bias = params[i].value.i;
-+ cret = vserverWriteToConfig(guest, "sched/prio-bias", "%d\n",
-+ params[i].value.i);
-+ break;
-+ case VC_VXSM_IDLE_TIME:
-+ cret = vserverWriteToConfig(guest, "sched/idle-time", "%b",
-+ params[i].value.b);
-+ break;
-+ default:
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
-+ "Unknown scheduler parameter");
-+ return -1;
-+ }
-+ if (cret == -1) {
-+ vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
-+ "vserverWriteToConfig");
-+ return -1;
-+ }
-+ guest->sched.set_mask |= sched_fields[j].id;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+virDriver vserverDriver = {
-+ VIR_DRV_VSERVER,
-+ "Linux-VServer",
-+ LIBVIR_VERSION_NUMBER,
-+ vserverOpen,
-+ vserverClose,
-+ NULL, /* supports_feature */
-+ vserverGetType,
-+ vserverGetVersion,
-+ vserverGetHostname,
-+ vserverGetURI,
-+ NULL, /* getMaxVcpus */
-+ vserverNodeGetInfo,
-+ NULL, /* getCapabilties */
-+ vserverListDomains,
-+ vserverNumOfDomains,
-+ vserverDomainCreateLinux,
-+ vserverDomainLookupByID,
-+ vserverDomainLookupByUUID,
-+ vserverDomainLookupByName,
-+ vserverDomainSuspend,
-+ vserverDomainResume,
-+ vserverDomainShutdown,
-+ vserverDomainReboot,
-+ vserverDomainDestroy,
-+ vserverDomainGetOSType,
-+ vserverDomainGetMaxMemory,
-+ vserverDomainSetMaxMemory,
-+ NULL, /* domainSetMemory */
-+ vserverDomainGetInfo,
-+ NULL, /* domainSave */
-+ NULL, /* domainRestore */
-+ NULL, /* domainCoreDump */
-+ NULL, /* domainSetVcpus */
-+ NULL, /* domainPinVcpu */
-+ NULL, /* domainGetVcpus */
-+ NULL, /* domainGetMaxVcpus */
-+ vserverDomainDumpXML,
-+ vserverListDefinedDomains,
-+ vserverNumOfDefinedDomains,
-+ vserverDomainCreate,
-+ vserverDomainDefineXML,
-+ vserverDomainUndefine,
-+ vserverDomainAttachDevice,
-+ vserverDomainDetachDevice,
-+ vserverDomainGetAutostart,
-+ vserverDomainSetAutostart,
-+ vserverDomainGetSchedulerType,
-+ vserverDomainGetSchedulerParams,
-+ vserverDomainSetSchedulerParams,
-+ NULL, /* domainMigratePrepare */
-+ NULL, /* domainMigratePerform */
-+ NULL, /* domainMigrateFinish */
-+ NULL, /* domainBlockStats */
-+ NULL, /* domainInterfaceStats */
-+ NULL, /* nodeGetCellsFreeMemory */
-+ NULL, /* getFreeMemory */
-+};
-+
-+int vserverRegister(void)
-+{
-+ if (virRegisterDriver(&vserverDriver) < 0)
-+ return -1;
-+ return 0;
-+}
-+
-+#endif
---- libvirt-0.4.0.orig/src/vserver/vserver_driver.h 1970-01-01 01:00:00.000000000 +0100
-+++ libvirt-0.4.0.vserver/src/vserver/vserver_driver.h 2008-01-09 19:14:08.000000000 +0100
-@@ -0,0 +1,137 @@
-+/*
-+ * Core driver for managing Linux-VServer guests
-+ *
-+ * Copyright (C) 2007 Daniel Hokka Zakrisson
-+ *
-+ * This library is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * This library is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ *
-+ * Author: Daniel Hokka Zakrisson <daniel hozac com>
-+ */
-+
-+#ifdef WITH_VSERVER
-+
-+/* Kind of a hack */
-+#ifdef IN_VSERVER
-+#ifndef HAVE_XID_T
-+typedef unsigned int xid_t;
-+#endif
-+#ifndef HAVE_NID_T
-+typedef unsigned int nid_t;
-+#endif
-+#ifndef HAVE_TAG_T
-+typedef unsigned int tag_t;
-+#endif
-+#include <vserver.h>
-+
-+#define VSERVER_NAME_MAX 64
-+#define VSERVER_UTS_MAX 255
-+
-+enum vserver_initstyle {
-+ VSERVER_INIT_NONE,
-+ VSERVER_INIT_SYSV,
-+ VSERVER_INIT_PLAIN,
-+ VSERVER_INIT_GENTOO,
-+ VSERVER_INIT_MINIT,
-+};
-+
-+struct vserver_ip {
-+ char interface[IFNAMSIZ+1];
-+ struct vc_net_addr addr;
-+ struct vserver_ip *next;
-+};
-+
-+enum fstab_flags {
-+ VSERVER_FSTAB_SHOW=1,
-+ VSERVER_FSTAB_OUTPUT=2,
-+};
-+struct vserver_fstab {
-+ char *source;
-+ const char *source_type;
-+ char *target;
-+ char *fstype;
-+ char *options;
-+ char *rest;
-+ int flags;
-+ struct vserver_fstab *next;
-+};
-+
-+struct vserver_guest {
-+ xid_t xid;
-+ char name[VSERVER_NAME_MAX];
-+ unsigned char uuid[VIR_UUID_BUFLEN];
-+ char *path;
-+
-+ struct {
-+ char hostname[VSERVER_UTS_MAX];
-+ char machine[VSERVER_UTS_MAX];
-+ char release[VSERVER_UTS_MAX];
-+ char version[VSERVER_UTS_MAX];
-+ } uts;
-+
-+ struct vserver_ip *ips;
-+
-+ struct vc_set_sched sched;
-+ unsigned long rss_hard;
-+
-+ char autostart;
-+ enum vserver_initstyle initstyle;
-+
-+ int status;
-+
-+ struct vserver_fstab *fstab;
-+
-+ struct vserver_guest *next;
-+};
-+
-+struct vserver_driver {
-+ struct vserver_guest *guests;
-+ xmlChar *uri;
-+ unsigned int active_guests;
-+ unsigned int inactive_guests;
-+ unsigned int initialized : 1;
-+};
-+
-+
-+#define list_add_tail(list, elem) \
-+ do { \
-+ __typeof__(list) iter; \
-+ if (list) { \
-+ for (iter = list; iter->next; iter = iter->next) \
-+ ; \
-+ iter->next = elem; \
-+ } \
-+ else \
-+ list = elem; \
-+ } while (0)
-+
-+static inline int
-+vserverIsRunning(struct vserver_guest *guest) {
-+ if (guest->status == VIR_DOMAIN_RUNNING || guest->status == VIR_DOMAIN_PAUSED)
-+ return 1;
-+ else
-+ return 0;
-+}
-+
-+
-+int vserverContextIsRunning(const char *path);
-+int vserverRunCommand(int do_daemon, const char *cmd, ...);
-+void vserverError(virConnectPtr con, virDomainPtr dom, virNetworkPtr net,
-+ virErrorNumber error, const char *info);
-+#endif
-+
-+
-+extern int vserverRegister(void);
-+
-+#endif