xend_internal.c 177.6 KB
Newer Older
1 2 3
/*
 * xend_internal.c: access to Xen though the Xen Daemon interface
 *
4 5
 * Copyright (C) 2010 Red Hat, Inc.
 * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
6 7 8 9 10 11
 *
 *  This file is subject to the terms and conditions of the GNU Lesser General
 *  Public License. See the file COPYING.LIB in the main directory of this
 *  archive for more details.
 */

12
#include <config.h>
13

14 15 16 17 18
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/errno.h>
R
Richard W.M. Jones 已提交
19 20
#include <sys/stat.h>
#include <fcntl.h>
21 22 23 24 25 26 27 28 29 30
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <stdarg.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
31
#include <libxml/uri.h>
32
#include <errno.h>
33

34
#include "virterror_internal.h"
35
#include "logging.h"
36
#include "datatypes.h"
37
#include "xend_internal.h"
38
#include "driver.h"
39
#include "util.h"
40
#include "sexpr.h"
41
#include "buf.h"
42
#include "uuid.h"
43 44
#include "xen_driver.h"
#include "xen_hypervisor.h"
45
#include "xs_internal.h" /* To extract VNC port & Serial console TTY */
46
#include "memory.h"
47

48 49 50
/* required for cpumap_t */
#include <xen/dom0_ops.h>

51 52
#define VIR_FROM_THIS VIR_FROM_XEND

53
#ifndef PROXY
54 55 56 57

/*
 * The number of Xen scheduler parameters
 */
58 59
# define XEN_SCHED_SEDF_NPARAM   6
# define XEN_SCHED_CRED_NPARAM   2
60

61
#endif /* PROXY */
62

63
#ifdef WITH_RHEL5_API
64 65
# define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 0
# define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 2
66
#else
67 68
# define XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU 3
# define XEND_CONFIG_MIN_VERS_PVFB_NEWCONF 3
69 70
#endif

D
Daniel Veillard 已提交
71

72 73 74 75 76 77
#ifndef PROXY
static int
xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
                        virDomainDiskDefPtr def,
                        virBufferPtr buf,
                        int hvm,
78 79
                        int xendConfigVersion,
                        int isAttach);
80 81 82 83 84
static int
xenDaemonFormatSxprNet(virConnectPtr conn ATTRIBUTE_UNUSED,
                       virDomainNetDefPtr def,
                       virBufferPtr buf,
                       int hvm,
85 86
                       int xendConfigVersion,
                       int isAttach);
87
static int
88
xenDaemonFormatSxprOnePCI(virDomainHostdevDefPtr def,
89 90
                          virBufferPtr buf,
                          int detach);
91 92

static int
93 94 95 96 97 98 99
virDomainXMLDevID(virDomainPtr domain,
                  virDomainDeviceDefPtr dev,
                  char *class,
                  char *ref,
                  int ref_len);
#endif

100 101
#define virXendError(code, ...)                                            \
        virReportErrorHelper(NULL, VIR_FROM_XEND, code, __FILE__,          \
102
                             __FUNCTION__, __LINE__, __VA_ARGS__)
103

104 105
#define virXendErrorInt(code, ival)                                        \
        virXendError(code, "%d", ival)
106

107 108 109 110 111 112 113 114 115
/**
 * do_connect:
 * @xend: pointer to the Xen Daemon structure
 *
 * Internal routine to (re)connect to the daemon
 *
 * Returns the socket file descriptor or -1 in case of error
 */
static int
116
do_connect(virConnectPtr xend)
117 118 119
{
    int s;
    int serrno;
120
    int no_slow_start = 1;
121
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) xend->privateData;
122

123
    s = socket(priv->addrfamily, SOCK_STREAM, priv->addrprotocol);
D
Daniel Veillard 已提交
124
    if (s == -1) {
125
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
126
                     "%s", _("failed to create a socket"));
127
        return -1;
D
Daniel Veillard 已提交
128
    }
129

130 131 132 133 134 135 136
    /*
     * try to desactivate slow-start
     */
    setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
               sizeof(no_slow_start));


137
    if (connect(s, (struct sockaddr *)&priv->addr, priv->addrlen) == -1) {
138 139 140 141
        serrno = errno;
        close(s);
        errno = serrno;
        s = -1;
142 143

        /*
J
John Levon 已提交
144 145
         * Connecting to XenD when privileged is mandatory, so log this
         * error
146
         */
J
John Levon 已提交
147
        if (xenHavePrivilege()) {
148
            virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
149
                         "%s", _("failed to connect to xend"));
150
        }
151 152 153 154 155 156 157
    }

    return s;
}

/**
 * wr_sync:
158
 * @xend: the xend connection object
159 160 161 162 163 164 165 166 167 168
 * @fd:  the file descriptor
 * @buffer: the I/O buffer
 * @size: the size of the I/O
 * @do_read: write operation if 0, read operation otherwise
 *
 * Do a synchronous read or write on the file descriptor
 *
 * Returns the number of bytes exchanged, or -1 in case of error
 */
static size_t
169
wr_sync(int fd, void *buffer, size_t size, int do_read)
170 171 172 173 174 175 176
{
    size_t offset = 0;

    while (offset < size) {
        ssize_t len;

        if (do_read) {
177
            len = read(fd, ((char *) buffer) + offset, size - offset);
178
        } else {
179
            len = write(fd, ((char *) buffer) + offset, size - offset);
180 181 182 183 184 185 186 187 188 189 190 191 192 193
        }

        /* recoverable error, retry  */
        if ((len == -1) && ((errno == EAGAIN) || (errno == EINTR))) {
            continue;
        }

        /* eof */
        if (len == 0) {
            break;
        }

        /* unrecoverable error */
        if (len == -1) {
194
            if (do_read)
195
                virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
196
                             "%s", _("failed to read from Xen Daemon"));
197
            else
198
                virXendError(VIR_ERR_INTERNAL_ERROR,
199
                             "%s", _("failed to write to Xen Daemon"));
200 201

            return (-1);
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
        }

        offset += len;
    }

    return offset;
}

/**
 * sread:
 * @fd:  the file descriptor
 * @buffer: the I/O buffer
 * @size: the size of the I/O
 *
 * Internal routine to do a synchronous read
 *
 * Returns the number of bytes read, or -1 in case of error
 */
static ssize_t
221
sread(int fd, void *buffer, size_t size)
222
{
223
    return wr_sync(fd, buffer, size, 1);
224 225 226 227 228 229 230 231 232 233 234 235 236
}

/**
 * swrite:
 * @fd:  the file descriptor
 * @buffer: the I/O buffer
 * @size: the size of the I/O
 *
 * Internal routine to do a synchronous write
 *
 * Returns the number of bytes written, or -1 in case of error
 */
static ssize_t
237
swrite(int fd, const void *buffer, size_t size)
238
{
239
    return wr_sync(fd, (void *) buffer, size, 0);
240 241 242 243 244 245 246 247 248 249 250 251
}

/**
 * swrites:
 * @fd:  the file descriptor
 * @string: the string to write
 *
 * Internal routine to do a synchronous write of a string
 *
 * Returns the number of bytes written, or -1 in case of error
 */
static ssize_t
252
swrites(int fd, const char *string)
253
{
254
    return swrite(fd, string, strlen(string));
255 256
}

257 258 259 260 261 262 263 264 265 266 267
/**
 * sreads:
 * @fd:  the file descriptor
 * @buffer: the I/O buffer
 * @n_buffer: the size of the I/O buffer
 *
 * Internal routine to do a synchronous read of a line
 *
 * Returns the number of bytes read, or -1 in case of error
 */
static ssize_t
268
sreads(int fd, char *buffer, size_t n_buffer)
269 270 271 272 273 274 275 276 277
{
    size_t offset;

    if (n_buffer < 1)
        return (-1);

    for (offset = 0; offset < (n_buffer - 1); offset++) {
        ssize_t ret;

278
        ret = sread(fd, buffer + offset, 1);
279 280 281 282 283 284 285 286 287 288 289 290 291 292
        if (ret == 0)
            break;
        else if (ret == -1)
            return ret;

        if (buffer[offset] == '\n') {
            offset++;
            break;
        }
    }
    buffer[offset] = 0;

    return offset;
}
293 294 295 296

static int
istartswith(const char *haystack, const char *needle)
{
297
    return STRCASEEQLEN(haystack, needle, strlen(needle));
298 299
}

300

301 302 303 304 305 306
/**
 * xend_req:
 * @fd: the file descriptor
 * @content: the buffer to store the content
 *
 * Read the HTTP response from a Xen Daemon request.
307 308
 * If the response contains content, memory is allocated to
 * hold the content.
309
 *
310 311
 * Returns the HTTP return code and @content is set to the
 * allocated memory containing HTTP content.
312 313
 */
static int
314
xend_req(int fd, char **content)
315 316
{
    char buffer[4096];
317
    int content_length = 0;
318 319
    int retcode = 0;

320
    while (sreads(fd, buffer, sizeof(buffer)) > 0) {
321
        if (STREQ(buffer, "\r\n"))
322
            break;
323 324 325 326 327

        if (istartswith(buffer, "Content-Length: "))
            content_length = atoi(buffer + 16);
        else if (istartswith(buffer, "HTTP/1.1 "))
            retcode = atoi(buffer + 9);
328 329
    }

330
    if (content_length > 0) {
331 332
        ssize_t ret;

333 334 335 336
        if (VIR_ALLOC_N(*content, content_length) < 0 ) {
            virReportOOMError();
            return -1;
        }
337

338
        ret = sread(fd, *content, content_length);
339 340
        if (ret < 0)
            return -1;
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
    }

    return retcode;
}

/**
 * xend_get:
 * @xend: pointer to the Xen Daemon structure
 * @path: the path used for the HTTP request
 * @content: the buffer to store the content
 *
 * Do an HTTP GET RPC with the Xen Daemon
 *
 * Returns the HTTP return code or -1 in case or error.
 */
static int
357
xend_get(virConnectPtr xend, const char *path,
358
         char **content)
359 360 361 362 363 364 365
{
    int ret;
    int s = do_connect(xend);

    if (s == -1)
        return s;

366 367 368
    swrites(s, "GET ");
    swrites(s, path);
    swrites(s, " HTTP/1.1\r\n");
369

370
    swrites(s,
371 372 373 374
            "Host: localhost:8000\r\n"
            "Accept-Encoding: identity\r\n"
            "Content-Type: application/x-www-form-urlencoded\r\n" "\r\n");

375
    ret = xend_req(s, content);
376 377
    close(s);

378
    if (((ret < 0) || (ret >= 300)) &&
379
        ((ret != 404) || (!STRPREFIX(path, "/xend/domain/")))) {
380
        virXendError(VIR_ERR_GET_FAILED,
J
John Levon 已提交
381
                     _("%d status from xen daemon: %s:%s"),
382 383
                     ret, path,
                     content ? *content: "NULL");
D
Daniel Veillard 已提交
384 385
    }

386 387 388
    return ret;
}

389
#ifndef PROXY
390 391 392 393
/**
 * xend_post:
 * @xend: pointer to the Xen Daemon structure
 * @path: the path used for the HTTP request
394
 * @ops: the information sent for the POST
395 396 397 398 399 400 401
 *
 * Do an HTTP POST RPC with the Xen Daemon, this usually makes changes at the
 * Xen level.
 *
 * Returns the HTTP return code or -1 in case or error.
 */
static int
402
xend_post(virConnectPtr xend, const char *path, const char *ops)
403 404
{
    char buffer[100];
405
    char *err_buf = NULL;
406 407 408 409 410 411
    int ret;
    int s = do_connect(xend);

    if (s == -1)
        return s;

412 413 414
    swrites(s, "POST ");
    swrites(s, path);
    swrites(s, " HTTP/1.1\r\n");
415

416
    swrites(s,
417 418 419 420
            "Host: localhost:8000\r\n"
            "Accept-Encoding: identity\r\n"
            "Content-Type: application/x-www-form-urlencoded\r\n"
            "Content-Length: ");
421
    snprintf(buffer, sizeof(buffer), "%d", (int) strlen(ops));
422 423 424
    swrites(s, buffer);
    swrites(s, "\r\n\r\n");
    swrites(s, ops);
425

426
    ret = xend_req(s, &err_buf);
427 428
    close(s);

D
Daniel Veillard 已提交
429
    if ((ret < 0) || (ret >= 300)) {
430
        virXendError(VIR_ERR_POST_FAILED,
431 432
                     _("xend_post: error from xen daemon: %s"), err_buf);
    } else if ((ret == 202) && err_buf && (strstr(err_buf, "failed") != NULL)) {
433
        virXendError(VIR_ERR_POST_FAILED,
434
                     _("xend_post: error from xen daemon: %s"), err_buf);
435
        ret = -1;
436 437
    } else if (((ret >= 200) && (ret <= 202)) && err_buf &&
               (strstr(err_buf, "xend.err") != NULL)) {
438 439 440
        /* This is to catch case of things like 'virsh dump Domain-0 foo'
         * which returns a success code, but the word 'xend.err'
         * in body to indicate error :-(
441
         */
442
        virXendError(VIR_ERR_POST_FAILED,
443
                     _("xend_post: error from xen daemon: %s"), err_buf);
444
        ret = -1;
D
Daniel Veillard 已提交
445 446
    }

447
    VIR_FREE(err_buf);
448 449
    return ret;
}
450 451
#endif /* ! PROXY */

452 453 454 455 456 457 458 459 460 461

/**
 * http2unix:
 * @ret: the http return code
 *
 * Convert the HTTP return code to 0/-1 and set errno if needed
 *
 * Return -1 in case of error code 0 otherwise
 */
static int
462
http2unix(int ret)
463 464 465 466 467 468 469 470 471 472 473
{
    switch (ret) {
        case -1:
            break;
        case 200:
        case 201:
        case 202:
            return 0;
        case 404:
            errno = ESRCH;
            break;
474 475 476
        case 500:
            errno = EIO;
            break;
477
        default:
478
            virXendErrorInt(VIR_ERR_HTTP_ERROR, ret);
479 480 481 482 483 484
            errno = EINVAL;
            break;
    }
    return -1;
}

485
#ifndef PROXY
486
/**
487
 * xend_op_ext:
488 489 490 491 492 493 494 495 496 497
 * @xend: pointer to the Xen Daemon structure
 * @path: path for the object
 * @key: the key for the operation
 * @ap: input values to pass to the operation
 *
 * internal routine to run a POST RPC operation to the Xen Daemon
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
498
xend_op_ext(virConnectPtr xend, const char *path, const char *key, va_list ap)
499 500
{
    const char *k = key, *v;
501
    virBuffer buf = VIR_BUFFER_INITIALIZER;
502
    int ret;
503
    char *content;
504 505 506 507

    while (k) {
        v = va_arg(ap, const char *);

508 509 510
        virBufferVSprintf(&buf, "%s", k);
        virBufferVSprintf(&buf, "%s", "=");
        virBufferVSprintf(&buf, "%s", v);
511 512 513
        k = va_arg(ap, const char *);

        if (k)
514
            virBufferVSprintf(&buf, "%s", "&");
515 516
    }

517
    if (virBufferError(&buf)) {
518
        virBufferFreeAndReset(&buf);
519
        virReportOOMError();
520 521 522 523
        return -1;
    }

    content = virBufferContentAndReset(&buf);
524
    ret = http2unix(xend_post(xend, path, content));
525
    VIR_FREE(content);
526 527

    return ret;
528 529
}

530

531
/**
532
 * xend_op:
533 534 535 536 537 538 539 540 541 542 543
 * @xend: pointer to the Xen Daemon structure
 * @name: the domain name target of this operation
 * @key: the key for the operation
 * @ap: input values to pass to the operation
 * @...: input values to pass to the operation
 *
 * internal routine to run a POST RPC operation to the Xen Daemon targetting
 * a given domain.
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
P
Paolo Bonzini 已提交
544
static int ATTRIBUTE_SENTINEL
545
xend_op(virConnectPtr xend, const char *name, const char *key, ...)
546 547 548 549 550 551 552 553
{
    char buffer[1024];
    va_list ap;
    int ret;

    snprintf(buffer, sizeof(buffer), "/xend/domain/%s", name);

    va_start(ap, key);
554
    ret = xend_op_ext(xend, buffer, key, ap);
555 556 557 558 559
    va_end(ap);

    return ret;
}

560
#endif /* ! PROXY */
561 562 563 564 565 566 567 568 569 570 571

/**
 * sexpr_get:
 * @xend: pointer to the Xen Daemon structure
 * @fmt: format string for the path of the operation
 * @...: extra data to build the path of the operation
 *
 * Internal routine to run a simple GET RPC operation to the Xen Daemon
 *
 * Returns a parsed S-Expression in case of success, NULL in case of failure
 */
572
static struct sexpr *sexpr_get(virConnectPtr xend, const char *fmt, ...)
573
  ATTRIBUTE_FMT_PRINTF(2,3);
574

575
static struct sexpr *
576
sexpr_get(virConnectPtr xend, const char *fmt, ...)
577
{
578
    char *buffer = NULL;
579 580 581
    char path[1024];
    va_list ap;
    int ret;
582
    struct sexpr *res = NULL;
583 584 585 586 587

    va_start(ap, fmt);
    vsnprintf(path, sizeof(path), fmt, ap);
    va_end(ap);

588
    ret = xend_get(xend, path, &buffer);
589
    ret = http2unix(ret);
590
    if (ret == -1)
591 592 593 594 595 596
        goto cleanup;

    if (buffer == NULL)
        goto cleanup;

    res = string2sexpr(buffer);
597

598 599 600
cleanup:
    VIR_FREE(buffer);
    return res;
601 602 603 604 605 606 607 608 609
}

/**
 * sexpr_int:
 * @sexpr: an S-Expression
 * @name: the name for the value
 *
 * convenience function to lookup an int value in the S-Expression
 *
610 611 612
 * Returns the value found or 0 if not found (but may not be an error).
 * This function suffers from the flaw that zero is both a correct
 * return value and an error indicator: careful!
613 614
 */
static int
615
sexpr_int(const struct sexpr *sexpr, const char *name)
616 617 618 619 620 621 622 623 624
{
    const char *value = sexpr_node(sexpr, name);

    if (value) {
        return strtol(value, NULL, 0);
    }
    return 0;
}

625

626 627 628 629 630 631 632 633 634 635
/**
 * sexpr_float:
 * @sexpr: an S-Expression
 * @name: the name for the value
 *
 * convenience function to lookup a float value in the S-Expression
 *
 * Returns the value found or 0 if not found (but may not be an error)
 */
static double
636
sexpr_float(const struct sexpr *sexpr, const char *name)
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
{
    const char *value = sexpr_node(sexpr, name);

    if (value) {
        return strtod(value, NULL);
    }
    return 0;
}

/**
 * sexpr_u64:
 * @sexpr: an S-Expression
 * @name: the name for the value
 *
 * convenience function to lookup a 64bits unsigned int value in the
 * S-Expression
 *
 * Returns the value found or 0 if not found (but may not be an error)
 */
static uint64_t
657
sexpr_u64(const struct sexpr *sexpr, const char *name)
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
{
    const char *value = sexpr_node(sexpr, name);

    if (value) {
        return strtoll(value, NULL, 0);
    }
    return 0;
}


/**
 * sexpr_uuid:
 * @ptr: where to store the UUID, incremented
 * @sexpr: an S-Expression
 * @name: the name for the value
 *
 * convenience function to lookup an UUID value from the S-Expression
 *
676
 * Returns a -1 on error, 0 on success
677
 */
678
static int
679
sexpr_uuid(unsigned char *ptr, const struct sexpr *node, const char *path)
680 681
{
    const char *r = sexpr_node(node, path);
682 683 684
    if (!r)
        return -1;
    return virUUIDParse(r, ptr);
685 686 687
}


688
#ifndef PROXY
689 690 691 692 693 694 695 696 697 698 699 700
/**
 * urlencode:
 * @string: the input URL
 *
 * Encode an URL see RFC 2396 and following
 *
 * Returns the new string or NULL in case of error.
 */
static char *
urlencode(const char *string)
{
    size_t len = strlen(string);
701 702
    char *buffer;
    char *ptr;
703 704
    size_t i;

705
    if (VIR_ALLOC_N(buffer, len * 3 + 1) < 0) {
706
        virReportOOMError();
707
        return (NULL);
708
    }
709
    ptr = buffer;
710 711 712 713
    for (i = 0; i < len; i++) {
        switch (string[i]) {
            case ' ':
            case '\n':
714
                snprintf(ptr, 4, "%%%02x", string[i]);
715 716 717 718 719 720 721 722 723 724 725 726
                ptr += 3;
                break;
            default:
                *ptr = string[i];
                ptr++;
        }
    }

    *ptr = 0;

    return buffer;
}
727
#endif /* ! PROXY */
D
Daniel Veillard 已提交
728

729 730 731
/* PUBLIC FUNCTIONS */

/**
732
 * xenDaemonOpen_unix:
733
 * @conn: an existing virtual connection block
734 735 736 737 738
 * @path: the path for the Xen Daemon socket
 *
 * Creates a localhost Xen Daemon connection
 * Note: this doesn't try to check if the connection actually works
 *
739
 * Returns 0 in case of success, -1 in case of error.
740
 */
741
int
742
xenDaemonOpen_unix(virConnectPtr conn, const char *path)
743 744
{
    struct sockaddr_un *addr;
745
    xenUnifiedPrivatePtr priv;
746

747
    if ((conn == NULL) || (path == NULL))
748
        return (-1);
749

750
    priv = (xenUnifiedPrivatePtr) conn->privateData;
751 752
    memset(&priv->addr, 0, sizeof(priv->addr));
    priv->addrfamily = AF_UNIX;
753 754 755 756 757
    /*
     * This must be zero on Solaris at least for AF_UNIX (which should
     * really be PF_UNIX, but doesn't matter).
     */
    priv->addrprotocol = 0;
758 759 760
    priv->addrlen = sizeof(struct sockaddr_un);

    addr = (struct sockaddr_un *)&priv->addr;
761 762
    addr->sun_family = AF_UNIX;
    memset(addr->sun_path, 0, sizeof(addr->sun_path));
C
Chris Lalancette 已提交
763 764
    if (virStrcpyStatic(addr->sun_path, path) == NULL)
        return -1;
765

766
    return (0);
767 768
}

769
#ifndef PROXY
770
/**
771
 * xenDaemonOpen_tcp:
772
 * @conn: an existing virtual connection block
773
 * @host: the host name for the Xen Daemon
774
 * @port: the port
775 776 777 778
 *
 * Creates a possibly remote Xen Daemon connection
 * Note: this doesn't try to check if the connection actually works
 *
779
 * Returns 0 in case of success, -1 in case of error.
780
 */
781
static int
782
xenDaemonOpen_tcp(virConnectPtr conn, const char *host, const char *port)
783
{
784
    xenUnifiedPrivatePtr priv;
785 786 787 788
    struct addrinfo *res, *r;
    struct addrinfo hints;
    int saved_errno = EINVAL;
    int ret;
789

790
    if ((conn == NULL) || (host == NULL) || (port == NULL))
791
        return (-1);
792

793 794
    priv = (xenUnifiedPrivatePtr) conn->privateData;

795 796 797 798 799 800 801 802 803 804
    priv->addrlen = 0;
    memset(&priv->addr, 0, sizeof(priv->addr));

    // http://people.redhat.com/drepper/userapi-ipv6.html
    memset (&hints, 0, sizeof hints);
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_ADDRCONFIG;

    ret = getaddrinfo (host, port, &hints, &res);
    if (ret != 0) {
805
        virXendError(VIR_ERR_UNKNOWN_HOST,
806 807 808 809 810 811 812 813 814 815 816 817 818
                     _("unable to resolve hostname '%s': %s"),
                     host, gai_strerror (ret));
        return -1;
    }

    /* Try to connect to each returned address in turn. */
    for (r = res; r; r = r->ai_next) {
        int sock;

        sock = socket (r->ai_family, SOCK_STREAM, r->ai_protocol);
        if (sock == -1) {
            saved_errno = errno;
            continue;
819
        }
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834

        if (connect (sock, r->ai_addr, r->ai_addrlen) == -1) {
            saved_errno = errno;
            close (sock);
            continue;
        }

        priv->addrlen = r->ai_addrlen;
        priv->addrfamily = r->ai_family;
        priv->addrprotocol = r->ai_protocol;
        memcpy(&priv->addr,
               r->ai_addr,
               r->ai_addrlen);
        close(sock);
        break;
835 836
    }

837
    freeaddrinfo (res);
838

839
    if (!priv->addrlen) {
840 841
        /* Don't raise error when unprivileged, since proxy takes over */
        if (xenHavePrivilege())
842
            virReportSystemError(saved_errno,
843 844
                                 _("unable to connect to '%s:%s'"),
                                 host, port);
845 846
        return -1;
    }
847

848
    return 0;
849 850
}

851

852 853 854 855 856 857 858 859 860 861 862
/**
 * xend_wait_for_devices:
 * @xend: pointer to the Xem Daemon block
 * @name: name for the domain
 *
 * Block the domain until all the virtual devices are ready. This operation
 * is needed when creating a domain before resuming it.
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
863
xend_wait_for_devices(virConnectPtr xend, const char *name)
864 865 866 867
{
    return xend_op(xend, name, "op", "wait_for_devices", NULL);
}

868 869 870

#endif /* PROXY */

871 872

/**
873
 * xenDaemonListDomainsOld:
874 875 876 877 878 879 880
 * @xend: pointer to the Xem Daemon block
 *
 * This method will return an array of names of currently running
 * domains.  The memory should be released will a call to free().
 *
 * Returns a list of names or NULL in case of error.
 */
881
char **
882
xenDaemonListDomainsOld(virConnectPtr xend)
883 884 885 886 887 888 889 890 891 892 893 894 895
{
    size_t extra = 0;
    struct sexpr *root = NULL;
    char **ret = NULL;
    int count = 0;
    int i;
    char *ptr;
    struct sexpr *_for_i, *node;

    root = sexpr_get(xend, "/xend/domain");
    if (root == NULL)
        goto error;

896 897
    for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
         _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
898 899
        if (node->kind != SEXPR_VALUE)
            continue;
900
        extra += strlen(node->u.value) + 1;
901 902 903
        count++;
    }

904 905 906 907 908 909 910 911 912
    /*
     * We can'tuse the normal allocation routines as we are mixing
     * an array of char * at the beginning followed by an array of char
     * ret points to the NULL terminated array of char *
     * ptr points to the current string after that array but in the same
     * allocated block
     */
    if (virAlloc((void *)&ptr,
                 (count + 1) * sizeof(char *) + extra * sizeof(char)) < 0)
913 914 915 916 917 918
        goto error;

    ret = (char **) ptr;
    ptr += sizeof(char *) * (count + 1);

    i = 0;
919 920
    for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
         _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
921 922 923
        if (node->kind != SEXPR_VALUE)
            continue;
        ret[i] = ptr;
924 925
        strcpy(ptr, node->u.value);
        ptr += strlen(node->u.value) + 1;
926 927 928 929 930 931 932 933 934 935
        i++;
    }

    ret[i] = NULL;

  error:
    sexpr_free(root);
    return ret;
}

936
#ifndef PROXY
937
/**
938
 * xenDaemonDomainCreateXML:
939 940 941 942 943
 * @xend: A xend instance
 * @sexpr: An S-Expr description of the domain.
 *
 * This method will create a domain based the passed in description.  The
 * domain will be paused after creation and must be unpaused with
944
 * xenDaemonResumeDomain() to begin execution.
945 946 947 948 949 950 951
 * This method may be deprecated once switching to XML-RPC based communcations
 * with xend.
 *
 * Returns 0 for success, -1 (with errno) on error
 */

int
952
xenDaemonDomainCreateXML(virConnectPtr xend, const char *sexpr)
953 954 955 956 957
{
    int ret, serrno;
    char *ptr;

    ptr = urlencode(sexpr);
958
    if (ptr == NULL) {
959
        /* this should be caught at the interface but ... */
960
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
961
                     "%s", _("failed to urlencode the create S-Expr"));
962
        return (-1);
963
    }
964 965 966 967

    ret = xend_op(xend, "", "op", "create", "config", ptr, NULL);

    serrno = errno;
968
    VIR_FREE(ptr);
969 970 971 972
    errno = serrno;

    return ret;
}
973
#endif /* ! PROXY */
974

975
/**
976
 * xenDaemonDomainLookupByName_ids:
977
 * @xend: A xend instance
978 979
 * @domname: The name of the domain
 * @uuid: return value for the UUID if not NULL
980 981 982 983 984 985
 *
 * This method looks up the id of a domain
 *
 * Returns the id on success; -1 (with errno) on error
 */
int
986
xenDaemonDomainLookupByName_ids(virConnectPtr xend, const char *domname,
987
                                unsigned char *uuid)
988 989 990 991 992
{
    struct sexpr *root;
    const char *value;
    int ret = -1;

993
    if (uuid != NULL)
994
        memset(uuid, 0, VIR_UUID_BUFLEN);
995 996 997 998 999
    root = sexpr_get(xend, "/xend/domain/%s?detail=1", domname);
    if (root == NULL)
        goto error;

    value = sexpr_node(root, "domain/domid");
1000
    if (value == NULL) {
1001
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1002
                     "%s", _("domain information incomplete, missing domid"));
1003
        goto error;
1004
    }
1005
    ret = strtol(value, NULL, 0);
1006
    if ((ret == 0) && (value[0] != '0')) {
1007
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1008
                     "%s", _("domain information incorrect domid not numeric"));
1009
        ret = -1;
1010
    } else if (uuid != NULL) {
1011
        if (sexpr_uuid(uuid, root, "domain/uuid") < 0) {
1012
            virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1013
                         "%s", _("domain information incomplete, missing uuid"));
1014
        }
1015
    }
1016

1017
  error:
1018
    sexpr_free(root);
1019
    return (ret);
1020 1021
}

1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035

/**
 * xenDaemonDomainLookupByID:
 * @xend: A xend instance
 * @id: The id of the domain
 * @name: return value for the name if not NULL
 * @uuid: return value for the UUID if not NULL
 *
 * This method looks up the name of a domain based on its id
 *
 * Returns the 0 on success; -1 (with errno) on error
 */
int
xenDaemonDomainLookupByID(virConnectPtr xend,
1036 1037 1038
                          int id,
                          char **domname,
                          unsigned char *uuid)
1039 1040 1041 1042
{
    const char *name = NULL;
    struct sexpr *root;

1043
    memset(uuid, 0, VIR_UUID_BUFLEN);
1044 1045 1046 1047 1048 1049 1050

    root = sexpr_get(xend, "/xend/domain/%d?detail=1", id);
    if (root == NULL)
      goto error;

    name = sexpr_node(root, "domain/name");
    if (name == NULL) {
1051
      virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1052
                   "%s", _("domain information incomplete, missing name"));
1053 1054
      goto error;
    }
1055
    if (domname) {
1056
      *domname = strdup(name);
1057
      if (*domname == NULL) {
1058
          virReportOOMError();
1059 1060 1061
          goto error;
      }
    }
1062

1063
    if (sexpr_uuid(uuid, root, "domain/uuid") < 0) {
1064
      virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1065
                   "%s", _("domain information incomplete, missing uuid"));
1066 1067 1068 1069 1070 1071 1072 1073
      goto error;
    }

    sexpr_free(root);
    return (0);

error:
    sexpr_free(root);
1074 1075
    if (domname)
        VIR_FREE(*domname);
1076 1077 1078
    return (-1);
}

1079

1080
#ifndef PROXY
1081 1082
static int
xend_detect_config_version(virConnectPtr conn) {
1083 1084
    struct sexpr *root;
    const char *value;
1085
    xenUnifiedPrivatePtr priv;
1086 1087

    if (!VIR_IS_CONNECT(conn)) {
1088
        virXendError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1089 1090 1091
        return (-1);
    }

1092 1093
    priv = (xenUnifiedPrivatePtr) conn->privateData;

1094 1095 1096
    root = sexpr_get(conn, "/xend/node/");
    if (root == NULL)
        return (-1);
1097

1098
    value = sexpr_node(root, "node/xend_config_format");
1099

1100
    if (value) {
1101
        priv->xendConfigVersion = strtol(value, NULL, 10);
1102 1103 1104
    }  else {
        /* Xen prior to 3.0.3 did not have the xend_config_format
           field, and is implicitly version 1. */
1105
        priv->xendConfigVersion = 1;
1106
    }
1107
    sexpr_free(root);
1108
    return (0);
1109 1110
}

1111
#endif /* PROXY */
D
Daniel Veillard 已提交
1112

1113 1114
/*****************************************************************
 ******
1115
 ****** Parsing of SEXPR into virDomainDef objects
1116 1117
 ******
 *****************************************************************/
1118 1119

/**
1120
 * xenDaemonParseSxprOS
1121
 * @node: the root of the parsed S-Expression
1122
 * @def: the domain config
1123
 * @hvm: true or 1 if no contains HVM S-Expression
1124
 * @bootloader: true or 1 if a bootloader is defined
1125 1126 1127 1128 1129 1130
 *
 * Parse the xend sexp for description of os and append it to buf.
 *
 * Returns 0 in case of success and -1 in case of error
 */
static int
1131
xenDaemonParseSxprOS(const struct sexpr *node,
1132 1133
                     virDomainDefPtr def,
                     int hvm)
1134 1135
{
    if (hvm) {
1136 1137 1138 1139 1140
        if (sexpr_node_copy(node, "domain/image/hvm/loader", &def->os.loader) < 0)
            goto no_memory;
        if (def->os.loader == NULL) {
            if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.loader) < 0)
                goto no_memory;
1141

1142
            if (def->os.loader == NULL) {
1143
                virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1144
                             "%s", _("domain information incomplete, missing HVM loader"));
1145
                return(-1);
1146
            }
1147
        } else {
1148 1149 1150 1151 1152 1153 1154 1155
            if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.kernel) < 0)
                goto no_memory;
            if (sexpr_node_copy(node, "domain/image/hvm/ramdisk", &def->os.initrd) < 0)
                goto no_memory;
            if (sexpr_node_copy(node, "domain/image/hvm/args", &def->os.cmdline) < 0)
                goto no_memory;
            if (sexpr_node_copy(node, "domain/image/hvm/root", &def->os.root) < 0)
                goto no_memory;
1156 1157
        }
    } else {
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
        if (sexpr_node_copy(node, "domain/image/linux/kernel", &def->os.kernel) < 0)
            goto no_memory;
        if (sexpr_node_copy(node, "domain/image/linux/ramdisk", &def->os.initrd) < 0)
            goto no_memory;
        if (sexpr_node_copy(node, "domain/image/linux/args", &def->os.cmdline) < 0)
            goto no_memory;
        if (sexpr_node_copy(node, "domain/image/linux/root", &def->os.root) < 0)
            goto no_memory;
    }

    /* If HVM kenrel == loader, then old xend, so kill off kernel */
    if (hvm &&
        def->os.kernel &&
        STREQ(def->os.kernel, def->os.loader)) {
        VIR_FREE(def->os.kernel);
    }

    if (!def->os.kernel &&
        hvm) {
        const char *boot = sexpr_node(node, "domain/image/hvm/boot");
        if ((boot != NULL) && (boot[0] != 0)) {
            while (*boot &&
                   def->os.nBootDevs < VIR_DOMAIN_BOOT_LAST) {
                if (*boot == 'a')
                    def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_FLOPPY;
                else if (*boot == 'c')
                    def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_DISK;
                else if (*boot == 'd')
                    def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_CDROM;
                else if (*boot == 'n')
                    def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_NET;
                boot++;
1190
            }
1191
        }
1192 1193
    }

1194 1195 1196
    if (!hvm &&
        !def->os.kernel &&
        !def->os.bootloader) {
1197
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1198
                     "%s", _("domain information incomplete, missing kernel & bootloader"));
1199 1200 1201 1202 1203 1204
        return -1;
    }

    return 0;

no_memory:
1205
    virReportOOMError();
1206
    return -1;
1207 1208
}

1209
virDomainChrDefPtr
1210
xenDaemonParseSxprChar(const char *value,
1211 1212
                       const char *tty)
{
C
Chris Lalancette 已提交
1213
    const char *prefix;
1214 1215 1216 1217
    char *tmp;
    virDomainChrDefPtr def;

    if (VIR_ALLOC(def) < 0) {
1218
        virReportOOMError();
1219 1220 1221
        return NULL;
    }

C
Chris Lalancette 已提交
1222
    prefix = value;
1223 1224 1225 1226

    if (value[0] == '/') {
        def->type = VIR_DOMAIN_CHR_TYPE_DEV;
    } else {
C
Chris Lalancette 已提交
1227
        if ((tmp = strchr(value, ':')) != NULL) {
1228
            *tmp = '\0';
C
Chris Lalancette 已提交
1229
            value = tmp + 1;
1230 1231
        }

C
Chris Lalancette 已提交
1232
        if (STRPREFIX(prefix, "telnet")) {
1233 1234 1235 1236
            def->type = VIR_DOMAIN_CHR_TYPE_TCP;
            def->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
        } else {
            if ((def->type = virDomainChrTypeFromString(prefix)) < 0) {
1237
                virXendError(VIR_ERR_INTERNAL_ERROR,
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263
                             _("unknown chr device type '%s'"), prefix);
                goto error;
            }
        }
    }

    /* Compat with legacy  <console tty='/dev/pts/5'/> syntax */
    switch (def->type) {
    case VIR_DOMAIN_CHR_TYPE_PTY:
        if (tty != NULL &&
            !(def->data.file.path = strdup(tty)))
            goto no_memory;
        break;

    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
        if (!(def->data.file.path = strdup(value)))
            goto no_memory;
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
    {
        const char *offset = strchr(value, ':');
        const char *offset2;

        if (offset == NULL) {
1264
            virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1265
                         "%s", _("malformed char device string"));
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
            goto error;
        }

        if (offset != value &&
            (def->data.tcp.host = strndup(value, offset - value)) == NULL)
            goto no_memory;

        offset2 = strchr(offset, ',');
        if (offset2 == NULL)
            def->data.tcp.service = strdup(offset+1);
        else
            def->data.tcp.service = strndup(offset+1, offset2-(offset+1));
        if (def->data.tcp.service == NULL)
            goto no_memory;

1281
        if (offset2 && strstr(offset2, ",server"))
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291
            def->data.tcp.listen = 1;
    }
    break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
    {
        const char *offset = strchr(value, ':');
        const char *offset2, *offset3;

        if (offset == NULL) {
1292
            virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1293
                         "%s", _("malformed char device string"));
1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
            goto error;
        }

        if (offset != value &&
            (def->data.udp.connectHost = strndup(value, offset - value)) == NULL)
            goto no_memory;

        offset2 = strchr(offset, '@');
        if (offset2 != NULL) {
            if ((def->data.udp.connectService = strndup(offset + 1, offset2-(offset+1))) == NULL)
                goto no_memory;

            offset3 = strchr(offset2, ':');
            if (offset3 == NULL) {
1308
                virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1309
                             "%s", _("malformed char device string"));
1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
                goto error;
            }

            if (offset3 > (offset2 + 1) &&
                (def->data.udp.bindHost = strndup(offset2 + 1, offset3 - (offset2+1))) == NULL)
                goto no_memory;

            if ((def->data.udp.bindService = strdup(offset3 + 1)) == NULL)
                goto no_memory;
        } else {
            if ((def->data.udp.connectService = strdup(offset + 1)) == NULL)
                goto no_memory;
        }
    }
    break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
    {
        const char *offset = strchr(value, ',');
        if (offset)
            def->data.nix.path = strndup(value, (offset - value));
        else
            def->data.nix.path = strdup(value);
        if (def->data.nix.path == NULL)
            goto no_memory;

        if (offset != NULL &&
1337
            strstr(offset, ",server") != NULL)
1338 1339 1340 1341 1342 1343 1344 1345
            def->data.nix.listen = 1;
    }
    break;
    }

    return def;

no_memory:
1346
    virReportOOMError();
1347 1348 1349 1350
error:
    virDomainChrDefFree(def);
    return NULL;
}
R
Richard W.M. Jones 已提交
1351 1352

/**
1353
 * xend_parse_sexp_desc_disks
R
Richard W.M. Jones 已提交
1354 1355 1356 1357
 * @conn: connection
 * @root: root sexpr
 * @xendConfigVersion: version of xend
 *
1358
 * This parses out block devices from the domain sexpr
R
Richard W.M. Jones 已提交
1359 1360 1361 1362
 *
 * Returns 0 if successful or -1 if failed.
 */
static int
1363
xenDaemonParseSxprDisks(virDomainDefPtr def,
1364
                        const struct sexpr *root,
1365 1366
                        int hvm,
                        int xendConfigVersion)
R
Richard W.M. Jones 已提交
1367
{
1368
    const struct sexpr *cur, *node;
1369
    virDomainDiskDefPtr disk = NULL;
R
Richard W.M. Jones 已提交
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393

    for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        node = cur->u.s.car;
        /* Normally disks are in a (device (vbd ...)) block
           but blktap disks ended up in a differently named
           (device (tap ....)) block.... */
        if (sexpr_lookup(node, "device/vbd") ||
            sexpr_lookup(node, "device/tap")) {
            char *offset;
            const char *src = NULL;
            const char *dst = NULL;
            const char *mode = NULL;

            /* Again dealing with (vbd...) vs (tap ...) differences */
            if (sexpr_lookup(node, "device/vbd")) {
                src = sexpr_node(node, "device/vbd/uname");
                dst = sexpr_node(node, "device/vbd/dev");
                mode = sexpr_node(node, "device/vbd/mode");
            } else {
                src = sexpr_node(node, "device/tap/uname");
                dst = sexpr_node(node, "device/tap/dev");
                mode = sexpr_node(node, "device/tap/mode");
            }

1394 1395 1396
            if (VIR_ALLOC(disk) < 0)
                goto no_memory;

R
Richard W.M. Jones 已提交
1397
            if (dst == NULL) {
1398
                virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1399
                             "%s", _("domain information incomplete, vbd has no dev"));
1400
                goto error;
R
Richard W.M. Jones 已提交
1401 1402 1403 1404 1405
            }

            if (src == NULL) {
                /* There is a case without the uname to the CD-ROM device */
                offset = strchr(dst, ':');
1406 1407 1408
                if (!offset ||
                    !hvm ||
                    STRNEQ(offset, ":cdrom")) {
1409
                    virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1410
                                 "%s", _("domain information incomplete, vbd has no src"));
1411
                    goto error;
R
Richard W.M. Jones 已提交
1412 1413 1414
                }
            }

1415
            if (src != NULL) {
R
Richard W.M. Jones 已提交
1416 1417
                offset = strchr(src, ':');
                if (!offset) {
1418
                    virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1419
                                 "%s", _("cannot parse vbd filename, missing driver name"));
1420
                    goto error;
R
Richard W.M. Jones 已提交
1421 1422
                }

1423 1424
                if (VIR_ALLOC_N(disk->driverName, (offset-src)+1) < 0)
                    goto no_memory;
C
Chris Lalancette 已提交
1425 1426
                if (virStrncpy(disk->driverName, src, offset-src,
                              (offset-src)+1) == NULL) {
1427
                    virXendError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
1428 1429 1430 1431
                                 _("Driver name %s too big for destination"),
                                 src);
                    goto error;
                }
R
Richard W.M. Jones 已提交
1432 1433 1434

                src = offset + 1;

1435
                if (STREQ (disk->driverName, "tap")) {
R
Richard W.M. Jones 已提交
1436 1437
                    offset = strchr(src, ':');
                    if (!offset) {
1438
                        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
1439
                                     "%s", _("cannot parse vbd filename, missing driver type"));
1440
                        goto error;
R
Richard W.M. Jones 已提交
1441 1442
                    }

1443 1444
                    if (VIR_ALLOC_N(disk->driverType, (offset-src)+1)< 0)
                        goto no_memory;
C
Chris Lalancette 已提交
1445 1446
                    if (virStrncpy(disk->driverType, src, offset-src,
                                   (offset-src)+1) == NULL) {
1447
                        virXendError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
1448 1449 1450 1451
                                     _("Driver type %s too big for destination"),
                                     src);
                        goto error;
                    }
1452

R
Richard W.M. Jones 已提交
1453 1454 1455 1456 1457 1458
                    src = offset + 1;
                    /* Its possible to use blktap driver for block devs
                       too, but kinda pointless because blkback is better,
                       so we assume common case here. If blktap becomes
                       omnipotent, we can revisit this, perhaps stat()'ing
                       the src file in question */
1459 1460 1461 1462 1463
                    disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
                } else if (STREQ(disk->driverName, "phy")) {
                    disk->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
                } else if (STREQ(disk->driverName, "file")) {
                    disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
R
Richard W.M. Jones 已提交
1464
                }
1465 1466 1467 1468 1469
            } else {
                /* No CDROM media so can't really tell. We'll just
                   call if a FILE for now and update when media
                   is inserted later */
                disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
R
Richard W.M. Jones 已提交
1470 1471 1472 1473 1474
            }

            if (STREQLEN (dst, "ioemu:", 6))
                dst += 6;

1475
            disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
R
Richard W.M. Jones 已提交
1476 1477 1478 1479 1480
            /* New style disk config from Xen >= 3.0.3 */
            if (xendConfigVersion > 1) {
                offset = strrchr(dst, ':');
                if (offset) {
                    if (STREQ (offset, ":cdrom")) {
1481
                        disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
R
Richard W.M. Jones 已提交
1482 1483 1484 1485 1486 1487 1488 1489 1490
                    } else if (STREQ (offset, ":disk")) {
                        /* The default anyway */
                    } else {
                        /* Unknown, lets pretend its a disk too */
                    }
                    offset[0] = '\0';
                }
            }

1491 1492 1493 1494 1495
            if (!(disk->dst = strdup(dst)))
                goto no_memory;
            if (src &&
                !(disk->src = strdup(src)))
                goto no_memory;
R
Richard W.M. Jones 已提交
1496

1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
            if (STRPREFIX(disk->dst, "xvd"))
                disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
            else if (STRPREFIX(disk->dst, "hd"))
                disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
            else if (STRPREFIX(disk->dst, "sd"))
                disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
            else
                disk->bus = VIR_DOMAIN_DISK_BUS_IDE;

            if (mode &&
                strchr(mode, 'r'))
                disk->readonly = 1;
            if (mode &&
                strchr(mode, '!'))
                disk->shared = 1;

1513 1514
            if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
                goto no_memory;
R
Richard W.M. Jones 已提交
1515

1516
            def->disks[def->ndisks++] = disk;
1517
            disk = NULL;
R
Richard W.M. Jones 已提交
1518 1519 1520 1521
        }
    }

    return 0;
1522 1523

no_memory:
1524
    virReportOOMError();
1525 1526 1527 1528

error:
    virDomainDiskDefFree(disk);
    return -1;
R
Richard W.M. Jones 已提交
1529 1530
}

1531

R
Richard W.M. Jones 已提交
1532
static int
1533
xenDaemonParseSxprNets(virDomainDefPtr def,
1534
                       const struct sexpr *root)
R
Richard W.M. Jones 已提交
1535
{
1536
    virDomainNetDefPtr net = NULL;
1537
    const struct sexpr *cur, *node;
1538 1539 1540 1541 1542 1543
    const char *tmp;
    int vif_index = 0;

    for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        node = cur->u.s.car;
        if (sexpr_lookup(node, "device/vif")) {
1544
            const char *tmp2, *model, *type;
1545 1546 1547 1548
            char buf[50];
            tmp2 = sexpr_node(node, "device/vif/script");
            tmp = sexpr_node(node, "device/vif/bridge");
            model = sexpr_node(node, "device/vif/model");
1549
            type = sexpr_node(node, "device/vif/type");
1550 1551 1552 1553

            if (VIR_ALLOC(net) < 0)
                goto no_memory;

J
John Levon 已提交
1554 1555
            if (tmp != NULL ||
                (tmp2 != NULL && STREQ(tmp2, DEFAULT_VIF_SCRIPT))) {
1556 1557 1558 1559 1560 1561
                net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
                /* XXX virtual network reverse resolve */

                if (tmp &&
                    !(net->data.bridge.brname = strdup(tmp)))
                    goto no_memory;
1562 1563 1564 1565
                if (tmp2 &&
                    net->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
                    !(net->data.bridge.script = strdup(tmp2)))
                    goto no_memory;
1566 1567 1568 1569
                tmp = sexpr_node(node, "device/vif/ip");
                if (tmp &&
                    !(net->data.bridge.ipaddr = strdup(tmp)))
                    goto no_memory;
1570 1571
            } else {
                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
1572 1573 1574
                if (tmp2 &&
                    !(net->data.ethernet.script = strdup(tmp2)))
                    goto no_memory;
1575 1576 1577 1578
                tmp = sexpr_node(node, "device/vif/ip");
                if (tmp &&
                    !(net->data.ethernet.ipaddr = strdup(tmp)))
                    goto no_memory;
1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
            }

            tmp = sexpr_node(node, "device/vif/vifname");
            if (!tmp) {
                snprintf(buf, sizeof(buf), "vif%d.%d", def->id, vif_index);
                tmp = buf;
            }
            if (!(net->ifname = strdup(tmp)))
                goto no_memory;

            tmp = sexpr_node(node, "device/vif/mac");
            if (tmp) {
1591
                if (virParseMacAddr(tmp, net->mac) < 0) {
1592
                    virXendError(VIR_ERR_INTERNAL_ERROR,
1593
                                 _("malformed mac address '%s'"), tmp);
1594 1595 1596 1597 1598 1599 1600 1601
                    goto cleanup;
                }
            }

            if (model &&
                !(net->model = strdup(model)))
                goto no_memory;

1602 1603 1604 1605 1606
            if (!model && type &&
                STREQ(type, "netfront") &&
                !(net->model = strdup("netfront")))
                goto no_memory;

1607 1608
            if (VIR_REALLOC_N(def->nets, def->nnets + 1) < 0)
                goto no_memory;
1609

1610
            def->nets[def->nnets++] = net;
1611
            vif_index++;
R
Richard W.M. Jones 已提交
1612
        }
1613 1614 1615 1616 1617
    }

    return 0;

no_memory:
1618
    virReportOOMError();
1619 1620 1621 1622 1623
cleanup:
    virDomainNetDefFree(net);
    return -1;
}

1624 1625

int
1626
xenDaemonParseSxprSound(virDomainDefPtr def,
1627 1628 1629 1630
                        const char *str)
{
    if (STREQ(str, "all")) {
        int i;
1631

1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644
        /*
         * Special compatability code for Xen with a bogus
         * sound=all in config.
         *
         * NB delibrately, don't include all possible
         * sound models anymore, just the 2 that were
         * historically present in Xen's QEMU.
         *
         * ie just es1370 + sb16.
         *
         * Hence use of MODEL_ES1370 + 1, instead of MODEL_LAST
         */

1645
        if (VIR_ALLOC_N(def->sounds,
1646
                        VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) < 0)
1647 1648
            goto no_memory;

1649 1650

        for (i = 0 ; i < (VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) ; i++) {
1651 1652 1653 1654
            virDomainSoundDefPtr sound;
            if (VIR_ALLOC(sound) < 0)
                goto no_memory;
            sound->model = i;
1655
            def->sounds[def->nsounds++] = sound;
R
Richard W.M. Jones 已提交
1656 1657
        }
    } else {
1658 1659
        char model[10];
        const char *offset = str, *offset2;
1660

1661 1662 1663 1664 1665 1666 1667 1668
        do {
            int len;
            virDomainSoundDefPtr sound;
            offset2 = strchr(offset, ',');
            if (offset2)
                len = (offset2 - offset);
            else
                len = strlen(offset);
C
Chris Lalancette 已提交
1669
            if (virStrncpy(model, offset, len, sizeof(model)) == NULL) {
1670
                virXendError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
1671 1672
                                 _("Sound model %s too big for destination"),
                             offset);
1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
                goto error;
            }

            if (VIR_ALLOC(sound) < 0)
                goto no_memory;

            if ((sound->model = virDomainSoundModelTypeFromString(model)) < 0) {
                VIR_FREE(sound);
                goto error;
            }

1684 1685 1686 1687 1688 1689
            if (VIR_REALLOC_N(def->sounds, def->nsounds+1) < 0) {
                virDomainSoundDefFree(sound);
                goto no_memory;
            }

            def->sounds[def->nsounds++] = sound;
1690 1691
            offset = offset2 ? offset2 + 1 : NULL;
        } while (offset);
R
Richard W.M. Jones 已提交
1692
    }
1693 1694 1695 1696

    return 0;

no_memory:
1697
    virReportOOMError();
1698 1699 1700 1701 1702 1703
error:
    return -1;
}


static int
1704
xenDaemonParseSxprUSB(virDomainDefPtr def,
1705
                      const struct sexpr *root)
1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725
{
    struct sexpr *cur, *node;
    const char *tmp;

    for (cur = sexpr_lookup(root, "domain/image/hvm"); cur && cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        node = cur->u.s.car;
        if (sexpr_lookup(node, "usbdevice")) {
            tmp = sexpr_node(node, "usbdevice");
            if (tmp && *tmp) {
                if (STREQ(tmp, "tablet") ||
                    STREQ(tmp, "mouse")) {
                    virDomainInputDefPtr input;
                    if (VIR_ALLOC(input) < 0)
                        goto no_memory;
                    input->bus = VIR_DOMAIN_INPUT_BUS_USB;
                    if (STREQ(tmp, "tablet"))
                        input->type = VIR_DOMAIN_INPUT_TYPE_TABLET;
                    else
                        input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;

1726 1727 1728 1729 1730
                    if (VIR_REALLOC_N(def->inputs, def->ninputs+1) < 0) {
                        VIR_FREE(input);
                        goto no_memory;
                    }
                    def->inputs[def->ninputs++] = input;
1731 1732 1733 1734 1735
                } else {
                    /* XXX Handle other non-input USB devices later */
                }
            }
        }
R
Richard W.M. Jones 已提交
1736
    }
1737 1738 1739
    return 0;

no_memory:
1740
    virReportOOMError();
1741 1742 1743 1744 1745 1746
    return -1;
}

static int
xenDaemonParseSxprGraphicsOld(virConnectPtr conn,
                              virDomainDefPtr def,
1747
                              const struct sexpr *root,
1748 1749 1750
                              int hvm,
                              int xendConfigVersion)
{
D
Daniel P. Berrange 已提交
1751 1752 1753
#ifndef PROXY
    xenUnifiedPrivatePtr priv = conn->privateData;
#endif
1754 1755 1756 1757 1758 1759
    const char *tmp;
    virDomainGraphicsDefPtr graphics = NULL;

    if ((tmp = sexpr_fmt_node(root, "domain/image/%s/vnc", hvm ? "hvm" : "linux")) &&
        tmp[0] == '1') {
        /* Graphics device (HVM, or old (pre-3.0.4) style PV VNC config) */
D
Daniel P. Berrange 已提交
1760
        int port;
1761 1762 1763 1764 1765
        const char *listenAddr = sexpr_fmt_node(root, "domain/image/%s/vnclisten", hvm ? "hvm" : "linux");
        const char *vncPasswd = sexpr_fmt_node(root, "domain/image/%s/vncpasswd", hvm ? "hvm" : "linux");
        const char *keymap = sexpr_fmt_node(root, "domain/image/%s/keymap", hvm ? "hvm" : "linux");
        const char *unused = sexpr_fmt_node(root, "domain/image/%s/vncunused", hvm ? "hvm" : "linux");

D
Daniel P. Berrange 已提交
1766 1767 1768 1769
        xenUnifiedLock(priv);
        port = xenStoreDomainGetVNCPort(conn, def->id);
        xenUnifiedUnlock(priv);

1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798
        if (VIR_ALLOC(graphics) < 0)
            goto no_memory;

        graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
        /* For Xen >= 3.0.3, don't generate a fixed port mapping
         * because it will almost certainly be wrong ! Just leave
         * it as -1 which lets caller see that the VNC server isn't
         * present yet. Subsquent dumps of the XML will eventually
         * find the port in XenStore once VNC server has started
         */
        if (port == -1 && xendConfigVersion < 2)
            port = 5900 + def->id;

        if ((unused && STREQ(unused, "1")) || port == -1)
            graphics->data.vnc.autoport = 1;
        graphics->data.vnc.port = port;

        if (listenAddr &&
            !(graphics->data.vnc.listenAddr = strdup(listenAddr)))
            goto no_memory;

        if (vncPasswd &&
            !(graphics->data.vnc.passwd = strdup(vncPasswd)))
            goto no_memory;

        if (keymap &&
            !(graphics->data.vnc.keymap = strdup(keymap)))
            goto no_memory;

1799 1800 1801 1802 1803
        if (VIR_ALLOC_N(def->graphics, 1) < 0)
            goto no_memory;
        def->graphics[0] = graphics;
        def->ngraphics = 1;
        graphics = NULL;
1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820
    } else if ((tmp = sexpr_fmt_node(root, "domain/image/%s/sdl", hvm ? "hvm" : "linux")) &&
               tmp[0] == '1') {
        /* Graphics device (HVM, or old (pre-3.0.4) style PV sdl config) */
        const char *display = sexpr_fmt_node(root, "domain/image/%s/display", hvm ? "hvm" : "linux");
        const char *xauth = sexpr_fmt_node(root, "domain/image/%s/xauthority", hvm ? "hvm" : "linux");

        if (VIR_ALLOC(graphics) < 0)
            goto no_memory;

        graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
        if (display &&
            !(graphics->data.sdl.display = strdup(display)))
            goto no_memory;
        if (xauth &&
            !(graphics->data.sdl.xauth = strdup(xauth)))
            goto no_memory;

1821 1822 1823 1824 1825
        if (VIR_ALLOC_N(def->graphics, 1) < 0)
            goto no_memory;
        def->graphics[0] = graphics;
        def->ngraphics = 1;
        graphics = NULL;
1826 1827 1828 1829 1830
    }

    return 0;

no_memory:
1831
    virReportOOMError();
1832 1833 1834 1835 1836 1837 1838 1839
    virDomainGraphicsDefFree(graphics);
    return -1;
}


static int
xenDaemonParseSxprGraphicsNew(virConnectPtr conn,
                              virDomainDefPtr def,
1840
                              const struct sexpr *root)
1841
{
D
Daniel P. Berrange 已提交
1842 1843 1844
#ifndef PROXY
    xenUnifiedPrivatePtr priv = conn->privateData;
#endif
1845
    virDomainGraphicsDefPtr graphics = NULL;
1846
    const struct sexpr *cur, *node;
1847 1848 1849 1850 1851 1852 1853 1854
    const char *tmp;

    /* append network devices and framebuffer */
    for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        node = cur->u.s.car;
        if (sexpr_lookup(node, "device/vfb")) {
            /* New style graphics config for PV guests in >= 3.0.4,
             * or for HVM guests in >= 3.0.5 */
1855 1856 1857 1858 1859 1860 1861 1862 1863
            if (sexpr_node(node, "device/vfb/type")) {
                tmp = sexpr_node(node, "device/vfb/type");
            } else if (sexpr_node(node, "device/vfb/vnc")) {
                tmp = "vnc";
            } else if (sexpr_node(node, "device/vfb/sdl")) {
                tmp = "sdl";
            } else {
                tmp = "unknown";
            }
1864 1865 1866 1867 1868

            if (VIR_ALLOC(graphics) < 0)
                goto no_memory;

            if ((graphics->type = virDomainGraphicsTypeFromString(tmp)) < 0) {
1869
                virXendError(VIR_ERR_INTERNAL_ERROR,
1870 1871 1872
                             _("unknown graphics type '%s'"), tmp);
                goto error;
            }
R
Richard W.M. Jones 已提交
1873

1874 1875 1876 1877 1878 1879 1880 1881 1882 1883
            if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
                const char *display = sexpr_node(node, "device/vfb/display");
                const char *xauth = sexpr_node(node, "device/vfb/xauthority");
                if (display &&
                    !(graphics->data.sdl.display = strdup(display)))
                    goto no_memory;
                if (xauth &&
                    !(graphics->data.sdl.xauth = strdup(xauth)))
                    goto no_memory;
            } else {
D
Daniel P. Berrange 已提交
1884
                int port;
1885
                const char *listenAddr = sexpr_node(node, "device/vfb/vnclisten");
D
Daniel Veillard 已提交
1886
                const char *vncPasswd = sexpr_node(node, "device/vfb/vncpasswd");
1887 1888 1889
                const char *keymap = sexpr_node(node, "device/vfb/keymap");
                const char *unused = sexpr_node(node, "device/vfb/vncunused");

D
Daniel P. Berrange 已提交
1890 1891 1892 1893
                xenUnifiedLock(priv);
                port = xenStoreDomainGetVNCPort(conn, def->id);
                xenUnifiedUnlock(priv);

1894
                // Didn't find port entry in xenstore
D
Daniel P. Berrange 已提交
1895
                if (port == -1) {
1896 1897 1898 1899
                    const char *str = sexpr_node(node, "device/vfb/vncdisplay");
                    int val;
                    if (str != NULL && virStrToLong_i(str, NULL, 0, &val) == 0)
                        port = val;
D
Daniel P. Berrange 已提交
1900 1901
                }

1902
                if ((unused && STREQ(unused, "1")) || port == -1)
1903
                    graphics->data.vnc.autoport = 1;
1904 1905 1906

                if (port >= 0 && port < 5900)
                    port += 5900;
1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921
                graphics->data.vnc.port = port;

                if (listenAddr &&
                    !(graphics->data.vnc.listenAddr = strdup(listenAddr)))
                    goto no_memory;

                if (vncPasswd &&
                    !(graphics->data.vnc.passwd = strdup(vncPasswd)))
                    goto no_memory;

                if (keymap &&
                    !(graphics->data.vnc.keymap = strdup(keymap)))
                    goto no_memory;
            }

1922 1923 1924 1925 1926
            if (VIR_ALLOC_N(def->graphics, 1) < 0)
                goto no_memory;
            def->graphics[0] = graphics;
            def->ngraphics = 1;
            graphics = NULL;
1927 1928 1929
            break;
        }
    }
R
Richard W.M. Jones 已提交
1930 1931

    return 0;
1932 1933

no_memory:
1934
    virReportOOMError();
1935 1936 1937
error:
    virDomainGraphicsDefFree(graphics);
    return -1;
R
Richard W.M. Jones 已提交
1938 1939
}

1940 1941 1942 1943 1944 1945 1946 1947 1948
/**
 * xenDaemonParseSxprPCI
 * @root: root sexpr
 *
 * This parses out block devices from the domain sexpr
 *
 * Returns 0 if successful or -1 if failed.
 */
static int
1949
xenDaemonParseSxprPCI(virDomainDefPtr def,
1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993
                      const struct sexpr *root)
{
    const struct sexpr *cur, *tmp = NULL, *node;
    virDomainHostdevDefPtr dev = NULL;

    /*
     * With the (domain ...) block we have the following odd setup
     *
     * (device
     *    (pci
     *       (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0))
     *       (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0))
     *    )
     * )
     *
     * Normally there is one (device ...) block per device, but in
     * wierd world of Xen PCI, once (device ...) covers multiple
     * devices.
     */

    for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        node = cur->u.s.car;
        if ((tmp = sexpr_lookup(node, "device/pci")) != NULL)
            break;
    }

    if (!tmp)
        return 0;

    for (cur = tmp; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        const char *domain = NULL;
        const char *bus = NULL;
        const char *slot = NULL;
        const char *func = NULL;
        int domainID;
        int busID;
        int slotID;
        int funcID;

        node = cur->u.s.car;
        if (!sexpr_lookup(node, "dev"))
            continue;

        if (!(domain = sexpr_node(node, "dev/domain"))) {
1994
            virXendError(VIR_ERR_INTERNAL_ERROR,
1995 1996 1997 1998
                         "%s", _("missing PCI domain"));
            goto error;
        }
        if (!(bus = sexpr_node(node, "dev/bus"))) {
1999
            virXendError(VIR_ERR_INTERNAL_ERROR,
2000 2001 2002 2003
                         "%s", _("missing PCI bus"));
            goto error;
        }
        if (!(slot = sexpr_node(node, "dev/slot"))) {
2004
            virXendError(VIR_ERR_INTERNAL_ERROR,
2005 2006 2007 2008
                         "%s", _("missing PCI slot"));
            goto error;
        }
        if (!(func = sexpr_node(node, "dev/func"))) {
2009
            virXendError(VIR_ERR_INTERNAL_ERROR,
2010 2011 2012 2013 2014
                         "%s", _("missing PCI func"));
            goto error;
        }

        if (virStrToLong_i(domain, NULL, 0, &domainID) < 0) {
2015
            virXendError(VIR_ERR_INTERNAL_ERROR,
2016 2017 2018 2019
                         _("cannot parse PCI domain '%s'"), domain);
            goto error;
        }
        if (virStrToLong_i(bus, NULL, 0, &busID) < 0) {
2020
            virXendError(VIR_ERR_INTERNAL_ERROR,
2021 2022 2023 2024
                         _("cannot parse PCI bus '%s'"), bus);
            goto error;
        }
        if (virStrToLong_i(slot, NULL, 0, &slotID) < 0) {
2025
            virXendError(VIR_ERR_INTERNAL_ERROR,
2026 2027 2028 2029
                         _("cannot parse PCI slot '%s'"), slot);
            goto error;
        }
        if (virStrToLong_i(func, NULL, 0, &funcID) < 0) {
2030
            virXendError(VIR_ERR_INTERNAL_ERROR,
2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055
                         _("cannot parse PCI func '%s'"), func);
            goto error;
        }

        if (VIR_ALLOC(dev) < 0)
            goto no_memory;

        dev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        dev->managed = 0;
        dev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
        dev->source.subsys.u.pci.domain = domainID;
        dev->source.subsys.u.pci.bus = busID;
        dev->source.subsys.u.pci.slot = slotID;
        dev->source.subsys.u.pci.function = funcID;

        if (VIR_REALLOC_N(def->hostdevs, def->nhostdevs+1) < 0) {
            goto no_memory;
        }

        def->hostdevs[def->nhostdevs++] = dev;
    }

    return 0;

no_memory:
2056
    virReportOOMError();
2057 2058 2059 2060 2061 2062

error:
    virDomainHostdevDefFree(dev);
    return -1;
}

2063

D
Daniel Veillard 已提交
2064
/**
2065
 * xenDaemonParseSxpr:
2066
 * @conn: the connection associated with the XML
D
Daniel Veillard 已提交
2067
 * @root: the root of the parsed S-Expression
2068
 * @xendConfigVersion: version of xend
2069
 * @cpus: set of cpus the domain may be pinned to
D
Daniel Veillard 已提交
2070 2071 2072 2073 2074 2075 2076
 *
 * Parse the xend sexp description and turn it into the XML format similar
 * to the one unsed for creation.
 *
 * Returns the 0 terminated XML string or NULL in case of error.
 *         the caller must free() the returned value.
 */
2077 2078
static virDomainDefPtr
xenDaemonParseSxpr(virConnectPtr conn,
2079
                   const struct sexpr *root,
2080 2081
                   int xendConfigVersion,
                   const char *cpus)
2082
{
D
Daniel P. Berrange 已提交
2083 2084 2085
#ifndef PROXY
    xenUnifiedPrivatePtr priv = conn->privateData;
#endif
D
Daniel Veillard 已提交
2086
    const char *tmp;
2087 2088 2089
    virDomainDefPtr def;
    int hvm = 0;
    char *tty = NULL;
D
Daniel Veillard 已提交
2090

2091 2092
    if (VIR_ALLOC(def) < 0)
        goto no_memory;
D
Daniel Veillard 已提交
2093

2094 2095
    tmp = sexpr_node(root, "domain/domid");
    if (tmp == NULL && xendConfigVersion < 3) { /* Old XenD, domid was mandatory */
2096
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
2097
                     "%s", _("domain information incomplete, missing id"));
2098 2099
        goto error;
    }
2100
    def->virtType = VIR_DOMAIN_VIRT_XEN;
2101
    if (tmp)
2102
        def->id = sexpr_int(root, "domain/domid");
2103
    else
2104
        def->id = -1;
2105

2106 2107 2108
    if (sexpr_node_copy(root, "domain/name", &def->name) < 0)
        goto no_memory;
    if (def->name == NULL) {
2109
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
2110
                     "%s", _("domain information incomplete, missing name"));
2111
        goto error;
D
Daniel Veillard 已提交
2112
    }
2113

2114
    tmp = sexpr_node(root, "domain/uuid");
2115
    if (tmp == NULL) {
2116
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
2117
                     "%s", _("domain information incomplete, missing name"));
2118
        goto error;
2119
    }
2120
    virUUIDParse(tmp, def->uuid);
2121

2122 2123 2124
    if (sexpr_node_copy(root, "domain/description", &def->description) < 0)
        goto no_memory;

2125 2126
    hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0;
    if (!hvm) {
2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139
        if (sexpr_node_copy(root, "domain/bootloader",
                            &def->os.bootloader) < 0)
            goto no_memory;

        if (!def->os.bootloader &&
            sexpr_has(root, "domain/bootloader") &&
            (def->os.bootloader = strdup("")) == NULL)
            goto no_memory;

        if (def->os.bootloader &&
            sexpr_node_copy(root, "domain/bootloader_args",
                            &def->os.bootloaderArgs) < 0)
            goto no_memory;
2140
    }
2141

2142 2143 2144 2145
    if (!(def->os.type = strdup(hvm ? "hvm" : "linux")))
        goto no_memory;

    if (def->id != 0) {
2146
        if (sexpr_lookup(root, "domain/image")) {
2147
            if (xenDaemonParseSxprOS(root, def, hvm) < 0)
D
Daniel P. Berrange 已提交
2148
                goto error;
2149
        }
D
Daniel Veillard 已提交
2150
    }
2151

2152 2153 2154 2155
    def->maxmem = (unsigned long) (sexpr_u64(root, "domain/maxmem") << 10);
    def->memory = (unsigned long) (sexpr_u64(root, "domain/memory") << 10);
    if (def->memory > def->maxmem)
        def->maxmem = def->memory;
2156

2157
    if (cpus != NULL) {
2158 2159
        def->cpumasklen = VIR_DOMAIN_CPUMASK_LEN;
        if (VIR_ALLOC_N(def->cpumask, def->cpumasklen) < 0) {
2160
            virReportOOMError();
2161 2162 2163
            goto error;
        }

2164
        if (virDomainCpuSetParse(&cpus,
2165
                                 0, def->cpumask,
2166
                                 def->cpumasklen) < 0) {
2167
            virXendError(VIR_ERR_INTERNAL_ERROR,
2168
                         _("invalid CPU mask %s"), cpus);
2169
            goto error;
2170
        }
2171
    }
2172

2173 2174
    def->vcpus = sexpr_int(root, "domain/vcpus");

2175
    tmp = sexpr_node(root, "domain/on_poweroff");
2176 2177
    if (tmp != NULL) {
        if ((def->onPoweroff = virDomainLifecycleTypeFromString(tmp)) < 0) {
2178
            virXendError(VIR_ERR_INTERNAL_ERROR,
2179 2180 2181 2182 2183 2184
                         _("unknown lifecycle type %s"), tmp);
            goto error;
        }
    } else
        def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;

2185
    tmp = sexpr_node(root, "domain/on_reboot");
2186 2187
    if (tmp != NULL) {
        if ((def->onReboot = virDomainLifecycleTypeFromString(tmp)) < 0) {
2188
            virXendError(VIR_ERR_INTERNAL_ERROR,
2189 2190 2191 2192 2193 2194
                         _("unknown lifecycle type %s"), tmp);
            goto error;
        }
    } else
        def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;

2195
    tmp = sexpr_node(root, "domain/on_crash");
2196 2197
    if (tmp != NULL) {
        if ((def->onCrash = virDomainLifecycleTypeFromString(tmp)) < 0) {
2198
            virXendError(VIR_ERR_INTERNAL_ERROR,
2199 2200 2201 2202 2203
                         _("unknown lifecycle type %s"), tmp);
            goto error;
        }
    } else
        def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;
2204

2205
    def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
2206
    if (hvm) {
2207
        if (sexpr_int(root, "domain/image/hvm/acpi"))
2208
            def->features |= (1 << VIR_DOMAIN_FEATURE_ACPI);
2209
        if (sexpr_int(root, "domain/image/hvm/apic"))
2210
            def->features |= (1 << VIR_DOMAIN_FEATURE_APIC);
2211
        if (sexpr_int(root, "domain/image/hvm/pae"))
2212
            def->features |= (1 << VIR_DOMAIN_FEATURE_PAE);
2213

2214
        /* Old XenD only allows localtime here for HVM */
2215
        if (sexpr_int(root, "domain/image/hvm/localtime"))
2216
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
2217
    }
2218

2219 2220
    /* Current XenD allows localtime here, for PV and HVM */
    if (sexpr_int(root, "domain/localtime"))
2221
        def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
2222

2223 2224 2225 2226 2227
    if (sexpr_node_copy(root, hvm ?
                        "domain/image/hvm/device_model" :
                        "domain/image/linux/device_model",
                        &def->emulator) < 0)
        goto no_memory;
2228

R
Richard W.M. Jones 已提交
2229
    /* append block devices */
2230
    if (xenDaemonParseSxprDisks(def, root, hvm, xendConfigVersion) < 0)
R
Richard W.M. Jones 已提交
2231 2232
        goto error;

2233
    if (xenDaemonParseSxprNets(def, root) < 0)
2234
        goto error;
2235

2236
    if (xenDaemonParseSxprPCI(def, root) < 0)
2237 2238
        goto error;

2239 2240 2241
    /* New style graphics device config */
    if (xenDaemonParseSxprGraphicsNew(conn, def, root) < 0)
        goto error;
2242

2243
    /* Graphics device (HVM <= 3.0.4, or PV <= 3.0.3) vnc config */
2244
    if ((def->ngraphics == 0) &&
2245 2246
        xenDaemonParseSxprGraphicsOld(conn, def, root, hvm, xendConfigVersion) < 0)
        goto error;
2247

2248 2249 2250 2251 2252

    /* Old style cdrom config from Xen <= 3.0.2 */
    if (hvm &&
        xendConfigVersion == 1) {
        tmp = sexpr_node(root, "domain/image/hvm/cdrom");
2253
        if ((tmp != NULL) && (tmp[0] != 0)) {
2254
            virDomainDiskDefPtr disk;
2255 2256 2257
            if (VIR_ALLOC(disk) < 0)
                goto no_memory;
            if (!(disk->src = strdup(tmp))) {
2258
                virDomainDiskDefFree(disk);
2259 2260 2261 2262 2263
                goto no_memory;
            }
            disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
            disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
            if (!(disk->dst = strdup("hdc"))) {
2264
                virDomainDiskDefFree(disk);
2265 2266 2267
                goto no_memory;
            }
            if (!(disk->driverName = strdup("file"))) {
2268
                virDomainDiskDefFree(disk);
2269 2270 2271 2272
                goto no_memory;
            }
            disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
            disk->readonly = 1;
2273

2274 2275 2276
            if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
                virDomainDiskDefFree(disk);
                goto no_memory;
2277
            }
2278
            def->disks[def->ndisks++] = disk;
2279
        }
2280
    }
2281

2282 2283

    /* Floppy disk config */
2284
    if (hvm) {
2285 2286
        const char *const fds[] = { "fda", "fdb" };
        int i;
J
Jim Meyering 已提交
2287
        for (i = 0 ; i < ARRAY_CARDINALITY(fds) ; i++) {
2288 2289
            tmp = sexpr_fmt_node(root, "domain/image/hvm/%s", fds[i]);
            if ((tmp != NULL) && (tmp[0] != 0)) {
2290
                virDomainDiskDefPtr disk;
2291 2292 2293 2294 2295
                if (VIR_ALLOC(disk) < 0)
                    goto no_memory;
                if (!(disk->src = strdup(tmp))) {
                    VIR_FREE(disk);
                    goto no_memory;
2296
                }
2297 2298 2299
                disk->type = VIR_DOMAIN_DISK_TYPE_FILE;
                disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                if (!(disk->dst = strdup(fds[i]))) {
2300
                    virDomainDiskDefFree(disk);
2301
                    goto no_memory;
2302
                }
2303
                if (!(disk->driverName = strdup("file"))) {
2304
                    virDomainDiskDefFree(disk);
2305 2306 2307
                    goto no_memory;
                }
                disk->bus = VIR_DOMAIN_DISK_BUS_FDC;
2308

2309 2310 2311
                if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0) {
                    virDomainDiskDefFree(disk);
                    goto no_memory;
2312
                }
2313
                def->disks[def->ndisks++] = disk;
2314
            }
2315
        }
D
Daniel Veillard 已提交
2316
    }
2317

2318 2319
    /* in case of HVM we have USB device emulation */
    if (hvm &&
2320
        xenDaemonParseSxprUSB(def, root) < 0)
2321 2322 2323
        goto error;

    /* Character device config */
D
Daniel P. Berrange 已提交
2324
    xenUnifiedLock(priv);
2325
    tty = xenStoreDomainGetConsolePath(conn, def->id);
D
Daniel P. Berrange 已提交
2326
    xenUnifiedUnlock(priv);
2327 2328 2329
    if (hvm) {
        tmp = sexpr_node(root, "domain/image/hvm/serial");
        if (tmp && STRNEQ(tmp, "none")) {
2330
            virDomainChrDefPtr chr;
2331
            if ((chr = xenDaemonParseSxprChar(tmp, tty)) == NULL)
2332
                goto error;
2333 2334 2335 2336
            if (VIR_REALLOC_N(def->serials, def->nserials+1) < 0) {
                virDomainChrDefFree(chr);
                goto no_memory;
            }
2337
            chr->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_SERIAL;
2338
            def->serials[def->nserials++] = chr;
2339 2340 2341
        }
        tmp = sexpr_node(root, "domain/image/hvm/parallel");
        if (tmp && STRNEQ(tmp, "none")) {
2342
            virDomainChrDefPtr chr;
2343
            /* XXX does XenD stuff parallel port tty info into xenstore somewhere ? */
2344
            if ((chr = xenDaemonParseSxprChar(tmp, NULL)) == NULL)
2345
                goto error;
2346 2347 2348 2349
            if (VIR_REALLOC_N(def->parallels, def->nparallels+1) < 0) {
                virDomainChrDefFree(chr);
                goto no_memory;
            }
2350
            chr->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_PARALLEL;
2351
            def->parallels[def->nparallels++] = chr;
2352 2353
        }
    } else {
2354
        /* Fake a paravirt console, since that's not in the sexpr */
2355
        if (!(def->console = xenDaemonParseSxprChar("pty", tty)))
2356
            goto error;
2357
        def->console->targetType = VIR_DOMAIN_CHR_TARGET_TYPE_CONSOLE;
2358
    }
2359
    VIR_FREE(tty);
2360

D
Daniel Veillard 已提交
2361

2362 2363 2364 2365
    /* Sound device config */
    if (hvm &&
        (tmp = sexpr_node(root, "domain/image/hvm/soundhw")) != NULL &&
        *tmp) {
2366
        if (xenDaemonParseSxprSound(def, tmp) < 0)
2367
            goto error;
2368 2369
    }

2370
    return def;
D
Daniel Veillard 已提交
2371

2372
no_memory:
2373
    virReportOOMError();
2374 2375 2376 2377
error:
    VIR_FREE(tty);
    virDomainDefFree(def);
    return NULL;
D
Daniel Veillard 已提交
2378
}
2379

2380 2381 2382 2383 2384 2385 2386
virDomainDefPtr
xenDaemonParseSxprString(virConnectPtr conn,
                         const char *sexpr,
                         int xendConfigVersion)
{
    struct sexpr *root = string2sexpr(sexpr);
    virDomainDefPtr def;
2387

2388 2389
    if (!root)
        return NULL;
2390

2391
    def = xenDaemonParseSxpr(conn, root, xendConfigVersion, NULL);
2392

2393
    sexpr_free(root);
2394

2395
    return def;
2396
}
D
Daniel Veillard 已提交
2397

2398

D
Daniel Veillard 已提交
2399
/**
2400 2401 2402 2403 2404 2405 2406 2407 2408 2409
 * sexpr_to_xend_domain_info:
 * @root: an S-Expression describing a domain
 * @info: a info data structure to fill=up
 *
 * Internal routine filling up the info structure with the values from
 * the domain root provided.
 *
 * Returns 0 in case of success, -1 in case of error
 */
static int
2410 2411
sexpr_to_xend_domain_info(virDomainPtr domain, const struct sexpr *root,
                          virDomainInfoPtr info)
2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427
{
    const char *flags;


    if ((root == NULL) || (info == NULL))
        return (-1);

    info->memory = sexpr_u64(root, "domain/memory") << 10;
    info->maxMem = sexpr_u64(root, "domain/maxmem") << 10;
    flags = sexpr_node(root, "domain/state");

    if (flags) {
        if (strchr(flags, 'c'))
            info->state = VIR_DOMAIN_CRASHED;
        else if (strchr(flags, 's'))
            info->state = VIR_DOMAIN_SHUTOFF;
2428 2429
        else if (strchr(flags, 'd'))
            info->state = VIR_DOMAIN_SHUTDOWN;
2430 2431 2432 2433 2434 2435 2436
        else if (strchr(flags, 'p'))
            info->state = VIR_DOMAIN_PAUSED;
        else if (strchr(flags, 'b'))
            info->state = VIR_DOMAIN_BLOCKED;
        else if (strchr(flags, 'r'))
            info->state = VIR_DOMAIN_RUNNING;
    } else {
2437 2438
        /* Inactive domains don't have a state reported, so
           mark them SHUTOFF, rather than NOSTATE */
2439
        if (domain->id < 0)
2440 2441 2442
            info->state = VIR_DOMAIN_SHUTOFF;
        else
            info->state = VIR_DOMAIN_NOSTATE;
2443 2444 2445 2446 2447 2448
    }
    info->cpuTime = sexpr_float(root, "domain/cpu_time") * 1000000000;
    info->nrVirtCpu = sexpr_int(root, "domain/vcpus");
    return (0);
}

2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459
/**
 * sexpr_to_xend_node_info:
 * @root: an S-Expression describing a domain
 * @info: a info data structure to fill up
 *
 * Internal routine filling up the info structure with the values from
 * the node root provided.
 *
 * Returns 0 in case of success, -1 in case of error
 */
static int
2460
sexpr_to_xend_node_info(const struct sexpr *root, virNodeInfoPtr info)
2461 2462 2463 2464 2465 2466 2467 2468
{
    const char *machine;


    if ((root == NULL) || (info == NULL))
        return (-1);

    machine = sexpr_node(root, "node/machine");
2469
    if (machine == NULL) {
2470
        info->model[0] = 0;
2471
    } else {
2472
        snprintf(&info->model[0], sizeof(info->model) - 1, "%s", machine);
2473
        info->model[sizeof(info->model) - 1] = 0;
2474 2475 2476 2477 2478 2479 2480
    }
    info->memory = (unsigned long) sexpr_u64(root, "node/total_memory") << 10;

    info->cpus = sexpr_int(root, "node/nr_cpus");
    info->mhz = sexpr_int(root, "node/cpu_mhz");
    info->nodes = sexpr_int(root, "node/nr_nodes");
    info->sockets = sexpr_int(root, "node/sockets_per_node");
2481 2482 2483
    info->cores = sexpr_int(root, "node/cores_per_socket");
    info->threads = sexpr_int(root, "node/threads_per_core");

2484 2485 2486 2487 2488 2489 2490
    /* Xen 3.2.0 replaces sockets_per_node with 'nr_cpus'.
     * Old Xen calculated sockets_per_node using its internal
     * nr_cpus / (nodes*cores*threads), so fake it ourselves
     * in the same way
     */
    if (info->sockets == 0) {
        int nr_cpus = sexpr_int(root, "node/nr_cpus");
2491 2492 2493 2494 2495
        int procs = info->nodes * info->cores * info->threads;
        if (procs == 0) /* Sanity check in case of Xen bugs in futures..*/
            return (-1);
        info->sockets = nr_cpus / procs;
        /* Should already be fine, but for further sanity make
2496 2497 2498 2499 2500
         * sure we have at least one socket
         */
        if (info->sockets == 0)
            info->sockets = 1;
    }
2501 2502 2503
    return (0);
}

2504

2505
/**
2506
 * sexpr_to_xend_topology
2507
 * @root: an S-Expression describing a node
2508
 * @caps: capability info
2509
 *
2510 2511
 * Internal routine populating capability info with
 * NUMA node mapping details
2512
 *
2513 2514
 * Does nothing when the system doesn't support NUMA (not an error).
 *
2515 2516
 * Returns 0 in case of success, -1 in case of error
 */
2517
static int
2518
sexpr_to_xend_topology(const struct sexpr *root,
2519
                       virCapsPtr caps)
2520 2521
{
    const char *nodeToCpu;
2522 2523 2524 2525 2526
    const char *cur;
    char *cpuset = NULL;
    int *cpuNums = NULL;
    int cell, cpu, nb_cpus;
    int n = 0;
2527 2528 2529
    int numCpus;

    nodeToCpu = sexpr_node(root, "node/node_to_cpu");
2530 2531
    if (nodeToCpu == NULL)
        return 0;               /* no NUMA support */
2532 2533 2534

    numCpus = sexpr_int(root, "node/nr_cpus");

2535

2536
    if (VIR_ALLOC_N(cpuset, numCpus) < 0)
2537
        goto memory_error;
2538
    if (VIR_ALLOC_N(cpuNums, numCpus) < 0)
2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557
        goto memory_error;

    cur = nodeToCpu;
    while (*cur != 0) {
        /*
         * Find the next NUMA cell described in the xend output
         */
        cur = strstr(cur, "node");
        if (cur == NULL)
            break;
        cur += 4;
        cell = virParseNumber(&cur);
        if (cell < 0)
            goto parse_error;
        virSkipSpaces(&cur);
        if (*cur != ':')
            goto parse_error;
        cur++;
        virSkipSpaces(&cur);
2558
        if (STRPREFIX(cur, "no cpus")) {
2559 2560 2561 2562
            nb_cpus = 0;
            for (cpu = 0; cpu < numCpus; cpu++)
                cpuset[cpu] = 0;
        } else {
2563
            nb_cpus = virDomainCpuSetParse(&cur, 'n', cpuset, numCpus);
2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577
            if (nb_cpus < 0)
                goto error;
        }

        for (n = 0, cpu = 0; cpu < numCpus; cpu++)
            if (cpuset[cpu] == 1)
                cpuNums[n++] = cpu;

        if (virCapabilitiesAddHostNUMACell(caps,
                                           cell,
                                           nb_cpus,
                                           cpuNums) < 0)
            goto memory_error;
    }
2578 2579
    VIR_FREE(cpuNums);
    VIR_FREE(cpuset);
2580
    return (0);
2581

2582
  parse_error:
2583
    virXendError(VIR_ERR_XEN_CALL, "%s", _("topology syntax error"));
2584
  error:
2585 2586
    VIR_FREE(cpuNums);
    VIR_FREE(cpuset);
2587

2588
    return (-1);
2589

2590
  memory_error:
2591 2592
    VIR_FREE(cpuNums);
    VIR_FREE(cpuset);
2593
    virReportOOMError();
2594 2595 2596
    return (-1);
}

2597

2598
#ifndef PROXY
2599 2600 2601 2602 2603 2604 2605 2606 2607 2608
/**
 * sexpr_to_domain:
 * @conn: an existing virtual connection block
 * @root: an S-Expression describing a domain
 *
 * Internal routine returning the associated virDomainPtr for this domain
 *
 * Returns the domain pointer or NULL in case of error.
 */
static virDomainPtr
2609
sexpr_to_domain(virConnectPtr conn, const struct sexpr *root)
2610
{
2611
    virDomainPtr ret = NULL;
2612
    unsigned char uuid[VIR_UUID_BUFLEN];
2613
    const char *name;
2614
    const char *tmp;
2615
    xenUnifiedPrivatePtr priv;
2616 2617 2618 2619

    if ((conn == NULL) || (root == NULL))
        return(NULL);

2620 2621
    priv = (xenUnifiedPrivatePtr) conn->privateData;

2622
    if (sexpr_uuid(uuid, root, "domain/uuid") < 0)
2623 2624 2625 2626 2627
        goto error;
    name = sexpr_node(root, "domain/name");
    if (name == NULL)
        goto error;

2628
    ret = virGetDomain(conn, name, uuid);
2629 2630
    if (ret == NULL) return NULL;

2631 2632 2633 2634
    tmp = sexpr_node(root, "domain/domid");
    /* New 3.0.4 XenD will not report a domid for inactive domains,
     * so only error out for old XenD
     */
2635
    if (!tmp && priv->xendConfigVersion < 3)
2636 2637
        goto error;

2638
    if (tmp)
2639
        ret->id = sexpr_int(root, "domain/domid");
2640
    else
2641
        ret->id = -1; /* An inactive domain */
2642

2643
    return (ret);
2644

2645
error:
2646
    virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
2647
                 "%s", _("failed to parse Xend domain information"));
2648
    if (ret != NULL)
2649
        virUnrefDomain(ret);
2650 2651
    return(NULL);
}
2652
#endif /* !PROXY */
2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664

/*****************************************************************
 ******
 ******
 ******
 ******
             Refactored
 ******
 ******
 ******
 ******
 *****************************************************************/
2665
#ifndef PROXY
2666 2667 2668 2669 2670 2671 2672 2673 2674 2675
/**
 * xenDaemonOpen:
 * @conn: an existing virtual connection block
 * @name: optional argument to select a connection type
 * @flags: combination of virDrvOpenFlag(s)
 *
 * Creates a localhost Xen Daemon connection
 *
 * Returns 0 in case of success, -1 in case of error.
 */
2676
virDrvOpenStatus
2677 2678
xenDaemonOpen(virConnectPtr conn,
              virConnectAuthPtr auth ATTRIBUTE_UNUSED,
2679
              int flags ATTRIBUTE_UNUSED)
2680
{
2681 2682
    char *port = NULL;
    int ret = VIR_DRV_OPEN_ERROR;
2683 2684 2685

    /* Switch on the scheme, which we expect to be NULL (file),
     * "http" or "xen".
2686
     */
2687
    if (conn->uri->scheme == NULL) {
2688
        /* It should be a file access */
2689
        if (conn->uri->path == NULL) {
2690
            virXendError(VIR_ERR_NO_CONNECT, __FUNCTION__);
2691 2692
            goto failed;
        }
2693 2694
        if (xenDaemonOpen_unix(conn, conn->uri->path) < 0 ||
            xend_detect_config_version(conn) == -1)
2695 2696
            goto failed;
    }
2697
    else if (STRCASEEQ (conn->uri->scheme, "xen")) {
2698
        /*
2699 2700
         * try first to open the unix socket
         */
2701 2702
        if (xenDaemonOpen_unix(conn, "/var/lib/xend/xend-socket") == 0 &&
            xend_detect_config_version(conn) != -1)
2703 2704 2705 2706 2707
            goto done;

        /*
         * try though http on port 8000
         */
2708 2709
        if (xenDaemonOpen_tcp(conn, "localhost", "8000") < 0 ||
            xend_detect_config_version(conn) == -1)
2710
            goto failed;
2711
    } else if (STRCASEEQ (conn->uri->scheme, "http")) {
2712
        if (conn->uri->port &&
2713
            virAsprintf(&port, "%d", conn->uri->port) == -1) {
2714
            virReportOOMError();
2715
            goto failed;
2716
        }
2717

2718 2719 2720
        if (xenDaemonOpen_tcp(conn,
                              conn->uri->server ? conn->uri->server : "localhost",
                              port ? port : "8000") < 0 ||
2721
            xend_detect_config_version(conn) == -1)
2722
            goto failed;
2723
    } else {
2724
        virXendError(VIR_ERR_NO_CONNECT, __FUNCTION__);
2725
        goto failed;
2726
    }
2727

2728
 done:
2729
    ret = VIR_DRV_OPEN_SUCCESS;
2730

2731
failed:
2732 2733
    VIR_FREE(port);
    return ret;
2734
}
2735

2736 2737 2738 2739 2740 2741 2742 2743 2744

/**
 * xenDaemonClose:
 * @conn: an existing virtual connection block
 *
 * This method should be called when a connection to xend instance
 * initialized with xenDaemonOpen is no longer needed
 * to free the associated resources.
 *
2745
 * Returns 0 in case of success, -1 in case of error
2746 2747 2748 2749
 */
int
xenDaemonClose(virConnectPtr conn ATTRIBUTE_UNUSED)
{
2750
    return 0;
2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765
}

/**
 * xenDaemonDomainSuspend:
 * @domain: pointer to the Domain block
 *
 * Pause the domain, the domain is not scheduled anymore though its resources
 * are preserved. Use xenDaemonDomainResume() to resume execution.
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
xenDaemonDomainSuspend(virDomainPtr domain)
{
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
2766
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2767 2768
        return(-1);
    }
2769 2770

    if (domain->id < 0) {
2771
        virXendError(VIR_ERR_OPERATION_INVALID,
2772
                     _("Domain %s isn't running."), domain->name);
2773
        return(-1);
2774 2775
    }

2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791
    return xend_op(domain->conn, domain->name, "op", "pause", NULL);
}

/**
 * xenDaemonDomainResume:
 * @xend: pointer to the Xem Daemon block
 * @name: name for the domain
 *
 * Resume the domain after xenDaemonDomainSuspend() has been called
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
xenDaemonDomainResume(virDomainPtr domain)
{
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
2792
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2793 2794
        return(-1);
    }
2795 2796

    if (domain->id < 0) {
2797
        virXendError(VIR_ERR_OPERATION_INVALID,
2798
                     _("Domain %s isn't running."), domain->name);
2799
        return(-1);
2800 2801
    }

2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818
    return xend_op(domain->conn, domain->name, "op", "unpause", NULL);
}

/**
 * xenDaemonDomainShutdown:
 * @domain: pointer to the Domain block
 *
 * Shutdown the domain, the OS is requested to properly shutdown
 * and the domain may ignore it.  It will return immediately
 * after queuing the request.
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
xenDaemonDomainShutdown(virDomainPtr domain)
{
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
2819
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2820 2821
        return(-1);
    }
2822 2823

    if (domain->id < 0) {
2824
        virXendError(VIR_ERR_OPERATION_INVALID,
2825
                     _("Domain %s isn't running."), domain->name);
2826
        return(-1);
2827 2828
    }

2829
    return xend_op(domain->conn, domain->name, "op", "shutdown", "reason", "poweroff", NULL);
2830 2831
}

2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846
/**
 * xenDaemonDomainReboot:
 * @domain: pointer to the Domain block
 * @flags: extra flags for the reboot operation, not used yet
 *
 * Reboot the domain, the OS is requested to properly shutdown
 * and restart but the domain may ignore it.  It will return immediately
 * after queuing the request.
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
xenDaemonDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
{
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
2847
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2848 2849
        return(-1);
    }
2850 2851

    if (domain->id < 0) {
2852
        virXendError(VIR_ERR_OPERATION_INVALID,
2853
                     _("Domain %s isn't running."), domain->name);
2854
        return(-1);
2855 2856
    }

2857 2858 2859
    return xend_op(domain->conn, domain->name, "op", "shutdown", "reason", "reboot", NULL);
}

2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876
/**
 * xenDaemonDomainDestroy:
 * @domain: pointer to the Domain block
 *
 * Abruptly halt the domain, the OS is not properly shutdown and the
 * resources allocated for the domain are immediately freed, mounted
 * filesystems will be marked as uncleanly shutdown.
 * After calling this function, the domain's status will change to
 * dying and will go away completely once all of the resources have been
 * unmapped (usually from the backend devices).
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
xenDaemonDomainDestroy(virDomainPtr domain)
{
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
2877
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2878 2879
        return(-1);
    }
2880 2881

    if (domain->id < 0) {
2882
        virXendError(VIR_ERR_OPERATION_INVALID,
2883
                     _("Domain %s isn't running."), domain->name);
2884
        return(-1);
2885 2886
    }

2887 2888 2889
    return xend_op(domain->conn, domain->name, "op", "destroy", NULL);
}

2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906
/**
 * xenDaemonDomainGetOSType:
 * @domain: a domain object
 *
 * Get the type of domain operation system.
 *
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
static char *
xenDaemonDomainGetOSType(virDomainPtr domain)
{
    char *type;
    struct sexpr *root;
    xenUnifiedPrivatePtr priv;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
2907
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926
        return(NULL);
    }

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

    if (domain->id < 0 && priv->xendConfigVersion < 3)
        return(NULL);

    /* can we ask for a subset ? worth it ? */
    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL)
        return(NULL);

    if (sexpr_lookup(root, "domain/image/hvm")) {
        type = strdup("hvm");
    } else {
        type = strdup("linux");
    }

2927
    if (type == NULL)
2928
        virReportOOMError();
2929

2930 2931 2932 2933 2934
    sexpr_free(root);

    return(type);
}

2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951
/**
 * xenDaemonDomainSave:
 * @domain: pointer to the Domain block
 * @filename: path for the output file
 *
 * This method will suspend a domain and save its memory contents to
 * a file on disk.  Use xenDaemonDomainRestore() to restore a domain after
 * saving.
 * Note that for remote Xen Daemon the file path will be interpreted in
 * the remote host.
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
xenDaemonDomainSave(virDomainPtr domain, const char *filename)
{
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
2952
        (filename == NULL)) {
2953
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2954 2955
        return(-1);
    }
2956

2957
    if (domain->id < 0) {
2958
        virXendError(VIR_ERR_OPERATION_INVALID,
2959 2960 2961
                     _("Domain %s isn't running."), domain->name);
        return(-1);
    }
2962 2963 2964

    /* We can't save the state of Domain-0, that would mean stopping it too */
    if (domain->id == 0) {
2965
        return(-1);
2966 2967
    }

2968 2969 2970
    return xend_op(domain->conn, domain->name, "op", "save", "file", filename, NULL);
}

D
Daniel Veillard 已提交
2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988
/**
 * xenDaemonDomainCoreDump:
 * @domain: pointer to the Domain block
 * @filename: path for the output file
 * @flags: extra flags, currently unused
 *
 * This method will dump the core of a domain on a given file for analysis.
 * Note that for remote Xen Daemon the file path will be interpreted in
 * the remote host.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
static int
xenDaemonDomainCoreDump(virDomainPtr domain, const char *filename,
                        int flags ATTRIBUTE_UNUSED)
{
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        (filename == NULL)) {
2989
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
D
Daniel Veillard 已提交
2990 2991
        return(-1);
    }
2992 2993

    if (domain->id < 0) {
2994
        virXendError(VIR_ERR_OPERATION_INVALID,
2995
                     _("Domain %s isn't running."), domain->name);
D
Daniel Veillard 已提交
2996
        return(-1);
2997 2998
    }

2999 3000
    return xend_op(domain->conn, domain->name,
                   "op", "dump", "file", filename, "live", "0",
P
Paolo Bonzini 已提交
3001
                   "live", (flags & VIR_DUMP_LIVE ? "1" : "0"),
3002 3003
                   "crash", (flags & VIR_DUMP_CRASH ? "1" : "0"),
                   NULL);
D
Daniel Veillard 已提交
3004 3005
}

3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021
/**
 * xenDaemonDomainRestore:
 * @conn: pointer to the Xem Daemon block
 * @filename: path for the output file
 *
 * This method will restore a domain saved to disk by xenDaemonDomainSave().
 * Note that for remote Xen Daemon the file path will be interpreted in
 * the remote host.
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
xenDaemonDomainRestore(virConnectPtr conn, const char *filename)
{
    if ((conn == NULL) || (filename == NULL)) {
        /* this should be caught at the interface but ... */
3022
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3023 3024 3025 3026
        return (-1);
    }
    return xend_op(conn, "", "op", "restore", "file", filename, NULL);
}
3027
#endif /* !PROXY */
3028

3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041
/**
 * xenDaemonDomainGetMaxMemory:
 * @domain: pointer to the domain block
 *
 * Ask the Xen Daemon for the maximum memory allowed for a domain
 *
 * Returns the memory size in kilobytes or 0 in case of error.
 */
unsigned long
xenDaemonDomainGetMaxMemory(virDomainPtr domain)
{
    unsigned long ret = 0;
    struct sexpr *root;
3042
    xenUnifiedPrivatePtr priv;
3043 3044

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3045
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3046 3047
        return(-1);
    }
3048 3049 3050 3051

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

    if (domain->id < 0 && priv->xendConfigVersion < 3)
3052
        return(-1);
3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064

    /* can we ask for a subset ? worth it ? */
    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL)
        return(0);

    ret = (unsigned long) sexpr_u64(root, "domain/memory") << 10;
    sexpr_free(root);

    return(ret);
}

3065
#ifndef PROXY
3066 3067 3068 3069 3070 3071 3072
/**
 * xenDaemonDomainSetMaxMemory:
 * @domain: pointer to the Domain block
 * @memory: The maximum memory in kilobytes
 *
 * This method will set the maximum amount of memory that can be allocated to
 * a domain.  Please note that a domain is able to allocate up to this amount
3073
 * on its own.
3074 3075 3076 3077 3078 3079 3080
 *
 * Returns 0 for success; -1 (with errno) on error
 */
int
xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
{
    char buf[1024];
3081
    xenUnifiedPrivatePtr priv;
3082 3083

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3084
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3085 3086
        return(-1);
    }
3087 3088 3089 3090

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

    if (domain->id < 0 && priv->xendConfigVersion < 3)
3091 3092
        return(-1);

3093 3094 3095 3096 3097
    snprintf(buf, sizeof(buf), "%lu", memory >> 10);
    return xend_op(domain->conn, domain->name, "op", "maxmem_set", "memory",
                   buf, NULL);
}

3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117
/**
 * xenDaemonDomainSetMemory:
 * @domain: pointer to the Domain block
 * @memory: The target memory in kilobytes
 *
 * This method will set a target memory allocation for a given domain and
 * request that the guest meet this target.  The guest may or may not actually
 * achieve this target.  When this function returns, it does not signify that
 * the domain has actually reached that target.
 *
 * Memory for a domain can only be allocated up to the maximum memory setting.
 * There is no safe guard for allocations that are too small so be careful
 * when using this function to reduce a domain's memory usage.
 *
 * Returns 0 for success; -1 (with errno) on error
 */
int
xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory)
{
    char buf[1024];
3118
    xenUnifiedPrivatePtr priv;
3119 3120

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3121
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3122 3123
        return(-1);
    }
3124 3125 3126 3127

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

    if (domain->id < 0 && priv->xendConfigVersion < 3)
3128 3129
        return(-1);

3130 3131 3132 3133 3134
    snprintf(buf, sizeof(buf), "%lu", memory >> 10);
    return xend_op(domain->conn, domain->name, "op", "mem_target_set",
                   "target", buf, NULL);
}

3135 3136
#endif /* ! PROXY */

3137 3138 3139 3140 3141
virDomainDefPtr
xenDaemonDomainFetch(virConnectPtr conn,
                     int domid,
                     const char *name,
                     const char *cpus)
3142 3143
{
    struct sexpr *root;
3144
    xenUnifiedPrivatePtr priv;
3145
    virDomainDefPtr def;
3146

3147 3148 3149 3150
    if (name)
        root = sexpr_get(conn, "/xend/domain/%s?detail=1", name);
    else
        root = sexpr_get(conn, "/xend/domain/%d?detail=1", domid);
3151
    if (root == NULL) {
3152
        virXendError(VIR_ERR_XEN_CALL,
J
Jim Meyering 已提交
3153
                      "%s", _("xenDaemonDomainFetch failed to"
3154
                        " find this domain"));
3155
        return (NULL);
3156
    }
3157

3158 3159
    priv = (xenUnifiedPrivatePtr) conn->privateData;

3160 3161 3162
    if (!(def = xenDaemonParseSxpr(conn,
                                   root,
                                   priv->xendConfigVersion,
3163 3164 3165 3166
                                   cpus)))
        goto cleanup;

cleanup:
3167 3168
    sexpr_free(root);

3169
    return (def);
3170 3171 3172
}


3173
#ifndef PROXY
3174 3175
/**
 * xenDaemonDomainDumpXML:
D
Daniel Veillard 已提交
3176
 * @domain: a domain object
3177 3178
 * @flags: potential dump flags
 * @cpus: list of cpu the domain is pinned to.
D
Daniel Veillard 已提交
3179
 *
3180
 * Provide an XML description of the domain.
D
Daniel Veillard 已提交
3181 3182 3183 3184 3185
 *
 * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
 *         the caller must free() the returned value.
 */
char *
3186
xenDaemonDomainDumpXML(virDomainPtr domain, int flags, const char *cpus)
3187
{
3188
    xenUnifiedPrivatePtr priv;
3189 3190
    virDomainDefPtr def;
    char *xml;
3191

3192
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3193
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3194
        return(NULL);
3195
    }
3196 3197
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

3198
    if (domain->id < 0 && priv->xendConfigVersion < 3) {
3199
        // fall-through to the next driver to handle
3200
        return(NULL);
3201 3202
    }

3203 3204 3205 3206 3207 3208
    if (!(def = xenDaemonDomainFetch(domain->conn,
                                     domain->id,
                                     domain->name,
                                     cpus)))
        return(NULL);

3209
    xml = virDomainDefFormat(def, flags);
3210 3211 3212 3213

    virDomainDefFree(def);

    return xml;
D
Daniel Veillard 已提交
3214
}
3215
#endif /* !PROXY */
3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231

/**
 * xenDaemonDomainGetInfo:
 * @domain: a domain object
 * @info: pointer to a virDomainInfo structure allocated by the user
 *
 * This method looks up information about a domain and update the
 * information block provided.
 *
 * Returns 0 in case of success, -1 in case of error
 */
int
xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
    struct sexpr *root;
    int ret;
3232
    xenUnifiedPrivatePtr priv;
3233

3234 3235
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        (info == NULL)) {
3236
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3237 3238
        return(-1);
    }
3239 3240 3241 3242

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

    if (domain->id < 0 && priv->xendConfigVersion < 3)
3243
        return(-1);
3244 3245 3246 3247 3248

    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL)
        return (-1);

3249
    ret = sexpr_to_xend_domain_info(domain, root, info);
3250 3251 3252 3253
    sexpr_free(root);
    return (ret);
}

3254
#ifndef PROXY
3255
/**
3256
 * xenDaemonLookupByName:
3257 3258 3259 3260 3261 3262 3263 3264 3265 3266
 * @conn: A xend instance
 * @name: The name of the domain
 *
 * This method looks up information about a domain and returns
 * it in the form of a struct xend_domain.  This should be
 * free()'d when no longer needed.
 *
 * Returns domain info on success; NULL (with errno) on error
 */
virDomainPtr
3267
xenDaemonLookupByName(virConnectPtr conn, const char *domname)
3268 3269 3270 3271 3272
{
    struct sexpr *root;
    virDomainPtr ret = NULL;

    if ((conn == NULL) || (domname == NULL)) {
3273
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3274
        return(NULL);
3275
    }
3276

3277 3278 3279 3280 3281 3282 3283 3284 3285 3286
    root = sexpr_get(conn, "/xend/domain/%s?detail=1", domname);
    if (root == NULL)
        goto error;

    ret = sexpr_to_domain(conn, root);

error:
    sexpr_free(root);
    return(ret);
}
3287
#endif /* ! PROXY */
3288

3289 3290 3291 3292
/**
 * xenDaemonNodeGetInfo:
 * @conn: pointer to the Xen Daemon block
 * @info: pointer to a virNodeInfo structure allocated by the user
3293
 *
3294 3295 3296 3297
 * Extract hardware information about the node.
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
3298
int
3299 3300 3301 3302 3303
xenDaemonNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) {
    int ret = -1;
    struct sexpr *root;

    if (!VIR_IS_CONNECT(conn)) {
3304
        virXendError(VIR_ERR_INVALID_CONN, __FUNCTION__);
3305 3306 3307
        return (-1);
    }
    if (info == NULL) {
3308
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320
        return (-1);
    }

    root = sexpr_get(conn, "/xend/node/");
    if (root == NULL)
        return (-1);

    ret = sexpr_to_xend_node_info(root, info);
    sexpr_free(root);
    return (ret);
}

3321 3322 3323
/**
 * xenDaemonNodeGetTopology:
 * @conn: pointer to the Xen Daemon block
3324
 * @caps: capabilities info
3325 3326 3327 3328 3329 3330
 *
 * This method retrieves a node's topology information.
 *
 * Returns -1 in case of error, 0 otherwise.
 */
int
3331 3332
xenDaemonNodeGetTopology(virConnectPtr conn,
                         virCapsPtr caps) {
3333 3334 3335 3336
    int ret = -1;
    struct sexpr *root;

    if (!VIR_IS_CONNECT(conn)) {
3337
        virXendError(VIR_ERR_INVALID_CONN, __FUNCTION__);
3338 3339 3340
        return (-1);
    }

3341
    if (caps == NULL) {
3342
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3343
        return (-1);
3344
    }
3345 3346 3347 3348 3349 3350

    root = sexpr_get(conn, "/xend/node/");
    if (root == NULL) {
        return (-1);
    }

3351
    ret = sexpr_to_xend_topology(root, caps);
3352 3353 3354 3355
    sexpr_free(root);
    return (ret);
}

3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366
/**
 * xenDaemonGetVersion:
 * @conn: pointer to the Xen Daemon block
 * @hvVer: return value for the version of the running hypervisor (OUT)
 *
 * Get the version level of the Hypervisor running.
 *
 * Returns -1 in case of error, 0 otherwise. if the version can't be
 *    extracted by lack of capacities returns 0 and @hvVer is 0, otherwise
 *    @hvVer value is major * 1,000,000 + minor * 1,000 + release
 */
3367
int
3368 3369
xenDaemonGetVersion(virConnectPtr conn, unsigned long *hvVer)
{
3370
    struct sexpr *root;
3371
    int major, minor;
3372
    unsigned long version;
3373

3374
    if (!VIR_IS_CONNECT(conn)) {
3375
        virXendError(VIR_ERR_INVALID_CONN, __FUNCTION__);
3376 3377 3378
        return (-1);
    }
    if (hvVer == NULL) {
3379
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3380 3381
        return (-1);
    }
3382 3383
    root = sexpr_get(conn, "/xend/node/");
    if (root == NULL)
3384
        return(-1);
3385 3386 3387 3388

    major = sexpr_int(root, "node/xen_major");
    minor = sexpr_int(root, "node/xen_minor");
    sexpr_free(root);
3389
    version = major * 1000000 + minor * 1000;
3390 3391 3392
    *hvVer = version;
    return(0);
}
3393

3394
#ifndef PROXY
3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406
/**
 * xenDaemonListDomains:
 * @conn: pointer to the hypervisor connection
 * @ids: array to collect the list of IDs of active domains
 * @maxids: size of @ids
 *
 * Collect the list of active domains, and store their ID in @maxids
 * TODO: this is quite expensive at the moment since there isn't one
 *       xend RPC providing both name and id for all domains.
 *
 * Returns the number of domain found or -1 in case of error
 */
3407
int
3408 3409 3410 3411 3412 3413 3414
xenDaemonListDomains(virConnectPtr conn, int *ids, int maxids)
{
    struct sexpr *root = NULL;
    int ret = -1;
    struct sexpr *_for_i, *node;
    long id;

3415 3416 3417 3418
    if (maxids == 0)
        return(0);

    if ((ids == NULL) || (maxids < 0))
3419 3420 3421 3422 3423 3424 3425
        goto error;
    root = sexpr_get(conn, "/xend/domain");
    if (root == NULL)
        goto error;

    ret = 0;

3426 3427
    for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
         _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
3428 3429
        if (node->kind != SEXPR_VALUE)
            continue;
3430
        id = xenDaemonDomainLookupByName_ids(conn, node->u.value, NULL);
3431
        if (id >= 0)
3432 3433 3434
            ids[ret++] = (int) id;
        if (ret >= maxids)
            break;
3435 3436 3437
    }

error:
3438
    sexpr_free(root);
3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449
    return(ret);
}

/**
 * xenDaemonNumOfDomains:
 * @conn: pointer to the hypervisor connection
 *
 * Provides the number of active domains.
 *
 * Returns the number of domain found or -1 in case of error
 */
3450
int
3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462
xenDaemonNumOfDomains(virConnectPtr conn)
{
    struct sexpr *root = NULL;
    int ret = -1;
    struct sexpr *_for_i, *node;

    root = sexpr_get(conn, "/xend/domain");
    if (root == NULL)
        goto error;

    ret = 0;

3463 3464
    for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
         _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
3465 3466
        if (node->kind != SEXPR_VALUE)
            continue;
3467
        ret++;
3468 3469 3470
    }

error:
3471
    sexpr_free(root);
3472 3473
    return(ret);
}
3474
#endif /* ! PROXY */
3475

3476
#ifndef PROXY
3477 3478 3479 3480 3481 3482 3483 3484 3485
/**
 * xenDaemonLookupByID:
 * @conn: pointer to the hypervisor connection
 * @id: the domain ID number
 *
 * Try to find a domain based on the hypervisor ID number
 *
 * Returns a new domain object or NULL in case of failure
 */
3486
virDomainPtr
3487 3488
xenDaemonLookupByID(virConnectPtr conn, int id) {
    char *name = NULL;
3489
    unsigned char uuid[VIR_UUID_BUFLEN];
3490 3491
    virDomainPtr ret;

3492
    if (xenDaemonDomainLookupByID(conn, id, &name, uuid) < 0) {
3493
        goto error;
3494
    }
3495 3496

    ret = virGetDomain(conn, name, uuid);
3497
    if (ret == NULL) goto error;
3498

3499
    ret->id = id;
3500
    VIR_FREE(name);
3501 3502
    return (ret);

3503
 error:
3504
    VIR_FREE(name);
3505 3506 3507
    return (NULL);
}

3508 3509 3510 3511 3512 3513 3514 3515 3516 3517
/**
 * xenDaemonDomainSetVcpus:
 * @domain: pointer to domain object
 * @nvcpus: the new number of virtual CPUs for this domain
 *
 * Dynamically change the number of virtual CPUs used by the domain.
 *
 * Returns 0 for success; -1 (with errno) on error
 */
int
3518
xenDaemonDomainSetVcpus(virDomainPtr domain, unsigned int vcpus)
3519
{
3520
    char buf[VIR_UUID_BUFLEN];
3521
    xenUnifiedPrivatePtr priv;
3522 3523 3524

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
     || (vcpus < 1)) {
3525
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3526 3527
        return (-1);
    }
3528 3529 3530 3531

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

    if (domain->id < 0 && priv->xendConfigVersion < 3)
3532 3533
        return(-1);

3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544
    snprintf(buf, sizeof(buf), "%d", vcpus);
    return(xend_op(domain->conn, domain->name, "op", "set_vcpus", "vcpus",
                   buf, NULL));
}

/**
 * xenDaemonDomainPinCpu:
 * @domain: pointer to domain object
 * @vcpu: virtual CPU number
 * @cpumap: pointer to a bit map of real CPUs (in 8-bit bytes)
 * @maplen: length of cpumap in bytes
3545
 *
3546
 * Dynamically change the real CPUs which can be allocated to a virtual CPU.
3547 3548 3549 3550 3551
 * NOTE: The XenD cpu affinity map format changed from "[0,1,2]" to
 *       "0,1,2"
 *       the XenD cpu affinity works only after cset 19579.
 *       there is no fine grained xend version detection possible, so we
 *       use the old format for anything before version 3
3552 3553 3554 3555 3556 3557 3558
 *
 * Returns 0 for success; -1 (with errno) on error
 */
int
xenDaemonDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
                     unsigned char *cpumap, int maplen)
{
3559
    char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64];
3560
    int i, j;
3561
    xenUnifiedPrivatePtr priv;
3562 3563 3564

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
     || (cpumap == NULL) || (maplen < 1) || (maplen > (int)sizeof(cpumap_t))) {
3565
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3566 3567
        return (-1);
    }
3568

3569 3570
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xendConfigVersion < 3) {
H
Henrik Persson 已提交
3571 3572
        mapstr[0] = '[';
        mapstr[1] = 0;
3573
    } else {
H
Henrik Persson 已提交
3574
        mapstr[0] = 0;
3575 3576
    }

3577 3578 3579
    /* from bit map, build character string of mapped CPU numbers */
    for (i = 0; i < maplen; i++) for (j = 0; j < 8; j++)
     if (cpumap[i] & (1 << j)) {
3580
        snprintf(buf, sizeof(buf), "%d,", (8 * i) + j);
3581 3582
        strcat(mapstr, buf);
    }
3583 3584 3585 3586 3587
    if (priv->xendConfigVersion < 3)
        mapstr[strlen(mapstr) - 1] = ']';
    else
        mapstr[strlen(mapstr) - 1] = 0;

3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598
    snprintf(buf, sizeof(buf), "%d", vcpu);
    return(xend_op(domain->conn, domain->name, "op", "pincpu", "vcpu", buf,
                  "cpumap", mapstr, NULL));
}

/**
 * virDomainGetVcpus:
 * @domain: pointer to domain object, or NULL for Domain0
 * @info: pointer to an array of virVcpuInfo structures (OUT)
 * @maxinfo: number of structures in info array
 * @cpumaps: pointer to an bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
D
Daniel Veillard 已提交
3599
 *	If cpumaps is NULL, then no cpumap information is returned by the API.
3600 3601 3602 3603 3604 3605
 *	It's assumed there is <maxinfo> cpumap in cpumaps array.
 *	The memory allocated to cpumaps must be (maxinfo * maplen) bytes
 *	(ie: calloc(maxinfo, maplen)).
 *	One cpumap inside cpumaps has the format described in virDomainPinVcpu() API.
 * @maplen: number of bytes in one cpumap, from 1 up to size of CPU map in
 *	underlying virtualization system (Xen...).
3606
 *
3607
 * Extract information about virtual CPUs of domain, store it in info array
D
Daniel Veillard 已提交
3608
 * and also in cpumaps if this pointer isn't NULL.
3609 3610 3611 3612 3613
 *
 * Returns the number of info filled in case of success, -1 in case of failure.
 */
int
xenDaemonDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
3614
                        unsigned char *cpumaps, int maplen)
3615 3616 3617 3618 3619 3620 3621 3622
{
    struct sexpr *root, *s, *t;
    virVcpuInfoPtr ipt = info;
    int nbinfo = 0, oln;
    unsigned char *cpumap;
    int vcpu, cpu;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
3623
        || (info == NULL) || (maxinfo < 1)) {
3624
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3625 3626 3627
        return (-1);
    }
    if (cpumaps != NULL && maplen < 1) {
3628
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3629 3630
        return (-1);
    }
3631

3632 3633 3634 3635 3636
    root = sexpr_get(domain->conn, "/xend/domain/%s?op=vcpuinfo", domain->name);
    if (root == NULL)
        return (-1);

    if (cpumaps != NULL)
3637
        memset(cpumaps, 0, maxinfo * maplen);
3638 3639

    /* scan the sexprs from "(vcpu (number x)...)" and get parameter values */
3640 3641 3642
    for (s = root; s->kind == SEXPR_CONS; s = s->u.s.cdr) {
        if ((s->u.s.car->kind == SEXPR_CONS) &&
            (s->u.s.car->u.s.car->kind == SEXPR_VALUE) &&
3643
            STREQ(s->u.s.car->u.s.car->u.value, "vcpu")) {
3644
            t = s->u.s.car;
3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660
            vcpu = ipt->number = sexpr_int(t, "vcpu/number");
            if ((oln = sexpr_int(t, "vcpu/online")) != 0) {
                if (sexpr_int(t, "vcpu/running")) ipt->state = VIR_VCPU_RUNNING;
                if (sexpr_int(t, "vcpu/blocked")) ipt->state = VIR_VCPU_BLOCKED;
            }
            else
                ipt->state = VIR_VCPU_OFFLINE;
            ipt->cpuTime = sexpr_float(t, "vcpu/cpu_time") * 1000000000;
            ipt->cpu = oln ? sexpr_int(t, "vcpu/cpu") : -1;

            if (cpumaps != NULL && vcpu >= 0 && vcpu < maxinfo) {
                cpumap = (unsigned char *) VIR_GET_CPUMAP(cpumaps, maplen, vcpu);
                /*
                 * get sexpr from "(cpumap (x y z...))" and convert values
                 * to bitmap
                 */
3661 3662 3663
                for (t = t->u.s.cdr; t->kind == SEXPR_CONS; t = t->u.s.cdr)
                    if ((t->u.s.car->kind == SEXPR_CONS) &&
                        (t->u.s.car->u.s.car->kind == SEXPR_VALUE) &&
3664
                        STREQ(t->u.s.car->u.s.car->u.value, "cpumap") &&
3665 3666
                        (t->u.s.car->u.s.cdr->kind == SEXPR_CONS)) {
                        for (t = t->u.s.car->u.s.cdr->u.s.car; t->kind == SEXPR_CONS; t = t->u.s.cdr)
3667
                            if (t->u.s.car->kind == SEXPR_VALUE
3668
                                && virStrToLong_i(t->u.s.car->u.value, NULL, 10, &cpu) == 0
3669 3670 3671
                                && cpu >= 0
                                && (VIR_CPU_MAPLEN(cpu+1) <= maplen)) {
                                VIR_USE_CPU(cpumap, cpu);
3672 3673 3674
                            }
                        break;
                    }
3675 3676
            }

3677 3678 3679
            if (++nbinfo == maxinfo) break;
            ipt++;
        }
3680 3681 3682 3683 3684
    }
    sexpr_free(root);
    return(nbinfo);
}

3685 3686 3687 3688 3689 3690 3691 3692 3693
/**
 * xenDaemonLookupByUUID:
 * @conn: pointer to the hypervisor connection
 * @uuid: the raw UUID for the domain
 *
 * Try to lookup a domain on xend based on its UUID.
 *
 * Returns a new domain object or NULL in case of failure
 */
3694
virDomainPtr
3695 3696 3697 3698 3699
xenDaemonLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
    virDomainPtr ret;
    char *name = NULL;
    int id = -1;
3700 3701
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;

3702
    /* Old approach for xen <= 3.0.3 */
3703
    if (priv->xendConfigVersion < 3) {
3704 3705 3706 3707 3708 3709
        char **names, **tmp;
        unsigned char ident[VIR_UUID_BUFLEN];
        names = xenDaemonListDomainsOld(conn);
        tmp = names;

        if (names == NULL) {
3710
            return (NULL);
3711 3712 3713 3714 3715 3716
        }
        while (*tmp != NULL) {
            id = xenDaemonDomainLookupByName_ids(conn, *tmp, &ident[0]);
            if (id >= 0) {
                if (!memcmp(uuid, ident, VIR_UUID_BUFLEN)) {
                    name = strdup(*tmp);
3717 3718

                    if (name == NULL)
3719
                        virReportOOMError();
3720

3721 3722
                    break;
                }
3723
            }
3724
            tmp++;
3725
        }
3726
        VIR_FREE(names);
3727 3728 3729 3730 3731
    } else { /* New approach for xen >= 3.0.4 */
        char *domname = NULL;
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        struct sexpr *root = NULL;

3732
        virUUIDFormat(uuid, uuidstr);
3733 3734 3735 3736 3737 3738 3739 3740
        root = sexpr_get(conn, "/xend/domain/%s?detail=1", uuidstr);
        if (root == NULL)
            return (NULL);
        domname = (char*)sexpr_node(root, "domain/name");
        if (sexpr_node(root, "domain/domid")) /* only active domains have domid */
            id = sexpr_int(root, "domain/domid");
        else
            id = -1;
3741 3742 3743 3744 3745

        if (domname) {
            name = strdup(domname);

            if (name == NULL)
3746
                virReportOOMError();
3747 3748
        }

3749
        sexpr_free(root);
3750 3751 3752
    }

    if (name == NULL)
3753
        return (NULL);
3754 3755

    ret = virGetDomain(conn, name, uuid);
3756
    if (ret == NULL) goto cleanup;
3757

3758
    ret->id = id;
3759 3760

  cleanup:
3761
    VIR_FREE(name);
3762 3763
    return (ret);
}
3764 3765

/**
3766
 * xenDaemonCreateXML:
3767 3768 3769 3770 3771 3772
 * @conn: pointer to the hypervisor connection
 * @xmlDesc: an XML description of the domain
 * @flags: an optional set of virDomainFlags
 *
 * Launch a new Linux guest domain, based on an XML description similar
 * to the one returned by virDomainGetXMLDesc()
3773
 * This function may requires privileged access to the hypervisor.
3774
 *
3775 3776 3777
 * Returns a new domain object or NULL in case of failure
 */
static virDomainPtr
3778
xenDaemonCreateXML(virConnectPtr conn, const char *xmlDesc,
3779 3780 3781 3782
                     unsigned int flags ATTRIBUTE_UNUSED)
{
    int ret;
    char *sexpr;
3783
    virDomainPtr dom = NULL;
3784
    xenUnifiedPrivatePtr priv;
3785
    virDomainDefPtr def;
3786

3787 3788
    priv = (xenUnifiedPrivatePtr) conn->privateData;

3789
    if (!(def = virDomainDefParseString(priv->caps,
3790 3791
                                        xmlDesc,
                                        VIR_DOMAIN_XML_INACTIVE)))
3792
        return (NULL);
3793

3794 3795
    if (!(sexpr = xenDaemonFormatSxpr(conn, def, priv->xendConfigVersion))) {
        virDomainDefFree(def);
3796 3797 3798
        return (NULL);
    }

3799
    ret = xenDaemonDomainCreateXML(conn, sexpr);
3800
    VIR_FREE(sexpr);
3801 3802 3803 3804
    if (ret != 0) {
        goto error;
    }

3805 3806
    /* This comes before wait_for_devices, to ensure that latter
       cleanup will destroy the domain upon failure */
3807
    if (!(dom = virDomainLookupByName(conn, def->name)))
3808 3809
        goto error;

3810
    if (xend_wait_for_devices(conn, def->name) < 0)
3811 3812
        goto error;

3813
    if (xenDaemonDomainResume(dom) < 0)
3814 3815
        goto error;

3816
    virDomainDefFree(def);
3817
    return (dom);
3818

3819
  error:
3820 3821 3822
    /* Make sure we don't leave a still-born domain around */
    if (dom != NULL) {
        xenDaemonDomainDestroy(dom);
3823
        virUnrefDomain(dom);
3824
    }
3825
    virDomainDefFree(def);
3826 3827
    return (NULL);
}
3828 3829

/**
3830
 * xenDaemonAttachDeviceFlags:
3831 3832
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
3833
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
3834
 *
3835 3836 3837 3838 3839 3840
 * Create a virtual device attachment to backend.
 * XML description is translated into S-expression.
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
3841 3842
xenDaemonAttachDeviceFlags(virDomainPtr domain, const char *xml,
                           unsigned int flags)
3843
{
3844
    xenUnifiedPrivatePtr priv;
3845 3846 3847 3848 3849
    char *sexpr = NULL;
    int ret = -1;
    virDomainDeviceDefPtr dev = NULL;
    virDomainDefPtr def = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
3850
    char class[8], ref[80];
3851 3852

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3853
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3854
        return -1;
3855
    }
3856

3857 3858
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

3859 3860 3861
    if (domain->id < 0) {
        /* If xendConfigVersion < 3 only live config can be changed */
        if (priv->xendConfigVersion < 3) {
3862
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
3863
                         _("Xend version does not support modifying "
3864
                           "persistent config"));
3865 3866 3867 3868
            return -1;
        }
        /* Cannot modify live config if domain is inactive */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
3869
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
3870 3871 3872 3873 3874 3875 3876 3877
                         _("Cannot modify live config if domain is inactive"));
            return -1;
        }
    } else {
        /* Only live config can be changed if xendConfigVersion < 3 */
        if (priv->xendConfigVersion < 3 &&
            (flags != VIR_DOMAIN_DEVICE_MODIFY_CURRENT ||
             flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) {
3878
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
3879
                         _("Xend version does not support modifying "
3880
                           "persistent config"));
3881 3882
            return -1;
        }
3883
        /* Xen only supports modifying both live and persistent config if
3884 3885 3886 3887
         * xendConfigVersion >= 3
         */
        if (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                      VIR_DOMAIN_DEVICE_MODIFY_CONFIG)) {
3888
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
3889
                         _("Xend only supports modifying both live and "
3890
                           "persistent config"));
3891 3892 3893
            return -1;
        }
    }
3894

3895 3896 3897 3898 3899 3900
    if (!(def = xenDaemonDomainFetch(domain->conn,
                                     domain->id,
                                     domain->name,
                                     NULL)))
        goto cleanup;

3901
    if (!(dev = virDomainDeviceDefParse(priv->caps,
G
Guido Günther 已提交
3902
                                        def, xml, VIR_DOMAIN_XML_INACTIVE)))
3903 3904 3905 3906 3907 3908 3909 3910 3911
        goto cleanup;


    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
        if (xenDaemonFormatSxprDisk(domain->conn,
                                    dev->data.disk,
                                    &buf,
                                    STREQ(def->os.type, "hvm") ? 1 : 0,
3912
                                    priv->xendConfigVersion, 1) < 0)
3913
            goto cleanup;
3914
        break;
3915 3916 3917 3918 3919 3920

    case VIR_DOMAIN_DEVICE_NET:
        if (xenDaemonFormatSxprNet(domain->conn,
                                   dev->data.net,
                                   &buf,
                                   STREQ(def->os.type, "hvm") ? 1 : 0,
3921
                                   priv->xendConfigVersion, 1) < 0)
3922
            goto cleanup;
3923
        break;
3924

3925 3926 3927
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
3928
            if (xenDaemonFormatSxprOnePCI(dev->data.hostdev,
3929
                                          &buf, 0) < 0)
3930 3931
                goto cleanup;
        } else {
3932
            virXendError(VIR_ERR_NO_SUPPORT, "%s",
3933 3934 3935 3936 3937
                         _("unsupported device type"));
            goto cleanup;
        }
        break;

3938
    default:
3939
        virXendError(VIR_ERR_NO_SUPPORT, "%s",
3940 3941
                     _("unsupported device type"));
        goto cleanup;
3942
    }
3943 3944 3945 3946

    sexpr = virBufferContentAndReset(&buf);

    if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref))) {
3947 3948
        /* device doesn't exist, define it */
        ret = xend_op(domain->conn, domain->name, "op", "device_create",
3949
                      "config", sexpr, NULL);
3950
    }
3951 3952
    else {
        /* device exists, attempt to modify it */
3953
        ret = xend_op(domain->conn, domain->name, "op", "device_configure",
3954
                      "config", sexpr, "dev", ref, NULL);
3955
    }
3956 3957

cleanup:
3958
    VIR_FREE(sexpr);
3959 3960
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
3961 3962 3963
    return ret;
}

3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986
/**
 * xenDaemonUpdateDeviceFlags:
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
 *
 * Create a virtual device attachment to backend.
 * XML description is translated into S-expression.
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
xenDaemonUpdateDeviceFlags(virDomainPtr domain, const char *xml,
                           unsigned int flags)
{
    xenUnifiedPrivatePtr priv;
    char *sexpr = NULL;
    int ret = -1;
    virDomainDeviceDefPtr dev = NULL;
    virDomainDefPtr def = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char class[8], ref[80];

3987 3988 3989 3990
    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_CURRENT |
                  VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

3991
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3992
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3993 3994 3995 3996 3997 3998 3999 4000
        return -1;
    }

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

    if (domain->id < 0) {
        /* If xendConfigVersion < 3 only live config can be changed */
        if (priv->xendConfigVersion < 3) {
4001
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
4002 4003 4004 4005 4006 4007
                         _("Xend version does not support modifying "
                           "persistent config"));
            return -1;
        }
        /* Cannot modify live config if domain is inactive */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
4008
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
4009 4010 4011 4012 4013 4014 4015 4016
                         _("Cannot modify live config if domain is inactive"));
            return -1;
        }
    } else {
        /* Only live config can be changed if xendConfigVersion < 3 */
        if (priv->xendConfigVersion < 3 &&
            (flags != VIR_DOMAIN_DEVICE_MODIFY_CURRENT ||
             flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) {
4017
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
4018 4019 4020 4021 4022 4023 4024 4025 4026
                         _("Xend version does not support modifying "
                           "persistent config"));
            return -1;
        }
        /* Xen only supports modifying both live and persistent config if
         * xendConfigVersion >= 3
         */
        if (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                      VIR_DOMAIN_DEVICE_MODIFY_CONFIG)) {
4027
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055
                         _("Xend only supports modifying both live and "
                           "persistent config"));
            return -1;
        }
    }

    if (!(def = xenDaemonDomainFetch(domain->conn,
                                     domain->id,
                                     domain->name,
                                     NULL)))
        goto cleanup;

    if (!(dev = virDomainDeviceDefParse(priv->caps,
                                        def, xml, VIR_DOMAIN_XML_INACTIVE)))
        goto cleanup;


    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
        if (xenDaemonFormatSxprDisk(domain->conn,
                                    dev->data.disk,
                                    &buf,
                                    STREQ(def->os.type, "hvm") ? 1 : 0,
                                    priv->xendConfigVersion, 1) < 0)
            goto cleanup;
        break;

    default:
4056
        virXendError(VIR_ERR_NO_SUPPORT, "%s",
4057 4058 4059 4060 4061 4062 4063
                     _("unsupported device type"));
        goto cleanup;
    }

    sexpr = virBufferContentAndReset(&buf);

    if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref))) {
4064
        virXendError(VIR_ERR_OPERATION_INVALID, "%s",
4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079
                     _("requested device does not exist"));
        goto cleanup;
    } else {
        /* device exists, attempt to modify it */
        ret = xend_op(domain->conn, domain->name, "op", "device_configure",
                      "config", sexpr, "dev", ref, NULL);
    }

cleanup:
    VIR_FREE(sexpr);
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

4080
/**
4081
 * xenDaemonDetachDeviceFlags:
4082 4083
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
4084
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
4085
 *
4086 4087 4088 4089 4090
 * Destroy a virtual device attachment to backend.
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
4091 4092
xenDaemonDetachDeviceFlags(virDomainPtr domain, const char *xml,
                           unsigned int flags)
4093
{
4094
    xenUnifiedPrivatePtr priv;
4095
    char class[8], ref[80];
4096 4097 4098
    virDomainDeviceDefPtr dev = NULL;
    virDomainDefPtr def = NULL;
    int ret = -1;
4099 4100
    char *xendev = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
4101 4102

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
4103
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
4104 4105
        return (-1);
    }
4106 4107 4108

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

4109 4110 4111
    if (domain->id < 0) {
        /* If xendConfigVersion < 3 only live config can be changed */
        if (priv->xendConfigVersion < 3) {
4112
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
4113
                         _("Xend version does not support modifying "
4114
                           "persistent config"));
4115 4116 4117 4118
            return -1;
        }
        /* Cannot modify live config if domain is inactive */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
4119
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
4120 4121 4122 4123 4124 4125 4126 4127
                         _("Cannot modify live config if domain is inactive"));
            return -1;
        }
    } else {
        /* Only live config can be changed if xendConfigVersion < 3 */
        if (priv->xendConfigVersion < 3 &&
            (flags != VIR_DOMAIN_DEVICE_MODIFY_CURRENT ||
             flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) {
4128
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
4129
                         _("Xend version does not support modifying "
4130
                           "persistent config"));
4131 4132
            return -1;
        }
4133
        /* Xen only supports modifying both live and persistent config if
4134 4135 4136 4137
         * xendConfigVersion >= 3
         */
        if (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                      VIR_DOMAIN_DEVICE_MODIFY_CONFIG)) {
4138
            virXendError(VIR_ERR_OPERATION_INVALID, "%s",
4139
                         _("Xend only supports modifying both live and "
4140
                           "persistent config"));
4141 4142 4143
            return -1;
        }
    }
4144 4145 4146 4147 4148 4149 4150

    if (!(def = xenDaemonDomainFetch(domain->conn,
                                     domain->id,
                                     domain->name,
                                     NULL)))
        goto cleanup;

4151
    if (!(dev = virDomainDeviceDefParse(priv->caps,
G
Guido Günther 已提交
4152
                                        def, xml, VIR_DOMAIN_XML_INACTIVE)))
4153 4154 4155 4156 4157
        goto cleanup;

    if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref)))
        goto cleanup;

4158 4159 4160
    if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
        if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
4161
            if (xenDaemonFormatSxprOnePCI(dev->data.hostdev,
4162 4163 4164
                                          &buf, 1) < 0)
                goto cleanup;
        } else {
4165
            virXendError(VIR_ERR_NO_SUPPORT, "%s",
4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178
                         _("unsupported device type"));
            goto cleanup;
        }
        xendev = virBufferContentAndReset(&buf);
        ret = xend_op(domain->conn, domain->name, "op", "device_configure",
                      "config", xendev, "dev", ref, NULL);
        VIR_FREE(xendev);
    }
    else {
        ret = xend_op(domain->conn, domain->name, "op", "device_destroy",
                      "type", class, "dev", ref, "force", "0", "rm_cfg", "1",
                      NULL);
    }
4179 4180 4181 4182 4183 4184

cleanup:
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);

    return ret;
4185
}
4186

4187 4188 4189 4190 4191 4192 4193 4194 4195
int
xenDaemonDomainGetAutostart(virDomainPtr domain,
                            int *autostart)
{
    struct sexpr *root;
    const char *tmp;
    xenUnifiedPrivatePtr priv;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
4196
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208
        return (-1);
    }

    /* xm_internal.c (the support for defined domains from /etc/xen
     * config files used by old Xen) will handle this.
     */
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xendConfigVersion < 3)
        return(-1);

    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL) {
4209
        virXendError(VIR_ERR_XEN_CALL,
J
Jim Meyering 已提交
4210
                      "%s", _("xenDaemonGetAutostart failed to find this domain"));
4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234
        return (-1);
    }

    *autostart = 0;

    tmp = sexpr_node(root, "domain/on_xend_start");
    if (tmp && STREQ(tmp, "start")) {
        *autostart = 1;
    }

    sexpr_free(root);
    return 0;
}

int
xenDaemonDomainSetAutostart(virDomainPtr domain,
                            int autostart)
{
    struct sexpr *root, *autonode;
    char buf[4096];
    int ret = -1;
    xenUnifiedPrivatePtr priv;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
4235
        virXendError(VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247
        return (-1);
    }

    /* xm_internal.c (the support for defined domains from /etc/xen
     * config files used by old Xen) will handle this.
     */
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xendConfigVersion < 3)
        return(-1);

    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL) {
4248
        virXendError(VIR_ERR_XEN_CALL,
J
Jim Meyering 已提交
4249
                      "%s", _("xenDaemonSetAutostart failed to find this domain"));
4250 4251 4252
        return (-1);
    }

4253 4254 4255 4256
    autonode = sexpr_lookup(root, "domain/on_xend_start");
    if (autonode) {
        const char *val = (autonode->u.s.car->kind == SEXPR_VALUE
                           ? autonode->u.s.car->u.value : NULL);
4257
        if (!val || (!STREQ(val, "ignore") && !STREQ(val, "start"))) {
4258
            virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4259
                         "%s", _("unexpected value from on_xend_start"));
4260 4261 4262 4263
            goto error;
        }

        // Change the autostart value in place, then define the new sexpr
4264
        VIR_FREE(autonode->u.s.car->u.value);
4265 4266 4267
        autonode->u.s.car->u.value = (autostart ? strdup("start")
                                                : strdup("ignore"));
        if (!(autonode->u.s.car->u.value)) {
4268
            virReportOOMError();
4269 4270 4271 4272
            goto error;
        }

        if (sexpr2string(root, buf, sizeof(buf)) == 0) {
4273
            virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4274
                         "%s", _("sexpr2string failed"));
4275 4276 4277
            goto error;
        }
        if (xend_op(domain->conn, "", "op", "new", "config", buf, NULL) != 0) {
4278
            virXendError(VIR_ERR_XEN_CALL,
J
Jim Meyering 已提交
4279
                         "%s", _("Failed to redefine sexpr"));
4280 4281 4282
            goto error;
        }
    } else {
4283
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4284
                     "%s", _("on_xend_start not present in sexpr"));
4285 4286 4287 4288 4289 4290 4291 4292
        goto error;
    }

    ret = 0;
  error:
    sexpr_free(root);
    return ret;
}
4293

4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308
int
xenDaemonDomainMigratePrepare (virConnectPtr dconn,
                               char **cookie ATTRIBUTE_UNUSED,
                               int *cookielen ATTRIBUTE_UNUSED,
                               const char *uri_in,
                               char **uri_out,
                               unsigned long flags ATTRIBUTE_UNUSED,
                               const char *dname ATTRIBUTE_UNUSED,
                               unsigned long resource ATTRIBUTE_UNUSED)
{
    /* If uri_in is NULL, get the current hostname as a best guess
     * of how the source host should connect to us.  Note that caller
     * deallocates this string.
     */
    if (uri_in == NULL) {
4309 4310
        *uri_out = virGetHostname(dconn);
        if (*uri_out == NULL)
4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335
            return -1;
    }

    return 0;
}

int
xenDaemonDomainMigratePerform (virDomainPtr domain,
                               const char *cookie ATTRIBUTE_UNUSED,
                               int cookielen ATTRIBUTE_UNUSED,
                               const char *uri,
                               unsigned long flags,
                               const char *dname,
                               unsigned long bandwidth)
{
    /* Upper layers have already checked domain. */
    /* NB: Passing port=0 to xend means it ignores
     * the port.  However this is somewhat specific to
     * the internals of the xend Python code. (XXX).
     */
    char port[16] = "0";
    char live[2] = "0";
    int ret;
    char *p, *hostname = NULL;

4336 4337
    int undefined_source = 0;

4338 4339
    /* Xen doesn't support renaming domains during migration. */
    if (dname) {
4340
        virXendError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
4341
                      "%s", _("xenDaemonDomainMigrate: Xen does not support"
4342
                        " renaming domains during migration"));
4343 4344 4345 4346 4347 4348 4349
        return -1;
    }

    /* Xen (at least up to 3.1.0) takes a resource parameter but
     * ignores it.
     */
    if (bandwidth) {
4350
        virXendError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
4351
                      "%s", _("xenDaemonDomainMigrate: Xen does not support"
4352
                        " bandwidth limits during migration"));
4353 4354 4355
        return -1;
    }

4356 4357 4358
    /*
     * Check the flags.
     */
4359 4360 4361 4362
    if ((flags & VIR_MIGRATE_LIVE)) {
        strcpy (live, "1");
        flags &= ~VIR_MIGRATE_LIVE;
    }
4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373

    /* Undefine the VM on the source host after migration? */
    if (flags & VIR_MIGRATE_UNDEFINE_SOURCE) {
       undefined_source = 1;
       flags &= ~VIR_MIGRATE_UNDEFINE_SOURCE;
    }

    /* Ignore the persist_dest flag here */
    if (flags & VIR_MIGRATE_PERSIST_DEST)
        flags &= ~VIR_MIGRATE_PERSIST_DEST;

4374 4375 4376 4377
    /* This is buggy in Xend, but could be supported in principle.  Give
     * a nice error message.
     */
    if (flags & VIR_MIGRATE_PAUSED) {
4378
        virXendError(VIR_ERR_NO_SUPPORT,
4379 4380 4381 4382
                      "%s", _("xenDaemonDomainMigrate: xend cannot migrate paused domains"));
        return -1;
    }

4383 4384
    /* XXX we could easily do tunnelled & peer2peer migration too
       if we want to. support these... */
4385
    if (flags != 0) {
4386
        virXendError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
4387
                      "%s", _("xenDaemonDomainMigrate: unsupported flag"));
4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398
        return -1;
    }

    /* Set hostname and port.
     *
     * URI is non-NULL (guaranteed by caller).  We expect either
     * "hostname", "hostname:port" or "xenmigr://hostname[:port]/".
     */
    if (strstr (uri, "//")) {   /* Full URI. */
        xmlURIPtr uriptr = xmlParseURI (uri);
        if (!uriptr) {
4399
            virXendError(VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
4400
                          "%s", _("xenDaemonDomainMigrate: invalid URI"));
4401 4402 4403
            return -1;
        }
        if (uriptr->scheme && STRCASENEQ (uriptr->scheme, "xenmigr")) {
4404
            virXendError(VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
4405
                          "%s", _("xenDaemonDomainMigrate: only xenmigr://"
4406
                            " migrations are supported by Xen"));
4407 4408 4409 4410
            xmlFreeURI (uriptr);
            return -1;
        }
        if (!uriptr->server) {
4411
            virXendError(VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
4412
                          "%s", _("xenDaemonDomainMigrate: a hostname must be"
4413
                            " specified in the URI"));
4414 4415 4416 4417 4418
            xmlFreeURI (uriptr);
            return -1;
        }
        hostname = strdup (uriptr->server);
        if (!hostname) {
4419
            virReportOOMError();
4420 4421 4422 4423 4424 4425 4426 4427 4428 4429
            xmlFreeURI (uriptr);
            return -1;
        }
        if (uriptr->port)
            snprintf (port, sizeof port, "%d", uriptr->port);
        xmlFreeURI (uriptr);
    }
    else if ((p = strrchr (uri, ':')) != NULL) { /* "hostname:port" */
        int port_nr, n;

4430
        if (virStrToLong_i(p+1, NULL, 10, &port_nr) < 0) {
4431
            virXendError(VIR_ERR_INVALID_ARG,
J
Jim Meyering 已提交
4432
                          "%s", _("xenDaemonDomainMigrate: invalid port number"));
4433 4434 4435 4436 4437 4438 4439 4440
            return -1;
        }
        snprintf (port, sizeof port, "%d", port_nr);

        /* Get the hostname. */
        n = p - uri; /* n = Length of hostname in bytes. */
        hostname = strdup (uri);
        if (!hostname) {
4441
            virReportOOMError();
4442 4443 4444 4445 4446 4447 4448
            return -1;
        }
        hostname[n] = '\0';
    }
    else {                      /* "hostname" (or IP address) */
        hostname = strdup (uri);
        if (!hostname) {
4449
            virReportOOMError();
4450 4451 4452 4453
            return -1;
        }
    }

4454
    DEBUG("hostname = %s, port = %s", hostname, port);
4455

J
Jim Fehlig 已提交
4456 4457 4458 4459 4460 4461
    /* Make the call.
     * NB:  xend will fail the operation if any parameters are
     * missing but happily accept unknown parameters.  This works
     * to our advantage since all parameters supported and required
     * by current xend can be included without breaking older xend.
     */
4462 4463 4464 4465 4466
    ret = xend_op (domain->conn, domain->name,
                   "op", "migrate",
                   "destination", hostname,
                   "live", live,
                   "port", port,
J
Jim Fehlig 已提交
4467 4468 4469 4470
                   "node", "-1", /* xen-unstable c/s 17753 */
                   "ssl", "0", /* xen-unstable c/s 17709 */
                   "change_home_server", "0", /* xen-unstable c/s 20326 */
                   "resource", "0", /* removed by xen-unstable c/s 17553 */
4471
                   NULL);
4472
    VIR_FREE (hostname);
4473

4474 4475 4476
    if (ret == 0 && undefined_source)
        xenDaemonDomainUndefine (domain);

4477
    DEBUG0("migration done");
4478 4479 4480 4481

    return ret;
}

4482 4483 4484 4485
virDomainPtr xenDaemonDomainDefineXML(virConnectPtr conn, const char *xmlDesc) {
    int ret;
    char *sexpr;
    virDomainPtr dom;
4486
    xenUnifiedPrivatePtr priv;
4487
    virDomainDefPtr def;
4488 4489 4490 4491

    priv = (xenUnifiedPrivatePtr) conn->privateData;

    if (priv->xendConfigVersion < 3)
4492
        return(NULL);
4493

4494
    if (!(def = virDomainDefParseString(priv->caps, xmlDesc,
4495
                                        VIR_DOMAIN_XML_INACTIVE))) {
4496
        virXendError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
4497
                     "%s", _("failed to parse domain description"));
4498 4499 4500
        return (NULL);
    }

4501
    if (!(sexpr = xenDaemonFormatSxpr(conn, def, priv->xendConfigVersion))) {
4502
        virXendError(VIR_ERR_XML_ERROR,
J
Jim Meyering 已提交
4503
                     "%s", _("failed to build sexpr"));
4504 4505 4506
        goto error;
    }

4507 4508
    DEBUG("Defining w/ sexpr: \n%s", sexpr);

4509
    ret = xend_op(conn, "", "op", "new", "config", sexpr, NULL);
4510
    VIR_FREE(sexpr);
4511
    if (ret != 0) {
4512
        virXendError(VIR_ERR_XEN_CALL,
4513
                     _("Failed to create inactive domain %s"), def->name);
4514 4515 4516
        goto error;
    }

4517
    dom = virDomainLookupByName(conn, def->name);
4518 4519 4520
    if (dom == NULL) {
        goto error;
    }
4521
    virDomainDefFree(def);
4522
    return (dom);
4523

4524
  error:
4525
    virDomainDefFree(def);
4526 4527
    return (NULL);
}
4528 4529 4530
int xenDaemonDomainCreate(virDomainPtr domain)
{
    xenUnifiedPrivatePtr priv;
4531 4532
    int ret;
    virDomainPtr tmp;
4533

4534
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
4535
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
4536 4537
        return(-1);
    }
4538 4539 4540 4541

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

    if (priv->xendConfigVersion < 3)
4542 4543
        return(-1);

4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554
    ret = xend_op(domain->conn, domain->name, "op", "start", NULL);

    if (ret != -1) {
        /* Need to force a refresh of this object's ID */
        tmp = virDomainLookupByName(domain->conn, domain->name);
        if (tmp) {
            domain->id = tmp->id;
            virDomainFree(tmp);
        }
    }
    return ret;
4555 4556
}

4557 4558 4559 4560
int xenDaemonDomainUndefine(virDomainPtr domain)
{
    xenUnifiedPrivatePtr priv;

4561
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
4562
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
4563 4564
        return(-1);
    }
4565 4566 4567 4568

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

    if (priv->xendConfigVersion < 3)
4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587
        return(-1);

    return xend_op(domain->conn, domain->name, "op", "delete", NULL);
}

/**
 * xenDaemonNumOfDomains:
 * @conn: pointer to the hypervisor connection
 *
 * Provides the number of active domains.
 *
 * Returns the number of domain found or -1 in case of error
 */
static int
xenDaemonNumOfDefinedDomains(virConnectPtr conn)
{
    struct sexpr *root = NULL;
    int ret = -1;
    struct sexpr *_for_i, *node;
4588
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
4589

4590 4591 4592
    /* xm_internal.c (the support for defined domains from /etc/xen
     * config files used by old Xen) will handle this.
     */
4593
    if (priv->xendConfigVersion < 3)
4594 4595
        return(-1);

4596 4597 4598 4599 4600 4601
    root = sexpr_get(conn, "/xend/domain?state=halted");
    if (root == NULL)
        goto error;

    ret = 0;

4602 4603
    for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
         _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
4604 4605 4606 4607 4608 4609
        if (node->kind != SEXPR_VALUE)
            continue;
        ret++;
    }

error:
4610
    sexpr_free(root);
4611 4612 4613
    return(ret);
}

4614 4615
static int
xenDaemonListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) {
4616
    struct sexpr *root = NULL;
4617
    int i, ret = -1;
4618
    struct sexpr *_for_i, *node;
4619
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
4620

4621
    if (priv->xendConfigVersion < 3)
4622 4623
        return(-1);

4624
    if ((names == NULL) || (maxnames < 0))
4625
        goto error;
4626 4627 4628
    if (maxnames == 0)
        return(0);

4629 4630 4631 4632 4633 4634
    root = sexpr_get(conn, "/xend/domain?state=halted");
    if (root == NULL)
        goto error;

    ret = 0;

4635 4636
    for (_for_i = root, node = root->u.s.car; _for_i->kind == SEXPR_CONS;
         _for_i = _for_i->u.s.cdr, node = _for_i->u.s.car) {
4637 4638 4639
        if (node->kind != SEXPR_VALUE)
            continue;

4640
        if ((names[ret++] = strdup(node->u.value)) == NULL) {
4641
            virReportOOMError();
4642 4643 4644
            goto error;
        }

4645 4646 4647 4648
        if (ret >= maxnames)
            break;
    }

4649 4650 4651 4652
cleanup:
    sexpr_free(root);
    return(ret);

4653
error:
4654 4655 4656
    for (i = 0; i < ret; ++i)
        VIR_FREE(names[i]);

4657 4658 4659
    ret = -1;

    goto cleanup;
4660 4661
}

4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681
/**
 * xenDaemonGetSchedulerType:
 * @domain: pointer to the Domain block
 * @nparams: give a number of scheduler parameters
 *
 * Get the scheduler type of Xen
 *
 * Returns a scheduler name (credit or sedf) which must be freed by the
 * caller or NULL in case of failure
 */
static char *
xenDaemonGetSchedulerType(virDomainPtr domain, int *nparams)
{
    xenUnifiedPrivatePtr priv;
    struct sexpr *root;
    const char *ret = NULL;
    char *schedulertype = NULL;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
        || (nparams == NULL)) {
4682
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
4683 4684 4685 4686 4687 4688
        return NULL;
    }

    /* Support only xendConfigVersion >=4 */
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xendConfigVersion < 4) {
4689
        virXendError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
4690
                      "%s", _("unsupported in xendConfigVersion < 4"));
4691 4692 4693 4694 4695 4696 4697 4698 4699 4700
        return NULL;
    }

    root = sexpr_get(domain->conn, "/xend/node/");
    if (root == NULL)
        return NULL;

    /* get xen_scheduler from xend/node */
    ret = sexpr_node(root, "node/xen_scheduler");
    if (ret == NULL){
4701
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4702
                     "%s", _("node information incomplete, missing scheduler name"));
4703 4704 4705 4706 4707
        goto error;
    }
    if (STREQ (ret, "credit")) {
        schedulertype = strdup("credit");
        if (schedulertype == NULL){
4708
            virReportOOMError();
4709 4710 4711 4712 4713 4714
            goto error;
        }
        *nparams = XEN_SCHED_CRED_NPARAM;
    } else if (STREQ (ret, "sedf")) {
        schedulertype = strdup("sedf");
        if (schedulertype == NULL){
4715
            virReportOOMError();
4716 4717 4718 4719
            goto error;
        }
        *nparams = XEN_SCHED_SEDF_NPARAM;
    } else {
4720
        virXendError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746
        goto error;
    }

error:
    sexpr_free(root);
    return schedulertype;

}

static const char *str_weight = "weight";
static const char *str_cap = "cap";

/**
 * xenDaemonGetSchedulerParameters:
 * @domain: pointer to the Domain block
 * @params: pointer to scheduler parameters
 *          This memory area must be allocated by the caller
 * @nparams: a number of scheduler parameters which should be same as a
 *           given number from xenDaemonGetSchedulerType()
 *
 * Get the scheduler parameters
 *
 * Returns 0 or -1 in case of failure
 */
static int
xenDaemonGetSchedulerParameters(virDomainPtr domain,
4747
                                virSchedParameterPtr params, int *nparams)
4748 4749 4750 4751 4752 4753 4754 4755 4756
{
    xenUnifiedPrivatePtr priv;
    struct sexpr *root;
    char *sched_type = NULL;
    int sched_nparam = 0;
    int ret = -1;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
        || (params == NULL) || (nparams == NULL)) {
4757
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
4758 4759 4760 4761 4762 4763
        return (-1);
    }

    /* Support only xendConfigVersion >=4 */
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xendConfigVersion < 4) {
4764
        virXendError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
4765
                      "%s", _("unsupported in xendConfigVersion < 4"));
4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776
        return (-1);
    }

    /* look up the information by domain name */
    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL)
        return (-1);

    /* get the scheduler type */
    sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
    if (sched_type == NULL) {
4777
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4778
                     "%s", _("Failed to get a scheduler name"));
4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789
        goto error;
    }

    switch (sched_nparam){
        case XEN_SCHED_SEDF_NPARAM:
            /* TODO: Implement for Xen/SEDF */
            TODO
            goto error;
        case XEN_SCHED_CRED_NPARAM:
            /* get cpu_weight/cpu_cap from xend/domain */
            if (sexpr_node(root, "domain/cpu_weight") == NULL) {
4790
                virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4791
                        "%s", _("domain information incomplete, missing cpu_weight"));
4792 4793 4794
                goto error;
            }
            if (sexpr_node(root, "domain/cpu_cap") == NULL) {
4795
                virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4796
                        "%s", _("domain information incomplete, missing cpu_cap"));
4797 4798 4799
                goto error;
            }

C
Chris Lalancette 已提交
4800
            if (virStrcpyStatic(params[0].field, str_weight) == NULL) {
4801
                virXendError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
4802 4803 4804 4805
                             _("Weight %s too big for destination"),
                             str_weight);
                goto error;
            }
4806 4807 4808
            params[0].type = VIR_DOMAIN_SCHED_FIELD_UINT;
            params[0].value.ui = sexpr_int(root, "domain/cpu_weight");

C
Chris Lalancette 已提交
4809
            if (virStrcpyStatic(params[1].field, str_cap) == NULL) {
4810
                virXendError(VIR_ERR_INTERNAL_ERROR,
C
Chris Lalancette 已提交
4811 4812 4813
                             _("Cap %s too big for destination"), str_cap);
                goto error;
            }
4814 4815 4816 4817 4818 4819
            params[1].type = VIR_DOMAIN_SCHED_FIELD_UINT;
            params[1].value.ui = sexpr_int(root, "domain/cpu_cap");
            *nparams = XEN_SCHED_CRED_NPARAM;
            ret = 0;
            break;
        default:
4820
            virXendError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
4821 4822 4823 4824 4825
            goto error;
    }

error:
    sexpr_free(root);
4826
    VIR_FREE(sched_type);
4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852
    return (ret);
}

/**
 * xenDaemonSetSchedulerParameters:
 * @domain: pointer to the Domain block
 * @params: pointer to scheduler parameters
 * @nparams: a number of scheduler setting parameters
 *
 * Set the scheduler parameters
 *
 * Returns 0 or -1 in case of failure
 */
static int
xenDaemonSetSchedulerParameters(virDomainPtr domain,
                                virSchedParameterPtr params, int nparams)
{
    xenUnifiedPrivatePtr priv;
    struct sexpr *root;
    char *sched_type = NULL;
    int i;
    int sched_nparam = 0;
    int ret = -1;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
        || (params == NULL)) {
4853
        virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
4854 4855 4856 4857 4858 4859
        return (-1);
    }

    /* Support only xendConfigVersion >=4 and active domains */
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xendConfigVersion < 4) {
4860
        virXendError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
4861
                      "%s", _("unsupported in xendConfigVersion < 4"));
4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872
        return (-1);
    }

    /* look up the information by domain name */
    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL)
        return (-1);

    /* get the scheduler type */
    sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
    if (sched_type == NULL) {
4873
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4874
                     "%s", _("Failed to get a scheduler name"));
4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899
        goto error;
    }

    switch (sched_nparam){
        case XEN_SCHED_SEDF_NPARAM:
            /* TODO: Implement for Xen/SEDF */
            TODO
            goto error;
        case XEN_SCHED_CRED_NPARAM: {
            char buf_weight[VIR_UUID_BUFLEN];
            char buf_cap[VIR_UUID_BUFLEN];
            const char *weight = NULL;
            const char *cap = NULL;

            /* get the scheduler parameters */
            memset(&buf_weight, 0, VIR_UUID_BUFLEN);
            memset(&buf_cap, 0, VIR_UUID_BUFLEN);
            for (i = 0; i < nparams; i++) {
                if (STREQ (params[i].field, str_weight) &&
                    params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
                    snprintf(buf_weight, sizeof(buf_weight), "%u", params[i].value.ui);
                } else if (STREQ (params[i].field, str_cap) &&
                    params[i].type == VIR_DOMAIN_SCHED_FIELD_UINT) {
                    snprintf(buf_cap, sizeof(buf_cap), "%u", params[i].value.ui);
                } else {
4900
                    virXendError(VIR_ERR_INVALID_ARG, __FUNCTION__);
4901 4902 4903 4904 4905 4906 4907 4908
                    goto error;
                }
            }

            /* if not get the scheduler parameter, set the current setting */
            if (strlen(buf_weight) == 0) {
                weight = sexpr_node(root, "domain/cpu_weight");
                if (weight == NULL) {
4909
                    virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4910
                                "%s", _("domain information incomplete, missing cpu_weight"));
4911 4912 4913 4914 4915 4916 4917
                    goto error;
                }
                snprintf(buf_weight, sizeof(buf_weight), "%s", weight);
            }
            if (strlen(buf_cap) == 0) {
                cap = sexpr_node(root, "domain/cpu_cap");
                if (cap == NULL) {
4918
                    virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
4919
                                "%s", _("domain information incomplete, missing cpu_cap"));
4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930
                    goto error;
                }
                snprintf(buf_cap, sizeof(buf_cap), "%s", cap);
            }

            ret = xend_op(domain->conn, domain->name, "op",
                          "domain_sched_credit_set", "weight", buf_weight,
                          "cap", buf_cap, NULL);
            break;
        }
        default:
4931
            virXendError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
4932 4933 4934 4935 4936
            goto error;
    }

error:
    sexpr_free(root);
4937
    VIR_FREE(sched_type);
4938 4939 4940
    return (ret);
}

R
Richard W.M. Jones 已提交
4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956
/**
 * xenDaemonDomainBlockPeek:
 * @dom: domain object
 * @path: path to the file or device
 * @offset: offset
 * @size: size
 * @buffer: return buffer
 *
 * Returns 0 if successful, -1 if error, -2 if declined.
 */
int
xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path,
                          unsigned long long offset, size_t size,
                          void *buffer)
{
    xenUnifiedPrivatePtr priv;
4957 4958
    struct sexpr *root = NULL;
    int fd = -1, ret = -1;
4959
    int found = 0, i;
4960
    virDomainDefPtr def;
R
Richard W.M. Jones 已提交
4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

    if (domain->id < 0 && priv->xendConfigVersion < 3)
        return -2;              /* Decline, allow XM to handle it. */

    /* Security check: The path must correspond to a block device. */
    if (domain->id > 0)
        root = sexpr_get (domain->conn, "/xend/domain/%d?detail=1",
                          domain->id);
    else if (domain->id < 0)
        root = sexpr_get (domain->conn, "/xend/domain/%s?detail=1",
                          domain->name);
    else {
        /* This call always fails for dom0. */
4976
        virXendError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
4977
                      "%s", _("domainBlockPeek is not supported for dom0"));
R
Richard W.M. Jones 已提交
4978 4979 4980 4981
        return -1;
    }

    if (!root) {
4982
        virXendError(VIR_ERR_XEN_CALL, __FUNCTION__);
R
Richard W.M. Jones 已提交
4983 4984 4985
        return -1;
    }

4986 4987
    if (!(def = xenDaemonParseSxpr(domain->conn, root, priv->xendConfigVersion, NULL)))
        goto cleanup;
R
Richard W.M. Jones 已提交
4988

4989 4990 4991
    for (i = 0 ; i < def->ndisks ; i++) {
        if (def->disks[i]->src &&
            STREQ(def->disks[i]->src, path)) {
4992 4993 4994 4995 4996
            found = 1;
            break;
        }
    }
    if (!found) {
4997
        virXendError(VIR_ERR_INVALID_ARG,
4998
                      _("%s: invalid path"), path);
4999
        goto cleanup;
R
Richard W.M. Jones 已提交
5000 5001 5002 5003
    }

    /* The path is correct, now try to open it and get its size. */
    fd = open (path, O_RDONLY);
5004
    if (fd == -1) {
5005
        virReportSystemError(errno,
5006 5007
                             _("failed to open for reading: %s"),
                             path);
5008
        goto cleanup;
R
Richard W.M. Jones 已提交
5009 5010 5011 5012 5013 5014 5015 5016
    }

    /* Seek and read. */
    /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
     * be 64 bits on all platforms.
     */
    if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
        saferead (fd, buffer, size) == (ssize_t) -1) {
5017
        virReportSystemError(errno,
5018 5019
                             _("failed to lseek or read from file: %s"),
                             path);
5020
        goto cleanup;
R
Richard W.M. Jones 已提交
5021 5022 5023
    }

    ret = 0;
5024
 cleanup:
R
Richard W.M. Jones 已提交
5025
    if (fd >= 0) close (fd);
5026 5027
    sexpr_free(root);
    virDomainDefFree(def);
R
Richard W.M. Jones 已提交
5028 5029 5030
    return ret;
}

5031 5032 5033 5034 5035 5036 5037 5038 5039
struct xenUnifiedDriver xenDaemonDriver = {
    xenDaemonOpen,               /* open */
    xenDaemonClose,              /* close */
    xenDaemonGetVersion,         /* version */
    NULL,                        /* hostname */
    xenDaemonNodeGetInfo,        /* nodeGetInfo */
    NULL,                        /* getCapabilities */
    xenDaemonListDomains,        /* listDomains */
    xenDaemonNumOfDomains,       /* numOfDomains */
5040
    xenDaemonCreateXML,          /* domainCreateXML */
5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062
    xenDaemonDomainSuspend,      /* domainSuspend */
    xenDaemonDomainResume,       /* domainResume */
    xenDaemonDomainShutdown,     /* domainShutdown */
    xenDaemonDomainReboot,       /* domainReboot */
    xenDaemonDomainDestroy,      /* domainDestroy */
    xenDaemonDomainGetOSType,    /* domainGetOSType */
    xenDaemonDomainGetMaxMemory, /* domainGetMaxMemory */
    xenDaemonDomainSetMaxMemory, /* domainSetMaxMemory */
    xenDaemonDomainSetMemory,    /* domainMaxMemory */
    xenDaemonDomainGetInfo,      /* domainGetInfo */
    xenDaemonDomainSave,         /* domainSave */
    xenDaemonDomainRestore,      /* domainRestore */
    xenDaemonDomainCoreDump,     /* domainCoreDump */
    xenDaemonDomainSetVcpus,     /* domainSetVcpus */
    xenDaemonDomainPinVcpu,      /* domainPinVcpu */
    xenDaemonDomainGetVcpus,     /* domainGetVcpus */
    NULL,                        /* domainGetMaxVcpus */
    xenDaemonListDefinedDomains, /* listDefinedDomains */
    xenDaemonNumOfDefinedDomains,/* numOfDefinedDomains */
    xenDaemonDomainCreate,       /* domainCreate */
    xenDaemonDomainDefineXML,    /* domainDefineXML */
    xenDaemonDomainUndefine,     /* domainUndefine */
5063 5064
    xenDaemonAttachDeviceFlags,       /* domainAttachDeviceFlags */
    xenDaemonDetachDeviceFlags,       /* domainDetachDeviceFlags */
5065
    xenDaemonUpdateDeviceFlags,       /* domainUpdateDeviceFlags */
5066 5067 5068 5069 5070 5071 5072
    xenDaemonDomainGetAutostart, /* domainGetAutostart */
    xenDaemonDomainSetAutostart, /* domainSetAutostart */
    xenDaemonGetSchedulerType,   /* domainGetSchedulerType */
    xenDaemonGetSchedulerParameters, /* domainGetSchedulerParameters */
    xenDaemonSetSchedulerParameters, /* domainSetSchedulerParameters */
};

5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093
/************************************************************************
 *									*
 * Converter functions to go from the XML tree to an S-Expr for Xen	*
 *									*
 ************************************************************************/


/**
 * virtDomainParseXMLGraphicsDescVFB:
 * @conn: pointer to the hypervisor connection
 * @node: node containing graphics description
 * @buf: a buffer for the result S-Expr
 *
 * Parse the graphics part of the XML description and add it to the S-Expr
 * in buf.  This is a temporary interface as the S-Expr interface will be
 * replaced by XML-RPC in the future. However the XML format should stay
 * valid over time.
 *
 * Returns 0 in case of success, -1 in case of error
 */
static int
5094
xenDaemonFormatSxprGraphicsNew(virDomainGraphicsDefPtr def,
5095 5096 5097 5098
                               virBufferPtr buf)
{
    if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
        def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
5099
        virXendError(VIR_ERR_INTERNAL_ERROR,
5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137
                     _("unexpected graphics type %d"),
                     def->type);
        return -1;
    }

    virBufferAddLit(buf, "(device (vkbd))");
    virBufferAddLit(buf, "(device (vfb ");

    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
        virBufferAddLit(buf, "(type sdl)");
        if (def->data.sdl.display)
            virBufferVSprintf(buf, "(display '%s')", def->data.sdl.display);
        if (def->data.sdl.xauth)
            virBufferVSprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
        virBufferAddLit(buf, "(type vnc)");
        if (def->data.vnc.autoport) {
            virBufferAddLit(buf, "(vncunused 1)");
        } else {
            virBufferAddLit(buf, "(vncunused 0)");
            virBufferVSprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
        }

        if (def->data.vnc.listenAddr)
            virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr);
        if (def->data.vnc.passwd)
            virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.passwd);
        if (def->data.vnc.keymap)
            virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
    }

    virBufferAddLit(buf, "))");

    return 0;
}


static int
5138
xenDaemonFormatSxprGraphicsOld(virDomainGraphicsDefPtr def,
5139 5140 5141 5142 5143
                               virBufferPtr buf,
                               int xendConfigVersion)
{
    if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
        def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
5144
        virXendError(VIR_ERR_INTERNAL_ERROR,
5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178
                     _("unexpected graphics type %d"),
                     def->type);
        return -1;
    }

    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
        virBufferAddLit(buf, "(sdl 1)");
        if (def->data.sdl.display)
            virBufferVSprintf(buf, "(display '%s')", def->data.sdl.display);
        if (def->data.sdl.xauth)
            virBufferVSprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
        virBufferAddLit(buf, "(vnc 1)");
        if (xendConfigVersion >= 2) {
            if (def->data.vnc.autoport) {
                virBufferAddLit(buf, "(vncunused 1)");
            } else {
                virBufferAddLit(buf, "(vncunused 0)");
                virBufferVSprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
            }

            if (def->data.vnc.listenAddr)
                virBufferVSprintf(buf, "(vnclisten '%s')", def->data.vnc.listenAddr);
            if (def->data.vnc.passwd)
                virBufferVSprintf(buf, "(vncpasswd '%s')", def->data.vnc.passwd);
            if (def->data.vnc.keymap)
                virBufferVSprintf(buf, "(keymap '%s')", def->data.vnc.keymap);

        }
    }

    return 0;
}

5179
int
5180
xenDaemonFormatSxprChr(virDomainChrDefPtr def,
5181
                       virBufferPtr buf)
5182 5183 5184 5185
{
    const char *type = virDomainChrTypeToString(def->type);

    if (!type) {
5186
        virXendError(VIR_ERR_INTERNAL_ERROR,
J
Jim Meyering 已提交
5187
                     "%s", _("unexpected chr device type"));
5188 5189 5190 5191 5192 5193 5194 5195
        return -1;
    }

    switch (def->type) {
    case VIR_DOMAIN_CHR_TYPE_NULL:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_PTY:
5196
        virBufferVSprintf(buf, "%s", type);
5197 5198 5199 5200
        break;

    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
5201
        virBufferVSprintf(buf, "%s:%s", type, def->data.file.path);
5202 5203 5204
        break;

    case VIR_DOMAIN_CHR_TYPE_DEV:
5205
        virBufferVSprintf(buf, "%s", def->data.file.path);
5206 5207 5208
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
5209
        virBufferVSprintf(buf, "%s:%s:%s%s",
5210 5211 5212 5213
                          (def->data.tcp.protocol == VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW ?
                           "tcp" : "telnet"),
                          (def->data.tcp.host ? def->data.tcp.host : ""),
                          (def->data.tcp.service ? def->data.tcp.service : ""),
5214
                          (def->data.tcp.listen ? ",server,nowait" : ""));
5215 5216 5217
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
5218
        virBufferVSprintf(buf, "%s:%s:%s@%s:%s", type,
5219 5220 5221 5222 5223 5224 5225
                          (def->data.udp.connectHost ? def->data.udp.connectHost : ""),
                          (def->data.udp.connectService ? def->data.udp.connectService : ""),
                          (def->data.udp.bindHost ? def->data.udp.bindHost : ""),
                          (def->data.udp.bindService ? def->data.udp.bindService : ""));
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
5226
        virBufferVSprintf(buf, "%s:%s%s", type,
5227
                          def->data.nix.path,
5228
                          def->data.nix.listen ? ",server,nowait" : "");
5229 5230 5231
        break;
    }

5232
    if (virBufferError(buf)) {
5233
        virReportOOMError();
D
Daniel P. Berrange 已提交
5234
        return -1;
5235
    }
D
Daniel P. Berrange 已提交
5236

5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259
    return 0;
}


/**
 * virDomainParseXMLDiskDesc:
 * @node: node containing disk description
 * @conn: pointer to the hypervisor connection
 * @buf: a buffer for the result S-Expr
 * @xendConfigVersion: xend configuration file format
 *
 * Parse the one disk in the XML description and add it to the S-Expr in buf
 * This is a temporary interface as the S-Expr interface
 * will be replaced by XML-RPC in the future. However the XML format should
 * stay valid over time.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
static int
xenDaemonFormatSxprDisk(virConnectPtr conn ATTRIBUTE_UNUSED,
                        virDomainDiskDefPtr def,
                        virBufferPtr buf,
                        int hvm,
5260 5261
                        int xendConfigVersion,
                        int isAttach)
5262 5263 5264 5265 5266
{
    /* Xend (all versions) put the floppy device config
     * under the hvm (image (os)) block
     */
    if (hvm &&
5267 5268
        def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
        if (isAttach) {
5269
            virXendError(VIR_ERR_INVALID_ARG,
5270 5271 5272
                     _("Cannot directly attach floppy %s"), def->src);
            return -1;
        }
5273
        return 0;
5274
    }
5275 5276 5277 5278

    /* Xend <= 3.0.2 doesn't include cdrom config here */
    if (hvm &&
        def->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
5279 5280
        xendConfigVersion == 1) {
        if (isAttach) {
5281
            virXendError(VIR_ERR_INVALID_ARG,
5282 5283 5284
                     _("Cannot directly attach CDROM %s"), def->src);
            return -1;
        }
5285
        return 0;
5286
    }
5287

5288 5289 5290
    if (!isAttach)
        virBufferAddLit(buf, "(device ");

5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308
    /* Normally disks are in a (device (vbd ...)) block
     * but blktap disks ended up in a differently named
     * (device (tap ....)) block.... */
    if (def->driverName &&
        STREQ(def->driverName, "tap")) {
        virBufferAddLit(buf, "(tap ");
    } else {
        virBufferAddLit(buf, "(vbd ");
    }

    if (hvm) {
        /* Xend <= 3.0.2 wants a ioemu: prefix on devices for HVM */
        if (xendConfigVersion == 1)
            virBufferVSprintf(buf, "(dev 'ioemu:%s')", def->dst);
        else                    /* But newer does not */
            virBufferVSprintf(buf, "(dev '%s:%s')", def->dst,
                              def->device == VIR_DOMAIN_DISK_DEVICE_CDROM ?
                              "cdrom" : "disk");
J
John Levon 已提交
5309 5310
    } else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
        virBufferVSprintf(buf, "(dev '%s:cdrom')", def->dst);
5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329
    } else {
        virBufferVSprintf(buf, "(dev '%s')", def->dst);
    }

    if (def->src) {
        if (def->driverName) {
            if (STREQ(def->driverName, "tap")) {
                virBufferVSprintf(buf, "(uname '%s:%s:%s')",
                                  def->driverName,
                                  def->driverType ? def->driverType : "aio",
                                  def->src);
            } else {
                virBufferVSprintf(buf, "(uname '%s:%s')",
                                  def->driverName,
                                  def->src);
            }
        } else {
            if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                virBufferVSprintf(buf, "(uname 'file:%s')", def->src);
5330
            } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5331 5332 5333 5334
                if (def->src[0] == '/')
                    virBufferVSprintf(buf, "(uname 'phy:%s')", def->src);
                else
                    virBufferVSprintf(buf, "(uname 'phy:/dev/%s')", def->src);
5335
            } else {
5336
                virXendError(VIR_ERR_CONFIG_UNSUPPORTED,
5337 5338 5339
                             _("unsupported disk type %s"),
                             virDomainDiskTypeToString(def->type));
                return -1;
5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350
            }
        }
    }

    if (def->readonly)
        virBufferAddLit(buf, "(mode 'r')");
    else if (def->shared)
        virBufferAddLit(buf, "(mode 'w!')");
    else
        virBufferAddLit(buf, "(mode 'w')");

5351 5352 5353
    if (!isAttach)
        virBufferAddLit(buf, ")");

5354
    virBufferAddLit(buf, ")");
5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377

    return 0;
}

/**
 * xenDaemonFormatSxprNet
 * @conn: pointer to the hypervisor connection
 * @node: node containing the interface description
 * @buf: a buffer for the result S-Expr
 * @xendConfigVersion: xend configuration file format
 *
 * Parse the one interface the XML description and add it to the S-Expr in buf
 * This is a temporary interface as the S-Expr interface
 * will be replaced by XML-RPC in the future. However the XML format should
 * stay valid over time.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
static int
xenDaemonFormatSxprNet(virConnectPtr conn,
                       virDomainNetDefPtr def,
                       virBufferPtr buf,
                       int hvm,
5378 5379
                       int xendConfigVersion,
                       int isAttach)
5380
{
5381 5382
    const char *script = DEFAULT_VIF_SCRIPT;

5383 5384 5385
    if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
        def->type != VIR_DOMAIN_NET_TYPE_NETWORK &&
        def->type != VIR_DOMAIN_NET_TYPE_ETHERNET) {
5386
        virXendError(VIR_ERR_INTERNAL_ERROR,
5387 5388 5389 5390
                     _("unsupported network type %d"), def->type);
        return -1;
    }

5391 5392 5393
    if (!isAttach)
        virBufferAddLit(buf, "(device ");

5394
    virBufferAddLit(buf, "(vif ");
5395 5396 5397 5398 5399 5400 5401 5402 5403

    virBufferVSprintf(buf,
                      "(mac '%02x:%02x:%02x:%02x:%02x:%02x')",
                      def->mac[0], def->mac[1], def->mac[2],
                      def->mac[3], def->mac[4], def->mac[5]);

    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        virBufferVSprintf(buf, "(bridge '%s')", def->data.bridge.brname);
5404 5405 5406 5407
        if (def->data.bridge.script)
            script = def->data.bridge.script;

        virBufferVSprintf(buf, "(script '%s')", script);
5408 5409
        if (def->data.bridge.ipaddr != NULL)
            virBufferVSprintf(buf, "(ip '%s')", def->data.bridge.ipaddr);
5410 5411 5412 5413 5414 5415 5416 5417 5418
        break;

    case VIR_DOMAIN_NET_TYPE_NETWORK:
    {
        virNetworkPtr network =
            virNetworkLookupByName(conn, def->data.network.name);
        char *bridge;

        if (!network) {
5419
            virXendError(VIR_ERR_NO_NETWORK, "%s",
5420 5421 5422 5423 5424 5425 5426
                         def->data.network.name);
            return -1;
        }

        bridge = virNetworkGetBridgeName(network);
        virNetworkFree(network);
        if (!bridge) {
5427
            virXendError(VIR_ERR_INTERNAL_ERROR,
5428
                         _("network %s is not active"),
5429 5430 5431 5432
                         def->data.network.name);
            return -1;
        }
        virBufferVSprintf(buf, "(bridge '%s')", bridge);
5433
        virBufferVSprintf(buf, "(script '%s')", script);
5434 5435 5436 5437 5438 5439 5440 5441 5442 5443
        VIR_FREE(bridge);
    }
    break;

    case VIR_DOMAIN_NET_TYPE_ETHERNET:
        if (def->data.ethernet.script)
            virBufferVSprintf(buf, "(script '%s')", def->data.ethernet.script);
        if (def->data.ethernet.ipaddr != NULL)
            virBufferVSprintf(buf, "(ip '%s')", def->data.ethernet.ipaddr);
        break;
D
David Allan 已提交
5444 5445 5446 5447 5448 5449 5450 5451 5452

    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
    case VIR_DOMAIN_NET_TYPE_DIRECT:
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
5453 5454 5455 5456 5457 5458
    }

    if (def->ifname != NULL &&
        !STRPREFIX(def->ifname, "vif"))
        virBufferVSprintf(buf, "(vifname '%s')", def->ifname);

5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474
    if (!hvm) {
        if (def->model != NULL)
            virBufferVSprintf(buf, "(model '%s')", def->model);
    }
    else if (def->model == NULL) {
        /*
         * apparently (type ioemu) breaks paravirt drivers on HVM so skip
         * this from XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU
         */
        if (xendConfigVersion <= XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU)
            virBufferAddLit(buf, "(type ioemu)");
    }
    else if (STREQ(def->model, "netfront")) {
        virBufferAddLit(buf, "(type netfront)");
    }
    else {
5475 5476
        virBufferVSprintf(buf, "(model '%s')", def->model);
        virBufferAddLit(buf, "(type ioemu)");
5477
    }
5478

5479 5480 5481
    if (!isAttach)
        virBufferAddLit(buf, ")");

5482
    virBufferAddLit(buf, ")");
5483 5484 5485 5486

    return 0;
}

5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499

static void
xenDaemonFormatSxprPCI(virDomainHostdevDefPtr def,
                       virBufferPtr buf)
{
    virBufferVSprintf(buf, "(dev (domain 0x%04x)(bus 0x%02x)(slot 0x%02x)(func 0x%x))",
                      def->source.subsys.u.pci.domain,
                      def->source.subsys.u.pci.bus,
                      def->source.subsys.u.pci.slot,
                      def->source.subsys.u.pci.function);
}

static int
5500
xenDaemonFormatSxprOnePCI(virDomainHostdevDefPtr def,
5501 5502
                          virBufferPtr buf,
                          int detach)
5503 5504
{
    if (def->managed) {
5505
        virXendError(VIR_ERR_NO_SUPPORT, "%s",
5506 5507 5508 5509 5510 5511
                     _("managed PCI devices not supported with XenD"));
        return -1;
    }

    virBufferAddLit(buf, "(pci ");
    xenDaemonFormatSxprPCI(def, buf);
5512 5513 5514 5515
    if (detach)
        virBufferAddLit(buf, "(state 'Closing')");
    else
        virBufferAddLit(buf, "(state 'Initialising')");
5516 5517 5518 5519 5520 5521
    virBufferAddLit(buf, ")");

    return 0;
}

static int
5522
xenDaemonFormatSxprAllPCI(virDomainDefPtr def,
5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545
                          virBufferPtr buf)
{
    int hasPCI = 0;
    int i;

    for (i = 0 ; i < def->nhostdevs ; i++)
        if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
            hasPCI = 1;

    if (!hasPCI)
        return 0;

    /*
     * With the (domain ...) block we have the following odd setup
     *
     * (device
     *    (pci
     *       (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0))
     *       (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0))
     *    )
     * )
     *
5546 5547
     * Normally there is one (device ...) block per device, but in the
     * weird world of Xen PCI, one (device ...) covers multiple devices.
5548 5549 5550 5551 5552 5553 5554
     */

    virBufferAddLit(buf, "(device (pci ");
    for (i = 0 ; i < def->nhostdevs ; i++) {
        if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
            if (def->hostdevs[i]->managed) {
5555
                virXendError(VIR_ERR_NO_SUPPORT, "%s",
5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567
                             _("managed PCI devices not supported with XenD"));
                return -1;
            }

            xenDaemonFormatSxprPCI(def->hostdevs[i], buf);
        }
    }
    virBufferAddLit(buf, "))");

    return 0;
}

5568
int
5569
xenDaemonFormatSxprSound(virDomainDefPtr def,
5570 5571 5572
                         virBufferPtr buf)
{
    const char *str;
5573
    int i;
5574

5575 5576
    for (i = 0 ; i < def->nsounds ; i++) {
        if (!(str = virDomainSoundModelTypeToString(def->sounds[i]->model))) {
5577
            virXendError(VIR_ERR_INTERNAL_ERROR,
5578 5579
                         _("unexpected sound model %d"),
                         def->sounds[i]->model);
5580 5581
            return -1;
        }
5582
        virBufferVSprintf(buf, "%s%s", i ? "," : "", str);
5583 5584
    }

5585
    if (virBufferError(buf)) {
5586
        virReportOOMError();
D
Daniel P. Berrange 已提交
5587
        return -1;
5588
    }
D
Daniel P. Berrange 已提交
5589

5590 5591 5592 5593 5594
    return 0;
}


static int
5595
xenDaemonFormatSxprInput(virDomainInputDefPtr input,
5596 5597 5598 5599 5600 5601 5602
                         virBufferPtr buf)
{
    if (input->bus != VIR_DOMAIN_INPUT_BUS_USB)
        return 0;

    if (input->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
        input->type != VIR_DOMAIN_INPUT_TYPE_TABLET) {
5603
        virXendError(VIR_ERR_INTERNAL_ERROR,
5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643
                     _("unexpected input type %d"), input->type);
        return -1;
    }

    virBufferVSprintf(buf, "(usbdevice %s)",
                      input->type == VIR_DOMAIN_INPUT_TYPE_MOUSE ?
                      "mouse" : "tablet");

    return 0;
}


/**
 * xenDaemonFormatSxpr:
 * @conn: pointer to the hypervisor connection
 * @def: domain config definition
 * @xendConfigVersion: xend configuration file format
 *
 * Generate an SEXPR representing the domain configuration.
 *
 * Returns the 0 terminatedi S-Expr string or NULL in case of error.
 *         the caller must free() the returned value.
 */
char *
xenDaemonFormatSxpr(virConnectPtr conn,
                    virDomainDefPtr def,
                    int xendConfigVersion)
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    const char *tmp;
    int hvm = 0, i;

    virBufferAddLit(&buf, "(vm ");
    virBufferVSprintf(&buf, "(name '%s')", def->name);
    virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)",
                      def->memory/1024, def->maxmem/1024);
    virBufferVSprintf(&buf, "(vcpus %lu)", def->vcpus);

    if (def->cpumask) {
5644
        char *ranges = virDomainCpuSetFormat(def->cpumask, def->cpumasklen);
5645 5646 5647 5648 5649 5650 5651 5652 5653
        if (ranges == NULL)
            goto error;
        virBufferVSprintf(&buf, "(cpus '%s')", ranges);
        VIR_FREE(ranges);
    }

    virUUIDFormat(def->uuid, uuidstr);
    virBufferVSprintf(&buf, "(uuid '%s')", uuidstr);

5654 5655 5656
    if (def->description)
        virBufferVSprintf(&buf, "(description '%s')", def->description);

5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667
    if (def->os.bootloader) {
        if (def->os.bootloader[0])
            virBufferVSprintf(&buf, "(bootloader '%s')", def->os.bootloader);
        else
            virBufferAddLit(&buf, "(bootloader)");

        if (def->os.bootloaderArgs)
            virBufferVSprintf(&buf, "(bootloader_args '%s')", def->os.bootloaderArgs);
    }

    if (!(tmp = virDomainLifecycleTypeToString(def->onPoweroff))) {
5668
        virXendError(VIR_ERR_INTERNAL_ERROR,
5669 5670 5671 5672 5673 5674
                     _("unexpected lifecycle value %d"), def->onPoweroff);
        goto error;
    }
    virBufferVSprintf(&buf, "(on_poweroff '%s')", tmp);

    if (!(tmp = virDomainLifecycleTypeToString(def->onReboot))) {
5675
        virXendError(VIR_ERR_INTERNAL_ERROR,
5676 5677 5678 5679 5680 5681
                     _("unexpected lifecycle value %d"), def->onReboot);
        goto error;
    }
    virBufferVSprintf(&buf, "(on_reboot '%s')", tmp);

    if (!(tmp = virDomainLifecycleTypeToString(def->onCrash))) {
5682
        virXendError(VIR_ERR_INTERNAL_ERROR,
5683 5684 5685 5686 5687
                     _("unexpected lifecycle value %d"), def->onCrash);
        goto error;
    }
    virBufferVSprintf(&buf, "(on_crash '%s')", tmp);

5688
    /* Set localtime here for current XenD (both PV & HVM) */
5689 5690
    if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME) {
        if (def->clock.data.timezone) {
5691
            virXendError(VIR_ERR_CONFIG_UNSUPPORTED,
L
Laine Stump 已提交
5692
                         "%s", _("configurable timezones are not supported"));
5693 5694 5695
            goto error;
        }

5696
        virBufferAddLit(&buf, "(localtime 1)");
5697
    } else if (def->clock.offset != VIR_DOMAIN_CLOCK_OFFSET_UTC) {
5698
        virXendError(VIR_ERR_CONFIG_UNSUPPORTED,
5699 5700 5701 5702
                     _("unsupported clock offset '%s'"),
                     virDomainClockOffsetTypeToString(def->clock.offset));
        goto error;
    }
5703

5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714
    if (!def->os.bootloader) {
        if (STREQ(def->os.type, "hvm"))
            hvm = 1;

        if (hvm)
            virBufferAddLit(&buf, "(image (hvm ");
        else
            virBufferAddLit(&buf, "(image (linux ");

        if (hvm &&
            def->os.loader == NULL) {
5715
            virXendError(VIR_ERR_INTERNAL_ERROR,
5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762
                         "%s",_("no HVM domain loader"));
            goto error;
        }

        if (def->os.kernel)
            virBufferVSprintf(&buf, "(kernel '%s')", def->os.kernel);
        if (def->os.initrd)
            virBufferVSprintf(&buf, "(ramdisk '%s')", def->os.initrd);
        if (def->os.root)
            virBufferVSprintf(&buf, "(root '%s')", def->os.root);
        if (def->os.cmdline)
            virBufferVSprintf(&buf, "(args '%s')", def->os.cmdline);

        if (hvm) {
            char bootorder[VIR_DOMAIN_BOOT_LAST+1];
            if (def->os.kernel)
                virBufferVSprintf(&buf, "(loader '%s')", def->os.loader);
            else
                virBufferVSprintf(&buf, "(kernel '%s')", def->os.loader);

            virBufferVSprintf(&buf, "(vcpus %lu)", def->vcpus);

            for (i = 0 ; i < def->os.nBootDevs ; i++) {
                switch (def->os.bootDevs[i]) {
                case VIR_DOMAIN_BOOT_FLOPPY:
                    bootorder[i] = 'a';
                    break;
                default:
                case VIR_DOMAIN_BOOT_DISK:
                    bootorder[i] = 'c';
                    break;
                case VIR_DOMAIN_BOOT_CDROM:
                    bootorder[i] = 'd';
                    break;
                case VIR_DOMAIN_BOOT_NET:
                    bootorder[i] = 'n';
                    break;
                }
            }
            if (def->os.nBootDevs == 0) {
                bootorder[0] = 'c';
                bootorder[1] = '\0';
            } else {
                bootorder[def->os.nBootDevs] = '\0';
            }
            virBufferVSprintf(&buf, "(boot %s)", bootorder);

5763 5764 5765 5766 5767 5768
            /* some disk devices are defined here */
            for (i = 0 ; i < def->ndisks ; i++) {
                switch (def->disks[i]->device) {
                case VIR_DOMAIN_DISK_DEVICE_CDROM:
                    /* Only xend <= 3.0.2 wants cdrom config here */
                    if (xendConfigVersion != 1)
5769
                        break;
5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785
                    if (!STREQ(def->disks[i]->dst, "hdc") ||
                        def->disks[i]->src == NULL)
                        break;

                    virBufferVSprintf(&buf, "(cdrom '%s')",
                                      def->disks[i]->src);
                    break;

                case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
                    /* all xend versions define floppies here */
                    virBufferVSprintf(&buf, "(%s '%s')", def->disks[i]->dst,
                        def->disks[i]->src);
                    break;

                default:
                    break;
5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797
                }
            }

            if (def->features & (1 << VIR_DOMAIN_FEATURE_ACPI))
                virBufferAddLit(&buf, "(acpi 1)");
            if (def->features & (1 << VIR_DOMAIN_FEATURE_APIC))
                virBufferAddLit(&buf, "(apic 1)");
            if (def->features & (1 << VIR_DOMAIN_FEATURE_PAE))
                virBufferAddLit(&buf, "(pae 1)");

            virBufferAddLit(&buf, "(usb 1)");

5798
            for (i = 0 ; i < def->ninputs ; i++)
5799
                if (xenDaemonFormatSxprInput(def->inputs[i], &buf) < 0)
5800 5801 5802
                    goto error;

            if (def->parallels) {
5803
                virBufferAddLit(&buf, "(parallel ");
5804
                if (xenDaemonFormatSxprChr(def->parallels[0], &buf) < 0)
5805
                    goto error;
5806
                virBufferAddLit(&buf, ")");
5807 5808 5809 5810
            } else {
                virBufferAddLit(&buf, "(parallel none)");
            }
            if (def->serials) {
5811
                virBufferAddLit(&buf, "(serial ");
5812
                if (xenDaemonFormatSxprChr(def->serials[0], &buf) < 0)
5813
                    goto error;
5814
                virBufferAddLit(&buf, ")");
5815 5816 5817 5818
            } else {
                virBufferAddLit(&buf, "(serial none)");
            }

5819
            /* Set localtime here to keep old XenD happy for HVM */
5820
            if (def->clock.offset == VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME)
5821 5822
                virBufferAddLit(&buf, "(localtime 1)");

5823 5824
            if (def->sounds) {
                virBufferAddLit(&buf, "(soundhw '");
5825
                if (xenDaemonFormatSxprSound(def, &buf) < 0)
5826 5827 5828
                    goto error;
                virBufferAddLit(&buf, "')");
            }
5829 5830 5831 5832 5833 5834 5835 5836
        }

        /* get the device emulation model */
        if (def->emulator && (hvm || xendConfigVersion >= 3))
            virBufferVSprintf(&buf, "(device_model '%s')", def->emulator);


        /* PV graphics for xen <= 3.0.4, or HVM graphics for xen <= 3.1.0 */
5837
        if ((!hvm && xendConfigVersion < XEND_CONFIG_MIN_VERS_PVFB_NEWCONF) ||
5838
            (hvm && xendConfigVersion < 4)) {
5839
            if ((def->ngraphics == 1) &&
5840
                xenDaemonFormatSxprGraphicsOld(def->graphics[0],
5841
                                               &buf, xendConfigVersion) < 0)
5842 5843 5844 5845 5846 5847
                goto error;
        }

        virBufferAddLit(&buf, "))");
    }

5848 5849 5850
    for (i = 0 ; i < def->ndisks ; i++)
        if (xenDaemonFormatSxprDisk(conn, def->disks[i],
                                    &buf, hvm, xendConfigVersion, 0) < 0)
5851 5852
            goto error;

5853 5854 5855
    for (i = 0 ; i < def->nnets ; i++)
        if (xenDaemonFormatSxprNet(conn, def->nets[i],
                                   &buf, hvm, xendConfigVersion, 0) < 0)
5856 5857
            goto error;

5858
    if (xenDaemonFormatSxprAllPCI(def, &buf) < 0)
5859 5860
        goto error;

5861 5862
    /* New style PV graphics config xen >= 3.0.4,
     * or HVM graphics config xen >= 3.0.5 */
5863
    if ((xendConfigVersion >= XEND_CONFIG_MIN_VERS_PVFB_NEWCONF && !hvm) ||
5864
        (xendConfigVersion >= 4 && hvm)) {
5865
        if ((def->ngraphics == 1) &&
5866
            xenDaemonFormatSxprGraphicsNew(def->graphics[0], &buf) < 0)
5867 5868 5869 5870 5871
            goto error;
    }

    virBufferAddLit(&buf, ")"); /* closes (vm */

5872
    if (virBufferError(&buf)) {
5873
        virReportOOMError();
5874
        goto error;
5875 5876
    }

5877 5878 5879
    return virBufferContentAndReset(&buf);

error:
5880
    virBufferFreeAndReset(&buf);
5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895
    return NULL;
}


/**
 * virDomainXMLDevID:
 * @domain: pointer to domain object
 * @dev: pointer to device config object
 * @class: Xen device class "vbd" or "vif" (OUT)
 * @ref: Xen device reference (OUT)
 *
 * Set class according to XML root, and:
 *  - if disk, copy in ref the target name from description
 *  - if network, get MAC address from description, scan XenStore and
 *    copy in ref the corresponding vif number.
5896 5897
 *  - if pci, get BDF from description, scan XenStore and
 *    copy in ref the corresponding dev number.
5898 5899 5900 5901 5902 5903 5904 5905 5906 5907
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
virDomainXMLDevID(virDomainPtr domain,
                  virDomainDeviceDefPtr dev,
                  char *class,
                  char *ref,
                  int ref_len)
{
D
Daniel P. Berrange 已提交
5908
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
5909
    char *xref;
C
Chris Lalancette 已提交
5910
    char *tmp;
5911 5912

    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5913 5914 5915 5916 5917 5918
        if (dev->data.disk->driverName &&
            STREQ(dev->data.disk->driverName, "tap"))
            strcpy(class, "tap");
        else
            strcpy(class, "vbd");

5919 5920
        if (dev->data.disk->dst == NULL)
            return -1;
D
Daniel P. Berrange 已提交
5921
        xenUnifiedLock(priv);
5922 5923
        xref = xenStoreDomainGetDiskID(domain->conn, domain->id,
                                       dev->data.disk->dst);
D
Daniel P. Berrange 已提交
5924
        xenUnifiedUnlock(priv);
5925 5926 5927
        if (xref == NULL)
            return -1;

C
Chris Lalancette 已提交
5928
        tmp = virStrcpy(ref, xref, ref_len);
5929
        VIR_FREE(xref);
C
Chris Lalancette 已提交
5930 5931
        if (tmp == NULL)
            return -1;
5932 5933 5934 5935 5936 5937 5938 5939 5940
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
        char mac[30];
        virDomainNetDefPtr def = dev->data.net;
        snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
                 def->mac[0], def->mac[1], def->mac[2],
                 def->mac[3], def->mac[4], def->mac[5]);

        strcpy(class, "vif");

D
Daniel P. Berrange 已提交
5941
        xenUnifiedLock(priv);
5942 5943
        xref = xenStoreDomainGetNetworkID(domain->conn, domain->id,
                                          mac);
D
Daniel P. Berrange 已提交
5944
        xenUnifiedUnlock(priv);
5945 5946 5947
        if (xref == NULL)
            return -1;

C
Chris Lalancette 已提交
5948
        tmp = virStrcpy(ref, xref, ref_len);
5949
        VIR_FREE(xref);
C
Chris Lalancette 已提交
5950 5951
        if (tmp == NULL)
            return -1;
5952 5953 5954
    } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
               dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
               dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
5955 5956 5957 5958 5959 5960 5961 5962
        char *bdf;
        virDomainHostdevDefPtr def = dev->data.hostdev;

        if (virAsprintf(&bdf, "%04x:%02x:%02x.%0x",
                        def->source.subsys.u.pci.domain,
                        def->source.subsys.u.pci.bus,
                        def->source.subsys.u.pci.slot,
                        def->source.subsys.u.pci.function) < 0) {
5963
            virReportOOMError();
5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979
            return -1;
        }

        strcpy(class, "pci");

        xenUnifiedLock(priv);
        xref = xenStoreDomainGetPCIID(domain->conn, domain->id, bdf);
        xenUnifiedUnlock(priv);
        VIR_FREE(bdf);
        if (xref == NULL)
            return -1;

        tmp = virStrcpy(ref, xref, ref_len);
        VIR_FREE(xref);
        if (tmp == NULL)
            return -1;
5980
    } else {
5981
        virXendError(VIR_ERR_NO_SUPPORT,
J
Jim Meyering 已提交
5982
                     "%s", _("hotplug of device type not supported"));
5983 5984 5985 5986 5987 5988
        return -1;
    }

    return 0;
}

5989
#endif /* ! PROXY */