]> TLD Linux GIT Repositories - packages/libvirt.git/blob - vserver.patch
- updated to 1.2.14, killed systemd stuff
[packages/libvirt.git] / vserver.patch
1 https://www.redhat.com/archives/libvir-list/2008-January/msg00097.html
2
3 From: "Daniel Hokka Zakrisson" <daniel hozac com>
4 To: libvir-list redhat com
5 Subject: [Libvir] [PATCH] Linux-VServer support
6 Date: Wed, 9 Jan 2008 22:51:20 +0100 (CET)
7
8 This patch implements support for Linux-VServer guests. It is currently
9 missing vcpu and console support, and the necessary virsh code to support
10 it, but is otherwise pretty feature complete.
11
12 This is an XML dump from one of my guests:
13 <domain type='vserver' id='40010'>
14   <name>lenny</name>
15   <uuid>19e12957-261a-5a06-d6d0-89917d6d439f</uuid>
16   <memory>2048000</memory>
17   <os>
18     <hostname>lenny.test</hostname>
19     <type arch='i686'>vserver</type>
20   </os>
21   <devices>
22     <interface type='ethernet'>
23       <ip prefix='24' interface='dummy0' address='192.168.20.4' />
24     </interface>
25     <interface type='ethernet'>
26       <ip prefix='24' interface='dummy0' type='range' address='192.168.32.100' address2='192.168.32.200'/>
27     </interface>
28     <disk type='directory' device='directory'>
29       <source directory='/vservers/lenny' type='auto' options='defaults'/>
30       <target directory='/'/>
31     </disk>
32     <disk type='directory' device='directory'>
33       <source directory='/srv' type='ext3' options='bind,ro'/>
34       <target directory='/srv'/>
35     </disk>
36     <disk type='block' device='directory'>
37        <source dev='/dev/mapper/test' type='ext3' options='defaults'/>
38        <target directory='/mnt'/>
39     </disk>
40   </devices>
41 </domain>
42
43 -- 
44 Daniel Hokka Zakrisson
45 --- libvirt-1.2.3/configure.ac~ 2014-04-06 12:21:22.000000000 +0300
46 +++ libvirt-1.2.3/configure.ac  2014-04-06 12:22:55.249258975 +0300
47 @@ -546,6 +546,10 @@
48    [AS_HELP_STRING([--with-parallels],
49      [add Parallels Cloud Server support @<:@default=check@:>@])])
50  m4_divert_text([DEFAULTS], [with_parallels=check])
51 +AC_ARG_WITH([vserver],
52 +  [AS_HELP_STRING([--with-vserver],
53 +    [add Linux-VServer support @<:@default=check@:>@])])
54 +m4_divert_text([DEFAULTS], [with_vserver=check])
55  AC_ARG_WITH([test],
56    [AS_HELP_STRING([--with-test],
57      [add test driver support @<:@default=yes@:>@])])
58 @@ -991,6 +991,39 @@
59    fi
60  fi
61  
62 +if test "$with_vserver" = "yes" ; then
63 +    AC_CHECK_LIB(vserver, [vc_rlimit_stat],, [with_vserver=no])
64 +    AC_CHECK_TYPES([xid_t, nid_t, tag_t])
65 +    AC_CHECK_HEADER(vserver.h,, [with_vserver=no], [AC_INCLUDES_DEFAULT()
66 +#ifndef HAVE_XID_T
67 +typedef unsigned int xid_t;
68 +#endif
69 +#ifndef HAVE_NID_T
70 +typedef unsigned int nid_t;
71 +#endif
72 +#ifndef HAVE_TAG_T
73 +typedef unsigned int tag_t;
74 +#endif])
75 +
76 +    AC_MSG_CHECKING([for vserver configuration directory])
77 +    VSERVER_CONF_DIR=`env PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" \
78 +        vserver-info - SYSINFO | sed -n 's/^.*cfg-Directory:.//p'`
79 +    AC_MSG_RESULT([$VSERVER_CONF_DIR])
80 +    AC_DEFINE_UNQUOTED([VSERVER_CONF_DIR], ["$VSERVER_CONF_DIR"],
81 +        [The default path to the Linux-VServer configuration files])
82 +
83 +    AC_MSG_CHECKING([for the vserver program])
84 +    PROG_VSERVER=`env PATH="/sbin:/usr/sbin:/usr/local/sbin:$PATH" \
85 +        which vserver 2> /dev/null` || with_vserver=no
86 +    AC_MSG_RESULT([$PROG_VSERVER])
87 +    AC_DEFINE_UNQUOTED([PROG_VSERVER], ["$PROG_VSERVER"],
88 +        [The path to the vserver program])
89 +
90 +    if test "$with_vserver" = "yes" ; then
91 +        LIBVIRT_FEATURES="$LIBVIRT_FEATURES -DWITH_VSERVER"
92 +    fi
93 +fi
94 +
95  
96  dnl
97  dnl check for kernel headers required by src/bridge.c
98 @@ -2759,6 +2759,7 @@
99  AC_MSG_NOTICE([      ESX: $with_esx])
100  AC_MSG_NOTICE([  Hyper-V: $with_hyperv])
101  AC_MSG_NOTICE([Parallels: $with_parallels])
102 +AC_MSG_NOTICE([  VServer: $with_vserver])
103  LIBVIRT_DRIVER_RESULT_BHYVE
104  AC_MSG_NOTICE([     Test: $with_test])
105  AC_MSG_NOTICE([   Remote: $with_remote])
106 --- libvirt-1.1.1/include/libvirt/virterror.h~  2013-07-24 03:23:07.000000000 +0300
107 +++ libvirt-1.1.1/include/libvirt/virterror.h   2013-09-01 00:07:44.097192613 +0300
108 @@ -121,6 +121,8 @@
109      VIR_FROM_ACCESS = 55,       /* Error from access control manager */
110      VIR_FROM_SYSTEMD = 56,      /* Error from systemd code */
111  
112 +    VIR_FROM_VSERVER = 57,      /* Error from Linux-VServer driver */
113 +
114  # ifdef VIR_ENUM_SENTINELS
115      VIR_ERR_DOMAIN_LAST
116  # endif
117 --- libvirt-1.2.3/src/driver.h~ 2014-03-27 12:35:00.000000000 +0200
118 +++ libvirt-1.2.3/src/driver.h  2014-04-06 12:25:03.124800629 +0300
119 @@ -48,6 +48,7 @@
120      VIR_DRV_HYPERV = 15,
121      VIR_DRV_PARALLELS = 16,
122      VIR_DRV_BHYVE = 17,
123 +    VIR_DRV_VSERVER = 18,
124  } virDrvNo;
125  
126  
127 --- libvirt-1.1.1/src/libvirt.c~        2013-09-01 00:20:50.000000000 +0300
128 +++ libvirt-1.1.1/src/libvirt.c 2013-09-01 00:21:02.812830784 +0300
129 @@ -94,6 +94,9 @@
130  #ifdef WITH_PARALLELS
131  # include "parallels/parallels_driver.h"
132  #endif
133 +#ifdef WITH_VSERVER
134 +# include "server/vserver_driver.h"
135 +#endif
136  
137  #define VIR_FROM_THIS VIR_FROM_NONE
138  
139 @@ -479,6 +482,10 @@
140      if (parallelsRegister() == -1)
141          goto error;
142  #endif
143 +#ifdef WITH_VSERVER
144 +    if (verversRegister() == -1)
145 +        goto error;
146 +#endif
147  #ifdef WITH_REMOTE
148      if (remoteRegister() == -1)
149          goto error;
150 --- libvirt-1.1.1/src/Makefile.am~      2013-07-30 10:21:31.000000000 +0300
151 +++ libvirt-1.1.1/src/Makefile.am       2013-09-01 00:11:19.080124997 +0300
152 @@ -467,6 +467,7 @@
153         $(NWFILTER_DRIVER_SOURCES) \
154         $(OPENVZ_DRIVER_SOURCES) \
155         $(PARALLELS_DRIVER_SOURCES) \
156 +       $(VSERVER_DRIVER_SOURCES) \
157         $(PHYP_DRIVER_SOURCES) \
158         $(QEMU_DRIVER_SOURCES) \
159         $(REMOTE_DRIVER_SOURCES) \
160 @@ -727,6 +728,12 @@
161                 parallels/parallels_storage.c           \
162                 parallels/parallels_network.c
163  
164 +VSERVER_DRIVER_SOURCES =                                       \
165 +               vserver/vserver_driver.h                        \
166 +               vserver/vserver_driver.c                        \
167 +               vserver/vserver_conf.h                          \
168 +               vserver/vserver_conf.c
169 +
170  NETWORK_DRIVER_SOURCES =                                       \
171                 network/bridge_driver.h network/bridge_driver.c
172  
173 --- libvirt-1.2.3/src/util/virerror.c~  2014-03-27 12:35:01.000000000 +0200
174 +++ libvirt-1.2.3/src/util/virerror.c   2014-04-06 12:25:58.523869047 +0300
175 @@ -127,6 +127,7 @@
176  
177                "Access Manager", /* 55 */
178                "Systemd",
179 +              "Vserver",
180                "Bhyve",
181                "Crypto",
182      )
183 --- libvirt-0.4.0.orig/src/vserver/vserver_conf.c       1970-01-01 01:00:00.000000000 +0100
184 +++ libvirt-0.4.0.vserver/src/vserver/vserver_conf.c    2008-01-09 08:52:11.000000000 +0100
185 @@ -0,0 +1,751 @@
186 +/*
187 + * Configuration handling for Linux-VServer guests
188 + *
189 + * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
190 + *
191 + * This library is free software; you can redistribute it and/or
192 + * modify it under the terms of the GNU Lesser General Public
193 + * License as published by the Free Software Foundation; either
194 + * version 2.1 of the License, or (at your option) any later version.
195 + *
196 + * This library is distributed in the hope that it will be useful,
197 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
198 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
199 + * Lesser General Public License for more details.
200 + *
201 + * You should have received a copy of the GNU Lesser General Public
202 + * License along with this library; if not, write to the Free Software
203 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
204 + *
205 + * Author: Daniel Hokka Zakrisson <daniel hozac com>
206 + */
207 +
208 +#ifdef WITH_VSERVER
209 +
210 +#define _GNU_SOURCE
211 +
212 +#ifdef HAVE_CONFIG_H
213 +#  include <config.h>
214 +#endif
215 +
216 +#include <stdio.h>
217 +#include <unistd.h>
218 +#include <stdlib.h>
219 +#include <fcntl.h>
220 +#include <dirent.h>
221 +#include <errno.h>
222 +#include <sys/types.h>
223 +#include <sys/socket.h>
224 +#include <arpa/inet.h>
225 +#include <net/if.h>
226 +#include <sys/stat.h>
227 +#include <ctype.h>
228 +
229 +#include <libvirt/virterror.h>
230 +
231 +#define IN_VSERVER 1
232 +#include "internal.h"
233 +#include "vserver_driver.h"
234 +#include "vserver_conf.h"
235 +#include "uuid.h"
236 +
237 +static int
238 +readStr(char *dst, size_t len, const char *name, const char *setting)
239 +{
240 +    char file[strlen(name) + strlen(setting) + 2];
241 +    int fd;
242 +    ssize_t bytes;
243 +    char *p;
244 +
245 +    sprintf(file, "%s/%s", name, setting);
246 +
247 +    /* a non-existant file is not a failure */
248 +    *dst = '\0';
249 +    if ((fd = open(file, O_RDONLY)) == -1)
250 +        return 1;
251 +
252 +    if ((bytes = read(fd, dst, len - 1)) == -1) {
253 +        close(fd);
254 +        return -1;
255 +    }
256 +    close(fd);
257 +
258 +    dst[bytes] = '\0';
259 +
260 +    if ((p = strchr(dst, '\n')) != NULL)
261 +        *p = '\0';
262 +
263 +    return 0;
264 +}
265 +
266 +static int
267 +readLong(void *v_dst, const char *name, const char *setting)
268 +{
269 +    char buf[128], *endptr;
270 +    int ret;
271 +    long *dst = v_dst;
272 +
273 +    ret = readStr(buf, sizeof(buf), name, setting);
274 +    if (ret)
275 +        return ret;
276 +
277 +    *dst = strtol(buf, &endptr, 0);
278 +    if (endptr && *endptr != '\0')
279 +        return -1;
280 +
281 +    return 0;
282 +}
283 +
284 +static int
285 +readInt(void *v_dst, const char *name, const char *setting)
286 +{
287 +    long val;
288 +    int *dst = v_dst;
289 +    int ret;
290 +
291 +    ret = readLong(&val, name, setting);
292 +    if (ret)
293 +        return ret;
294 +
295 +    *dst = (int) val;
296 +
297 +    return 0;
298 +}
299 +
300 +static int
301 +readBool(char *dst, const char *name, const char *setting)
302 +{
303 +    char file[strlen(name) + strlen(setting) + 2];
304 +
305 +    sprintf(file, "%s/%s", name, setting);
306 +
307 +    *dst = access(file, F_OK) != -1;
308 +
309 +    return 0;
310 +}
311 +
312 +int
313 +vserverWriteToConfig(struct vserver_guest *guest, const char *filename,
314 +                     const char *format, ...)
315 +{
316 +    char path[strlen(guest->path) + 1 + strlen(filename) + 1];
317 +    va_list va;
318 +    char value[1024];
319 +    int fd;
320 +    ssize_t len, off, ret;
321 +    char *dir;
322 +
323 +    sprintf(path, "%s/%s", guest->path, filename);
324 +
325 +    /* ensure the directory exists */
326 +    dir = strrchr(path, '/');
327 +    *dir = '\0';
328 +    if (mkdir(path, 0755) && errno != EEXIST)
329 +        return -1;
330 +    *dir = '/';
331 +
332 +    va_start(va, format);
333 +    if (strcmp(format, "%b") == 0) {
334 +        /* bool, this is a special case */
335 +        if (va_arg(va, int)) {
336 +            *value = '\0';
337 +            len = 0;
338 +        }
339 +        else {
340 +            if (unlink(path) == -1 && errno != ENOENT)
341 +                return -1;
342 +            else
343 +                return 0;
344 +        }
345 +    }
346 +    else
347 +        len = vsnprintf(value, sizeof(value), format, va);
348 +    va_end(va);
349 +
350 +    fd = open(path, O_WRONLY|O_TRUNC|O_CREAT, 0644);
351 +    if (fd == -1)
352 +        return -1;
353 +
354 +    for (off = 0; off < len; off += ret) {
355 +        ret = write(fd, value + off, len - off);
356 +        if (ret == -1) {
357 +            close(fd);
358 +            return -1;
359 +        }
360 +    }
361 +
362 +    if (close(fd) == -1)
363 +        return -1;
364 +    return 0;
365 +}
366 +
367 +#define WRITE(...)  if (vserverWriteToConfig(guest, __VA_ARGS__) == -1)    \
368 +                        return -1
369 +#define WRITE_SCHED_VAL(sched, file, mask, format, value)           \
370 +    if ((sched)->set_mask & mask) {                                 \
371 +        WRITE(file, format, value);                                 \
372 +    }
373 +#define WRITE_SCHED(dir, sched)                                     \
374 +    do {                                                            \
375 +        WRITE_SCHED_VAL(sched, dir "/fill-rate",                    \
376 +                        VC_VXSM_FILL_RATE, "%u\n",                  \
377 +                        (sched)->fill_rate);                        \
378 +        WRITE_SCHED_VAL(sched, dir "/interval",                     \
379 +                        VC_VXSM_INTERVAL, "%u\n",                   \
380 +                        (sched)->interval);                         \
381 +        WRITE_SCHED_VAL(sched, dir "/fill-rate2",                   \
382 +                        VC_VXSM_FILL_RATE2, "%u\n",                 \
383 +                        (sched)->fill_rate2);                       \
384 +        WRITE_SCHED_VAL(sched, dir "/interval2",                    \
385 +                        VC_VXSM_INTERVAL2, "%u\n",                  \
386 +                        (sched)->interval2);                        \
387 +        WRITE_SCHED_VAL(sched, dir "/tokens-min",                   \
388 +                        VC_VXSM_TOKENS_MIN, "%u\n",                 \
389 +                        (sched)->tokens_min);                       \
390 +        WRITE_SCHED_VAL(sched, dir "/tokens-max",                   \
391 +                        VC_VXSM_TOKENS_MAX, "%u\n",                 \
392 +                        (sched)->tokens_max);                       \
393 +        WRITE_SCHED_VAL(sched, dir "/priority-bias",                \
394 +                        VC_VXSM_PRIO_BIAS, "%u\n",                  \
395 +                        (sched)->priority_bias);                    \
396 +        WRITE(dir "/idle-time", "%b",                               \
397 +              (sched)->set_mask & VC_VXSM_IDLE_TIME);               \
398 +    } while (0)
399 +#define WRITE_IP(filename, v4var, v6var)                            \
400 +            strcpy(file, filename);                                 \
401 +            switch (type) {                                         \
402 +            case VC_NXA_TYPE_IPV4:                                  \
403 +                inet_ntop(AF_INET, (v4var), buf, sizeof(buf));      \
404 +                break;                                              \
405 +            case VC_NXA_TYPE_IPV6:                                  \
406 +                inet_ntop(AF_INET6, (v6var), buf, sizeof(buf));     \
407 +                break;                                              \
408 +            }                                                       \
409 +            WRITE(dir, "%s\n", buf);
410 +
411 +static int
412 +writeInterfaces(struct vserver_guest *guest)
413 +{
414 +    char name[strlen(guest->path) + sizeof("/interfaces/XXXXXX/prefix")],
415 +         *dir, *file;
416 +    char buf[128];
417 +    struct vserver_ip *ip;
418 +    unsigned int i;
419 +
420 +    snprintf(name, sizeof(name), "%s/interfaces", guest->path);
421 +    if (vserverRunCommand(0, "rm", "-fr", name, NULL) != 0)
422 +        return -1;
423 +    if (mkdir(name, 0755) == -1)
424 +        return -1;
425 +
426 +    dir = name + strlen(guest->path) + 1;
427 +    for (ip = guest->ips, i = 0; ip; ip = ip->next, i++) {
428 +        uint16_t type;
429 +
430 +        /* Yeah right... */
431 +        if (i > 999999) {
432 +            errno = EOVERFLOW;
433 +            return -1;
434 +        }
435 +
436 +        file = dir;
437 +        file += snprintf(dir, sizeof(name) - (dir - name), "interfaces/%u", i);
438 +        if (mkdir(name, 0755) == -1)
439 +            return -1;
440 +
441 +        type = ip->addr.vna_type & (VC_NXA_TYPE_IPV4|VC_NXA_TYPE_IPV6);
442 +
443 +        strcpy(file, "/prefix");
444 +        WRITE(dir, "%u\n", ip->addr.vna_prefix);
445 +
446 +        if (*ip->interface) {
447 +            strcpy(file, "/dev");
448 +            WRITE(dir, "%s\n", ip->interface);
449 +        }
450 +        else {
451 +            strcpy(file, "/nodev");
452 +            WRITE(dir, "%b", 1);
453 +        }
454 +
455 +        WRITE_IP("/ip", &ip->addr.vna_v4_ip, &ip->addr.vna_v6_ip);
456 +        if (ip->addr.vna_type & VC_NXA_TYPE_RANGE) {
457 +            WRITE_IP("/ip2", &ip->addr.vna_v4_ip2, &ip->addr.vna_v6_ip2);
458 +        }
459 +        if (ip->addr.vna_type & (VC_NXA_TYPE_RANGE|VC_NXA_TYPE_MASK)) {
460 +            WRITE_IP("/mask", &ip->addr.vna_v4_mask, &ip->addr.vna_v6_mask);
461 +        }
462 +    }
463 +    return 0;
464 +}
465 +
466 +static int
467 +writeFstab(struct vserver_guest *guest)
468 +{
469 +    FILE *fp;
470 +    struct vserver_fstab *ent;
471 +    char file[strlen(guest->path) + sizeof("/fstab")];
472 +
473 +    sprintf(file, "%s/fstab", guest->path);
474 +    fp = fopen(file, "w");
475 +    if (fp == NULL)
476 +        return -1;
477 +
478 +    for (ent = guest->fstab; ent; ent = ent->next) {
479 +        if (!(ent->flags & VSERVER_FSTAB_OUTPUT))
480 +            continue;
481 +        fprintf(fp, "%s\t%s\t%s\t%s\t%s\n", ent->source, ent->target,
482 +                ent->fstype, ent->options, (ent->rest ? ent->rest : ""));
483 +    }
484 +
485 +    if (fclose(fp) == -1)
486 +        return -1;
487 +
488 +    return 0;
489 +}
490 +
491 +int
492 +vserverWriteGuestToConfig(struct vserver_guest *guest)
493 +{
494 +    char buf[128];
495 +
496 +    WRITE("context", "%u\n", guest->xid);
497 +    WRITE("name", "%s\n", guest->name);
498 +    virUUIDFormat(guest->uuid, buf);
499 +    WRITE("uuid", "%s\n", buf);
500 +    if (*guest->uts.hostname)
501 +        WRITE("uts/nodename", "%s\n", guest->uts.hostname);
502 +    if (*guest->uts.machine)
503 +        WRITE("uts/machine", "%s\n", guest->uts.machine);
504 +    if (*guest->uts.release)
505 +        WRITE("uts/release", "%s\n", guest->uts.release);
506 +    if (*guest->uts.version)
507 +        WRITE("uts/version", "%s\n", guest->uts.version);
508 +    if (guest->rss_hard > 0)
509 +        WRITE("rlimits/rss.hard", "%lu\n", guest->rss_hard);
510 +    WRITE("apps/init/mark", (guest->autostart ? "default\n" : "\n"));
511 +    WRITE_SCHED("sched", &guest->sched);
512 +
513 +    if (writeInterfaces(guest) == -1)
514 +        return -1;
515 +
516 +    if (writeFstab(guest) == -1)
517 +        return -1;
518 +
519 +    return 0;
520 +}
521 +#undef WRITE_IP
522 +#undef WRITE_SCHED
523 +#undef WRITE_SCHED_VAL
524 +#undef WRITE
525 +
526 +static int
527 +parseInterfaces(struct vserver_guest *guest, const char *directory)
528 +{
529 +    DIR *interfaces;
530 +    struct dirent *interface;
531 +    struct vserver_ip *ip = NULL;
532 +    char ipath[256], *subdir;
533 +    size_t spare;
534 +    char s_ip[48], s_prefix[4], s_mask[48], s_dev[32], s_ip2[48];
535 +
536 +    subdir = ipath;
537 +    subdir += snprintf(ipath, sizeof(ipath), "%s/%s", guest->name, directory);
538 +    spare = sizeof(ipath) - (subdir - ipath);
539 +
540 +    interfaces = opendir(ipath);
541 +    if (!interfaces)
542 +        return 0;
543 +
544 +    while ((interface = readdir(interfaces)) != NULL) {
545 +        if (*interface->d_name == '.')
546 +            continue;
547 +        /* would overflow */
548 +        if (strlen(interface->d_name) + sizeof("//disabled") > spare)
549 +            continue;
550 +
551 +        snprintf(subdir, spare, "/%s/disabled", interface->d_name);
552 +        if (access(ipath, F_OK) != -1)
553 +            continue;
554 +
555 +        snprintf(subdir, spare, "/%s", interface->d_name);
556 +        *s_mask = '\0';
557 +        *s_prefix = '\0';
558 +        if (readStr(s_ip, sizeof(s_ip), ipath, "ip") == 0 &&
559 +            (readStr(s_prefix, sizeof(s_prefix), ipath, "prefix") == 0 ||
560 +             readStr(s_mask, sizeof(s_mask), ipath, "mask") == 0)) {
561 +            if (readStr(s_dev, sizeof(s_dev), ipath, "dev") != 0)
562 +                *s_dev = '\0';
563 +            if (readStr(s_ip2, sizeof(s_ip2), ipath, "ip2") != 0)
564 +                *s_ip2 = '\0';
565 +        }
566 +        else
567 +            continue;
568 +
569 +        if (!ip)
570 +            guest->ips = ip = calloc(1, sizeof(*ip));
571 +        else {
572 +            ip->next = calloc(1, sizeof(*ip));
573 +            ip = ip->next;
574 +        }
575 +        if (!ip)
576 +            goto cleanup;
577 +
578 +        strcpy(ip->interface, s_dev);
579 +
580 +        if (inet_pton(AF_INET6, s_ip, &ip->addr.vna_v6_ip) > 0)
581 +            ip->addr.vna_type = VC_NXA_TYPE_IPV6;
582 +        else if (inet_pton(AF_INET, s_ip, &ip->addr.vna_v4_ip) > 0)
583 +            ip->addr.vna_type = VC_NXA_TYPE_IPV4;
584 +        else
585 +            goto cleanup;
586 +
587 +        if (ip->addr.vna_type == VC_NXA_TYPE_IPV6) {
588 +            if (*s_mask) {
589 +                if (inet_pton(AF_INET6, s_mask, &ip->addr.vna_v6_mask) <= 0)
590 +                    goto cleanup;
591 +            }
592 +            if (*s_ip2) {
593 +                if (inet_pton(AF_INET6, s_ip2, &ip->addr.vna_v6_ip2) <= 0)
594 +                    goto cleanup;
595 +                ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
596 +            }
597 +            else
598 +                ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
599 +        }
600 +        else if (ip->addr.vna_type == VC_NXA_TYPE_IPV4) {
601 +            if (*s_mask) {
602 +                if (inet_pton(AF_INET, s_mask, &ip->addr.vna_v4_mask) <= 0)
603 +                    goto cleanup;
604 +            }
605 +            if (*s_ip2) {
606 +                if (inet_pton(AF_INET, s_ip2, &ip->addr.vna_v4_ip2) <= 0)
607 +                    goto cleanup;
608 +                ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
609 +            }
610 +            else
611 +                ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
612 +        }
613 +
614 +        if (*s_prefix) {
615 +            char *endptr;
616 +            ip->addr.vna_prefix = strtoul(s_prefix, &endptr, 0);
617 +            if (*endptr != '\n' && *endptr)
618 +                goto cleanup;
619 +        }
620 +    }
621 +
622 +    closedir(interfaces);
623 +    return 0;
624 +
625 +cleanup:
626 +    closedir(interfaces);
627 +    return -1;
628 +}
629 +
630 +static inline char *
631 +endOfField(char *start)
632 +{
633 +    char *end;
634 +    for (end = start; *(end - 1) != '\\' &&
635 +                      !isspace(*end) &&
636 +                      *end != '\0'; end++)
637 +        ;
638 +    return end;
639 +}
640 +
641 +static inline char *
642 +startOfField(char *end)
643 +{
644 +    char *start;
645 +    for (start = end + 1; isspace(*start) &&
646 +                          *start != '\0'; start++)
647 +        ;
648 +    return start;
649 +}
650 +
651 +static const struct {
652 +    int mode;
653 +    const char *type;
654 +} source_types[] = {
655 +    { S_IFBLK, "block" },
656 +    { S_IFREG, "file" },
657 +    { S_IFDIR, "directory" },
658 +};
659 +
660 +const char *
661 +vserverFindSourceType(const char *source)
662 +{
663 +    struct stat st;
664 +    int mode, i;
665 +    if (stat(source, &st) == -1)
666 +        mode = -1;
667 +    else
668 +        mode = st.st_mode & S_IFMT;
669 +    for (i = 0; i < (sizeof(source_types) / sizeof(*source_types)); i++) {
670 +        if (mode == source_types[i].mode)
671 +            return source_types[i].type;
672 +    }
673 +    return NULL;
674 +}
675 +
676 +static int
677 +parseFstab(struct vserver_guest *guest, const char *filename)
678 +{
679 +    FILE *fp;
680 +    char buf[256], *start, *end;
681 +    struct vserver_fstab *ent = NULL;
682 +    char path[strlen(guest->name) + 2 + strlen(filename)];
683 +
684 +    sprintf(path, "%s/%s", guest->name, filename);
685 +    if ((fp = fopen(path, "r")) == NULL)
686 +        return 0;
687 +
688 +    while (fgets(buf, sizeof(buf), fp) != NULL) {
689 +        if (!ent)
690 +            guest->fstab = ent = calloc(1, sizeof(*ent));
691 +        else {
692 +            ent->next = calloc(1, sizeof(*ent));
693 +            ent = ent->next;
694 +        }
695 +        if (!ent)
696 +            goto err;
697 +
698 +        start = buf;
699 +        end = endOfField(start);
700 +        *end = '\0';
701 +        ent->source = strdup(start);
702 +        ent->source_type = vserverFindSourceType(start);
703 +
704 +        ent->flags |= VSERVER_FSTAB_OUTPUT;
705 +        if (ent->source_type)
706 +            ent->flags |= VSERVER_FSTAB_SHOW;
707 +
708 +        start = startOfField(end);
709 +        end = endOfField(start);
710 +        *end = '\0';
711 +        ent->target = strdup(start);
712 +
713 +        start = startOfField(end);
714 +        end = endOfField(start);
715 +        *end = '\0';
716 +        ent->fstype = strdup(start);
717 +
718 +        start = startOfField(end);
719 +        end = endOfField(start);
720 +        if (*end != '\0') {
721 +            char *ptr;
722 +            ent->rest = strdup(end + 1);
723 +            ptr = strchr(ent->rest, '\n');
724 +            if (ptr)
725 +                *ptr = '\0';
726 +        }
727 +        else
728 +            ent->rest = NULL;
729 +        *end = '\0';
730 +        ent->options = strdup(start);
731 +
732 +        if (!ent->source || !ent->target || !ent->fstype || !ent->options)
733 +            goto err;
734 +    }
735 +
736 +    fclose(fp);
737 +    return 0;
738 +
739 +err:
740 +    fclose(fp);
741 +    return -1;
742 +}
743 +
744 +virDrvOpenStatus
745 +vserverInitializeDriver(virConnectPtr conn, struct vserver_driver *driver,
746 +                        const char *path)
747 +{
748 +    struct vserver_guest *guest = NULL;
749 +    DIR *dp = NULL;
750 +    struct dirent *de;
751 +    int cwd;
752 +    const char *conf_dir = (*path ? path : VSERVER_CONF_DIR);
753 +
754 +    if (driver->initialized == 1)
755 +        return VIR_DRV_OPEN_SUCCESS;
756 +
757 +    driver->guests = NULL;
758 +    driver->inactive_guests = driver->active_guests = 0;
759 +
760 +    cwd = open(".", O_RDONLY);
761 +    if (cwd == -1 ||
762 +        chdir(conf_dir) == -1 ||
763 +        (dp = opendir(".")) == NULL) {
764 +        vserverError(conn, NULL, NULL, VIR_ERR_OPEN_FAILED, conf_dir);
765 +        goto error;
766 +    }
767 +
768 +    while ((de = readdir(dp)) != NULL) {
769 +        char uuidstr[VIR_UUID_STRING_BUFLEN + 1];
770 +        char mark[32];
771 +        char tmp;
772 +
773 +        if (*de->d_name == '.')
774 +            continue;
775 +
776 +        if (driver->guests == NULL)
777 +            driver->guests = guest = calloc(1, sizeof(struct vserver_guest));
778 +        else {
779 +            guest->next = calloc(1, sizeof(struct vserver_guest));
780 +            guest = guest->next;
781 +        }
782 +
783 +        if (!guest) {
784 +            vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
785 +                         "vserver_guest");
786 +            goto error;
787 +        }
788 +
789 +        guest->path = calloc(strlen(conf_dir) + 1 + strlen(de->d_name) + 1, sizeof(char));
790 +        if (!guest->path)
791 +            goto nomem;
792 +        sprintf(guest->path, "%s/%s", conf_dir, de->d_name);
793 +
794 +#define CHECK(x)                                                            \
795 +    if ((x) == -1) {                                                        \
796 +        goto parseerror;                                                    \
797 +    }
798 +#define DO_SCHED(type, var, file, bit)                                      \
799 +    do {                                                                    \
800 +        int ret;                                                            \
801 +        CHECK(ret = read ## type((var), de->d_name, (file)));               \
802 +        if (ret == 0)                                                       \
803 +            guest->sched.set_mask |= (bit);                                 \
804 +    } while (0)
805 +
806 +        /* Parse simple values */
807 +        CHECK(readInt(&guest->xid, de->d_name, "context"));
808 +        CHECK(readStr(guest->name, sizeof(guest->name), de->d_name, "name"));
809 +        CHECK(readStr(guest->uts.hostname, sizeof(guest->uts.hostname), de->d_name,
810 +                      "uts/nodename"));
811 +        CHECK(readStr(guest->uts.machine, sizeof(guest->uts.machine), de->d_name,
812 +                      "uts/machine"));
813 +        CHECK(readStr(guest->uts.release, sizeof(guest->uts.release), de->d_name,
814 +                      "uts/release"));
815 +        CHECK(readStr(guest->uts.version, sizeof(guest->uts.version), de->d_name,
816 +                      "uts/version"));
817 +        CHECK(readStr(mark, sizeof(mark), de->d_name, "apps/init/mark"));
818 +
819 +        DO_SCHED(Int, &guest->sched.fill_rate,     "sched/fill-rate",
820 +                 VC_VXSM_FILL_RATE);
821 +        DO_SCHED(Int, &guest->sched.interval,      "sched/interval",
822 +                 VC_VXSM_INTERVAL);
823 +        DO_SCHED(Int, &guest->sched.fill_rate2,    "sched/fill-rate2",
824 +                 VC_VXSM_FILL_RATE2);
825 +        DO_SCHED(Int, &guest->sched.interval2,     "sched/interval2",
826 +                 VC_VXSM_INTERVAL2);
827 +        DO_SCHED(Int, &guest->sched.tokens_min,    "sched/tokens-min",
828 +                 VC_VXSM_TOKENS_MIN);
829 +        DO_SCHED(Int, &guest->sched.tokens_max,    "sched/tokens-max",
830 +                 VC_VXSM_TOKENS_MAX);
831 +        DO_SCHED(Int, &guest->sched.priority_bias, "sched/priority-bias",
832 +                 VC_VXSM_PRIO_BIAS);
833 +        if (readBool(&tmp, de->d_name, "sched/idle-time") == 0) {
834 +            if (tmp)
835 +                guest->sched.set_mask |= VC_VXSM_IDLE_TIME;
836 +        }
837 +
838 +        CHECK(readLong(&guest->rss_hard, de->d_name, "rlimits/rss.hard"));
839 +
840 +        /* Generate a UUID if one doesn't already exist */
841 +        switch (readStr(uuidstr, sizeof(uuidstr), de->d_name, "uuid")) {
842 +        case 1:
843 +            CHECK(virUUIDGenerate(guest->uuid));
844 +            virUUIDFormat(guest->uuid, uuidstr);
845 +            CHECK(vserverWriteToConfig(guest, "uuid", "%s\n", uuidstr));
846 +            break;
847 +        case 0:
848 +            CHECK(virUUIDParse(uuidstr, guest->uuid));
849 +            break;
850 +        case -1:
851 +            goto parseerror;
852 +        }
853 +
854 +        /* Parse interfaces */
855 +        if (parseInterfaces(guest, "interfaces") == -1)
856 +            goto parseerror;
857 +
858 +        /* Parse fstab */
859 +        if (parseFstab(guest, "fstab") == -1)
860 +            goto parseerror;
861 +
862 +        /* Make sure the guest has the / directory in the disk output */
863 +        do {
864 +            struct vserver_fstab *ent;
865 +            int has_root = 0;
866 +            for (ent = guest->fstab; ent; ent = ent->next) {
867 +                if (strcmp(ent->target, "/") == 0) {
868 +                    has_root = 1;
869 +                    break;
870 +                }
871 +            }
872 +            if (!has_root) {
873 +                char vdir[strlen(de->d_name) + sizeof("/vdir")];
874 +
875 +                ent = calloc(1, sizeof(*ent));
876 +                if (!ent)
877 +                    goto nomem;
878 +
879 +                sprintf(vdir, "%s/vdir", de->d_name);
880 +                ent->source = realpath(vdir, NULL);
881 +
882 +                ent->flags = VSERVER_FSTAB_SHOW;
883 +                ent->source_type = vserverFindSourceType("/");
884 +                ent->target = strdup("/");
885 +                ent->fstype = strdup("auto");
886 +                ent->options = strdup("defaults");
887 +                if (!ent->source || !ent->target || !ent->fstype || !ent->options)
888 +                    goto nomem;
889 +                ent->next = guest->fstab;
890 +                guest->fstab = ent;
891 +            }
892 +        } while (0);
893 +#undef DO_SCHED
894 +#undef CHECK
895 +
896 +        if (STREQ(mark, "default"))
897 +            guest->autostart = 1;
898 +        if (vserverContextIsRunning(guest->path)) {
899 +            struct vc_ctx_flags flags;
900 +            if (vc_get_cflags(guest->xid, &flags) == 0 &&
901 +                (flags.flagword & VC_VXF_SCHED_PAUSE))
902 +                guest->status = VIR_DOMAIN_PAUSED;
903 +            else
904 +                guest->status = VIR_DOMAIN_RUNNING;
905 +            driver->active_guests++;
906 +        }
907 +        else {
908 +            guest->status = VIR_DOMAIN_SHUTOFF;
909 +            driver->inactive_guests++;
910 +        }
911 +    }
912 +
913 +    closedir(dp);
914 +    if (fchdir(cwd) == -1 || close(cwd) == -1) {
915 +        /* do nothing, we succeeded with everything else... */
916 +    }
917 +    driver->initialized = 1;
918 +
919 +    return VIR_DRV_OPEN_SUCCESS;
920 +
921 +nomem:
922 +    vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, NULL);
923 +    goto error;
924 +parseerror:
925 +    vserverError(conn, NULL, NULL, VIR_ERR_PARSE_FAILED, de->d_name);
926 +error:
927 +    if (dp)
928 +        closedir(dp);
929 +
930 +    if (fchdir(cwd) == -1 || close(cwd) == -1) {
931 +        /* we're already failing, nothing to do */
932 +    }
933 +    return VIR_DRV_OPEN_ERROR;
934 +}
935 +
936 +#endif
937 --- libvirt-0.4.0.orig/src/vserver/vserver_conf.h       1970-01-01 01:00:00.000000000 +0100
938 +++ libvirt-0.4.0.vserver/src/vserver/vserver_conf.h    2008-01-05 02:10:20.000000000 +0100
939 @@ -0,0 +1,36 @@
940 +/*
941 + * Configuration handling for Linux-VServer guests
942 + *
943 + * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
944 + *
945 + * This library is free software; you can redistribute it and/or
946 + * modify it under the terms of the GNU Lesser General Public
947 + * License as published by the Free Software Foundation; either
948 + * version 2.1 of the License, or (at your option) any later version.
949 + *
950 + * This library is distributed in the hope that it will be useful,
951 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
952 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
953 + * Lesser General Public License for more details.
954 + *
955 + * You should have received a copy of the GNU Lesser General Public
956 + * License along with this library; if not, write to the Free Software
957 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
958 + *
959 + * Author: Daniel Hokka Zakrisson <daniel hozac com>
960 + */
961 +
962 +#ifdef WITH_VSERVER
963 +
964 +/* Kind of a hack */
965 +#ifdef IN_VSERVER
966 +int vserverWriteToConfig(struct vserver_guest *guest, const char *filename,
967 +                         const char *format, ...);
968 +int vserverWriteGuestToConfig(struct vserver_guest *guest);
969 +virDrvOpenStatus vserverInitializeDriver(virConnectPtr conn,
970 +                                         struct vserver_driver *driver,
971 +                                         const char *path);
972 +const char *vserverFindSourceType(const char *source);
973 +#endif
974 +
975 +#endif
976 diff -Nurp libvirt-0.4.0.orig/src/vserver_driver.c libvirt-0.4.0.vserver/src/vserver_driver.c
977 --- libvirt-0.4.0.orig/src/vserver_driver.c     1970-01-01 01:00:00.000000000 +0100
978 +++ libvirt-0.4.0.vserver/src/vserver_driver.c  2008-01-09 22:43:23.000000000 +0100
979 @@ -0,0 +1,1625 @@
980 +/*
981 + * Core driver for managing Linux-VServer guests
982 + *
983 + * Copyright (C) 2007-2008 Daniel Hokka Zakrisson
984 + *
985 + * This library is free software; you can redistribute it and/or
986 + * modify it under the terms of the GNU Lesser General Public
987 + * License as published by the Free Software Foundation; either
988 + * version 2.1 of the License, or (at your option) any later version.
989 + *
990 + * This library is distributed in the hope that it will be useful,
991 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
992 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
993 + * Lesser General Public License for more details.
994 + *
995 + * You should have received a copy of the GNU Lesser General Public
996 + * License along with this library; if not, write to the Free Software
997 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
998 + *
999 + * Author: Daniel Hokka Zakrisson <daniel hozac com>
1000 + */
1001 +
1002 +#ifdef WITH_VSERVER
1003 +
1004 +#define _GNU_SOURCE
1005 +
1006 +#ifdef HAVE_CONFIG_H
1007 +#  include <config.h>
1008 +#endif
1009 +
1010 +#include <stdio.h>
1011 +#include <unistd.h>
1012 +#include <stdlib.h>
1013 +#include <string.h>
1014 +#include <fcntl.h>
1015 +#include <dirent.h>
1016 +#include <sys/wait.h>
1017 +#include <errno.h>
1018 +#include <sys/types.h>
1019 +#include <sys/socket.h>
1020 +#include <arpa/inet.h>
1021 +#include <net/if.h>
1022 +#include <sys/syscall.h>
1023 +
1024 +#include <libxml/uri.h>
1025 +#include <libxml/xpath.h>
1026 +#include <libxml/tree.h>
1027 +
1028 +#include <libvirt/virterror.h>
1029 +
1030 +#define IN_VSERVER 1
1031 +#include "internal.h"
1032 +#include "vserver_driver.h"
1033 +#include "vserver_conf.h"
1034 +#include "buf.h"
1035 +#include "uuid.h"
1036 +#include "xml.h"
1037 +#include "nodeinfo.h"
1038 +
1039 +#define GET_DOMAIN(dom, ret)                                            \
1040 +    struct vserver_driver *driver = (struct vserver_driver *)           \
1041 +                                    (dom)->conn->privateData;           \
1042 +    struct vserver_guest *guest = getGuestByUUID(driver, (dom)->uuid);  \
1043 +                                                                        \
1044 +    if (!guest) {                                                       \
1045 +        vserverError((dom)->conn, (dom), NULL, VIR_ERR_INVALID_ARG,     \
1046 +                     __FUNCTION__);                                     \
1047 +        return (ret);                                                   \
1048 +    }
1049 +
1050 +#ifndef MNT_DETACH
1051 +#  define MNT_DETACH    0x00000002
1052 +#endif
1053 +
1054 +static int PAGE_SHIFT_TO_KIBI = 2;
1055 +
1056 +static inline int sys_umount(const char *path, int flags)
1057 +{
1058 +    return syscall(__NR_umount2, path, flags);
1059 +}
1060 +
1061 +static inline struct vserver_guest *
1062 +getGuestByID(struct vserver_driver *driver,
1063 +             int id)
1064 +{
1065 +    struct vserver_guest *res;
1066 +    for (res = driver->guests; res; res = res->next) {
1067 +        if (res->xid == id)
1068 +            break;
1069 +    }
1070 +    return res;
1071 +}
1072 +
1073 +static inline struct vserver_guest *
1074 +getGuestByUUID(struct vserver_driver *driver,
1075 +               const unsigned char *uuid)
1076 +{
1077 +    struct vserver_guest *res;
1078 +    for (res = driver->guests; res; res = res->next) {
1079 +        if (memcmp(res->uuid, uuid, VIR_UUID_BUFLEN) == 0)
1080 +            break;
1081 +    }
1082 +    return res;
1083 +}
1084 +
1085 +static inline struct vserver_guest *
1086 +getGuestByName(struct vserver_driver *driver,
1087 +               const char *name)
1088 +{
1089 +    struct vserver_guest *res;
1090 +    for (res = driver->guests; res; res = res->next) {
1091 +        if (STREQ(res->name, name))
1092 +            break;
1093 +    }
1094 +    return res;
1095 +}
1096 +
1097 +void
1098 +vserverError(virConnectPtr con,
1099 +             virDomainPtr dom,
1100 +             virNetworkPtr net,
1101 +             virErrorNumber error,
1102 +             const char *info)
1103 +{
1104 +    const char *errmsg;
1105 +
1106 +    if (error == VIR_ERR_OK)
1107 +        return;
1108 +
1109 +    errmsg = __virErrorMsg(error, info);
1110 +    __virRaiseError(con, dom, net, VIR_FROM_VSERVER, error, VIR_ERR_ERROR,
1111 +                    errmsg, info, NULL, 0, 0, errmsg, info, 0);
1112 +}
1113 +
1114 +/* like execl, but uses /dev/null and handles forking/waiting/etc. */
1115 +int
1116 +vserverRunCommand(int do_daemon, const char *cmd, ...)
1117 +{
1118 +    pid_t pid;
1119 +    va_list va;
1120 +    char **argv;
1121 +    int i, argc;
1122 +    sighandler_t sigchld;
1123 +    int ret;
1124 +
1125 +    va_start(va, cmd);
1126 +    argc = 15;
1127 +    argv = calloc(argc, sizeof(*argv));
1128 +    argv[0] = (char *) cmd;
1129 +    for (i = 1; (argv[i] = va_arg(va, char *)) != NULL; i++) {
1130 +        if (i == argc-1) {
1131 +            argc += 5;
1132 +            argv = realloc(argv, sizeof(*argv) * argc);
1133 +        }
1134 +    }
1135 +
1136 +    va_end(va);
1137 +
1138 +    /* XXX: This is bad, since another child could die
1139 +     *      between here and where we restore it */
1140 +    sigchld = signal(SIGCHLD, SIG_DFL);
1141 +    if ((pid = fork()) == 0) {
1142 +        int fd;
1143 +        if (do_daemon) {
1144 +            pid_t not_a_zombie;
1145 +
1146 +            if (setsid() == -1)
1147 +                goto error;
1148 +
1149 +            not_a_zombie = fork();
1150 +            if (not_a_zombie == -1)
1151 +                goto error;
1152 +            else if (not_a_zombie > 0)
1153 +                _exit(0);
1154 +        }
1155 +        if ((fd = open("/dev/null", O_RDWR)) == -1)
1156 +            goto error;
1157 +        if (dup2(fd, 0) == -1 || dup2(fd, 1) == -1 || dup2(fd, 2) == -1)
1158 +            goto error;
1159 +        if (fd > 2 && close(fd) == -1)
1160 +            goto error;
1161 +        execvp(cmd, argv);
1162 +    error:
1163 +        _exit(1);
1164 +    }
1165 +    else if (pid == -1) {
1166 +        ret =  -1;
1167 +    }
1168 +    else {
1169 +        int status;
1170 +        if (waitpid(pid, &status, 0) == -1)
1171 +            ret = -1;
1172 +        else if (WEXITSTATUS(status) != 0)
1173 +            ret = 1;
1174 +        else
1175 +            ret = 0;
1176 +    }
1177 +
1178 +    signal(SIGCHLD, sigchld);
1179 +    return ret;
1180 +}
1181 +
1182 +int
1183 +vserverContextIsRunning(const char *path)
1184 +{
1185 +    return vc_getVserverCtx(path, vcCFG_AUTO, false, 0, vcCTX_XID) != VC_NOCTX;
1186 +}
1187 +
1188 +static void
1189 +vserverSetPagesize(void)
1190 +{
1191 +    long page_size = sysconf(_SC_PAGESIZE);
1192 +    PAGE_SHIFT_TO_KIBI = page_size / 1024;
1193 +}
1194 +
1195 +static virDrvOpenStatus
1196 +vserverOpen(virConnectPtr conn, xmlURIPtr uri,
1197 +            virConnectAuthPtr auth ATTRIBUTE_UNUSED,
1198 +            int flags ATTRIBUTE_UNUSED)
1199 +{
1200 +    virDrvOpenStatus ret;
1201 +    struct vserver_driver *driver;
1202 +
1203 +    if (!uri)
1204 +        return VIR_DRV_OPEN_DECLINED;
1205 +
1206 +    if (getuid() != 0)
1207 +        return VIR_DRV_OPEN_DECLINED;
1208 +
1209 +    if (!uri->scheme || STRNEQ(uri->scheme, "vserver"))
1210 +        return VIR_DRV_OPEN_DECLINED;
1211 +
1212 +    if (uri->server)
1213 +        return VIR_DRV_OPEN_DECLINED;
1214 +
1215 +    /* nothing else supported right now */
1216 +    if (strncmp(uri->path, "/system", 7) != 0)
1217 +        return VIR_DRV_OPEN_DECLINED;
1218 +
1219 +    /* make sure it's a Linux-VServer kernel */
1220 +    if (vc_get_version() == -1)
1221 +        return VIR_DRV_OPEN_DECLINED;
1222 +
1223 +    if (!conn->privateData)
1224 +        conn->privateData = calloc(1, sizeof(struct vserver_driver));
1225 +
1226 +    ret = vserverInitializeDriver(conn, conn->privateData, uri->path + 7);
1227 +    if (ret == VIR_DRV_OPEN_SUCCESS) {
1228 +        driver = conn->privateData;
1229 +        driver->uri = xmlSaveUri(uri);
1230 +    }
1231 +    else {
1232 +        free(conn->privateData);
1233 +    }
1234 +
1235 +    vserverSetPagesize();
1236 +
1237 +    return ret;
1238 +}
1239 +
1240 +static void
1241 +freeFstab(struct vserver_fstab *ent)
1242 +{
1243 +    free(ent->source);
1244 +    free(ent->target);
1245 +    free(ent->fstype);
1246 +    free(ent->options);
1247 +    free(ent);
1248 +}
1249 +
1250 +static void
1251 +freeGuest(struct vserver_guest *guest)
1252 +{
1253 +    struct vserver_ip *ip, *pip = NULL;
1254 +    struct vserver_fstab *ent, *pent = NULL;
1255 +    for (ip = guest->ips; ip; ip = ip->next) {
1256 +        if (pip)
1257 +            free(pip);
1258 +        pip = ip;
1259 +    }
1260 +    if (pip)
1261 +        free(pip);
1262 +    for (ent = guest->fstab; ent; ent = ent->next) {
1263 +        if (pent)
1264 +            freeFstab(pent);
1265 +        pent = ent;
1266 +    }
1267 +    if (pent)
1268 +        freeFstab(pent);
1269 +    free(guest->path);
1270 +    free(guest);
1271 +}
1272 +
1273 +static int
1274 +vserverClose(virConnectPtr conn)
1275 +{
1276 +    struct vserver_driver *driver = conn->privateData;
1277 +    struct vserver_guest *guest, *pguest;
1278 +
1279 +    if (!driver || !driver->initialized)
1280 +        return 0;
1281 +
1282 +    for (guest = driver->guests, pguest = NULL; guest; guest = guest->next) {
1283 +        if (pguest)
1284 +            freeGuest(pguest);
1285 +        pguest = guest;
1286 +    }
1287 +    if (pguest)
1288 +        freeGuest(pguest);
1289 +
1290 +    xmlFree(driver->uri);
1291 +    free(driver);
1292 +    conn->privateData = NULL;
1293 +
1294 +    return 0;
1295 +}
1296 +
1297 +static const char *
1298 +vserverGetType(virConnectPtr conn ATTRIBUTE_UNUSED)
1299 +{
1300 +    return "Linux-VServer";
1301 +}
1302 +
1303 +static int
1304 +vserverGetVersion(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned long *version)
1305 +{
1306 +    *version = 1;
1307 +    return 0;
1308 +}
1309 +
1310 +static char *
1311 +vserverGetHostname(virConnectPtr conn)
1312 +{
1313 +    char *ret;
1314 +
1315 +    ret = calloc(VSERVER_UTS_MAX + 1, sizeof(char));
1316 +    if (!ret) {
1317 +        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "gethostname");
1318 +        return NULL;
1319 +    }
1320 +
1321 +    if (gethostname(ret, VSERVER_UTS_MAX) == -1) {
1322 +        free(ret);
1323 +        vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, strerror(errno));
1324 +        return NULL;
1325 +    }
1326 +
1327 +    return ret;
1328 +}
1329 +
1330 +static char *
1331 +vserverGetURI(virConnectPtr conn)
1332 +{
1333 +    struct vserver_driver *driver = conn->privateData;
1334 +    return (char *) xmlStrdup(driver->uri);
1335 +}
1336 +
1337 +static int
1338 +vserverNodeGetInfo(virConnectPtr conn, virNodeInfoPtr nodeinfo)
1339 +{
1340 +    return virNodeInfoPopulate(conn, nodeinfo);
1341 +}
1342 +
1343 +static int
1344 +vserverListDomains(virConnectPtr conn, int *ids, int nids)
1345 +{
1346 +    struct vserver_driver *driver = conn->privateData;
1347 +    struct vserver_guest *guest;
1348 +    int i;
1349 +
1350 +    for (guest = driver->guests, i = 0; guest && i < nids;
1351 +         guest = guest->next) {
1352 +        if (guest->status != VIR_DOMAIN_SHUTOFF)
1353 +            ids[i++] = guest->xid;
1354 +    }
1355 +
1356 +    return i;
1357 +}
1358 +
1359 +static int
1360 +vserverNumOfDomains(virConnectPtr conn)
1361 +{
1362 +    struct vserver_driver *driver = conn->privateData;
1363 +
1364 +    return driver->active_guests;
1365 +}
1366 +
1367 +static virDomainPtr
1368 +vserverDomainLookupByID(virConnectPtr conn, int id)
1369 +{
1370 +    struct vserver_driver *driver = conn->privateData;
1371 +    struct vserver_guest *guest;
1372 +    virDomainPtr domain;
1373 +
1374 +    if ((guest = getGuestByID(driver, id)) == NULL) {
1375 +        vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
1376 +                     _("No domain by that ID found"));
1377 +        return NULL;
1378 +    }
1379 +
1380 +    domain = virGetDomain(conn, guest->name, guest->uuid);
1381 +    if (!domain) {
1382 +        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
1383 +        return NULL;
1384 +    }
1385 +
1386 +    if (vserverIsRunning(guest))
1387 +        domain->id = guest->xid;
1388 +
1389 +    return domain;
1390 +}
1391 +
1392 +static virDomainPtr
1393 +vserverDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
1394 +{
1395 +    struct vserver_driver *driver = conn->privateData;
1396 +    struct vserver_guest *guest;
1397 +    virDomainPtr domain;
1398 +
1399 +    if ((guest = getGuestByUUID(driver, uuid)) == NULL) {
1400 +        vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
1401 +                     _("No domain by that UUID found"));
1402 +        return NULL;
1403 +    }
1404 +
1405 +    domain = virGetDomain(conn, guest->name, guest->uuid);
1406 +    if (!domain) {
1407 +        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
1408 +        return NULL;
1409 +    }
1410 +
1411 +    if (vserverIsRunning(guest))
1412 +        domain->id = guest->xid;
1413 +
1414 +    return domain;
1415 +}
1416 +
1417 +static virDomainPtr
1418 +vserverDomainLookupByName(virConnectPtr conn, const char *name)
1419 +{
1420 +    struct vserver_driver *driver = conn->privateData;
1421 +    struct vserver_guest *guest;
1422 +    virDomainPtr domain;
1423 +
1424 +    if ((guest = getGuestByName(driver, name)) == NULL) {
1425 +        vserverError(conn, NULL, NULL, VIR_ERR_INVALID_DOMAIN,
1426 +                     _("No domain by that name found"));
1427 +        return NULL;
1428 +    }
1429 +
1430 +    domain = virGetDomain(conn, guest->name, guest->uuid);
1431 +    if (!domain) {
1432 +        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
1433 +        return NULL;
1434 +    }
1435 +
1436 +    if (vserverIsRunning(guest))
1437 +        domain->id = guest->xid;
1438 +
1439 +    return domain;
1440 +}
1441 +
1442 +static int
1443 +vserverDomainSuspend(virDomainPtr domain)
1444 +{
1445 +    struct vc_ctx_flags flags = {
1446 +        .flagword = VC_VXF_SCHED_PAUSE,
1447 +        .mask = VC_VXF_SCHED_PAUSE,
1448 +    };
1449 +    GET_DOMAIN(domain, -1);
1450 +
1451 +    if (guest->status == VIR_DOMAIN_PAUSED)
1452 +        return 0;
1453 +    if (guest->status != VIR_DOMAIN_RUNNING) {
1454 +        vserverError(domain->conn, domain, NULL, VIR_ERR_OPERATION_FAILED,
1455 +                     _("domain is not running"));
1456 +        return -1;
1457 +    }
1458 +
1459 +    if (vc_set_cflags(guest->xid, &flags) == -1) {
1460 +        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
1461 +                     strerror(errno));
1462 +        return -1;
1463 +    }
1464 +    guest->status = VIR_DOMAIN_PAUSED;
1465 +
1466 +    return 0;
1467 +}
1468 +
1469 +static int
1470 +vserverDomainResume(virDomainPtr domain)
1471 +{
1472 +    struct vc_ctx_flags flags = {
1473 +        .flagword = 0,
1474 +        .mask = VC_VXF_SCHED_PAUSE,
1475 +    };
1476 +    GET_DOMAIN(domain, -1);
1477 +
1478 +    if (guest->status == VIR_DOMAIN_RUNNING)
1479 +        return 0;
1480 +    if (guest->status != VIR_DOMAIN_PAUSED) {
1481 +        vserverError(domain->conn, domain, NULL, VIR_ERR_OPERATION_FAILED,
1482 +                     _("domain is not running"));
1483 +        return -1;
1484 +    }
1485 +
1486 +    if (vc_set_cflags(guest->xid, &flags) == -1) {
1487 +        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
1488 +                     strerror(errno));
1489 +        return -1;
1490 +    }
1491 +    guest->status = VIR_DOMAIN_RUNNING;
1492 +
1493 +    return 0;
1494 +}
1495 +
1496 +static int
1497 +vserverDomainShutdown(virDomainPtr domain)
1498 +{
1499 +    GET_DOMAIN(domain, -1);
1500 +
1501 +    if (vserverRunCommand(1, PROG_VSERVER, guest->path, "stop", NULL) != 0) {
1502 +        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
1503 +                     "vserver stop");
1504 +        return -1;
1505 +    }
1506 +
1507 +    driver->active_guests--;
1508 +    guest->status = VIR_DOMAIN_SHUTOFF;
1509 +    driver->inactive_guests++;
1510 +    return 0;
1511 +}
1512 +
1513 +static int
1514 +vserverDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
1515 +{
1516 +    GET_DOMAIN(domain, -1);
1517 +
1518 +    if (vserverRunCommand(1, PROG_VSERVER, guest->path, "restart", NULL) != 0) {
1519 +        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
1520 +                     "vserver restart");
1521 +        return -1;
1522 +    }
1523 +
1524 +    guest->status = VIR_DOMAIN_RUNNING;
1525 +    return 0;
1526 +}
1527 +
1528 +static int
1529 +vserverDomainDestroy(virDomainPtr domain)
1530 +{
1531 +    GET_DOMAIN(domain, -1);
1532 +
1533 +    if (vserverDomainShutdown(domain) == -1)
1534 +        return -1;
1535 +
1536 +    virFreeDomain(domain->conn, domain);
1537 +
1538 +    return 0;
1539 +}
1540 +
1541 +static char *
1542 +vserverDomainGetOSType(virDomainPtr domain ATTRIBUTE_UNUSED)
1543 +{
1544 +    return strdup("Linux");
1545 +}
1546 +
1547 +static unsigned long
1548 +vserverDomainGetMaxMemory(virDomainPtr domain)
1549 +{
1550 +    GET_DOMAIN(domain, (unsigned long) -1);
1551 +
1552 +    return guest->rss_hard << PAGE_SHIFT_TO_KIBI;
1553 +}
1554 +
1555 +static int
1556 +vserverDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
1557 +{
1558 +    struct vc_rlimit limit = {
1559 +        .min = 0,
1560 +    };
1561 +    GET_DOMAIN(domain, -1);
1562 +
1563 +    guest->rss_hard = memory >> PAGE_SHIFT_TO_KIBI;
1564 +    limit.soft = limit.hard = guest->rss_hard;
1565 +    if (vserverIsRunning(guest) &&
1566 +        vc_set_rlimit(guest->xid, RLIMIT_RSS, &limit) == -1) {
1567 +        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR, strerror(errno));
1568 +        return -1;
1569 +    }
1570 +
1571 +    if (vserverWriteToConfig(guest, "rlimits/rss.hard", "%lu\n", guest->rss_hard) == -1) {
1572 +        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
1573 +                     strerror(errno));
1574 +        return -1;
1575 +    }
1576 +
1577 +    return 0;
1578 +}
1579 +
1580 +static int
1581 +vserverDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
1582 +{
1583 +    struct vc_sched_info sinfo = { .user_msec = 0, .sys_msec = 0 };
1584 +    struct vc_rlimit_stat rss_stat = { .value = 0 };
1585 +    GET_DOMAIN(domain, -1);
1586 +
1587 +    if (vserverIsRunning(guest)) {
1588 +        if (vc_sched_info(guest->xid, &sinfo) == -1) {
1589 +            vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
1590 +                         strerror(errno));
1591 +            return -1;
1592 +        }
1593 +        if (vc_rlimit_stat(guest->xid, RLIMIT_RSS, &rss_stat) == -1) {
1594 +            vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
1595 +                         strerror(errno));
1596 +            return -1;
1597 +        }
1598 +    }
1599 +
1600 +    info->state = guest->status;
1601 +    info->maxMem = guest->rss_hard << PAGE_SHIFT_TO_KIBI;
1602 +    info->nrVirtCpu = -1;
1603 +    info->memory = rss_stat.value;
1604 +    info->cpuTime = (sinfo.user_msec + sinfo.sys_msec) * 1000000ULL;
1605 +
1606 +    return 0;
1607 +}
1608 +
1609 +static char *
1610 +vserverDomainDumpXML(virDomainPtr domain, int flags ATTRIBUTE_UNUSED)
1611 +{
1612 +    virBufferPtr buf;
1613 +    char uuid[VIR_UUID_STRING_BUFLEN + 1];
1614 +    struct vserver_ip *ip;
1615 +    GET_DOMAIN(domain, NULL);
1616 +
1617 +    buf = virBufferNew(4096);
1618 +    if (!buf)
1619 +        goto no_memory;
1620 +
1621 +    virUUIDFormat(guest->uuid, uuid);
1622 +    if (virBufferVSprintf(buf,
1623 +"<domain type='vserver' id='%d'>\n"
1624 +"  <name>%s</name>\n"
1625 +"  <uuid>%s</uuid>\n"
1626 +                             , guest->xid, guest->name, uuid
1627 +                             ) < 0)
1628 +        goto no_memory;
1629 +    if (guest->rss_hard > 0)
1630 +        if (virBufferVSprintf(buf, "  <memory>%lu</memory>\n",
1631 +                              guest->rss_hard << PAGE_SHIFT_TO_KIBI) < 0)
1632 +            goto no_memory;
1633 +
1634 +    if (virBufferVSprintf(buf, "  <os>\n"
1635 +                               "    <hostname>%s</hostname>\n"
1636 +                               , guest->uts.hostname) < 0)
1637 +        goto no_memory;
1638 +    if (virBufferVSprintf(buf, "    <type") < 0)
1639 +        goto no_memory;
1640 +    if (*guest->uts.machine)
1641 +        if (virBufferVSprintf(buf, " arch='%s'", guest->uts.machine) < 0)
1642 +            goto no_memory;
1643 +    if (virBufferVSprintf(buf, ">vserver</type>\n") < 0)
1644 +        goto no_memory;
1645 +    if (*guest->uts.release)
1646 +        if (virBufferVSprintf(buf, "    <release>%s</release>\n",
1647 +                              guest->uts.release) < 0)
1648 +            goto no_memory;
1649 +    if (*guest->uts.version)
1650 +        if (virBufferVSprintf(buf, "    <version>%s</version>\n",
1651 +                              guest->uts.version) < 0)
1652 +            goto no_memory;
1653 +    if (virBufferVSprintf(buf, "  </os>\n"
1654 +                               "  <devices>\n") < 0)
1655 +        goto no_memory;
1656 +
1657 +    for (ip = guest->ips; ip; ip = ip->next) {
1658 +        char addrbuf[128];
1659 +        if (virBufferVSprintf(buf, "    <interface type='ethernet'>\n"
1660 +                                   "      <ip prefix='%d'", ip->addr.vna_prefix) < 0)
1661 +            goto no_memory;
1662 +        if (*ip->interface)
1663 +            if (virBufferVSprintf(buf, " interface='%s'", ip->interface) < 0)
1664 +                goto no_memory;
1665 +
1666 +        switch (ip->addr.vna_type & (VC_NXA_TYPE_IPV4|VC_NXA_TYPE_IPV6)) {
1667 +            case VC_NXA_TYPE_IPV4:
1668 +                inet_ntop(AF_INET, &ip->addr.vna_v4_ip, addrbuf, sizeof(addrbuf));
1669 +                if (virBufferVSprintf(buf, " address='%s'", addrbuf) < 0)
1670 +                    goto no_memory;
1671 +                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_RANGE)) {
1672 +                    inet_ntop(AF_INET, &ip->addr.vna_v4_ip2, addrbuf, sizeof(addrbuf));
1673 +                    if (virBufferVSprintf(buf, " address2='%s' type='range'", addrbuf) < 0)
1674 +                        goto no_memory;
1675 +                }
1676 +                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_MASK)) {
1677 +                    if (virBufferVSprintf(buf, " type='mask'") < 0)
1678 +                        goto no_memory;
1679 +                }
1680 +                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_RANGE) ||
1681 +                    ip->addr.vna_type == (VC_NXA_TYPE_IPV4 | VC_NXA_TYPE_MASK)) {
1682 +                    inet_ntop(AF_INET, &ip->addr.vna_v4_mask, addrbuf, sizeof(addrbuf));
1683 +                    if (virBufferVSprintf(buf, " mask='%s'", addrbuf) < 0)
1684 +                        goto no_memory;
1685 +                }
1686 +                break;
1687 +
1688 +            case VC_NXA_TYPE_IPV6:
1689 +                inet_ntop(AF_INET6, &ip->addr.vna_v6_ip, addrbuf, sizeof(addrbuf));
1690 +                if (virBufferVSprintf(buf, " address='%s'", addrbuf) < 0)
1691 +                    goto no_memory;
1692 +                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_RANGE)) {
1693 +                    inet_ntop(AF_INET6, &ip->addr.vna_v6_ip2, addrbuf, sizeof(addrbuf));
1694 +                    if (virBufferVSprintf(buf, " address2='%s' type='range'", addrbuf) < 0)
1695 +                        goto no_memory;
1696 +                }
1697 +                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_MASK)) {
1698 +                    if (virBufferVSprintf(buf, " type='mask'") < 0)
1699 +                        goto no_memory;
1700 +                }
1701 +                if (ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_RANGE) ||
1702 +                    ip->addr.vna_type == (VC_NXA_TYPE_IPV6 | VC_NXA_TYPE_MASK)) {
1703 +                    inet_ntop(AF_INET6, &ip->addr.vna_v6_mask, addrbuf, sizeof(addrbuf));
1704 +                    if (virBufferVSprintf(buf, " mask='%s'", addrbuf) < 0)
1705 +                        goto no_memory;
1706 +                }
1707 +                break;
1708 +        }
1709 +
1710 +        if (virBufferVSprintf(buf, " />\n"
1711 +                                   "    </interface>\n") < 0)
1712 +            goto no_memory;
1713 +    }
1714 +
1715 +    if (guest->fstab) {
1716 +        struct vserver_fstab *ent;
1717 +        for (ent = guest->fstab; ent; ent = ent->next) {
1718 +            /* Skip things like proc */
1719 +            if (!(ent->flags & VSERVER_FSTAB_SHOW))
1720 +                continue;
1721 +            if (virBufferVSprintf(buf, "    <disk type='%s' device='directory'>\n"
1722 +                                       "      <source %s='%s' type='%s' options='%s'/>\n"
1723 +                                       "      <target directory='%s'/>\n"
1724 +                                       "    </disk>\n",
1725 +                                  ent->source_type,
1726 +                                  (strcmp(ent->source_type, "block") == 0 ?
1727 +                                   "dev" : ent->source_type),
1728 +                                  ent->source,
1729 +                                  ent->fstype,
1730 +                                  ent->options,
1731 +                                  ent->target) < 0)
1732 +                goto no_memory;
1733 +        }
1734 +    }
1735 +
1736 +    if (virBufferVSprintf(buf, "  </devices>\n"
1737 +                               "</domain>\n") < 0)
1738 +        goto no_memory;
1739 +
1740 +    return virBufferContentAndFree(buf);
1741 +
1742 +no_memory:
1743 +    if (buf)
1744 +        virBufferFree(buf);
1745 +    vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY,
1746 +                 "xml");
1747 +    return NULL;
1748 +}
1749 +
1750 +static int
1751 +vserverParseIP(struct vserver_ip *ip, xmlNodePtr node)
1752 +{
1753 +    xmlChar *value;
1754 +    char *endptr;
1755 +
1756 +    value = xmlGetProp(node, BAD_CAST "address");
1757 +    if (!value)
1758 +        goto err;
1759 +    if (inet_pton(AF_INET6, (char *) value, &ip->addr.vna_v6_ip) > 0)
1760 +        ip->addr.vna_type = VC_NXA_TYPE_IPV6;
1761 +    else if (inet_pton(AF_INET, (char *) value, &ip->addr.vna_v4_ip) > 0)
1762 +        ip->addr.vna_type = VC_NXA_TYPE_IPV4;
1763 +    else
1764 +        goto err;
1765 +
1766 +    value = xmlGetProp(node, BAD_CAST "prefix");
1767 +    if (!value)
1768 +        goto err;
1769 +    ip->addr.vna_prefix = strtol((char *) value, &endptr, 0);
1770 +    if (*endptr)
1771 +        goto err;
1772 +    xmlFree(value);
1773 +
1774 +    value = xmlGetProp(node, BAD_CAST "type");
1775 +    if (!value)
1776 +        ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
1777 +    else {
1778 +        if (xmlStrcasecmp(value, BAD_CAST "address") == 0)
1779 +            ip->addr.vna_type |= VC_NXA_TYPE_ADDR;
1780 +        else if (xmlStrcasecmp(value, BAD_CAST "mask") == 0)
1781 +            ip->addr.vna_type |= VC_NXA_TYPE_MASK;
1782 +        else if (xmlStrcasecmp(value, BAD_CAST "range") == 0)
1783 +            ip->addr.vna_type |= VC_NXA_TYPE_RANGE;
1784 +        else
1785 +            goto err;
1786 +        xmlFree(value);
1787 +    }
1788 +
1789 +    value = xmlGetProp(node, BAD_CAST "interface");
1790 +    if (value) {
1791 +        strncpy(ip->interface, (char *) value, IFNAMSIZ);
1792 +        xmlFree(value);
1793 +    }
1794 +
1795 +    return 0;
1796 +
1797 +err:
1798 +    if (value)
1799 +        xmlFree(value);
1800 +    return -1;
1801 +}
1802 +
1803 +static const char *
1804 +diskTypeToAttr(const char *type)
1805 +{
1806 +    return (strcmp(type, "block") == 0 ? "dev" : type);
1807 +}
1808 +
1809 +static int
1810 +vserverParseDisk(struct vserver_fstab *ent, xmlNodePtr node)
1811 +{
1812 +    xmlChar *type = NULL, *value = NULL;
1813 +    xmlNodePtr iter, source = NULL, target = NULL;
1814 +
1815 +    for (iter = node->children; iter && (!source || !target); iter = iter->next) {
1816 +        if (iter->type != XML_ELEMENT_NODE)
1817 +            continue;
1818 +        if (xmlStrEqual(iter->name, BAD_CAST "source"))
1819 +            source = iter;
1820 +        else if (xmlStrEqual(iter->name, BAD_CAST "target"))
1821 +            target = iter;
1822 +    }
1823 +    if (!target || !source)
1824 +        goto err;
1825 +
1826 +    value = xmlGetProp(node, BAD_CAST "device");
1827 +    if (!value || !xmlStrEqual(value, BAD_CAST "directory"))
1828 +        goto err;
1829 +    xmlFree(value);
1830 +
1831 +    ent->target = (char *) xmlGetProp(target, BAD_CAST "directory");
1832 +    if (!value)
1833 +        goto err;
1834 +
1835 +    type = xmlGetProp(node, BAD_CAST "type");
1836 +    if (!type)
1837 +        goto err;
1838 +    ent->source = (char *) xmlGetProp(source, BAD_CAST diskTypeToAttr((char *) type));
1839 +    xmlFree(type);
1840 +    if (!ent->source)
1841 +        goto err;
1842 +
1843 +    ent->source_type = vserverFindSourceType(ent->source);
1844 +    if (!ent->source_type)
1845 +        goto err;
1846 +
1847 +    ent->fstype = (char *) xmlGetProp(source, BAD_CAST "type");
1848 +    if (!ent->fstype)
1849 +        ent->fstype = strdup("auto");
1850 +
1851 +    ent->options = (char *) xmlGetProp(source, BAD_CAST "options");
1852 +    if (!ent->options) {
1853 +        if (strcmp(ent->source_type, "file") == 0)
1854 +            ent->options = strdup("defaults,loop");
1855 +        else
1856 +            ent->options = strdup("defaults");
1857 +    }
1858 +
1859 +    ent->flags = VSERVER_FSTAB_SHOW | VSERVER_FSTAB_OUTPUT;
1860 +
1861 +    return 0;
1862 +
1863 +err:
1864 +    if (ent->fstype)
1865 +        xmlFree(ent->fstype);
1866 +    if (ent->source)
1867 +        xmlFree(ent->source);
1868 +    if (ent->target)
1869 +        xmlFree(ent->target);
1870 +    if (value)
1871 +        xmlFree(value);
1872 +    return -1;
1873 +}
1874 +
1875 +static int
1876 +vserverParseXML(struct vserver_guest *guest, xmlDocPtr doc)
1877 +{
1878 +    xmlNodePtr root;
1879 +    xmlXPathContextPtr xpath = NULL;
1880 +    xmlXPathObjectPtr obj;
1881 +    char *str;
1882 +    long l_tmp;
1883 +
1884 +    /* FIXME: This could use some better error reporting... */
1885 +    root = xmlDocGetRootElement(doc);
1886 +    if (!root || !xmlStrEqual(root->name, BAD_CAST "domain"))
1887 +        goto err;
1888 +
1889 +    xpath = xmlXPathNewContext(doc);
1890 +    if (!xpath)
1891 +        goto err;
1892 +
1893 +    if (virXPathLong("string(/domain[1]/@id)", xpath, &l_tmp) != 0)
1894 +        goto err;
1895 +    guest->xid = (int) l_tmp;
1896 +
1897 +    str = virXPathString("string(/domain/name[1])", xpath);
1898 +    if (!str)
1899 +        goto err;
1900 +    strncpy(guest->name, str, VSERVER_NAME_MAX - 1);
1901 +
1902 +    str = virXPathString("string(/domain/uuid[1])", xpath);
1903 +    if (!str) {
1904 +        if (virUUIDGenerate(guest->uuid) != 0)
1905 +            goto err;
1906 +    }
1907 +    else if (virUUIDParse(str, guest->uuid) < 0)
1908 +        goto err;
1909 +
1910 +    guest->rss_hard = 0;
1911 +    if (virXPathLong("string(/domain/memory[1])", xpath, (long *) &guest->rss_hard) == -2)
1912 +        goto err;
1913 +    guest->rss_hard >>= PAGE_SHIFT_TO_KIBI;
1914 +
1915 +    str = virXPathString("string(/domain/os[1]/hostname[1])", xpath);
1916 +    if (str)
1917 +        strncpy(guest->uts.hostname, str, VSERVER_UTS_MAX - 1);
1918 +
1919 +    str = virXPathString("string(/domain/os[1]/type[1]/@arch)", xpath);
1920 +    if (str)
1921 +        strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
1922 +
1923 +    str = virXPathString("string(/domain/os[1]/release[1])", xpath);
1924 +    if (str)
1925 +        strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
1926 +
1927 +    str = virXPathString("string(/domain/os[1]/version[1])", xpath);
1928 +    if (str)
1929 +        strncpy(guest->uts.machine, str, VSERVER_UTS_MAX - 1);
1930 +
1931 +    str = virXPathString("string(/domain/container/initstyle[1]/@type)", xpath);
1932 +    guest->initstyle = VSERVER_INIT_SYSV;
1933 +    if (str) {
1934 +        if (strcmp(str, "plain") == 0)
1935 +            guest->initstyle = VSERVER_INIT_PLAIN;
1936 +        else if (strcmp(str, "gentoo") == 0)
1937 +            guest->initstyle = VSERVER_INIT_GENTOO;
1938 +        else if (strcmp(str, "minit") == 0)
1939 +            guest->initstyle = VSERVER_INIT_MINIT;
1940 +        else if (strcmp(str, "sysv") == 0)
1941 +            guest->initstyle = VSERVER_INIT_SYSV;
1942 +    }
1943 +
1944 +    obj = xmlXPathEval(BAD_CAST "/domain/devices[1]/interface/ip", xpath);
1945 +    if (obj != NULL && obj->type == XPATH_NODESET && obj->nodesetval != NULL &&
1946 +        obj->nodesetval->nodeNr > 0) {
1947 +        int i;
1948 +        struct vserver_ip *ip = NULL;
1949 +
1950 +        for (i = 0; i < obj->nodesetval->nodeNr; i++) {
1951 +            if (ip == NULL)
1952 +                guest->ips = ip = calloc(1, sizeof(*ip));
1953 +            else {
1954 +                ip->next = calloc(1, sizeof(*ip));
1955 +                ip = ip->next;
1956 +            }
1957 +
1958 +            if (vserverParseIP(ip, obj->nodesetval->nodeTab[i]) == -1)
1959 +                goto nodeset_err;
1960 +        }
1961 +    }
1962 +    if (obj)
1963 +        xmlXPathFreeObject(obj);
1964 +
1965 +    obj = xmlXPathEval(BAD_CAST "/domain/devices[1]/disk", xpath);
1966 +    if (obj != NULL && obj->type == XPATH_NODESET && obj->nodesetval != NULL &&
1967 +        obj->nodesetval->nodeNr > 0) {
1968 +        int i;
1969 +        struct vserver_fstab *ent = NULL;
1970 +
1971 +        for (i = 0; i < obj->nodesetval->nodeNr; i++) {
1972 +            if (ent == NULL)
1973 +                guest->fstab = ent = calloc(1, sizeof(*ent));
1974 +            else {
1975 +                ent->next = calloc(1, sizeof(*ent));
1976 +                ent = ent->next;
1977 +            }
1978 +
1979 +            if (vserverParseDisk(ent, obj->nodesetval->nodeTab[i]) == -1)
1980 +                goto nodeset_err;
1981 +        }
1982 +    }
1983 +    if (obj)
1984 +        xmlXPathFreeObject(obj);
1985 +
1986 +    xmlXPathFreeContext(xpath);
1987 +    xpath = NULL;
1988 +
1989 +    return 0;
1990 +
1991 +nodeset_err:
1992 +    xmlXPathFreeObject(obj);
1993 +err:
1994 +    if (xpath)
1995 +        xmlXPathFreeContext(xpath);
1996 +    return -1;
1997 +}
1998 +
1999 +static virDomainPtr
2000 +vserverDomainDefineXML(virConnectPtr conn, const char *xml)
2001 +{
2002 +    struct vserver_driver *driver = conn->privateData;
2003 +    struct vserver_guest *guest, *tail;
2004 +    virDomainPtr domain;
2005 +    xmlDocPtr doc;
2006 +    char buf[128];
2007 +
2008 +    if ((guest = calloc(1, sizeof(struct vserver_guest))) == NULL) {
2009 +        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "vserver_guest");
2010 +        return NULL;
2011 +    }
2012 +
2013 +    if ((doc = xmlReadDoc(BAD_CAST xml, "domain.xml", NULL,
2014 +                          XML_PARSE_NOENT | XML_PARSE_NONET |
2015 +                          XML_PARSE_NOWARNING | XML_PARSE_NOERROR)) == NULL) {
2016 +        vserverError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
2017 +        free(guest);
2018 +        return NULL;
2019 +    }
2020 +
2021 +    if (vserverParseXML(guest, doc) == -1) {
2022 +        vserverError(conn, NULL, NULL, VIR_ERR_XML_ERROR, _("domain"));
2023 +        xmlFreeDoc(doc);
2024 +        free(guest);
2025 +        return NULL;
2026 +    }
2027 +
2028 +    xmlFreeDoc(doc);
2029 +
2030 +    guest->path = calloc(sizeof(VSERVER_CONF_DIR "/") + strlen(guest->name), sizeof(char));
2031 +    sprintf(guest->path, VSERVER_CONF_DIR "/%s", guest->name);
2032 +    guest->status = VIR_DOMAIN_SHUTOFF;
2033 +    if (vserverRunCommand(0, PROG_VSERVER, guest->name, "build", "-m",
2034 +                   "skeleton", "--confdir", guest->path, NULL) != 0) {
2035 +        vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, "vserver build");
2036 +        free(guest);
2037 +        return NULL;
2038 +    }
2039 +    virUUIDFormat(guest->uuid, buf);
2040 +    if (vserverWriteGuestToConfig(guest) == -1) {
2041 +        vserverError(conn, NULL, NULL, VIR_ERR_SYSTEM_ERROR, "vserverWriteToConfig");
2042 +        free(guest);
2043 +        return NULL;
2044 +    }
2045 +
2046 +    /* add it to the list */
2047 +    for (tail = driver->guests; tail && tail->next; tail = tail->next)
2048 +        ;
2049 +    if (!tail)
2050 +        driver->guests = guest;
2051 +    else
2052 +        tail->next = guest;
2053 +
2054 +    driver->inactive_guests++;
2055 +
2056 +    domain = virGetDomain(conn, guest->name, guest->uuid);
2057 +    if (!domain)
2058 +        vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "virGetDomain");
2059 +
2060 +    return domain;
2061 +}
2062 +
2063 +static int
2064 +vserverListDefinedDomains(virConnectPtr conn, char **const names,
2065 +                          int maxnames)
2066 +{
2067 +    struct vserver_driver *driver = conn->privateData;
2068 +    struct vserver_guest *guest;
2069 +    int i = 0;
2070 +
2071 +    for (guest = driver->guests; guest && i < maxnames; guest = guest->next) {
2072 +        if (guest->status == VIR_DOMAIN_SHUTOFF) {
2073 +            if ((names[i++] = strdup(guest->name)) == NULL) {
2074 +                vserverError(conn, NULL, NULL, VIR_ERR_NO_MEMORY, "names");
2075 +                return -1;
2076 +            }
2077 +        }
2078 +    }
2079 +
2080 +    return i;
2081 +}
2082 +
2083 +static int
2084 +vserverNumOfDefinedDomains(virConnectPtr conn)
2085 +{
2086 +    struct vserver_driver *driver = conn->privateData;
2087 +
2088 +    return driver->inactive_guests;
2089 +}
2090 +
2091 +static int
2092 +vserverDomainCreate(virDomainPtr domain)
2093 +{
2094 +    GET_DOMAIN(domain, -1);
2095 +
2096 +    if (vserverRunCommand(1, PROG_VSERVER, guest->path, "start", NULL) != 0) {
2097 +        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
2098 +                     "vserver start");
2099 +        return -1;
2100 +    }
2101 +
2102 +    driver->inactive_guests--;
2103 +    guest->status = VIR_DOMAIN_RUNNING;
2104 +    driver->active_guests++;
2105 +    return 0;
2106 +}
2107 +
2108 +static virDomainPtr
2109 +vserverDomainCreateLinux(virConnectPtr conn, const char *xml,
2110 +                         unsigned int flags ATTRIBUTE_UNUSED)
2111 +{
2112 +    virDomainPtr domain;
2113 +
2114 +    domain = vserverDomainDefineXML(conn, xml);
2115 +    if (!domain)
2116 +        return NULL;
2117 +
2118 +    if (vserverDomainCreate(domain) == -1)
2119 +        return NULL;
2120 +
2121 +    return domain;
2122 +}
2123 +
2124 +static int
2125 +vserverDomainUndefine(virDomainPtr domain)
2126 +{
2127 +    struct vserver_guest *prev;
2128 +    GET_DOMAIN(domain, -1);
2129 +
2130 +    for (prev = driver->guests; prev; prev = prev->next) {
2131 +        if (prev->next == guest)
2132 +            break;
2133 +    }
2134 +    if (!prev) {
2135 +        vserverError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
2136 +                     _("domain not found"));
2137 +        return -1;
2138 +    }
2139 +    if (vserverIsRunning(guest)) {
2140 +        vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG,
2141 +                     _("domain is running"));
2142 +        return -1;
2143 +    }
2144 +
2145 +    driver->inactive_guests--;
2146 +    prev->next = guest->next;
2147 +    /* XXX: deletes the domain's contents as well */
2148 +    vserverRunCommand(0, PROG_VSERVER, "--silent", guest->path, "delete", NULL);
2149 +    free(guest);
2150 +
2151 +    return 0;
2152 +}
2153 +
2154 +static int
2155 +doMount(int do_umount, struct vserver_guest *guest, struct vserver_fstab *ent)
2156 +{
2157 +    pid_t child;
2158 +    int status;
2159 +
2160 +    if ((child = fork()) == 0) {
2161 +        if (vc_enter_namespace(guest->xid, CLONE_NEWNS|CLONE_FS) == -1)
2162 +            _exit(errno);
2163 +        if (do_umount) {
2164 +            if (sys_umount(ent->target, MNT_DETACH) == -1)
2165 +                _exit(errno);
2166 +        }
2167 +        else {
2168 +            char target[strlen(guest->path) + sizeof("/vdir/") + strlen(ent->target)];
2169 +            sprintf(target, "%s/vdir/%s", guest->path, ent->target);
2170 +            if (vserverRunCommand(0, "mount", "-t", ent->fstype, "-n", "-o",
2171 +                                  ent->options, ent->source, target, NULL))
2172 +                _exit(errno);
2173 +        }
2174 +        _exit(0);
2175 +    }
2176 +    else if (child == -1)
2177 +        return -1;
2178 +    else {
2179 +        if (waitpid(child, &status, 0) == -1)
2180 +            return -1;
2181 +        if (WEXITSTATUS(status) != 0) {
2182 +            errno = WEXITSTATUS(status);
2183 +            return -1;
2184 +        }
2185 +    }
2186 +
2187 +    return 0;
2188 +}
2189 +
2190 +static int
2191 +vserverDomainHandleDevice(virDomainPtr domain, const char *xml, int attach)
2192 +{
2193 +    xmlDocPtr doc;
2194 +    xmlNodePtr node;
2195 +    GET_DOMAIN(domain, -1);
2196 +
2197 +    if ((doc = xmlReadDoc(BAD_CAST xml, "device.xml", NULL,
2198 +                          XML_PARSE_NOENT | XML_PARSE_NONET |
2199 +                          XML_PARSE_NOWARNING | XML_PARSE_NOERROR)) == NULL) {
2200 +        vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR, _("device"));
2201 +        return -1;
2202 +    }
2203 +
2204 +    node = xmlDocGetRootElement(doc);
2205 +    if (node == NULL) {
2206 +        vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
2207 +                     _("missing root element"));
2208 +        return -1;
2209 +    }
2210 +
2211 +    if (xmlStrEqual(node->name, BAD_CAST "interface")) {
2212 +        xmlNodePtr child;
2213 +        struct vserver_ip *ip;
2214 +
2215 +        for (child = node->children; child; child = child->next) {
2216 +            if (child->type != XML_ELEMENT_NODE)
2217 +                continue;
2218 +
2219 +            /* This should be an only child, but who knows. */
2220 +            if (xmlStrEqual(child->name, BAD_CAST "ip"))
2221 +                break;
2222 +        }
2223 +        if (!child) {
2224 +            vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
2225 +                         _("no <ip> element found"));
2226 +            return -1;
2227 +        }
2228 +
2229 +        ip = calloc(1, sizeof(*ip));
2230 +        if (vserverParseIP(ip, child) == -1) {
2231 +            vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
2232 +                         _("parsing IP failed"));
2233 +            return -1;
2234 +        }
2235 +
2236 +        if (attach) {
2237 +            list_add_tail(guest->ips, ip);
2238 +            if (vserverIsRunning(guest)) {
2239 +                if (vc_net_add(guest->xid, &ip->addr) == -1) {
2240 +                    vserverError(domain->conn, domain, NULL,
2241 +                                 VIR_ERR_SYSTEM_ERROR, strerror(errno));
2242 +                    return -1;
2243 +                }
2244 +            }
2245 +        }
2246 +
2247 +        else /* detach */ {
2248 +            struct vserver_ip *i, *p = NULL;
2249 +            for (i = guest->ips; i; i = i->next) {
2250 +                if (strcmp(ip->interface, i->interface) == 0 &&
2251 +                    memcmp(&ip->addr, &i->addr, sizeof(ip->addr)) == 0)
2252 +                    break;
2253 +                p = i;
2254 +            }
2255 +            if (i) {
2256 +                if (p)
2257 +                    p->next = i->next;
2258 +                else
2259 +                    guest->ips = i->next;
2260 +                if (vserverIsRunning(guest)) {
2261 +                    /* Not a lot of kernels support this, so don't fail. */
2262 +                    vc_net_remove(guest->xid, &ip->addr);
2263 +                }
2264 +                free(i);
2265 +            }
2266 +            free(ip);
2267 +        }
2268 +    }
2269 +    else if (xmlStrEqual(node->name, BAD_CAST "disk")) {
2270 +        struct vserver_fstab *ent = calloc(1, sizeof(*ent));
2271 +        if (!ent) {
2272 +            vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY, NULL);
2273 +            return -1;
2274 +        }
2275 +
2276 +        if (vserverParseDisk(ent, node) == -1) {
2277 +            vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR, "disk");
2278 +            return -1;
2279 +        }
2280 +
2281 +        if (attach) {
2282 +            list_add_tail(guest->fstab, ent);
2283 +            if (vserverIsRunning(guest)) {
2284 +                if (doMount(0, guest, ent) == -1) {
2285 +                    vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
2286 +                                 strerror(errno));
2287 +                    return -1;
2288 +                }
2289 +            }
2290 +        }
2291 +
2292 +        else /* detach */ {
2293 +            struct vserver_fstab *i, *p = NULL;
2294 +            for (i = guest->fstab; i; i = i->next) {
2295 +                /* These are the fields we care about */
2296 +                if (strcmp(ent->source, i->source) == 0 &&
2297 +                    strcmp(ent->target, i->target) == 0 &&
2298 +                    strcmp(ent->source_type, i->source_type) == 0)
2299 +                    break;
2300 +                p = i;
2301 +            }
2302 +            if (i) {
2303 +                if (p)
2304 +                    p->next = i->next;
2305 +                else
2306 +                    guest->fstab = i->next;
2307 +                if (vserverIsRunning(guest)) {
2308 +                    if (doMount(1, guest, ent) == -1) {
2309 +                        vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
2310 +                                     strerror(errno));
2311 +                        return -1;
2312 +                    }
2313 +                }
2314 +                freeFstab(i);
2315 +            }
2316 +            freeFstab(ent);
2317 +        }
2318 +    }
2319 +    else {
2320 +        vserverError(domain->conn, domain, NULL, VIR_ERR_XML_ERROR,
2321 +                     _("unknown device type"));
2322 +        return -1;
2323 +    }
2324 +
2325 +    /* Both fstab and interfaces need a lot of writing, so write the whole thing */
2326 +    if (vserverWriteGuestToConfig(guest) == -1) {
2327 +        vserverError(domain->conn, domain, NULL, VIR_ERR_WRITE_FAILED, guest->name);
2328 +        return -1;
2329 +    }
2330 +
2331 +    xmlFreeDoc(doc);
2332 +
2333 +    return 0;
2334 +}
2335 +
2336 +static int
2337 +vserverDomainAttachDevice(virDomainPtr domain, const char *xml)
2338 +{
2339 +    return vserverDomainHandleDevice(domain, xml, 1);
2340 +}
2341 +
2342 +static int
2343 +vserverDomainDetachDevice(virDomainPtr domain, const char *xml)
2344 +{
2345 +    return vserverDomainHandleDevice(domain, xml, 0);
2346 +}
2347 +
2348 +static int
2349 +vserverDomainGetAutostart(virDomainPtr domain, int *autostart)
2350 +{
2351 +    GET_DOMAIN(domain, -1);
2352 +
2353 +    *autostart = guest->autostart;
2354 +    return 0;
2355 +}
2356 +
2357 +static int
2358 +vserverDomainSetAutostart(virDomainPtr domain, int autostart)
2359 +{
2360 +    GET_DOMAIN(domain, -1);
2361 +
2362 +    if (vserverWriteToConfig(guest, "apps/init/mark",
2363 +                      (autostart ? "default\n" : "\n")) == -1) {
2364 +        vserverError(domain->conn, domain, NULL, VIR_ERR_WRITE_FAILED,
2365 +                     "apps/init/mark");
2366 +        return -1;
2367 +    }
2368 +    guest->autostart = autostart;
2369 +    return 0;
2370 +}
2371 +
2372 +static const struct {
2373 +    unsigned int id;
2374 +    const char *field;
2375 +    int type;
2376 +} sched_fields[] = {
2377 +    { VC_VXSM_FILL_RATE,  "fill_rate1",   VIR_DOMAIN_SCHED_FIELD_UINT },
2378 +    { VC_VXSM_INTERVAL,   "interval1",    VIR_DOMAIN_SCHED_FIELD_UINT },
2379 +    { VC_VXSM_FILL_RATE2, "fill_rate2",   VIR_DOMAIN_SCHED_FIELD_UINT },
2380 +    { VC_VXSM_INTERVAL2,  "interval2",    VIR_DOMAIN_SCHED_FIELD_UINT },
2381 +    { VC_VXSM_TOKENS_MIN, "tokens_min",   VIR_DOMAIN_SCHED_FIELD_UINT },
2382 +    { VC_VXSM_TOKENS_MAX, "tokens_max",   VIR_DOMAIN_SCHED_FIELD_UINT },
2383 +    { VC_VXSM_PRIO_BIAS,  "prio_bias",    VIR_DOMAIN_SCHED_FIELD_INT  },
2384 +    { VC_VXSM_IDLE_TIME,  "idle_time",    VIR_DOMAIN_SCHED_FIELD_BOOLEAN },
2385 +    { 0, NULL, 0 }
2386 +};
2387 +
2388 +static char *
2389 +vserverDomainGetSchedulerType(virDomainPtr domain, int *nparams)
2390 +{
2391 +    char *ret;
2392 +    int i;
2393 +    GET_DOMAIN(domain, NULL);
2394 +
2395 +    ret = strdup(guest->sched.set_mask & VC_VXSM_IDLE_TIME ? "fair" : "hard");
2396 +    if (!ret) {
2397 +        vserverError(domain->conn, domain, NULL, VIR_ERR_NO_MEMORY,
2398 +                     _("scheduler"));
2399 +        return NULL;
2400 +    }
2401 +
2402 +    *nparams = 0;
2403 +    for (i = 0; sched_fields[i].field != NULL; i++) {
2404 +        /* only returns fields which are set */
2405 +        if (guest->sched.set_mask & sched_fields[i].id)
2406 +            (*nparams)++;
2407 +    }
2408 +
2409 +    return ret;
2410 +}
2411 +
2412 +static int
2413 +vserverDomainGetSchedulerParams(virDomainPtr domain,
2414 +                                virSchedParameterPtr params,
2415 +                                int *nparams)
2416 +{
2417 +    int i, j;
2418 +    GET_DOMAIN(domain, -1);
2419 +
2420 +    for (i = 0, j = 0; sched_fields[i].field != NULL && i < *nparams; i++) {
2421 +        /* skip unset fields */
2422 +        if (!(guest->sched.set_mask & sched_fields[i].id))
2423 +            continue;
2424 +
2425 +        params[j].type = sched_fields[i].type;
2426 +        strncpy(params[j].field, sched_fields[i].field, sizeof(params[j].field) - 1);
2427 +        switch (sched_fields[i].id) {
2428 +            case VC_VXSM_FILL_RATE:
2429 +                params[j].value.ui = guest->sched.fill_rate;
2430 +                break;
2431 +            case VC_VXSM_INTERVAL:
2432 +                params[j].value.ui = guest->sched.interval;
2433 +                break;
2434 +            case VC_VXSM_FILL_RATE2:
2435 +                params[j].value.ui = guest->sched.fill_rate2;
2436 +                break;
2437 +            case VC_VXSM_INTERVAL2:
2438 +                params[j].value.ui = guest->sched.interval2;
2439 +                break;
2440 +            case VC_VXSM_TOKENS_MIN:
2441 +                params[j].value.ui = guest->sched.tokens_min;
2442 +                break;
2443 +            case VC_VXSM_TOKENS_MAX:
2444 +                params[j].value.ui = guest->sched.tokens_max;
2445 +                break;
2446 +            case VC_VXSM_PRIO_BIAS:
2447 +                params[j].value.i = guest->sched.priority_bias;
2448 +                break;
2449 +            case VC_VXSM_IDLE_TIME:
2450 +                params[j].value.b = guest->sched.set_mask & VC_VXSM_IDLE_TIME;
2451 +                break;
2452 +        }
2453 +        j++;
2454 +    }
2455 +    *nparams = j;
2456 +
2457 +    return 0;
2458 +}
2459 +
2460 +static int
2461 +vserverDomainSetSchedulerParams(virDomainPtr domain,
2462 +                                virSchedParameterPtr params,
2463 +                                int nparams)
2464 +{
2465 +    int i, j, cret;
2466 +    GET_DOMAIN(domain, -1);
2467 +
2468 +    for (i = 0; i < nparams; i++) {
2469 +        for (j = 0; sched_fields[j].field != NULL; j++) {
2470 +            if (STREQ(sched_fields[j].field, params[i].field))
2471 +                break;
2472 +        }
2473 +        if (sched_fields[j].field == NULL) {
2474 +            vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "field");
2475 +            return -1;
2476 +        }
2477 +        if (sched_fields[j].type != params[i].type) {
2478 +            vserverError(domain->conn, domain, NULL, VIR_ERR_INVALID_ARG, "type");
2479 +            return -1;
2480 +        }
2481 +        switch (sched_fields[j].id) {
2482 +            case VC_VXSM_FILL_RATE:
2483 +                guest->sched.fill_rate = params[i].value.ui;
2484 +                cret = vserverWriteToConfig(guest, "sched/fill-rate", "%u\n",
2485 +                                     params[i].value.ui);
2486 +                break;
2487 +            case VC_VXSM_INTERVAL:
2488 +                guest->sched.interval = params[i].value.ui;
2489 +                cret = vserverWriteToConfig(guest, "sched/interval", "%u\n",
2490 +                                     params[i].value.ui);
2491 +                break;
2492 +            case VC_VXSM_FILL_RATE2:
2493 +                guest->sched.fill_rate2 = params[i].value.ui;
2494 +                cret = vserverWriteToConfig(guest, "sched/fill-rate2", "%u\n",
2495 +                                     params[i].value.ui);
2496 +                break;
2497 +            case VC_VXSM_INTERVAL2:
2498 +                guest->sched.interval2 = params[i].value.ui;
2499 +                cret = vserverWriteToConfig(guest, "sched/interval2", "%u\n",
2500 +                                     params[i].value.ui);
2501 +                break;
2502 +            case VC_VXSM_TOKENS_MIN:
2503 +                guest->sched.tokens_min = params[i].value.ui;
2504 +                cret = vserverWriteToConfig(guest, "sched/tokens-min", "%u\n",
2505 +                                     params[i].value.ui);
2506 +                break;
2507 +            case VC_VXSM_TOKENS_MAX:
2508 +                guest->sched.tokens_max = params[i].value.ui;
2509 +                cret = vserverWriteToConfig(guest, "sched/tokens-max", "%u\n",
2510 +                                     params[i].value.ui);
2511 +                break;
2512 +            case VC_VXSM_PRIO_BIAS:
2513 +                guest->sched.priority_bias = params[i].value.i;
2514 +                cret = vserverWriteToConfig(guest, "sched/prio-bias", "%d\n",
2515 +                                     params[i].value.i);
2516 +                break;
2517 +            case VC_VXSM_IDLE_TIME:
2518 +                cret = vserverWriteToConfig(guest, "sched/idle-time", "%b",
2519 +                                     params[i].value.b);
2520 +                break;
2521 +            default:
2522 +                vserverError(domain->conn, domain, NULL, VIR_ERR_INTERNAL_ERROR,
2523 +                             "Unknown scheduler parameter");
2524 +                return -1;
2525 +        }
2526 +        if (cret == -1) {
2527 +            vserverError(domain->conn, domain, NULL, VIR_ERR_SYSTEM_ERROR,
2528 +                         "vserverWriteToConfig");
2529 +            return -1;
2530 +        }
2531 +        guest->sched.set_mask |= sched_fields[j].id;
2532 +    }
2533 +
2534 +    return 0;
2535 +}
2536 +
2537 +
2538 +virDriver vserverDriver = {
2539 +    VIR_DRV_VSERVER,
2540 +    "Linux-VServer",
2541 +    LIBVIR_VERSION_NUMBER,
2542 +    vserverOpen,
2543 +    vserverClose,
2544 +    NULL,   /* supports_feature */
2545 +    vserverGetType,
2546 +    vserverGetVersion,
2547 +    vserverGetHostname,
2548 +    vserverGetURI,
2549 +    NULL,   /* getMaxVcpus */
2550 +    vserverNodeGetInfo,
2551 +    NULL,   /* getCapabilties */
2552 +    vserverListDomains,
2553 +    vserverNumOfDomains,
2554 +    vserverDomainCreateLinux,
2555 +    vserverDomainLookupByID,
2556 +    vserverDomainLookupByUUID,
2557 +    vserverDomainLookupByName,
2558 +    vserverDomainSuspend,
2559 +    vserverDomainResume,
2560 +    vserverDomainShutdown,
2561 +    vserverDomainReboot,
2562 +    vserverDomainDestroy,
2563 +    vserverDomainGetOSType,
2564 +    vserverDomainGetMaxMemory,
2565 +    vserverDomainSetMaxMemory,
2566 +    NULL,   /* domainSetMemory */
2567 +    vserverDomainGetInfo,
2568 +    NULL,   /* domainSave */
2569 +    NULL,   /* domainRestore */
2570 +    NULL,   /* domainCoreDump */
2571 +    NULL,   /* domainSetVcpus */
2572 +    NULL,   /* domainPinVcpu */
2573 +    NULL,   /* domainGetVcpus */
2574 +    NULL,   /* domainGetMaxVcpus */
2575 +    vserverDomainDumpXML,
2576 +    vserverListDefinedDomains,
2577 +    vserverNumOfDefinedDomains,
2578 +    vserverDomainCreate,
2579 +    vserverDomainDefineXML,
2580 +    vserverDomainUndefine,
2581 +    vserverDomainAttachDevice,
2582 +    vserverDomainDetachDevice,
2583 +    vserverDomainGetAutostart,
2584 +    vserverDomainSetAutostart,
2585 +    vserverDomainGetSchedulerType,
2586 +    vserverDomainGetSchedulerParams,
2587 +    vserverDomainSetSchedulerParams,
2588 +    NULL,   /* domainMigratePrepare  */
2589 +    NULL,   /* domainMigratePerform */
2590 +    NULL,   /* domainMigrateFinish */
2591 +    NULL,   /* domainBlockStats */
2592 +    NULL,   /* domainInterfaceStats */
2593 +    NULL,   /* nodeGetCellsFreeMemory */
2594 +    NULL,   /* getFreeMemory */
2595 +};
2596 +
2597 +int vserverRegister(void)
2598 +{
2599 +    if (virRegisterDriver(&vserverDriver) < 0)
2600 +        return -1;
2601 +    return 0;
2602 +}
2603 +
2604 +#endif
2605 --- libvirt-0.4.0.orig/src/vserver/vserver_driver.h     1970-01-01 01:00:00.000000000 +0100
2606 +++ libvirt-0.4.0.vserver/src/vserver/vserver_driver.h  2008-01-09 19:14:08.000000000 +0100
2607 @@ -0,0 +1,137 @@
2608 +/*
2609 + * Core driver for managing Linux-VServer guests
2610 + *
2611 + * Copyright (C) 2007 Daniel Hokka Zakrisson
2612 + *
2613 + * This library is free software; you can redistribute it and/or
2614 + * modify it under the terms of the GNU Lesser General Public
2615 + * License as published by the Free Software Foundation; either
2616 + * version 2.1 of the License, or (at your option) any later version.
2617 + *
2618 + * This library is distributed in the hope that it will be useful,
2619 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
2620 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
2621 + * Lesser General Public License for more details.
2622 + *
2623 + * You should have received a copy of the GNU Lesser General Public
2624 + * License along with this library; if not, write to the Free Software
2625 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
2626 + *
2627 + * Author: Daniel Hokka Zakrisson <daniel hozac com>
2628 + */
2629 +
2630 +#ifdef WITH_VSERVER
2631 +
2632 +/* Kind of a hack */
2633 +#ifdef IN_VSERVER
2634 +#ifndef HAVE_XID_T
2635 +typedef unsigned int xid_t;
2636 +#endif
2637 +#ifndef HAVE_NID_T
2638 +typedef unsigned int nid_t;
2639 +#endif
2640 +#ifndef HAVE_TAG_T
2641 +typedef unsigned int tag_t;
2642 +#endif
2643 +#include <vserver.h>
2644 +
2645 +#define VSERVER_NAME_MAX                   64
2646 +#define VSERVER_UTS_MAX             255
2647 +
2648 +enum vserver_initstyle {
2649 +    VSERVER_INIT_NONE,
2650 +    VSERVER_INIT_SYSV,
2651 +    VSERVER_INIT_PLAIN,
2652 +    VSERVER_INIT_GENTOO,
2653 +    VSERVER_INIT_MINIT,
2654 +};
2655 +
2656 +struct vserver_ip {
2657 +    char interface[IFNAMSIZ+1];
2658 +    struct vc_net_addr addr;
2659 +    struct vserver_ip *next;
2660 +};
2661 +
2662 +enum fstab_flags {
2663 +    VSERVER_FSTAB_SHOW=1,
2664 +    VSERVER_FSTAB_OUTPUT=2,
2665 +};
2666 +struct vserver_fstab {
2667 +    char *source;
2668 +    const char *source_type;
2669 +    char *target;
2670 +    char *fstype;
2671 +    char *options;
2672 +    char *rest;
2673 +    int flags;
2674 +    struct vserver_fstab *next;
2675 +};
2676 +
2677 +struct vserver_guest {
2678 +    xid_t xid;
2679 +    char name[VSERVER_NAME_MAX];
2680 +    unsigned char uuid[VIR_UUID_BUFLEN];
2681 +    char *path;
2682 +
2683 +    struct {
2684 +        char hostname[VSERVER_UTS_MAX];
2685 +        char machine[VSERVER_UTS_MAX];
2686 +        char release[VSERVER_UTS_MAX];
2687 +        char version[VSERVER_UTS_MAX];
2688 +    } uts;
2689 +
2690 +    struct vserver_ip *ips;
2691 +
2692 +    struct vc_set_sched sched;
2693 +    unsigned long rss_hard;
2694 +
2695 +    char autostart;
2696 +    enum vserver_initstyle initstyle;
2697 +
2698 +    int status;
2699 +
2700 +    struct vserver_fstab *fstab;
2701 +
2702 +    struct vserver_guest *next;
2703 +};
2704 +
2705 +struct vserver_driver {
2706 +    struct vserver_guest *guests;
2707 +    xmlChar *uri;
2708 +    unsigned int active_guests;
2709 +    unsigned int inactive_guests;
2710 +    unsigned int initialized : 1;
2711 +};
2712 +
2713 +
2714 +#define list_add_tail(list, elem)                               \
2715 +    do {                                                        \
2716 +        __typeof__(list) iter;                                  \
2717 +        if (list) {                                             \
2718 +            for (iter = list; iter->next; iter = iter->next)    \
2719 +                ;                                               \
2720 +            iter->next = elem;                                  \
2721 +        }                                                       \
2722 +        else                                                    \
2723 +            list = elem;                                        \
2724 +    } while (0)
2725 +
2726 +static inline int
2727 +vserverIsRunning(struct vserver_guest *guest) {
2728 +    if (guest->status == VIR_DOMAIN_RUNNING || guest->status == VIR_DOMAIN_PAUSED)
2729 +        return 1;
2730 +    else
2731 +        return 0;
2732 +}
2733 +
2734 +
2735 +int vserverContextIsRunning(const char *path);
2736 +int vserverRunCommand(int do_daemon, const char *cmd, ...);
2737 +void vserverError(virConnectPtr con, virDomainPtr dom, virNetworkPtr net,
2738 +                  virErrorNumber error, const char *info);
2739 +#endif
2740 +
2741 +
2742 +extern int vserverRegister(void);
2743 +
2744 +#endif