xend_internal.c 98.4 KB
Newer Older
1 2 3
/*
 * xend_internal.c: access to Xen though the Xen Daemon interface
 *
4
 * Copyright (C) 2010-2013 Red Hat, Inc.
5
 * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
6
 *
E
Eric Blake 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
20 21
 */

22
#include <config.h>
23

24 25 26 27 28
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/errno.h>
R
Richard W.M. Jones 已提交
29 30
#include <sys/stat.h>
#include <fcntl.h>
31 32 33 34 35 36 37 38 39
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <stdarg.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
40
#include <errno.h>
41

42
#include "virerror.h"
43
#include "virlog.h"
44
#include "datatypes.h"
45
#include "xend_internal.h"
46
#include "driver.h"
47
#include "virsexpr.h"
48
#include "xen_sxpr.h"
49
#include "virbuffer.h"
50
#include "viruuid.h"
51 52
#include "xen_driver.h"
#include "xen_hypervisor.h"
53
#include "xs_internal.h" /* To extract VNC port & Serial console TTY */
54
#include "viralloc.h"
55
#include "count-one-bits.h"
E
Eric Blake 已提交
56
#include "virfile.h"
M
Martin Kletzander 已提交
57
#include "viruri.h"
58
#include "device_conf.h"
59
#include "virstring.h"
60

61 62 63
/* required for cpumap_t */
#include <xen/dom0_ops.h>

64 65
#define VIR_FROM_THIS VIR_FROM_XEND

66 67 68
/*
 * The number of Xen scheduler parameters
 */
69

70
#define XEND_RCV_BUF_MAX_LEN (256 * 1024)
D
Daniel Veillard 已提交
71

72
static int
73 74
virDomainXMLDevID(virDomainPtr domain, virDomainDeviceDefPtr dev, char *class,
                  char *ref, int ref_len);
75

76 77 78 79 80 81 82 83 84
/**
 * 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
85
do_connect(virConnectPtr xend)
86 87
{
    int s;
88
    int no_slow_start = 1;
89
    xenUnifiedPrivatePtr priv = xend->privateData;
90

91
    s = socket(priv->addrfamily, SOCK_STREAM, priv->addrprotocol);
D
Daniel Veillard 已提交
92
    if (s == -1) {
93 94
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("failed to create a socket"));
95
        return -1;
D
Daniel Veillard 已提交
96
    }
97

98
    /*
99
     * try to deactivate slow-start
100
     */
101 102
    ignore_value(setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
                            sizeof(no_slow_start)));
103

104
    if (connect(s, (struct sockaddr *)&priv->addr, priv->addrlen) == -1) {
105
        VIR_FORCE_CLOSE(s); /* preserves errno */
106 107

        /*
J
John Levon 已提交
108 109
         * Connecting to XenD when privileged is mandatory, so log this
         * error
110
         */
J
John Levon 已提交
111
        if (xenHavePrivilege()) {
112 113
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("failed to connect to xend"));
114
        }
115 116 117 118 119 120 121
    }

    return s;
}

/**
 * wr_sync:
122
 * @xend: the xend connection object
123 124 125 126 127 128 129 130 131 132
 * @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
133
wr_sync(int fd, void *buffer, size_t size, int do_read)
134 135 136 137 138 139 140
{
    size_t offset = 0;

    while (offset < size) {
        ssize_t len;

        if (do_read) {
141
            len = read(fd, ((char *) buffer) + offset, size - offset);
142
        } else {
143
            len = write(fd, ((char *) buffer) + offset, size - offset);
144 145 146 147 148 149 150 151 152 153 154 155 156 157
        }

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

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

        /* unrecoverable error */
        if (len == -1) {
158
            if (do_read)
159 160
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("failed to read from Xen Daemon"));
161
            else
162 163
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("failed to write to Xen Daemon"));
164

165
            return -1;
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
        }

        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
185
sread(int fd, void *buffer, size_t size)
186
{
187
    return wr_sync(fd, buffer, size, 1);
188 189 190 191 192 193 194 195 196 197 198 199 200
}

/**
 * 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
201
swrite(int fd, const void *buffer, size_t size)
202
{
203
    return wr_sync(fd, (void *) buffer, size, 0);
204 205 206 207 208 209 210 211 212 213 214 215
}

/**
 * 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
216
swrites(int fd, const char *string)
217
{
218
    return swrite(fd, string, strlen(string));
219 220
}

221 222 223 224 225 226 227 228 229 230 231
/**
 * 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
232
sreads(int fd, char *buffer, size_t n_buffer)
233 234 235 236
{
    size_t offset;

    if (n_buffer < 1)
237
        return -1;
238 239 240 241

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

242
        ret = sread(fd, buffer + offset, 1);
243 244 245 246 247 248 249 250 251 252 253 254 255 256
        if (ret == 0)
            break;
        else if (ret == -1)
            return ret;

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

    return offset;
}
257 258 259 260

static int
istartswith(const char *haystack, const char *needle)
{
261
    return STRCASEEQLEN(haystack, needle, strlen(needle));
262 263
}

264

265 266 267 268 269 270
/**
 * xend_req:
 * @fd: the file descriptor
 * @content: the buffer to store the content
 *
 * Read the HTTP response from a Xen Daemon request.
271 272
 * If the response contains content, memory is allocated to
 * hold the content.
273
 *
274 275
 * Returns the HTTP return code and @content is set to the
 * allocated memory containing HTTP content.
276
 */
277
static int ATTRIBUTE_NONNULL(2)
278
xend_req(int fd, char **content)
279
{
280 281
    char *buffer;
    size_t buffer_size = 4096;
282
    int content_length = 0;
283 284
    int retcode = 0;

285 286 287 288 289 290
    if (VIR_ALLOC_N(buffer, buffer_size) < 0) {
        virReportOOMError();
        return -1;
    }

    while (sreads(fd, buffer, buffer_size) > 0) {
291
        if (STREQ(buffer, "\r\n"))
292
            break;
293 294 295 296 297

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

300 301
    VIR_FREE(buffer);

302
    if (content_length > 0) {
303 304
        ssize_t ret;

J
Jim Fehlig 已提交
305
        if (content_length > XEND_RCV_BUF_MAX_LEN) {
306 307 308 309 310
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Xend returned HTTP Content-Length of %d, "
                             "which exceeds maximum of %d"),
                           content_length,
                           XEND_RCV_BUF_MAX_LEN);
J
Jim Fehlig 已提交
311 312 313 314 315 316
            return -1;
        }

        /* Allocate one byte beyond the end of the largest buffer we will read.
           Combined with the fact that VIR_ALLOC_N zeros the returned buffer,
           this guarantees that "content" will always be NUL-terminated. */
317
        if (VIR_ALLOC_N(*content, content_length + 1) < 0) {
318 319 320
            virReportOOMError();
            return -1;
        }
321

322
        ret = sread(fd, *content, content_length);
323 324
        if (ret < 0)
            return -1;
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
    }

    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.
 */
J
Jim Fehlig 已提交
340
static int ATTRIBUTE_NONNULL(3)
341
xend_get(virConnectPtr xend, const char *path, char **content)
342 343 344 345 346 347 348
{
    int ret;
    int s = do_connect(xend);

    if (s == -1)
        return s;

349 350 351
    swrites(s, "GET ");
    swrites(s, path);
    swrites(s, " HTTP/1.1\r\n");
352

353
    swrites(s,
354 355 356 357
            "Host: localhost:8000\r\n"
            "Accept-Encoding: identity\r\n"
            "Content-Type: application/x-www-form-urlencoded\r\n" "\r\n");

358
    ret = xend_req(s, content);
359
    VIR_FORCE_CLOSE(s);
360

361 362 363 364
    if (ret < 0)
        return ret;

    if ((ret >= 300) && ((ret != 404) || (!STRPREFIX(path, "/xend/domain/")))) {
365 366 367
        virReportError(VIR_ERR_GET_FAILED,
                       _("%d status from xen daemon: %s:%s"),
                       ret, path, NULLSTR(*content));
D
Daniel Veillard 已提交
368 369
    }

370 371 372 373 374 375 376
    return ret;
}

/**
 * xend_post:
 * @xend: pointer to the Xen Daemon structure
 * @path: the path used for the HTTP request
377
 * @ops: the information sent for the POST
378 379 380 381 382 383 384
 *
 * 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
385
xend_post(virConnectPtr xend, const char *path, const char *ops)
386 387
{
    char buffer[100];
388
    char *err_buf = NULL;
389 390 391 392 393 394
    int ret;
    int s = do_connect(xend);

    if (s == -1)
        return s;

395 396 397
    swrites(s, "POST ");
    swrites(s, path);
    swrites(s, " HTTP/1.1\r\n");
398

399
    swrites(s,
400 401 402 403
            "Host: localhost:8000\r\n"
            "Accept-Encoding: identity\r\n"
            "Content-Type: application/x-www-form-urlencoded\r\n"
            "Content-Length: ");
404
    snprintf(buffer, sizeof(buffer), "%d", (int) strlen(ops));
405 406 407
    swrites(s, buffer);
    swrites(s, "\r\n\r\n");
    swrites(s, ops);
408

409
    ret = xend_req(s, &err_buf);
410
    VIR_FORCE_CLOSE(s);
411

D
Daniel Veillard 已提交
412
    if ((ret < 0) || (ret >= 300)) {
413 414
        virReportError(VIR_ERR_POST_FAILED,
                       _("xend_post: error from xen daemon: %s"), err_buf);
415
    } else if ((ret == 202) && err_buf && (strstr(err_buf, "failed") != NULL)) {
416 417
        virReportError(VIR_ERR_POST_FAILED,
                       _("xend_post: error from xen daemon: %s"), err_buf);
418
        ret = -1;
419 420
    } else if (((ret >= 200) && (ret <= 202)) && err_buf &&
               (strstr(err_buf, "xend.err") != NULL)) {
421 422 423
        /* 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 :-(
424
         */
425 426
        virReportError(VIR_ERR_POST_FAILED,
                       _("xend_post: error from xen daemon: %s"), err_buf);
427
        ret = -1;
D
Daniel Veillard 已提交
428 429
    }

430
    VIR_FREE(err_buf);
431 432
    return ret;
}
433

434 435 436 437 438 439 440 441 442 443

/**
 * 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
444
http2unix(int ret)
445 446 447 448 449 450 451 452 453 454 455
{
    switch (ret) {
        case -1:
            break;
        case 200:
        case 201:
        case 202:
            return 0;
        case 404:
            errno = ESRCH;
            break;
456 457 458
        case 500:
            errno = EIO;
            break;
459
        default:
460 461
            virReportError(VIR_ERR_HTTP_ERROR,
                           _("Unexpected HTTP error code %d"), ret);
462 463 464 465 466 467 468
            errno = EINVAL;
            break;
    }
    return -1;
}

/**
469
 * xend_op_ext:
470 471 472 473 474 475 476 477 478 479
 * @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
480
xend_op_ext(virConnectPtr xend, const char *path, const char *key, va_list ap)
481 482
{
    const char *k = key, *v;
483
    virBuffer buf = VIR_BUFFER_INITIALIZER;
484
    int ret;
485
    char *content;
486 487 488 489

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

P
Philipp Hahn 已提交
490 491 492
        virBufferURIEncodeString(&buf, k);
        virBufferAddChar(&buf, '=');
        virBufferURIEncodeString(&buf, v);
493 494 495
        k = va_arg(ap, const char *);

        if (k)
496
            virBufferAddChar(&buf, '&');
497 498
    }

499
    if (virBufferError(&buf)) {
500
        virBufferFreeAndReset(&buf);
501
        virReportOOMError();
502 503 504 505
        return -1;
    }

    content = virBufferContentAndReset(&buf);
506
    VIR_DEBUG("xend op: %s\n", content);
507
    ret = http2unix(xend_post(xend, path, content));
508
    VIR_FREE(content);
509 510

    return ret;
511 512
}

513

514
/**
515
 * xend_op:
516 517 518 519 520 521 522 523 524 525 526
 * @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 已提交
527
static int ATTRIBUTE_SENTINEL
528
xend_op(virConnectPtr xend, const char *name, const char *key, ...)
529 530 531 532 533 534 535 536
{
    char buffer[1024];
    va_list ap;
    int ret;

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

    va_start(ap, key);
537
    ret = xend_op_ext(xend, buffer, key, ap);
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
    va_end(ap);

    return ret;
}


/**
 * 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
 */
554
static struct sexpr *sexpr_get(virConnectPtr xend, const char *fmt, ...)
555
  ATTRIBUTE_FMT_PRINTF(2,3);
556

557
static struct sexpr *
558
sexpr_get(virConnectPtr xend, const char *fmt, ...)
559
{
560
    char *buffer = NULL;
561 562 563
    char path[1024];
    va_list ap;
    int ret;
564
    struct sexpr *res = NULL;
565 566 567 568 569

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

570
    ret = xend_get(xend, path, &buffer);
571
    ret = http2unix(ret);
572
    if (ret == -1)
573 574 575 576 577 578
        goto cleanup;

    if (buffer == NULL)
        goto cleanup;

    res = string2sexpr(buffer);
579

580 581 582
cleanup:
    VIR_FREE(buffer);
    return res;
583 584 585 586 587 588 589 590 591 592
}

/**
 * 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
 *
593
 * Returns a -1 on error, 0 on success
594
 */
595
static int
596
sexpr_uuid(unsigned char *ptr, const struct sexpr *node, const char *path)
597 598
{
    const char *r = sexpr_node(node, path);
599 600 601
    if (!r)
        return -1;
    return virUUIDParse(r, ptr);
602 603 604 605 606
}

/* PUBLIC FUNCTIONS */

/**
607
 * xenDaemonOpen_unix:
608
 * @conn: an existing virtual connection block
609 610 611 612 613
 * @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
 *
614
 * Returns 0 in case of success, -1 in case of error.
615
 */
616
int
617
xenDaemonOpen_unix(virConnectPtr conn, const char *path)
618 619
{
    struct sockaddr_un *addr;
620
    xenUnifiedPrivatePtr priv = conn->privateData;
621

622 623
    memset(&priv->addr, 0, sizeof(priv->addr));
    priv->addrfamily = AF_UNIX;
624 625 626 627 628
    /*
     * This must be zero on Solaris at least for AF_UNIX (which should
     * really be PF_UNIX, but doesn't matter).
     */
    priv->addrprotocol = 0;
629 630 631
    priv->addrlen = sizeof(struct sockaddr_un);

    addr = (struct sockaddr_un *)&priv->addr;
632 633
    addr->sun_family = AF_UNIX;
    memset(addr->sun_path, 0, sizeof(addr->sun_path));
C
Chris Lalancette 已提交
634 635
    if (virStrcpyStatic(addr->sun_path, path) == NULL)
        return -1;
636

637
    return 0;
638 639
}

640

641
/**
642
 * xenDaemonOpen_tcp:
643
 * @conn: an existing virtual connection block
644
 * @host: the host name for the Xen Daemon
645
 * @port: the port
646 647 648 649
 *
 * Creates a possibly remote Xen Daemon connection
 * Note: this doesn't try to check if the connection actually works
 *
650
 * Returns 0 in case of success, -1 in case of error.
651
 */
652
static int
653
xenDaemonOpen_tcp(virConnectPtr conn, const char *host, const char *port)
654
{
655
    xenUnifiedPrivatePtr priv = conn->privateData;
656 657 658 659
    struct addrinfo *res, *r;
    struct addrinfo hints;
    int saved_errno = EINVAL;
    int ret;
660

661 662 663
    priv->addrlen = 0;
    memset(&priv->addr, 0, sizeof(priv->addr));

664
    /* http://people.redhat.com/drepper/userapi-ipv6.html */
665
    memset (&hints, 0, sizeof(hints));
666 667 668 669 670
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_ADDRCONFIG;

    ret = getaddrinfo (host, port, &hints, &res);
    if (ret != 0) {
671 672 673
        virReportError(VIR_ERR_UNKNOWN_HOST,
                       _("unable to resolve hostname '%s': %s"),
                       host, gai_strerror (ret));
674 675 676 677 678 679 680
        return -1;
    }

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

681
        sock = socket(r->ai_family, SOCK_STREAM, r->ai_protocol);
682 683 684
        if (sock == -1) {
            saved_errno = errno;
            continue;
685
        }
686

687
        if (connect(sock, r->ai_addr, r->ai_addrlen) == -1) {
688
            saved_errno = errno;
689
            VIR_FORCE_CLOSE(sock);
690 691 692 693 694 695 696 697 698
            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);
699
        VIR_FORCE_CLOSE(sock);
700
        break;
701 702
    }

703
    freeaddrinfo(res);
704

705
    if (!priv->addrlen) {
706 707
        /* Don't raise error when unprivileged, since proxy takes over */
        if (xenHavePrivilege())
708
            virReportSystemError(saved_errno,
709 710
                                 _("unable to connect to '%s:%s'"),
                                 host, port);
711 712
        return -1;
    }
713

714
    return 0;
715 716
}

717

718 719
/**
 * xend_wait_for_devices:
P
Philipp Hahn 已提交
720
 * @xend: pointer to the Xen Daemon block
721 722 723 724 725 726 727 728
 * @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
729
xend_wait_for_devices(virConnectPtr xend, const char *name)
730 731 732 733
{
    return xend_op(xend, name, "op", "wait_for_devices", NULL);
}

734

735
/**
736
 * xenDaemonListDomainsOld:
P
Philipp Hahn 已提交
737
 * @xend: pointer to the Xen Daemon block
738 739 740 741 742 743
 *
 * 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.
 */
744
char **
745
xenDaemonListDomainsOld(virConnectPtr xend)
746 747 748 749 750 751 752 753 754 755 756
{
    struct sexpr *root = NULL;
    char **ret = NULL;
    int count = 0;
    int i;
    struct sexpr *_for_i, *node;

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

757 758
    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) {
759 760 761 762 763
        if (node->kind != SEXPR_VALUE)
            continue;
        count++;
    }

E
Eric Blake 已提交
764 765
    if (VIR_ALLOC_N(ret, count + 1) < 0) {
        virReportOOMError();
766
        goto error;
E
Eric Blake 已提交
767
    }
768 769

    i = 0;
770 771
    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) {
772 773
        if (node->kind != SEXPR_VALUE)
            continue;
E
Eric Blake 已提交
774 775 776
        ret[i] = strdup(node->u.value);
        if (!ret[i])
            goto no_memory;
777 778 779 780 781 782 783 784
        i++;
    }

    ret[i] = NULL;

  error:
    sexpr_free(root);
    return ret;
E
Eric Blake 已提交
785 786 787 788 789 790

no_memory:
    for (i = 0; i < count; i++)
        VIR_FREE(ret[i]);
    VIR_FREE(ret);
    goto error;
791 792
}

793

794
/**
795
 * xenDaemonDomainCreateXML:
796 797 798
 * @xend: A xend instance
 * @sexpr: An S-Expr description of the domain.
 *
P
Philipp Hahn 已提交
799
 * This method will create a domain based on the passed in description.  The
800
 * domain will be paused after creation and must be unpaused with
801
 * xenDaemonResumeDomain() to begin execution.
802 803 804 805 806 807 808
 * This method may be deprecated once switching to XML-RPC based communcations
 * with xend.
 *
 * Returns 0 for success, -1 (with errno) on error
 */

int
809
xenDaemonDomainCreateXML(virConnectPtr xend, const char *sexpr)
810
{
P
Philipp Hahn 已提交
811
    int ret;
812

P
Philipp Hahn 已提交
813
    ret = xend_op(xend, "", "op", "create", "config", sexpr, NULL);
814 815 816

    return ret;
}
817

818

819
/**
820
 * xenDaemonDomainLookupByName_ids:
821
 * @xend: A xend instance
822 823
 * @domname: The name of the domain
 * @uuid: return value for the UUID if not NULL
824 825 826 827 828 829
 *
 * This method looks up the id of a domain
 *
 * Returns the id on success; -1 (with errno) on error
 */
int
830 831
xenDaemonDomainLookupByName_ids(virConnectPtr xend,
                                const char *domname,
832
                                unsigned char *uuid)
833 834 835 836 837
{
    struct sexpr *root;
    const char *value;
    int ret = -1;

838
    if (uuid != NULL)
839
        memset(uuid, 0, VIR_UUID_BUFLEN);
840 841 842 843 844
    root = sexpr_get(xend, "/xend/domain/%s?detail=1", domname);
    if (root == NULL)
        goto error;

    value = sexpr_node(root, "domain/domid");
845
    if (value == NULL) {
846 847
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("domain information incomplete, missing domid"));
848
        goto error;
849
    }
850
    ret = strtol(value, NULL, 0);
851
    if ((ret == 0) && (value[0] != '0')) {
852 853
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("domain information incorrect domid not numeric"));
854
        ret = -1;
855
    } else if (uuid != NULL) {
856
        if (sexpr_uuid(uuid, root, "domain/uuid") < 0) {
857 858
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("domain information incomplete, missing uuid"));
859
        }
860
    }
861

862
  error:
863
    sexpr_free(root);
864
    return ret;
865 866
}

867

868
static int
869 870
xend_detect_config_version(virConnectPtr conn)
{
871 872
    struct sexpr *root;
    const char *value;
873
    xenUnifiedPrivatePtr priv = conn->privateData;
874

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

879
    value = sexpr_node(root, "node/xend_config_format");
880

881
    if (value) {
882
        priv->xendConfigVersion = strtol(value, NULL, 10);
883 884 885
    }  else {
        /* Xen prior to 3.0.3 did not have the xend_config_format
           field, and is implicitly version 1. */
886
        priv->xendConfigVersion = XEND_CONFIG_VERSION_3_0_2;
887
    }
888
    sexpr_free(root);
889
    return 0;
890 891
}

D
Daniel Veillard 已提交
892

893 894 895 896 897 898 899 900 901 902
/**
 * sexpr_to_xend_domain_state:
 * @root: an S-Expression describing a domain
 *
 * Internal routine getting the domain's state from the domain root provided.
 *
 * Returns domain's state.
 */
static int
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2)
903
sexpr_to_xend_domain_state(virDomainDefPtr def, const struct sexpr *root)
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
{
    const char *flags;
    int state = VIR_DOMAIN_NOSTATE;

    if ((flags = sexpr_node(root, "domain/state"))) {
        if (strchr(flags, 'c'))
            state = VIR_DOMAIN_CRASHED;
        else if (strchr(flags, 's'))
            state = VIR_DOMAIN_SHUTOFF;
        else if (strchr(flags, 'd'))
            state = VIR_DOMAIN_SHUTDOWN;
        else if (strchr(flags, 'p'))
            state = VIR_DOMAIN_PAUSED;
        else if (strchr(flags, 'b'))
            state = VIR_DOMAIN_BLOCKED;
        else if (strchr(flags, 'r'))
            state = VIR_DOMAIN_RUNNING;
921
    } else if (def->id < 0 || sexpr_int(root, "domain/status") == 0) {
922 923 924 925 926 927 928
        /* As far as I can see the domain->id is a bad sign for checking
         * inactive domains as this is inaccurate after the domain has
         * been running once. However domain/status from xend seems to
         * be always present and 0 for inactive domains.
         * (keeping the check for id < 0 to be extra safe about backward
         * compatibility)
         */
929 930 931 932 933 934
        state = VIR_DOMAIN_SHUTOFF;
    }

    return state;
}

D
Daniel Veillard 已提交
935
/**
936 937 938 939 940 941 942 943 944 945
 * 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
946
sexpr_to_xend_domain_info(virDomainDefPtr def,
947
                          const struct sexpr *root,
948
                          virDomainInfoPtr info)
949
{
950
    int vcpus;
951

952
    info->state = sexpr_to_xend_domain_state(def, root);
953 954 955
    info->memory = sexpr_u64(root, "domain/memory") << 10;
    info->maxMem = sexpr_u64(root, "domain/maxmem") << 10;
    info->cpuTime = sexpr_float(root, "domain/cpu_time") * 1000000000;
956

957
    vcpus = sexpr_int(root, "domain/vcpus");
958
    info->nrVirtCpu = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail"));
959 960 961
    if (!info->nrVirtCpu || vcpus < info->nrVirtCpu)
        info->nrVirtCpu = vcpus;

962
    return 0;
963 964
}

965 966 967 968 969 970 971 972 973 974 975
/**
 * 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
976
sexpr_to_xend_node_info(const struct sexpr *root, virNodeInfoPtr info)
977 978 979 980
{
    const char *machine;

    machine = sexpr_node(root, "node/machine");
981
    if (machine == NULL) {
982
        info->model[0] = 0;
983
    } else {
984
        snprintf(&info->model[0], sizeof(info->model) - 1, "%s", machine);
985
        info->model[sizeof(info->model) - 1] = 0;
986 987 988 989 990 991 992
    }
    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");
993 994 995
    info->cores = sexpr_int(root, "node/cores_per_socket");
    info->threads = sexpr_int(root, "node/threads_per_core");

996 997 998 999 1000 1001 1002
    /* 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");
1003 1004
        int procs = info->nodes * info->cores * info->threads;
        if (procs == 0) /* Sanity check in case of Xen bugs in futures..*/
1005
            return -1;
1006
        info->sockets = nr_cpus / procs;
1007
    }
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021

    /* On systems where NUMA nodes are not composed of whole sockets either Xen
     * provided us wrong number of sockets per node or we computed the wrong
     * number in the compatibility code above. In such case, we compute the
     * correct number of sockets on the host, lie about the number of NUMA
     * nodes, and force apps to check capabilities XML for the actual NUMA
     * topology.
     */
    if (info->nodes * info->sockets * info->cores * info->threads
        != info->cpus) {
        info->nodes = 1;
        info->sockets = info->cpus / (info->cores * info->threads);
    }

1022
    return 0;
1023 1024
}

1025

1026
/**
1027
 * sexpr_to_xend_topology
1028
 * @root: an S-Expression describing a node
1029
 * @caps: capability info
1030
 *
1031 1032
 * Internal routine populating capability info with
 * NUMA node mapping details
1033
 *
1034 1035
 * Does nothing when the system doesn't support NUMA (not an error).
 *
1036 1037
 * Returns 0 in case of success, -1 in case of error
 */
1038
static int
1039
sexpr_to_xend_topology(const struct sexpr *root, virCapsPtr caps)
1040 1041
{
    const char *nodeToCpu;
1042
    const char *cur;
1043
    virCapsHostNUMACellCPUPtr cpuInfo = NULL;
1044
    int cell, cpu, nb_cpus = 0;
1045
    int n = 0;
1046
    int numCpus;
1047 1048

    nodeToCpu = sexpr_node(root, "node/node_to_cpu");
1049 1050
    if (nodeToCpu == NULL)
        return 0;               /* no NUMA support */
1051 1052 1053

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

1054 1055 1056

    cur = nodeToCpu;
    while (*cur != 0) {
1057
        virBitmapPtr cpuset = NULL;
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
        /*
         * 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;
E
Eric Blake 已提交
1068
        virSkipSpacesAndBackslash(&cur);
1069 1070 1071
        if (*cur != ':')
            goto parse_error;
        cur++;
E
Eric Blake 已提交
1072
        virSkipSpacesAndBackslash(&cur);
1073
        if (STRPREFIX(cur, "no cpus")) {
1074
            nb_cpus = 0;
1075 1076
            if (!(cpuset = virBitmapNew(numCpus)))
                goto memory_error;
1077
        } else {
1078
            nb_cpus = virBitmapParse(cur, 'n', &cpuset, numCpus);
1079 1080 1081 1082
            if (nb_cpus < 0)
                goto error;
        }

1083 1084
        if (VIR_ALLOC_N(cpuInfo, numCpus) < 0) {
            virBitmapFree(cpuset);
1085
            goto memory_error;
1086
        }
1087

1088 1089 1090 1091 1092
        for (n = 0, cpu = 0; cpu < numCpus; cpu++) {
            bool used;

            ignore_value(virBitmapGetBit(cpuset, cpu, &used));
            if (used)
1093
                cpuInfo[n++].id = cpu;
1094
        }
1095
        virBitmapFree(cpuset);
1096

1097
        if (virCapabilitiesAddHostNUMACell(caps, cell, nb_cpus, 0, cpuInfo) < 0)
1098
            goto memory_error;
1099
        cpuInfo = NULL;
1100
    }
1101

1102
    return 0;
1103

1104
  parse_error:
1105
    virReportError(VIR_ERR_XEN_CALL, "%s", _("topology syntax error"));
1106
  error:
1107 1108
    virCapabilitiesClearHostNUMACellCPUTopology(cpuInfo, nb_cpus);
    VIR_FREE(cpuInfo);
1109
    return -1;
1110

1111
  memory_error:
1112
    virReportOOMError();
1113
    goto error;
1114 1115
}

1116

1117 1118 1119 1120 1121 1122 1123
/**
 * 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
 *
1124
 * Returns the domain def pointer or NULL in case of error.
1125
 */
1126
static virDomainDefPtr
1127
sexpr_to_domain(virConnectPtr conn, const struct sexpr *root)
1128
{
1129
    virDomainDefPtr ret = NULL;
1130
    unsigned char uuid[VIR_UUID_BUFLEN];
1131
    const char *name;
1132
    const char *tmp;
1133
    int id = -1;
1134
    xenUnifiedPrivatePtr priv = conn->privateData;
1135

1136
    if (sexpr_uuid(uuid, root, "domain/uuid") < 0)
1137 1138 1139 1140 1141
        goto error;
    name = sexpr_node(root, "domain/name");
    if (name == NULL)
        goto error;

1142 1143 1144 1145
    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
     */
1146
    if (!tmp && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
1147 1148
        goto error;

1149
    if (tmp)
1150
        id = sexpr_int(root, "domain/domid");
1151

1152
    return virDomainDefNew(name, uuid, id);
1153

1154
error:
1155 1156
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   "%s", _("failed to parse Xend domain information"));
1157
    virObjectUnref(ret);
1158
    return NULL;
1159
}
1160

1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182

/*****************************************************************
 ******
 ******
 ******
 ******
             Refactored
 ******
 ******
 ******
 ******
 *****************************************************************/
/**
 * 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.
 */
1183
int
1184 1185
xenDaemonOpen(virConnectPtr conn,
              virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
1186
              unsigned int flags)
1187
{
1188
    char *port = NULL;
1189
    int ret = -1;
1190

1191
    virCheckFlags(VIR_CONNECT_RO, -1);
E
Eric Blake 已提交
1192

1193 1194
    /* Switch on the scheme, which we expect to be NULL (file),
     * "http" or "xen".
1195
     */
1196
    if (conn->uri->scheme == NULL) {
1197
        /* It should be a file access */
1198
        if (conn->uri->path == NULL) {
1199
            virReportError(VIR_ERR_NO_CONNECT, __FUNCTION__);
1200 1201
            goto failed;
        }
1202 1203
        if (xenDaemonOpen_unix(conn, conn->uri->path) < 0 ||
            xend_detect_config_version(conn) == -1)
1204 1205
            goto failed;
    }
1206
    else if (STRCASEEQ(conn->uri->scheme, "xen")) {
1207
        /*
1208 1209
         * try first to open the unix socket
         */
1210 1211
        if (xenDaemonOpen_unix(conn, "/var/lib/xend/xend-socket") == 0 &&
            xend_detect_config_version(conn) != -1)
1212 1213 1214 1215 1216
            goto done;

        /*
         * try though http on port 8000
         */
1217 1218
        if (xenDaemonOpen_tcp(conn, "localhost", "8000") < 0 ||
            xend_detect_config_version(conn) == -1)
1219
            goto failed;
1220
    } else if (STRCASEEQ(conn->uri->scheme, "http")) {
1221
        if (conn->uri->port &&
1222
            virAsprintf(&port, "%d", conn->uri->port) == -1) {
1223
            virReportOOMError();
1224
            goto failed;
1225
        }
1226

1227 1228 1229
        if (xenDaemonOpen_tcp(conn,
                              conn->uri->server ? conn->uri->server : "localhost",
                              port ? port : "8000") < 0 ||
1230
            xend_detect_config_version(conn) == -1)
1231
            goto failed;
1232
    } else {
1233
        virReportError(VIR_ERR_NO_CONNECT, __FUNCTION__);
1234
        goto failed;
1235
    }
1236

1237
 done:
1238
    ret = 0;
1239

1240
failed:
1241 1242
    VIR_FREE(port);
    return ret;
1243
}
1244

1245 1246 1247 1248 1249 1250 1251 1252 1253

/**
 * 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.
 *
1254
 * Returns 0 in case of success, -1 in case of error
1255 1256 1257 1258
 */
int
xenDaemonClose(virConnectPtr conn ATTRIBUTE_UNUSED)
{
1259
    return 0;
1260 1261 1262 1263
}

/**
 * xenDaemonDomainSuspend:
1264 1265
 * @conn: the connection object
 * @def: the domain to suspend
1266 1267 1268 1269 1270 1271 1272
 *
 * 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
1273
xenDaemonDomainSuspend(virConnectPtr conn, virDomainDefPtr def)
1274
{
1275
    if (def->id < 0) {
1276
        virReportError(VIR_ERR_OPERATION_INVALID,
1277
                       _("Domain %s isn't running."), def->name);
1278
        return -1;
1279 1280
    }

1281
    return xend_op(conn, def->name, "op", "pause", NULL);
1282 1283 1284 1285
}

/**
 * xenDaemonDomainResume:
1286 1287
 * @conn: the connection object
 * @def: the domain to resume
1288 1289 1290 1291 1292 1293
 *
 * Resume the domain after xenDaemonDomainSuspend() has been called
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
1294
xenDaemonDomainResume(virConnectPtr conn, virDomainDefPtr def)
1295
{
1296
    if (def->id < 0) {
1297
        virReportError(VIR_ERR_OPERATION_INVALID,
1298
                       _("Domain %s isn't running."), def->name);
1299
        return -1;
1300 1301
    }

1302
    return xend_op(conn, def->name, "op", "unpause", NULL);
1303 1304 1305 1306
}

/**
 * xenDaemonDomainShutdown:
1307 1308
 * @conn: the connection object
 * @def: the domain to shutdown
1309 1310 1311 1312 1313 1314 1315 1316
 *
 * 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
1317
xenDaemonDomainShutdown(virConnectPtr conn, virDomainDefPtr def)
1318
{
1319
    if (def->id < 0) {
1320
        virReportError(VIR_ERR_OPERATION_INVALID,
1321
                       _("Domain %s isn't running."), def->name);
1322
        return -1;
1323 1324
    }

1325
    return xend_op(conn, def->name, "op", "shutdown", "reason", "poweroff", NULL);
1326 1327
}

1328 1329
/**
 * xenDaemonDomainReboot:
1330 1331
 * @conn: the connection object
 * @def: the domain to reboot
1332 1333 1334 1335 1336 1337 1338 1339
 *
 * 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
1340
xenDaemonDomainReboot(virConnectPtr conn, virDomainDefPtr def)
1341
{
1342
    if (def->id < 0) {
1343
        virReportError(VIR_ERR_OPERATION_INVALID,
1344
                       _("Domain %s isn't running."), def->name);
1345
        return -1;
1346 1347
    }

1348
    return xend_op(conn, def->name, "op", "shutdown", "reason", "reboot", NULL);
1349 1350
}

1351
/**
1352
 * xenDaemonDomainDestroy:
1353 1354
 * @conn: the connection object
 * @def: the domain to destroy
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
 *
 * 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
1366
xenDaemonDomainDestroy(virConnectPtr conn, virDomainDefPtr def)
1367
{
1368
    if (def->id < 0) {
1369
        virReportError(VIR_ERR_OPERATION_INVALID,
1370
                       _("Domain %s isn't running."), def->name);
1371
        return -1;
1372 1373
    }

1374
    return xend_op(conn, def->name, "op", "destroy", NULL);
1375 1376
}

1377 1378 1379 1380 1381 1382 1383 1384 1385
/**
 * 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.
 */
1386
char *
1387 1388
xenDaemonDomainGetOSType(virConnectPtr conn,
                         virDomainDefPtr def)
1389 1390 1391 1392 1393
{
    char *type;
    struct sexpr *root;

    /* can we ask for a subset ? worth it ? */
1394
    root = sexpr_get(conn, "/xend/domain/%s?detail=1", def->name);
1395
    if (root == NULL)
1396
        return NULL;
1397 1398 1399 1400 1401 1402 1403

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

1404
    if (type == NULL)
1405
        virReportOOMError();
1406

1407 1408
    sexpr_free(root);

1409
    return type;
1410 1411
}

1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427
/**
 * 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)
{
1428
    if (domain->id < 0) {
1429 1430
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain %s isn't running."), domain->name);
1431
        return -1;
1432
    }
1433 1434 1435

    /* We can't save the state of Domain-0, that would mean stopping it too */
    if (domain->id == 0) {
1436 1437
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Cannot save host domain"));
1438
        return -1;
1439 1440
    }

1441 1442 1443
    return xend_op(domain->conn, domain->name, "op", "save", "file", filename, NULL);
}

D
Daniel Veillard 已提交
1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455
/**
 * 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.
 */
1456
int
1457 1458
xenDaemonDomainCoreDump(virDomainPtr domain,
                        const char *filename,
E
Eric Blake 已提交
1459
                        unsigned int flags)
D
Daniel Veillard 已提交
1460
{
E
Eric Blake 已提交
1461 1462
    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH, -1);

1463
    if (domain->id < 0) {
1464 1465
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain %s isn't running."), domain->name);
1466
        return -1;
1467 1468
    }

1469
    return xend_op(domain->conn, domain->name,
J
Jiri Denemark 已提交
1470
                   "op", "dump", "file", filename,
P
Paolo Bonzini 已提交
1471
                   "live", (flags & VIR_DUMP_LIVE ? "1" : "0"),
1472 1473
                   "crash", (flags & VIR_DUMP_CRASH ? "1" : "0"),
                   NULL);
D
Daniel Veillard 已提交
1474 1475
}

1476 1477
/**
 * xenDaemonDomainRestore:
P
Philipp Hahn 已提交
1478
 * @conn: pointer to the Xen Daemon block
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
 * @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)
{
    return xend_op(conn, "", "op", "restore", "file", filename, NULL);
}
1492

1493

1494 1495 1496 1497 1498 1499 1500 1501
/**
 * 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.
 */
1502
unsigned long long
1503
xenDaemonDomainGetMaxMemory(virConnectPtr conn, virDomainDefPtr def)
1504
{
1505
    unsigned long long ret = 0;
1506 1507 1508
    struct sexpr *root;

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

1513
    ret = sexpr_u64(root, "domain/memory") << 10;
1514 1515
    sexpr_free(root);

1516
    return ret;
1517 1518
}

1519

1520 1521 1522 1523 1524 1525 1526
/**
 * 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
1527
 * on its own.
1528 1529 1530 1531
 *
 * Returns 0 for success; -1 (with errno) on error
 */
int
1532 1533 1534
xenDaemonDomainSetMaxMemory(virConnectPtr conn,
                            virDomainDefPtr def,
                            unsigned long memory)
1535 1536
{
    char buf[1024];
1537

1538
    snprintf(buf, sizeof(buf), "%lu", VIR_DIV_UP(memory, 1024));
1539
    return xend_op(conn, def->name, "op", "maxmem_set", "memory",
1540 1541 1542
                   buf, NULL);
}

1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559
/**
 * 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
1560 1561 1562
xenDaemonDomainSetMemory(virConnectPtr conn,
                         virDomainDefPtr def,
                         unsigned long memory)
1563 1564
{
    char buf[1024];
1565

1566
    snprintf(buf, sizeof(buf), "%lu", VIR_DIV_UP(memory, 1024));
1567
    return xend_op(conn, def->name, "op", "mem_target_set",
1568 1569 1570
                   "target", buf, NULL);
}

1571

1572
virDomainDefPtr
1573
xenDaemonDomainFetch(virConnectPtr conn, int domid, const char *name,
1574
                     const char *cpus)
1575 1576
{
    struct sexpr *root;
1577
    xenUnifiedPrivatePtr priv = conn->privateData;
1578
    virDomainDefPtr def;
1579 1580 1581
    int id;
    char * tty;
    int vncport;
1582

1583 1584 1585 1586
    if (name)
        root = sexpr_get(conn, "/xend/domain/%s?detail=1", name);
    else
        root = sexpr_get(conn, "/xend/domain/%d?detail=1", domid);
1587
    if (root == NULL)
1588
        return NULL;
1589

1590 1591
    id = xenGetDomIdFromSxpr(root, priv->xendConfigVersion);
    xenUnifiedLock(priv);
1592 1593 1594 1595
    if (sexpr_lookup(root, "domain/image/hvm"))
        tty = xenStoreDomainGetSerialConsolePath(conn, id);
    else
        tty = xenStoreDomainGetConsolePath(conn, id);
1596 1597
    vncport = xenStoreDomainGetVNCPort(conn, id);
    xenUnifiedUnlock(priv);
M
Markus Groß 已提交
1598 1599 1600 1601 1602
    if (!(def = xenParseSxpr(root,
                             priv->xendConfigVersion,
                             cpus,
                             tty,
                             vncport)))
1603 1604 1605
        goto cleanup;

cleanup:
1606 1607
    sexpr_free(root);

1608
    return def;
1609 1610 1611
}


1612
/**
1613
 * xenDaemonDomainGetXMLDesc:
D
Daniel Veillard 已提交
1614
 * @domain: a domain object
1615 1616
 * @flags: potential dump flags
 * @cpus: list of cpu the domain is pinned to.
D
Daniel Veillard 已提交
1617
 *
1618
 * Provide an XML description of the domain.
D
Daniel Veillard 已提交
1619 1620 1621 1622 1623
 *
 * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
 *         the caller must free() the returned value.
 */
char *
1624 1625
xenDaemonDomainGetXMLDesc(virDomainPtr domain,
                          unsigned int flags,
E
Eric Blake 已提交
1626
                          const char *cpus)
1627
{
1628 1629
    virDomainDefPtr def;
    char *xml;
1630

E
Eric Blake 已提交
1631 1632
    /* Flags checked by virDomainDefFormat */

1633 1634 1635 1636
    if (!(def = xenDaemonDomainFetch(domain->conn,
                                     domain->id,
                                     domain->name,
                                     cpus)))
1637
        return NULL;
1638

1639
    xml = virDomainDefFormat(def, flags);
1640 1641 1642 1643

    virDomainDefFree(def);

    return xml;
D
Daniel Veillard 已提交
1644
}
1645

1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657

/**
 * 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
1658 1659 1660
xenDaemonDomainGetInfo(virConnectPtr conn,
                       virDomainDefPtr def,
                       virDomainInfoPtr info)
1661 1662 1663 1664
{
    struct sexpr *root;
    int ret;

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

1669
    ret = sexpr_to_xend_domain_info(def, root, info);
1670
    sexpr_free(root);
1671
    return ret;
1672
}
1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685


/**
 * xenDaemonDomainGetState:
 * @domain: a domain object
 * @state: returned domain's state
 * @reason: returned reason for the state
 *
 * This method looks up domain state and reason.
 *
 * Returns 0 in case of success, -1 in case of error
 */
int
1686 1687
xenDaemonDomainGetState(virConnectPtr conn,
                        virDomainDefPtr def,
1688
                        int *state,
1689
                        int *reason)
1690 1691 1692
{
    struct sexpr *root;

1693
    root = sexpr_get(conn, "/xend/domain/%s?detail=1", def->name);
1694 1695 1696
    if (!root)
        return -1;

1697
    *state = sexpr_to_xend_domain_state(def, root);
1698 1699 1700 1701 1702 1703
    if (reason)
        *reason = 0;

    sexpr_free(root);
    return 0;
}
1704

1705

1706
/**
1707
 * xenDaemonLookupByName:
1708 1709 1710 1711 1712 1713 1714
 * @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.
 *
1715
 * Returns domain def pointer on success; NULL on error
1716
 */
1717
virDomainDefPtr
1718
xenDaemonLookupByName(virConnectPtr conn, const char *domname)
1719 1720
{
    struct sexpr *root;
1721
    virDomainDefPtr ret = NULL;
1722 1723 1724 1725 1726 1727 1728 1729 1730

    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);
1731
    return ret;
1732
}
1733

1734

1735 1736 1737 1738
/**
 * xenDaemonNodeGetInfo:
 * @conn: pointer to the Xen Daemon block
 * @info: pointer to a virNodeInfo structure allocated by the user
1739
 *
1740 1741 1742 1743
 * Extract hardware information about the node.
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
1744
int
1745 1746
xenDaemonNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
{
1747 1748 1749 1750 1751
    int ret = -1;
    struct sexpr *root;

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

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

1759 1760 1761
/**
 * xenDaemonNodeGetTopology:
 * @conn: pointer to the Xen Daemon block
1762
 * @caps: capabilities info
1763 1764 1765 1766 1767 1768
 *
 * This method retrieves a node's topology information.
 *
 * Returns -1 in case of error, 0 otherwise.
 */
int
1769 1770
xenDaemonNodeGetTopology(virConnectPtr conn, virCapsPtr caps)
{
1771 1772 1773 1774 1775
    int ret = -1;
    struct sexpr *root;

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

1779
    ret = sexpr_to_xend_topology(root, caps);
1780
    sexpr_free(root);
1781
    return ret;
1782 1783
}

1784

1785 1786 1787 1788 1789 1790 1791 1792
/**
 * xenDaemonDomainSetVcpusFlags:
 * @domain: pointer to domain object
 * @nvcpus: the new number of virtual CPUs for this domain
 * @flags: bitwise-ORd from virDomainVcpuFlags
 *
 * Change virtual CPUs allocation of domain according to flags.
 *
1793
 * Returns 0 on success, -1 if an error message was issued
1794 1795
 */
int
1796 1797
xenDaemonDomainSetVcpusFlags(virDomainPtr domain,
                             unsigned int vcpus,
1798 1799 1800 1801 1802
                             unsigned int flags)
{
    char buf[VIR_UUID_BUFLEN];
    int max;

E
Eric Blake 已提交
1803 1804 1805 1806
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

1807
    if (vcpus < 1) {
1808
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1809
        return -1;
1810 1811
    }

1812
    if (domain->id < 0) {
1813
        if (flags & VIR_DOMAIN_VCPU_LIVE) {
1814 1815
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("domain not running"));
1816 1817 1818 1819 1820
            return -1;
        }
    } else {
        if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) !=
            (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) {
1821 1822 1823
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend only supports modifying both live and "
                             "persistent config"));
1824 1825 1826 1827 1828 1829 1830
        }
    }

    /* Unfortunately, xend_op does not validate whether this exceeds
     * the maximum.  */
    flags |= VIR_DOMAIN_VCPU_MAXIMUM;
    if ((max = xenDaemonDomainGetVcpusFlags(domain, flags)) < 0) {
1831 1832
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("could not determine max vcpus for the domain"));
1833 1834 1835
        return -1;
    }
    if (vcpus > max) {
1836 1837 1838
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), vcpus, max);
1839 1840 1841 1842 1843 1844 1845 1846
        return -1;
    }

    snprintf(buf, sizeof(buf), "%d", vcpus);
    return xend_op(domain->conn, domain->name, "op", "set_vcpus", "vcpus",
                   buf, NULL);
}

1847 1848 1849 1850 1851 1852
/**
 * 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
1853
 *
1854
 * Dynamically change the real CPUs which can be allocated to a virtual CPU.
1855 1856 1857 1858 1859
 * 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
1860 1861 1862 1863
 *
 * Returns 0 for success; -1 (with errno) on error
 */
int
1864 1865 1866 1867
xenDaemonDomainPinVcpu(virDomainPtr domain,
                       unsigned int vcpu,
                       unsigned char *cpumap,
                       int maplen)
1868
{
1869
    char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64];
1870
    int i, j, ret;
1871
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
1872
    virDomainDefPtr def = NULL;
1873

1874
    if (maplen > (int)sizeof(cpumap_t)) {
1875
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1876
        return -1;
1877
    }
1878

1879
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
H
Henrik Persson 已提交
1880 1881
        mapstr[0] = '[';
        mapstr[1] = 0;
1882
    } else {
H
Henrik Persson 已提交
1883
        mapstr[0] = 0;
1884 1885
    }

1886 1887 1888
    /* 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)) {
1889
        snprintf(buf, sizeof(buf), "%d,", (8 * i) + j);
1890 1891
        strcat(mapstr, buf);
    }
1892
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
1893 1894 1895 1896
        mapstr[strlen(mapstr) - 1] = ']';
    else
        mapstr[strlen(mapstr) - 1] = 0;

1897
    snprintf(buf, sizeof(buf), "%d", vcpu);
1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908

    ret = xend_op(domain->conn, domain->name, "op", "pincpu", "vcpu", buf,
                  "cpumap", mapstr, NULL);

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

    if (ret == 0) {
H
Hu Tao 已提交
1909 1910 1911 1912 1913 1914 1915
        if (!def->cputune.vcpupin) {
            if (VIR_ALLOC(def->cputune.vcpupin) < 0) {
                virReportOOMError();
                goto cleanup;
            }
            def->cputune.nvcpupin = 0;
        }
1916
        if (virDomainVcpuPinAdd(&def->cputune.vcpupin,
H
Hu Tao 已提交
1917 1918 1919 1920
                                &def->cputune.nvcpupin,
                                cpumap,
                                maplen,
                                vcpu) < 0) {
1921 1922
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("failed to add vcpupin xml entry"));
1923
            return -1;
1924 1925 1926 1927 1928 1929 1930 1931
        }
    }

    return ret;

cleanup:
    virDomainDefFree(def);
    return -1;
1932 1933
}

1934 1935 1936 1937 1938 1939 1940 1941
/**
 * xenDaemonDomainGetVcpusFlags:
 * @domain: pointer to domain object
 * @flags: bitwise-ORd from virDomainVcpuFlags
 *
 * Extract information about virtual CPUs of domain according to flags.
 *
 * Returns the number of vcpus on success, -1 if an error message was
1942
 * issued
1943 1944 1945 1946 1947 1948 1949 1950

 */
int
xenDaemonDomainGetVcpusFlags(virDomainPtr domain, unsigned int flags)
{
    struct sexpr *root;
    int ret;

E
Eric Blake 已提交
1951 1952 1953 1954
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

1955
    if (domain->id < 0 && (flags & VIR_DOMAIN_VCPU_LIVE)) {
1956 1957
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain not active"));
1958 1959 1960 1961 1962 1963 1964 1965 1966
        return -1;
    }

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

    ret = sexpr_int(root, "domain/vcpus");
    if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM)) {
1967
        int vcpus = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail"));
1968 1969 1970 1971
        if (vcpus)
            ret = MIN(vcpus, ret);
    }
    if (!ret)
1972
        ret = -1;
1973 1974 1975 1976
    sexpr_free(root);
    return ret;
}

1977 1978 1979 1980 1981
/**
 * 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
E
Eric Blake 已提交
1982
 * @cpumaps: pointer to a bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
D
Daniel Veillard 已提交
1983
 *	If cpumaps is NULL, then no cpumap information is returned by the API.
1984 1985 1986 1987 1988 1989
 *	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...).
1990
 *
1991
 * Extract information about virtual CPUs of domain, store it in info array
D
Daniel Veillard 已提交
1992
 * and also in cpumaps if this pointer isn't NULL.
1993 1994 1995 1996
 *
 * Returns the number of info filled in case of success, -1 in case of failure.
 */
int
1997 1998 1999 2000 2001
xenDaemonDomainGetVcpus(virDomainPtr domain,
                        virVcpuInfoPtr info,
                        int maxinfo,
                        unsigned char *cpumaps,
                        int maplen)
2002 2003 2004 2005 2006 2007 2008 2009 2010
{
    struct sexpr *root, *s, *t;
    virVcpuInfoPtr ipt = info;
    int nbinfo = 0, oln;
    unsigned char *cpumap;
    int vcpu, cpu;

    root = sexpr_get(domain->conn, "/xend/domain/%s?op=vcpuinfo", domain->name);
    if (root == NULL)
2011
        return -1;
2012 2013

    if (cpumaps != NULL)
2014
        memset(cpumaps, 0, maxinfo * maplen);
2015 2016

    /* scan the sexprs from "(vcpu (number x)...)" and get parameter values */
2017 2018 2019
    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) &&
2020
            STREQ(s->u.s.car->u.s.car->u.value, "vcpu")) {
2021
            t = s->u.s.car;
2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
            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
                 */
2038 2039 2040
                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) &&
2041
                        STREQ(t->u.s.car->u.s.car->u.value, "cpumap") &&
2042 2043
                        (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)
2044
                            if (t->u.s.car->kind == SEXPR_VALUE
2045
                                && virStrToLong_i(t->u.s.car->u.value, NULL, 10, &cpu) == 0
2046 2047 2048
                                && cpu >= 0
                                && (VIR_CPU_MAPLEN(cpu+1) <= maplen)) {
                                VIR_USE_CPU(cpumap, cpu);
2049 2050 2051
                            }
                        break;
                    }
2052 2053
            }

2054 2055 2056
            if (++nbinfo == maxinfo) break;
            ipt++;
        }
2057 2058
    }
    sexpr_free(root);
2059
    return nbinfo;
2060 2061
}

2062 2063 2064 2065 2066 2067 2068
/**
 * 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.
 *
2069
 * Returns domain def pointer on success; NULL on error
2070
 */
2071
virDomainDefPtr
2072 2073
xenDaemonLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
2074
    virDomainDefPtr ret;
2075 2076
    char *name = NULL;
    int id = -1;
2077
    xenUnifiedPrivatePtr priv = conn->privateData;
2078

2079
    /* Old approach for xen <= 3.0.3 */
2080
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
2081 2082 2083 2084 2085 2086
        char **names, **tmp;
        unsigned char ident[VIR_UUID_BUFLEN];
        names = xenDaemonListDomainsOld(conn);
        tmp = names;

        if (names == NULL) {
2087
            return NULL;
2088 2089 2090 2091 2092
        }
        while (*tmp != NULL) {
            id = xenDaemonDomainLookupByName_ids(conn, *tmp, &ident[0]);
            if (id >= 0) {
                if (!memcmp(uuid, ident, VIR_UUID_BUFLEN)) {
E
Eric Blake 已提交
2093
                    name = *tmp;
2094 2095
                    break;
                }
2096
            }
2097
            tmp++;
2098
        }
E
Eric Blake 已提交
2099 2100 2101 2102 2103 2104
        tmp = names;
        while (*tmp) {
            if (*tmp != name)
                VIR_FREE(*tmp);
            tmp++;
        }
2105
        VIR_FREE(names);
2106 2107 2108 2109 2110
    } else { /* New approach for xen >= 3.0.4 */
        char *domname = NULL;
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        struct sexpr *root = NULL;

2111
        virUUIDFormat(uuid, uuidstr);
2112 2113
        root = sexpr_get(conn, "/xend/domain/%s?detail=1", uuidstr);
        if (root == NULL)
2114
            return NULL;
2115 2116 2117 2118 2119
        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;
2120 2121 2122 2123 2124

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

            if (name == NULL)
2125
                virReportOOMError();
2126 2127
        }

2128
        sexpr_free(root);
2129 2130 2131
    }

    if (name == NULL)
2132
        return NULL;
2133

2134
    ret = virDomainDefNew(name, uuid, id);
2135

2136
    VIR_FREE(name);
2137
    return ret;
2138
}
2139 2140

/**
2141
 * xenDaemonCreateXML:
2142 2143 2144 2145 2146 2147
 * @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()
2148
 * This function may requires privileged access to the hypervisor.
2149
 *
2150 2151
 * Returns a new domain object or NULL in case of failure
 */
2152
virDomainPtr
2153
xenDaemonCreateXML(virConnectPtr conn, const char *xmlDesc)
2154 2155 2156
{
    int ret;
    char *sexpr;
2157
    virDomainPtr dom = NULL;
2158
    xenUnifiedPrivatePtr priv = conn->privateData;
2159
    virDomainDefPtr def;
2160

2161 2162
    if (!(def = virDomainDefParseString(xmlDesc, priv->caps, priv->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_XEN,
2163
                                        VIR_DOMAIN_XML_INACTIVE)))
2164
        return NULL;
2165

M
Markus Groß 已提交
2166
    if (!(sexpr = xenFormatSxpr(conn, def, priv->xendConfigVersion))) {
2167
        virDomainDefFree(def);
2168
        return NULL;
2169 2170
    }

2171
    ret = xenDaemonDomainCreateXML(conn, sexpr);
2172
    VIR_FREE(sexpr);
2173 2174 2175 2176
    if (ret != 0) {
        goto error;
    }

2177 2178
    /* This comes before wait_for_devices, to ensure that latter
       cleanup will destroy the domain upon failure */
2179
    if (!(dom = virDomainLookupByName(conn, def->name)))
2180 2181
        goto error;

2182
    if (xend_wait_for_devices(conn, def->name) < 0)
2183 2184
        goto error;

2185
    if (xenDaemonDomainResume(conn, def) < 0)
2186 2187
        goto error;

2188
    virDomainDefFree(def);
2189
    return dom;
2190

2191
  error:
2192 2193
    /* Make sure we don't leave a still-born domain around */
    if (dom != NULL) {
2194
        xenDaemonDomainDestroy(conn, def);
2195
        virObjectUnref(dom);
2196
    }
2197
    virDomainDefFree(def);
2198
    return NULL;
2199
}
2200 2201

/**
2202
 * xenDaemonAttachDeviceFlags:
2203 2204
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
2205
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
2206
 *
2207 2208 2209 2210 2211
 * 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.
 */
2212
int
2213 2214
xenDaemonAttachDeviceFlags(virDomainPtr domain,
                           const char *xml,
2215
                           unsigned int flags)
2216
{
2217
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
2218 2219 2220 2221 2222
    char *sexpr = NULL;
    int ret = -1;
    virDomainDeviceDefPtr dev = NULL;
    virDomainDefPtr def = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2223
    char class[8], ref[80];
2224
    char *target = NULL;
2225

E
Eric Blake 已提交
2226 2227
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2228
    if (domain->id < 0) {
2229 2230
        /* Cannot modify live config if domain is inactive */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
2231 2232
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Cannot modify live config if domain is inactive"));
2233 2234
            return -1;
        }
2235 2236
    } else {
        /* Only live config can be changed if xendConfigVersion < 3 */
2237
        if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4 &&
E
Eric Blake 已提交
2238
            (flags != VIR_DOMAIN_DEVICE_MODIFY_CURRENT &&
2239
             flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) {
2240 2241 2242
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend version does not support modifying "
                             "persistent config"));
2243 2244
            return -1;
        }
2245
        /* Xen only supports modifying both live and persistent config if
2246 2247
         * xendConfigVersion >= 3
         */
2248
        if (priv->xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4 &&
2249 2250
            (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                       VIR_DOMAIN_DEVICE_MODIFY_CONFIG))) {
2251 2252 2253
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend only supports modifying both live and "
                             "persistent config"));
2254 2255 2256
            return -1;
        }
    }
2257

2258 2259 2260 2261 2262 2263
    if (!(def = xenDaemonDomainFetch(domain->conn,
                                     domain->id,
                                     domain->name,
                                     NULL)))
        goto cleanup;

2264 2265
    if (!(dev = virDomainDeviceDefParse(xml, def, priv->caps, priv->xmlopt,
                                        VIR_DOMAIN_XML_INACTIVE)))
2266 2267 2268 2269 2270
        goto cleanup;


    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
2271 2272 2273 2274
        if (xenFormatSxprDisk(dev->data.disk,
                              &buf,
                              STREQ(def->os.type, "hvm") ? 1 : 0,
                              priv->xendConfigVersion, 1) < 0)
2275
            goto cleanup;
2276 2277 2278 2279 2280 2281 2282

        if (dev->data.disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
            if (!(target = strdup(dev->data.disk->dst))) {
                virReportOOMError();
                goto cleanup;
            }
        }
2283
        break;
2284 2285

    case VIR_DOMAIN_DEVICE_NET:
M
Markus Groß 已提交
2286 2287 2288 2289 2290
        if (xenFormatSxprNet(domain->conn,
                             dev->data.net,
                             &buf,
                             STREQ(def->os.type, "hvm") ? 1 : 0,
                             priv->xendConfigVersion, 1) < 0)
2291
            goto cleanup;
2292 2293

        char macStr[VIR_MAC_STRING_BUFLEN];
2294
        virMacAddrFormat(&dev->data.net->mac, macStr);
2295 2296 2297 2298 2299

        if (!(target = strdup(macStr))) {
            virReportOOMError();
            goto cleanup;
        }
2300
        break;
2301

2302 2303 2304
    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) {
M
Markus Groß 已提交
2305
            if (xenFormatSxprOnePCI(dev->data.hostdev, &buf, 0) < 0)
2306
                goto cleanup;
2307

2308
            virDevicePCIAddress PCIAddr;
2309

2310
            PCIAddr = dev->data.hostdev->source.subsys.u.pci.addr;
2311 2312
            if (virAsprintf(&target, "PCI device: %.4x:%.2x:%.2x",
                            PCIAddr.domain, PCIAddr.bus, PCIAddr.slot) < 0) {
2313 2314 2315
                virReportOOMError();
                goto cleanup;
            }
2316
        } else {
2317 2318
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("unsupported device type"));
2319 2320 2321 2322
            goto cleanup;
        }
        break;

2323
    default:
2324 2325
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("unsupported device type"));
2326
        goto cleanup;
2327
    }
2328 2329 2330 2331

    sexpr = virBufferContentAndReset(&buf);

    if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref))) {
2332 2333
        /* device doesn't exist, define it */
        ret = xend_op(domain->conn, domain->name, "op", "device_create",
2334
                      "config", sexpr, NULL);
2335 2336
    } else {
        if (dev->data.disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
2337 2338
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("target '%s' already exists"), target);
2339 2340 2341 2342 2343
        } else {
            /* device exists, attempt to modify it */
            ret = xend_op(domain->conn, domain->name, "op", "device_configure",
                          "config", sexpr, "dev", ref, NULL);
        }
2344
    }
2345 2346

cleanup:
2347
    VIR_FREE(sexpr);
2348 2349
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
2350
    VIR_FREE(target);
2351 2352 2353
    return ret;
}

2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364
/**
 * 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.
 */
2365
int
2366 2367
xenDaemonUpdateDeviceFlags(virDomainPtr domain,
                           const char *xml,
2368 2369
                           unsigned int flags)
{
2370
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
2371 2372 2373 2374 2375 2376 2377
    char *sexpr = NULL;
    int ret = -1;
    virDomainDeviceDefPtr dev = NULL;
    virDomainDefPtr def = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char class[8], ref[80];

E
Eric Blake 已提交
2378
    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
2379 2380
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

2381
    if (domain->id < 0) {
2382 2383
        /* Cannot modify live config if domain is inactive */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
2384 2385
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Cannot modify live config if domain is inactive"));
2386 2387
            return -1;
        }
2388 2389
    } else {
        /* Only live config can be changed if xendConfigVersion < 3 */
2390
        if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4 &&
E
Eric Blake 已提交
2391
            (flags != VIR_DOMAIN_DEVICE_MODIFY_CURRENT &&
2392
             flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) {
2393 2394 2395
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend version does not support modifying "
                             "persistent config"));
2396 2397 2398 2399 2400
            return -1;
        }
        /* Xen only supports modifying both live and persistent config if
         * xendConfigVersion >= 3
         */
2401
        if (priv->xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4 &&
2402 2403
            (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                       VIR_DOMAIN_DEVICE_MODIFY_CONFIG))) {
2404 2405 2406
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend only supports modifying both live and "
                             "persistent config"));
2407 2408 2409 2410 2411 2412 2413 2414 2415 2416
            return -1;
        }
    }

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

2417 2418
    if (!(dev = virDomainDeviceDefParse(xml, def, priv->caps, priv->xmlopt,
                                        VIR_DOMAIN_XML_INACTIVE)))
2419 2420 2421 2422 2423
        goto cleanup;


    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
2424
        if (xenFormatSxprDisk(dev->data.disk,
M
Markus Groß 已提交
2425 2426 2427
                              &buf,
                              STREQ(def->os.type, "hvm") ? 1 : 0,
                              priv->xendConfigVersion, 1) < 0)
2428 2429 2430 2431
            goto cleanup;
        break;

    default:
2432 2433
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("unsupported device type"));
2434 2435 2436 2437 2438 2439
        goto cleanup;
    }

    sexpr = virBufferContentAndReset(&buf);

    if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref))) {
2440 2441
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("requested device does not exist"));
2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455
        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;
}

2456
/**
2457
 * xenDaemonDetachDeviceFlags:
2458 2459
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
2460
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
2461
 *
2462 2463 2464 2465
 * Destroy a virtual device attachment to backend.
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
2466
int
2467 2468
xenDaemonDetachDeviceFlags(virDomainPtr domain,
                           const char *xml,
2469
                           unsigned int flags)
2470
{
2471
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
2472
    char class[8], ref[80];
2473 2474 2475
    virDomainDeviceDefPtr dev = NULL;
    virDomainDefPtr def = NULL;
    int ret = -1;
2476 2477
    char *xendev = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2478

E
Eric Blake 已提交
2479 2480
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

2481
    if (domain->id < 0) {
2482 2483
        /* Cannot modify live config if domain is inactive */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
2484 2485
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Cannot modify live config if domain is inactive"));
2486 2487
            return -1;
        }
2488 2489
    } else {
        /* Only live config can be changed if xendConfigVersion < 3 */
2490
        if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4 &&
E
Eric Blake 已提交
2491
            (flags != VIR_DOMAIN_DEVICE_MODIFY_CURRENT &&
2492
             flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) {
2493 2494 2495
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend version does not support modifying "
                             "persistent config"));
2496 2497
            return -1;
        }
2498
        /* Xen only supports modifying both live and persistent config if
2499 2500
         * xendConfigVersion >= 3
         */
2501
        if (priv->xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4 &&
2502 2503
            (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                       VIR_DOMAIN_DEVICE_MODIFY_CONFIG))) {
2504 2505 2506
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend only supports modifying both live and "
                             "persistent config"));
2507 2508 2509
            return -1;
        }
    }
2510 2511 2512 2513 2514 2515 2516

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

2517 2518
    if (!(dev = virDomainDeviceDefParse(xml, def, priv->caps, priv->xmlopt,
                                        VIR_DOMAIN_XML_INACTIVE)))
2519 2520 2521 2522 2523
        goto cleanup;

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

2524 2525 2526
    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) {
M
Markus Groß 已提交
2527
            if (xenFormatSxprOnePCI(dev->data.hostdev, &buf, 1) < 0)
2528 2529
                goto cleanup;
        } else {
2530 2531
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("unsupported device type"));
2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543
            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);
    }
2544 2545 2546 2547 2548 2549

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

    return ret;
2550
}
2551

2552
int
2553
xenDaemonDomainGetAutostart(virDomainPtr domain, int *autostart)
2554 2555 2556 2557 2558 2559
{
    struct sexpr *root;
    const char *tmp;

    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL) {
2560 2561
        virReportError(VIR_ERR_XEN_CALL,
                       "%s", _("xenDaemonGetAutostart failed to find this domain"));
2562
        return -1;
2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576
    }

    *autostart = 0;

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

    sexpr_free(root);
    return 0;
}

int
2577
xenDaemonDomainSetAutostart(virDomainPtr domain, int autostart)
2578 2579
{
    struct sexpr *root, *autonode;
2580 2581
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
    char *content = NULL;
2582 2583 2584 2585
    int ret = -1;

    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL) {
2586 2587
        virReportError(VIR_ERR_XEN_CALL,
                       "%s", _("xenDaemonSetAutostart failed to find this domain"));
2588
        return -1;
2589 2590
    }

2591 2592 2593 2594
    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);
2595
        if (!val || (!STREQ(val, "ignore") && !STREQ(val, "start"))) {
2596 2597
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("unexpected value from on_xend_start"));
2598 2599 2600
            goto error;
        }

2601
        /* Change the autostart value in place, then define the new sexpr */
2602
        VIR_FREE(autonode->u.s.car->u.value);
2603 2604 2605
        autonode->u.s.car->u.value = (autostart ? strdup("start")
                                                : strdup("ignore"));
        if (!(autonode->u.s.car->u.value)) {
2606
            virReportOOMError();
2607 2608 2609
            goto error;
        }

2610
        if (sexpr2string(root, &buffer) < 0) {
2611 2612
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("sexpr2string failed"));
2613 2614
            goto error;
        }
2615 2616 2617 2618 2619 2620 2621 2622 2623

        if (virBufferError(&buffer)) {
            virReportOOMError();
            goto error;
        }

        content = virBufferContentAndReset(&buffer);

        if (xend_op(domain->conn, "", "op", "new", "config", content, NULL) != 0) {
2624 2625
            virReportError(VIR_ERR_XEN_CALL,
                           "%s", _("Failed to redefine sexpr"));
2626 2627 2628
            goto error;
        }
    } else {
2629 2630
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("on_xend_start not present in sexpr"));
2631 2632 2633 2634 2635
        goto error;
    }

    ret = 0;
  error:
2636 2637
    virBufferFreeAndReset(&buffer);
    VIR_FREE(content);
2638 2639 2640
    sexpr_free(root);
    return ret;
}
2641

2642
int
2643
xenDaemonDomainMigratePrepare(virConnectPtr dconn ATTRIBUTE_UNUSED,
2644 2645 2646 2647 2648 2649 2650
                              char **cookie ATTRIBUTE_UNUSED,
                              int *cookielen ATTRIBUTE_UNUSED,
                              const char *uri_in,
                              char **uri_out,
                              unsigned long flags,
                              const char *dname ATTRIBUTE_UNUSED,
                              unsigned long resource ATTRIBUTE_UNUSED)
2651
{
E
Eric Blake 已提交
2652 2653
    virCheckFlags(XEN_MIGRATION_FLAGS, -1);

2654 2655 2656 2657 2658
    /* 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) {
2659
        *uri_out = virGetHostname();
2660
        if (*uri_out == NULL)
2661 2662 2663 2664 2665 2666 2667
            return -1;
    }

    return 0;
}

int
2668 2669 2670 2671 2672 2673 2674
xenDaemonDomainMigratePerform(virDomainPtr domain,
                              const char *cookie ATTRIBUTE_UNUSED,
                              int cookielen ATTRIBUTE_UNUSED,
                              const char *uri,
                              unsigned long flags,
                              const char *dname,
                              unsigned long bandwidth)
2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685
{
    /* 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;

2686 2687
    int undefined_source = 0;

E
Eric Blake 已提交
2688 2689
    virCheckFlags(XEN_MIGRATION_FLAGS, -1);

2690 2691
    /* Xen doesn't support renaming domains during migration. */
    if (dname) {
2692 2693 2694
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("xenDaemonDomainMigrate: Xen does not support"
                               " renaming domains during migration"));
2695 2696 2697 2698 2699 2700 2701
        return -1;
    }

    /* Xen (at least up to 3.1.0) takes a resource parameter but
     * ignores it.
     */
    if (bandwidth) {
2702 2703 2704
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("xenDaemonDomainMigrate: Xen does not support"
                               " bandwidth limits during migration"));
2705 2706 2707
        return -1;
    }

2708 2709 2710
    /*
     * Check the flags.
     */
2711
    if ((flags & VIR_MIGRATE_LIVE)) {
2712
        strcpy(live, "1");
2713 2714
        flags &= ~VIR_MIGRATE_LIVE;
    }
2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725

    /* 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;

2726 2727 2728 2729
    /* This is buggy in Xend, but could be supported in principle.  Give
     * a nice error message.
     */
    if (flags & VIR_MIGRATE_PAUSED) {
2730 2731
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("xenDaemonDomainMigrate: xend cannot migrate paused domains"));
2732 2733 2734
        return -1;
    }

2735 2736
    /* XXX we could easily do tunnelled & peer2peer migration too
       if we want to. support these... */
2737
    if (flags != 0) {
2738 2739
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("xenDaemonDomainMigrate: unsupported flag"));
2740 2741 2742 2743 2744 2745 2746 2747
        return -1;
    }

    /* Set hostname and port.
     *
     * URI is non-NULL (guaranteed by caller).  We expect either
     * "hostname", "hostname:port" or "xenmigr://hostname[:port]/".
     */
2748
    if (strstr(uri, "//")) {   /* Full URI. */
2749
        virURIPtr uriptr;
2750
        if (!(uriptr = virURIParse(uri)))
2751
            return -1;
2752

2753
        if (uriptr->scheme && STRCASENEQ(uriptr->scheme, "xenmigr")) {
2754 2755 2756
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("xenDaemonDomainMigrate: only xenmigr://"
                                   " migrations are supported by Xen"));
2757
            virURIFree(uriptr);
2758 2759 2760
            return -1;
        }
        if (!uriptr->server) {
2761 2762 2763
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("xenDaemonDomainMigrate: a hostname must be"
                                   " specified in the URI"));
2764
            virURIFree(uriptr);
2765 2766
            return -1;
        }
2767
        hostname = strdup(uriptr->server);
2768
        if (!hostname) {
2769
            virReportOOMError();
2770
            virURIFree(uriptr);
2771 2772 2773
            return -1;
        }
        if (uriptr->port)
2774 2775
            snprintf(port, sizeof(port), "%d", uriptr->port);
        virURIFree(uriptr);
2776
    }
2777
    else if ((p = strrchr(uri, ':')) != NULL) { /* "hostname:port" */
2778 2779
        int port_nr, n;

2780
        if (virStrToLong_i(p+1, NULL, 10, &port_nr) < 0) {
2781 2782
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("xenDaemonDomainMigrate: invalid port number"));
2783 2784
            return -1;
        }
2785
        snprintf(port, sizeof(port), "%d", port_nr);
2786 2787 2788

        /* Get the hostname. */
        n = p - uri; /* n = Length of hostname in bytes. */
2789
        hostname = strdup(uri);
2790
        if (!hostname) {
2791
            virReportOOMError();
2792 2793 2794 2795 2796
            return -1;
        }
        hostname[n] = '\0';
    }
    else {                      /* "hostname" (or IP address) */
2797
        hostname = strdup(uri);
2798
        if (!hostname) {
2799
            virReportOOMError();
2800 2801 2802 2803
            return -1;
        }
    }

2804
    VIR_DEBUG("hostname = %s, port = %s", hostname, port);
2805

J
Jim Fehlig 已提交
2806 2807 2808 2809 2810 2811
    /* 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.
     */
2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822
    ret = xend_op(domain->conn, domain->name,
                  "op", "migrate",
                  "destination", hostname,
                  "live", live,
                  "port", port,
                  "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 */
                  NULL);
    VIR_FREE(hostname);
2823

2824
    if (ret == 0 && undefined_source)
2825
        xenDaemonDomainUndefine(domain);
2826

2827
    VIR_DEBUG("migration done");
2828 2829 2830 2831

    return ret;
}

2832 2833 2834
virDomainPtr
xenDaemonDomainDefineXML(virConnectPtr conn, const char *xmlDesc)
{
2835 2836 2837
    int ret;
    char *sexpr;
    virDomainPtr dom;
2838
    xenUnifiedPrivatePtr priv = conn->privateData;
2839
    virDomainDefPtr def;
2840

2841 2842
    if (!(def = virDomainDefParseString(xmlDesc, priv->caps, priv->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_XEN,
2843
                                        VIR_DOMAIN_XML_INACTIVE))) {
2844 2845
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("failed to parse domain description"));
2846
        return NULL;
2847 2848
    }

M
Markus Groß 已提交
2849
    if (!(sexpr = xenFormatSxpr(conn, def, priv->xendConfigVersion))) {
2850 2851
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("failed to build sexpr"));
2852 2853 2854
        goto error;
    }

2855
    ret = xend_op(conn, "", "op", "new", "config", sexpr, NULL);
2856
    VIR_FREE(sexpr);
2857
    if (ret != 0) {
2858 2859
        virReportError(VIR_ERR_XEN_CALL,
                       _("Failed to create inactive domain %s"), def->name);
2860 2861 2862
        goto error;
    }

2863
    dom = virDomainLookupByName(conn, def->name);
2864 2865 2866
    if (dom == NULL) {
        goto error;
    }
2867
    virDomainDefFree(def);
2868
    return dom;
2869

2870
  error:
2871
    virDomainDefFree(def);
2872
    return NULL;
2873
}
2874 2875
int
xenDaemonDomainCreate(virDomainPtr domain)
2876
{
2877
    int ret;
2878

2879 2880
    ret = xend_op(domain->conn, domain->name, "op", "start", NULL);

2881 2882 2883 2884 2885
    if (ret == 0) {
        int id = xenDaemonDomainLookupByName_ids(domain->conn, domain->name,
                                                 domain->uuid);
        if (id > 0)
            domain->id = id;
2886
    }
2887

2888
    return ret;
2889 2890
}

2891 2892
int
xenDaemonDomainUndefine(virDomainPtr domain)
2893
{
2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904
    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
 */
2905
int
2906 2907 2908 2909 2910
xenDaemonNumOfDefinedDomains(virConnectPtr conn)
{
    struct sexpr *root = NULL;
    int ret = -1;
    struct sexpr *_for_i, *node;
2911

2912 2913 2914 2915 2916 2917
    root = sexpr_get(conn, "/xend/domain?state=halted");
    if (root == NULL)
        goto error;

    ret = 0;

2918
    /* coverity[copy_paste_error] */
2919 2920
    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) {
2921 2922 2923 2924 2925 2926
        if (node->kind != SEXPR_VALUE)
            continue;
        ret++;
    }

error:
2927
    sexpr_free(root);
2928
    return ret;
2929 2930
}

2931
int
2932 2933 2934 2935
xenDaemonListDefinedDomains(virConnectPtr conn,
                            char **const names,
                            int maxnames)
{
2936
    struct sexpr *root = NULL;
2937
    int i, ret = -1;
2938
    struct sexpr *_for_i, *node;
2939

2940
    if (maxnames == 0)
2941
        return 0;
2942

2943 2944 2945 2946 2947 2948
    root = sexpr_get(conn, "/xend/domain?state=halted");
    if (root == NULL)
        goto error;

    ret = 0;

2949
    /* coverity[copy_paste_error] */
2950 2951
    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) {
2952 2953 2954
        if (node->kind != SEXPR_VALUE)
            continue;

2955
        if ((names[ret++] = strdup(node->u.value)) == NULL) {
2956
            virReportOOMError();
2957 2958 2959
            goto error;
        }

2960 2961 2962 2963
        if (ret >= maxnames)
            break;
    }

2964 2965
cleanup:
    sexpr_free(root);
2966
    return ret;
2967

2968
error:
2969 2970 2971
    for (i = 0; i < ret; ++i)
        VIR_FREE(names[i]);

2972 2973 2974
    ret = -1;

    goto cleanup;
2975 2976
}

2977 2978 2979 2980 2981 2982 2983 2984 2985 2986
/**
 * 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
 */
2987
char *
2988 2989
xenDaemonGetSchedulerType(virDomainPtr domain, int *nparams)
{
2990
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
2991 2992 2993 2994 2995
    struct sexpr *root;
    const char *ret = NULL;
    char *schedulertype = NULL;

    /* Support only xendConfigVersion >=4 */
2996
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
2997 2998
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("unsupported in xendConfigVersion < 4"));
2999 3000 3001 3002 3003 3004 3005 3006 3007 3008
        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){
3009 3010
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("node information incomplete, missing scheduler name"));
3011 3012
        goto error;
    }
3013
    if (STREQ(ret, "credit")) {
3014 3015
        schedulertype = strdup("credit");
        if (schedulertype == NULL){
3016
            virReportOOMError();
3017 3018
            goto error;
        }
3019 3020
        if (nparams)
            *nparams = XEN_SCHED_CRED_NPARAM;
3021
    } else if (STREQ(ret, "sedf")) {
3022 3023
        schedulertype = strdup("sedf");
        if (schedulertype == NULL){
3024
            virReportOOMError();
3025 3026
            goto error;
        }
3027 3028
        if (nparams)
            *nparams = XEN_SCHED_SEDF_NPARAM;
3029
    } else {
3030
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051
        goto error;
    }

error:
    sexpr_free(root);
    return schedulertype;

}

/**
 * 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
 */
3052
int
3053
xenDaemonGetSchedulerParameters(virDomainPtr domain,
3054 3055
                                virTypedParameterPtr params,
                                int *nparams)
3056
{
3057
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
3058 3059 3060 3061 3062 3063
    struct sexpr *root;
    char *sched_type = NULL;
    int sched_nparam = 0;
    int ret = -1;

    /* Support only xendConfigVersion >=4 */
3064
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
3065 3066
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("unsupported in xendConfigVersion < 4"));
3067
        return -1;
3068 3069 3070 3071 3072
    }

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

    /* get the scheduler type */
    sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
    if (sched_type == NULL) {
3078 3079
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Failed to get a scheduler name"));
3080 3081 3082 3083 3084
        goto error;
    }

    switch (sched_nparam){
        case XEN_SCHED_SEDF_NPARAM:
3085
            if (*nparams < XEN_SCHED_SEDF_NPARAM) {
3086 3087
                virReportError(VIR_ERR_INVALID_ARG,
                               "%s", _("Invalid parameter count"));
3088 3089 3090
                goto error;
            }

3091 3092 3093 3094 3095 3096
            /* 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) {
3097 3098
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("domain information incomplete, missing cpu_weight"));
3099 3100 3101
                goto error;
            }
            if (sexpr_node(root, "domain/cpu_cap") == NULL) {
3102 3103
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("domain information incomplete, missing cpu_cap"));
3104 3105 3106
                goto error;
            }

3107 3108
            if (virStrcpyStatic(params[0].field,
                                VIR_DOMAIN_SCHEDULER_WEIGHT) == NULL) {
3109 3110 3111
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Weight %s too big for destination"),
                               VIR_DOMAIN_SCHEDULER_WEIGHT);
C
Chris Lalancette 已提交
3112 3113
                goto error;
            }
3114
            params[0].type = VIR_TYPED_PARAM_UINT;
3115 3116
            params[0].value.ui = sexpr_int(root, "domain/cpu_weight");

3117 3118 3119
            if (*nparams > 1) {
                if (virStrcpyStatic(params[1].field,
                                    VIR_DOMAIN_SCHEDULER_CAP) == NULL) {
3120 3121 3122
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Cap %s too big for destination"),
                                   VIR_DOMAIN_SCHEDULER_CAP);
3123 3124 3125 3126
                    goto error;
                }
                params[1].type = VIR_TYPED_PARAM_UINT;
                params[1].value.ui = sexpr_int(root, "domain/cpu_cap");
C
Chris Lalancette 已提交
3127
            }
3128 3129 3130

            if (*nparams > XEN_SCHED_CRED_NPARAM)
                *nparams = XEN_SCHED_CRED_NPARAM;
3131 3132 3133
            ret = 0;
            break;
        default:
3134
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
3135 3136 3137 3138 3139
            goto error;
    }

error:
    sexpr_free(root);
3140
    VIR_FREE(sched_type);
3141
    return ret;
3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153
}

/**
 * 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
 */
3154
int
3155
xenDaemonSetSchedulerParameters(virDomainPtr domain,
3156 3157
                                virTypedParameterPtr params,
                                int nparams)
3158
{
3159
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
3160 3161 3162 3163 3164 3165 3166
    struct sexpr *root;
    char *sched_type = NULL;
    int i;
    int sched_nparam = 0;
    int ret = -1;

    /* Support only xendConfigVersion >=4 and active domains */
3167
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
3168 3169
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("unsupported in xendConfigVersion < 4"));
3170
        return -1;
3171 3172 3173 3174 3175
    }

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

    /* get the scheduler type */
    sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
    if (sched_type == NULL) {
3181 3182
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Failed to get a scheduler name"));
3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200
        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++) {
3201
                if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_WEIGHT) &&
3202
                    params[i].type == VIR_TYPED_PARAM_UINT) {
3203
                    snprintf(buf_weight, sizeof(buf_weight), "%u", params[i].value.ui);
3204
                } else if (STREQ(params[i].field, VIR_DOMAIN_SCHEDULER_CAP) &&
3205
                    params[i].type == VIR_TYPED_PARAM_UINT) {
3206 3207
                    snprintf(buf_cap, sizeof(buf_cap), "%u", params[i].value.ui);
                } else {
3208
                    virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3209 3210 3211 3212 3213 3214 3215 3216
                    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) {
3217 3218
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("domain information incomplete, missing cpu_weight"));
3219 3220 3221 3222 3223 3224 3225
                    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) {
3226 3227
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("domain information incomplete, missing cpu_cap"));
3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238
                    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:
3239
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
3240 3241 3242 3243 3244
            goto error;
    }

error:
    sexpr_free(root);
3245
    VIR_FREE(sched_type);
3246
    return ret;
3247 3248
}

R
Richard W.M. Jones 已提交
3249 3250
/**
 * xenDaemonDomainBlockPeek:
P
Philipp Hahn 已提交
3251
 * @domain: domain object
R
Richard W.M. Jones 已提交
3252 3253 3254 3255 3256
 * @path: path to the file or device
 * @offset: offset
 * @size: size
 * @buffer: return buffer
 *
3257
 * Returns 0 if successful, -1 if error
R
Richard W.M. Jones 已提交
3258 3259
 */
int
3260 3261 3262 3263
xenDaemonDomainBlockPeek(virDomainPtr domain,
                         const char *path,
                         unsigned long long offset,
                         size_t size,
3264
                         void *buffer)
R
Richard W.M. Jones 已提交
3265
{
3266
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
3267 3268 3269
    struct sexpr *root = NULL;
    int fd = -1, ret = -1;
    virDomainDefPtr def;
3270 3271 3272
    int id;
    char * tty;
    int vncport;
3273
    const char *actual;
R
Richard W.M. Jones 已提交
3274 3275 3276

    /* Security check: The path must correspond to a block device. */
    if (domain->id > 0)
3277 3278
        root = sexpr_get(domain->conn, "/xend/domain/%d?detail=1",
                         domain->id);
R
Richard W.M. Jones 已提交
3279
    else if (domain->id < 0)
3280 3281
        root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1",
                         domain->name);
R
Richard W.M. Jones 已提交
3282 3283
    else {
        /* This call always fails for dom0. */
3284 3285
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domainBlockPeek is not supported for dom0"));
R
Richard W.M. Jones 已提交
3286 3287 3288 3289
        return -1;
    }

    if (!root) {
3290
        virReportError(VIR_ERR_XEN_CALL, __FUNCTION__);
R
Richard W.M. Jones 已提交
3291 3292 3293
        return -1;
    }

3294 3295 3296 3297 3298 3299
    id = xenGetDomIdFromSxpr(root, priv->xendConfigVersion);
    xenUnifiedLock(priv);
    tty = xenStoreDomainGetConsolePath(domain->conn, id);
    vncport = xenStoreDomainGetVNCPort(domain->conn, id);
    xenUnifiedUnlock(priv);

M
Markus Groß 已提交
3300 3301
    if (!(def = xenParseSxpr(root, priv->xendConfigVersion, NULL, tty,
                             vncport)))
3302
        goto cleanup;
R
Richard W.M. Jones 已提交
3303

3304
    if (!(actual = virDomainDiskPathByName(def, path))) {
3305 3306
        virReportError(VIR_ERR_INVALID_ARG,
                       _("%s: invalid path"), path);
3307
        goto cleanup;
R
Richard W.M. Jones 已提交
3308
    }
3309
    path = actual;
R
Richard W.M. Jones 已提交
3310 3311

    /* The path is correct, now try to open it and get its size. */
3312
    fd = open(path, O_RDONLY);
3313
    if (fd == -1) {
3314
        virReportSystemError(errno,
3315 3316
                             _("failed to open for reading: %s"),
                             path);
3317
        goto cleanup;
R
Richard W.M. Jones 已提交
3318 3319 3320 3321 3322 3323
    }

    /* Seek and read. */
    /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
     * be 64 bits on all platforms.
     */
3324 3325
    if (lseek(fd, offset, SEEK_SET) == (off_t) -1 ||
        saferead(fd, buffer, size) == (ssize_t) -1) {
3326
        virReportSystemError(errno,
3327 3328
                             _("failed to lseek or read from file: %s"),
                             path);
3329
        goto cleanup;
R
Richard W.M. Jones 已提交
3330 3331 3332
    }

    ret = 0;
3333
 cleanup:
3334
    VIR_FORCE_CLOSE(fd);
3335 3336
    sexpr_free(root);
    virDomainDefFree(def);
R
Richard W.M. Jones 已提交
3337 3338 3339
    return ret;
}

3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351

/**
 * 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.
3352 3353
 *  - if pci, get BDF from description, scan XenStore and
 *    copy in ref the corresponding dev number.
3354 3355 3356 3357 3358 3359 3360 3361 3362 3363
 *
 * 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 已提交
3364
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
3365
    char *xref;
C
Chris Lalancette 已提交
3366
    char *tmp;
3367 3368

    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
3369 3370 3371
        if (dev->data.disk->driverName &&
            STREQ(dev->data.disk->driverName, "tap"))
            strcpy(class, "tap");
J
Jim Fehlig 已提交
3372 3373 3374
        else if (dev->data.disk->driverName &&
            STREQ(dev->data.disk->driverName, "tap2"))
            strcpy(class, "tap2");
3375 3376 3377
        else
            strcpy(class, "vbd");

3378 3379
        if (dev->data.disk->dst == NULL)
            return -1;
D
Daniel P. Berrange 已提交
3380
        xenUnifiedLock(priv);
3381 3382
        xref = xenStoreDomainGetDiskID(domain->conn, domain->id,
                                       dev->data.disk->dst);
D
Daniel P. Berrange 已提交
3383
        xenUnifiedUnlock(priv);
3384 3385 3386
        if (xref == NULL)
            return -1;

C
Chris Lalancette 已提交
3387
        tmp = virStrcpy(ref, xref, ref_len);
3388
        VIR_FREE(xref);
C
Chris Lalancette 已提交
3389 3390
        if (tmp == NULL)
            return -1;
3391
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
3392
        char mac[VIR_MAC_STRING_BUFLEN];
3393
        virDomainNetDefPtr def = dev->data.net;
3394
        virMacAddrFormat(&def->mac, mac);
3395 3396 3397

        strcpy(class, "vif");

D
Daniel P. Berrange 已提交
3398
        xenUnifiedLock(priv);
3399
        xref = xenStoreDomainGetNetworkID(domain->conn, domain->id, mac);
D
Daniel P. Berrange 已提交
3400
        xenUnifiedUnlock(priv);
3401 3402 3403
        if (xref == NULL)
            return -1;

C
Chris Lalancette 已提交
3404
        tmp = virStrcpy(ref, xref, ref_len);
3405
        VIR_FREE(xref);
C
Chris Lalancette 已提交
3406 3407
        if (tmp == NULL)
            return -1;
3408 3409 3410
    } 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) {
3411 3412 3413 3414
        char *bdf;
        virDomainHostdevDefPtr def = dev->data.hostdev;

        if (virAsprintf(&bdf, "%04x:%02x:%02x.%0x",
3415 3416 3417 3418
                        def->source.subsys.u.pci.addr.domain,
                        def->source.subsys.u.pci.addr.bus,
                        def->source.subsys.u.pci.addr.slot,
                        def->source.subsys.u.pci.addr.function) < 0) {
3419
            virReportOOMError();
3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435
            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;
3436
    } else {
3437 3438
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("hotplug of device type not supported"));
3439 3440 3441 3442 3443
        return -1;
    }

    return 0;
}