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

12
#include <config.h>
13

14 15 16 17 18
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/errno.h>
R
Richard W.M. Jones 已提交
19 20
#include <sys/stat.h>
#include <fcntl.h>
21 22 23 24 25 26 27 28 29
#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>
30
#include <errno.h>
31

32
#include "virterror_internal.h"
33
#include "logging.h"
34
#include "datatypes.h"
35
#include "xend_internal.h"
36
#include "driver.h"
37
#include "util.h"
38
#include "sexpr.h"
39
#include "xen_sxpr.h"
40
#include "buf.h"
41
#include "uuid.h"
42 43
#include "xen_driver.h"
#include "xen_hypervisor.h"
44
#include "xs_internal.h" /* To extract VNC port & Serial console TTY */
45
#include "memory.h"
46
#include "count-one-bits.h"
E
Eric Blake 已提交
47
#include "virfile.h"
M
Martin Kletzander 已提交
48
#include "viruri.h"
49
#include "device_conf.h"
50

51 52 53
/* required for cpumap_t */
#include <xen/dom0_ops.h>

54 55
#define VIR_FROM_THIS VIR_FROM_XEND

56 57 58
/*
 * The number of Xen scheduler parameters
 */
59

60
#define XEND_RCV_BUF_MAX_LEN (256 * 1024)
D
Daniel Veillard 已提交
61

62
static int
63 64 65 66 67 68
virDomainXMLDevID(virDomainPtr domain,
                  virDomainDeviceDefPtr dev,
                  char *class,
                  char *ref,
                  int ref_len);

69 70 71 72 73 74 75 76 77
/**
 * 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
78
do_connect(virConnectPtr xend)
79 80
{
    int s;
81
    int no_slow_start = 1;
82
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) xend->privateData;
83

84
    s = socket(priv->addrfamily, SOCK_STREAM, priv->addrprotocol);
D
Daniel Veillard 已提交
85
    if (s == -1) {
86 87
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("failed to create a socket"));
88
        return -1;
D
Daniel Veillard 已提交
89
    }
90

91 92 93 94 95 96 97
    /*
     * try to desactivate slow-start
     */
    setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
               sizeof(no_slow_start));


98
    if (connect(s, (struct sockaddr *)&priv->addr, priv->addrlen) == -1) {
99
        VIR_FORCE_CLOSE(s); /* preserves errno */
100 101

        /*
J
John Levon 已提交
102 103
         * Connecting to XenD when privileged is mandatory, so log this
         * error
104
         */
J
John Levon 已提交
105
        if (xenHavePrivilege()) {
106 107
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("failed to connect to xend"));
108
        }
109 110 111 112 113 114 115
    }

    return s;
}

/**
 * wr_sync:
116
 * @xend: the xend connection object
117 118 119 120 121 122 123 124 125 126
 * @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
127
wr_sync(int fd, void *buffer, size_t size, int do_read)
128 129 130 131 132 133 134
{
    size_t offset = 0;

    while (offset < size) {
        ssize_t len;

        if (do_read) {
135
            len = read(fd, ((char *) buffer) + offset, size - offset);
136
        } else {
137
            len = write(fd, ((char *) buffer) + offset, size - offset);
138 139 140 141 142 143 144 145 146 147 148 149 150 151
        }

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

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

        /* unrecoverable error */
        if (len == -1) {
152
            if (do_read)
153 154
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("failed to read from Xen Daemon"));
155
            else
156 157
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("failed to write to Xen Daemon"));
158

159
            return -1;
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
        }

        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
179
sread(int fd, void *buffer, size_t size)
180
{
181
    return wr_sync(fd, buffer, size, 1);
182 183 184 185 186 187 188 189 190 191 192 193 194
}

/**
 * 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
195
swrite(int fd, const void *buffer, size_t size)
196
{
197
    return wr_sync(fd, (void *) buffer, size, 0);
198 199 200 201 202 203 204 205 206 207 208 209
}

/**
 * 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
210
swrites(int fd, const char *string)
211
{
212
    return swrite(fd, string, strlen(string));
213 214
}

215 216 217 218 219 220 221 222 223 224 225
/**
 * 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
226
sreads(int fd, char *buffer, size_t n_buffer)
227 228 229 230
{
    size_t offset;

    if (n_buffer < 1)
231
        return -1;
232 233 234 235

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

236
        ret = sread(fd, buffer + offset, 1);
237 238 239 240 241 242 243 244 245 246 247 248 249 250
        if (ret == 0)
            break;
        else if (ret == -1)
            return ret;

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

    return offset;
}
251 252 253 254

static int
istartswith(const char *haystack, const char *needle)
{
255
    return STRCASEEQLEN(haystack, needle, strlen(needle));
256 257
}

258

259 260 261 262 263 264
/**
 * xend_req:
 * @fd: the file descriptor
 * @content: the buffer to store the content
 *
 * Read the HTTP response from a Xen Daemon request.
265 266
 * If the response contains content, memory is allocated to
 * hold the content.
267
 *
268 269
 * Returns the HTTP return code and @content is set to the
 * allocated memory containing HTTP content.
270
 */
J
Jim Fehlig 已提交
271
static int ATTRIBUTE_NONNULL (2)
272
xend_req(int fd, char **content)
273
{
274 275
    char *buffer;
    size_t buffer_size = 4096;
276
    int content_length = 0;
277 278
    int retcode = 0;

279 280 281 282 283 284
    if (VIR_ALLOC_N(buffer, buffer_size) < 0) {
        virReportOOMError();
        return -1;
    }

    while (sreads(fd, buffer, buffer_size) > 0) {
285
        if (STREQ(buffer, "\r\n"))
286
            break;
287 288 289 290 291

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

294 295
    VIR_FREE(buffer);

296
    if (content_length > 0) {
297 298
        ssize_t ret;

J
Jim Fehlig 已提交
299
        if (content_length > XEND_RCV_BUF_MAX_LEN) {
300 301 302 303 304
            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 已提交
305 306 307 308 309 310 311
            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. */
        if (VIR_ALLOC_N(*content, content_length + 1) < 0 ) {
312 313 314
            virReportOOMError();
            return -1;
        }
315

316
        ret = sread(fd, *content, content_length);
317 318
        if (ret < 0)
            return -1;
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
    }

    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 已提交
334
static int ATTRIBUTE_NONNULL(3)
335
xend_get(virConnectPtr xend, const char *path,
336
         char **content)
337 338 339 340 341 342 343
{
    int ret;
    int s = do_connect(xend);

    if (s == -1)
        return s;

344 345 346
    swrites(s, "GET ");
    swrites(s, path);
    swrites(s, " HTTP/1.1\r\n");
347

348
    swrites(s,
349 350 351 352
            "Host: localhost:8000\r\n"
            "Accept-Encoding: identity\r\n"
            "Content-Type: application/x-www-form-urlencoded\r\n" "\r\n");

353
    ret = xend_req(s, content);
354
    VIR_FORCE_CLOSE(s);
355

356 357 358 359
    if (ret < 0)
        return ret;

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

365 366 367 368 369 370 371
    return ret;
}

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

    if (s == -1)
        return s;

390 391 392
    swrites(s, "POST ");
    swrites(s, path);
    swrites(s, " HTTP/1.1\r\n");
393

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

404
    ret = xend_req(s, &err_buf);
405
    VIR_FORCE_CLOSE(s);
406

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

425
    VIR_FREE(err_buf);
426 427
    return ret;
}
428

429 430 431 432 433 434 435 436 437 438

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

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

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

P
Philipp Hahn 已提交
485 486 487
        virBufferURIEncodeString(&buf, k);
        virBufferAddChar(&buf, '=');
        virBufferURIEncodeString(&buf, v);
488 489 490
        k = va_arg(ap, const char *);

        if (k)
491
            virBufferAddChar(&buf, '&');
492 493
    }

494
    if (virBufferError(&buf)) {
495
        virBufferFreeAndReset(&buf);
496
        virReportOOMError();
497 498 499 500
        return -1;
    }

    content = virBufferContentAndReset(&buf);
501
    VIR_DEBUG("xend op: %s\n", content);
502
    ret = http2unix(xend_post(xend, path, content));
503
    VIR_FREE(content);
504 505

    return ret;
506 507
}

508

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

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

    va_start(ap, key);
532
    ret = xend_op_ext(xend, buffer, key, ap);
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
    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
 */
549
static struct sexpr *sexpr_get(virConnectPtr xend, const char *fmt, ...)
550
  ATTRIBUTE_FMT_PRINTF(2,3);
551

552
static struct sexpr *
553
sexpr_get(virConnectPtr xend, const char *fmt, ...)
554
{
555
    char *buffer = NULL;
556 557 558
    char path[1024];
    va_list ap;
    int ret;
559
    struct sexpr *res = NULL;
560 561 562 563 564

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

565
    ret = xend_get(xend, path, &buffer);
566
    ret = http2unix(ret);
567
    if (ret == -1)
568 569 570 571 572 573
        goto cleanup;

    if (buffer == NULL)
        goto cleanup;

    res = string2sexpr(buffer);
574

575 576 577
cleanup:
    VIR_FREE(buffer);
    return res;
578 579 580 581 582 583 584 585 586 587
}

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

/* PUBLIC FUNCTIONS */

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

617
    if ((conn == NULL) || (path == NULL))
618
        return -1;
619

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

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

636
    return 0;
637 638
}

639

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

660
    if ((conn == NULL) || (host == NULL) || (port == NULL))
661
        return -1;
662

663 664
    priv = (xenUnifiedPrivatePtr) conn->privateData;

665 666 667
    priv->addrlen = 0;
    memset(&priv->addr, 0, sizeof(priv->addr));

668
    /* http://people.redhat.com/drepper/userapi-ipv6.html */
669
    memset (&hints, 0, sizeof(hints));
670 671 672 673 674
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_ADDRCONFIG;

    ret = getaddrinfo (host, port, &hints, &res);
    if (ret != 0) {
675 676 677
        virReportError(VIR_ERR_UNKNOWN_HOST,
                       _("unable to resolve hostname '%s': %s"),
                       host, gai_strerror (ret));
678 679 680 681 682 683 684 685 686 687 688
        return -1;
    }

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

        sock = socket (r->ai_family, SOCK_STREAM, r->ai_protocol);
        if (sock == -1) {
            saved_errno = errno;
            continue;
689
        }
690 691 692

        if (connect (sock, r->ai_addr, r->ai_addrlen) == -1) {
            saved_errno = errno;
693
            VIR_FORCE_CLOSE(sock);
694 695 696 697 698 699 700 701 702
            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);
703
        VIR_FORCE_CLOSE(sock);
704
        break;
705 706
    }

707
    freeaddrinfo (res);
708

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

718
    return 0;
719 720
}

721

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

738

739
/**
740
 * xenDaemonListDomainsOld:
P
Philipp Hahn 已提交
741
 * @xend: pointer to the Xen Daemon block
742 743 744 745 746 747
 *
 * 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.
 */
748
char **
749
xenDaemonListDomainsOld(virConnectPtr xend)
750 751 752 753 754 755 756 757 758 759 760
{
    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;

761 762
    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) {
763 764 765 766 767
        if (node->kind != SEXPR_VALUE)
            continue;
        count++;
    }

E
Eric Blake 已提交
768 769
    if (VIR_ALLOC_N(ret, count + 1) < 0) {
        virReportOOMError();
770
        goto error;
E
Eric Blake 已提交
771
    }
772 773

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

    ret[i] = NULL;

  error:
    sexpr_free(root);
    return ret;
E
Eric Blake 已提交
789 790 791 792 793 794

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

797

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

int
813
xenDaemonDomainCreateXML(virConnectPtr xend, const char *sexpr)
814
{
P
Philipp Hahn 已提交
815
    int ret;
816

P
Philipp Hahn 已提交
817
    ret = xend_op(xend, "", "op", "create", "config", sexpr, NULL);
818 819 820

    return ret;
}
821

822

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

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

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

865
  error:
866
    sexpr_free(root);
867
    return ret;
868 869
}

870 871 872 873 874 875 876 877 878 879 880 881 882 883

/**
 * xenDaemonDomainLookupByID:
 * @xend: A xend instance
 * @id: The id of the domain
 * @name: return value for the name if not NULL
 * @uuid: return value for the UUID if not NULL
 *
 * This method looks up the name of a domain based on its id
 *
 * Returns the 0 on success; -1 (with errno) on error
 */
int
xenDaemonDomainLookupByID(virConnectPtr xend,
884 885 886
                          int id,
                          char **domname,
                          unsigned char *uuid)
887 888 889 890
{
    const char *name = NULL;
    struct sexpr *root;

891
    memset(uuid, 0, VIR_UUID_BUFLEN);
892 893 894 895 896 897 898

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

    name = sexpr_node(root, "domain/name");
    if (name == NULL) {
899 900
      virReportError(VIR_ERR_INTERNAL_ERROR,
                     "%s", _("domain information incomplete, missing name"));
901 902
      goto error;
    }
903
    if (domname) {
904
      *domname = strdup(name);
905
      if (*domname == NULL) {
906
          virReportOOMError();
907 908 909
          goto error;
      }
    }
910

911
    if (sexpr_uuid(uuid, root, "domain/uuid") < 0) {
912 913
      virReportError(VIR_ERR_INTERNAL_ERROR,
                     "%s", _("domain information incomplete, missing uuid"));
914 915 916 917
      goto error;
    }

    sexpr_free(root);
918
    return 0;
919 920 921

error:
    sexpr_free(root);
922 923
    if (domname)
        VIR_FREE(*domname);
924
    return -1;
925 926
}

927

928 929
static int
xend_detect_config_version(virConnectPtr conn) {
930 931
    struct sexpr *root;
    const char *value;
932
    xenUnifiedPrivatePtr priv;
933 934

    if (!VIR_IS_CONNECT(conn)) {
935
        virReportError(VIR_ERR_INVALID_CONN, __FUNCTION__);
936
        return -1;
937 938
    }

939 940
    priv = (xenUnifiedPrivatePtr) conn->privateData;

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

945
    value = sexpr_node(root, "node/xend_config_format");
946

947
    if (value) {
948
        priv->xendConfigVersion = strtol(value, NULL, 10);
949 950 951
    }  else {
        /* Xen prior to 3.0.3 did not have the xend_config_format
           field, and is implicitly version 1. */
952
        priv->xendConfigVersion = XEND_CONFIG_VERSION_3_0_2;
953
    }
954
    sexpr_free(root);
955
    return 0;
956 957
}

D
Daniel Veillard 已提交
958

959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986
/**
 * 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)
sexpr_to_xend_domain_state(virDomainPtr domain, const struct sexpr *root)
{
    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;
987 988 989 990 991 992 993 994
    } else if (domain->id < 0 || sexpr_int(root, "domain/status") == 0) {
        /* 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)
         */
995 996 997 998 999 1000
        state = VIR_DOMAIN_SHUTOFF;
    }

    return state;
}

D
Daniel Veillard 已提交
1001
/**
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
 * 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
1012 1013
sexpr_to_xend_domain_info(virDomainPtr domain, const struct sexpr *root,
                          virDomainInfoPtr info)
1014
{
1015
    int vcpus;
1016 1017

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

1020
    info->state = sexpr_to_xend_domain_state(domain, root);
1021 1022 1023
    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;
1024

1025
    vcpus = sexpr_int(root, "domain/vcpus");
1026
    info->nrVirtCpu = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail"));
1027 1028 1029
    if (!info->nrVirtCpu || vcpus < info->nrVirtCpu)
        info->nrVirtCpu = vcpus;

1030
    return 0;
1031 1032
}

1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
/**
 * 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
1044
sexpr_to_xend_node_info(const struct sexpr *root, virNodeInfoPtr info)
1045 1046 1047 1048 1049
{
    const char *machine;


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

    machine = sexpr_node(root, "node/machine");
1053
    if (machine == NULL) {
1054
        info->model[0] = 0;
1055
    } else {
1056
        snprintf(&info->model[0], sizeof(info->model) - 1, "%s", machine);
1057
        info->model[sizeof(info->model) - 1] = 0;
1058 1059 1060 1061 1062 1063 1064
    }
    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");
1065 1066 1067
    info->cores = sexpr_int(root, "node/cores_per_socket");
    info->threads = sexpr_int(root, "node/threads_per_core");

1068 1069 1070 1071 1072 1073 1074
    /* 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");
1075 1076
        int procs = info->nodes * info->cores * info->threads;
        if (procs == 0) /* Sanity check in case of Xen bugs in futures..*/
1077
            return -1;
1078
        info->sockets = nr_cpus / procs;
1079
    }
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093

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

1094
    return 0;
1095 1096
}

1097

1098
/**
1099
 * sexpr_to_xend_topology
1100
 * @root: an S-Expression describing a node
1101
 * @caps: capability info
1102
 *
1103 1104
 * Internal routine populating capability info with
 * NUMA node mapping details
1105
 *
1106 1107
 * Does nothing when the system doesn't support NUMA (not an error).
 *
1108 1109
 * Returns 0 in case of success, -1 in case of error
 */
1110
static int
1111
sexpr_to_xend_topology(const struct sexpr *root,
1112
                       virCapsPtr caps)
1113 1114
{
    const char *nodeToCpu;
1115 1116 1117 1118 1119
    const char *cur;
    char *cpuset = NULL;
    int *cpuNums = NULL;
    int cell, cpu, nb_cpus;
    int n = 0;
1120 1121 1122
    int numCpus;

    nodeToCpu = sexpr_node(root, "node/node_to_cpu");
1123 1124
    if (nodeToCpu == NULL)
        return 0;               /* no NUMA support */
1125 1126 1127

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

1128

1129
    if (VIR_ALLOC_N(cpuset, numCpus) < 0)
1130
        goto memory_error;
1131
    if (VIR_ALLOC_N(cpuNums, numCpus) < 0)
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
        goto memory_error;

    cur = nodeToCpu;
    while (*cur != 0) {
        /*
         * Find the next NUMA cell described in the xend output
         */
        cur = strstr(cur, "node");
        if (cur == NULL)
            break;
        cur += 4;
        cell = virParseNumber(&cur);
        if (cell < 0)
            goto parse_error;
E
Eric Blake 已提交
1146
        virSkipSpacesAndBackslash(&cur);
1147 1148 1149
        if (*cur != ':')
            goto parse_error;
        cur++;
E
Eric Blake 已提交
1150
        virSkipSpacesAndBackslash(&cur);
1151
        if (STRPREFIX(cur, "no cpus")) {
1152 1153 1154 1155
            nb_cpus = 0;
            for (cpu = 0; cpu < numCpus; cpu++)
                cpuset[cpu] = 0;
        } else {
1156
            nb_cpus = virDomainCpuSetParse(cur, 'n', cpuset, numCpus);
1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
            if (nb_cpus < 0)
                goto error;
        }

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

        if (virCapabilitiesAddHostNUMACell(caps,
                                           cell,
                                           nb_cpus,
                                           cpuNums) < 0)
            goto memory_error;
    }
1171 1172
    VIR_FREE(cpuNums);
    VIR_FREE(cpuset);
1173
    return 0;
1174

1175
  parse_error:
1176
    virReportError(VIR_ERR_XEN_CALL, "%s", _("topology syntax error"));
1177
  error:
1178 1179
    VIR_FREE(cpuNums);
    VIR_FREE(cpuset);
1180

1181
    return -1;
1182

1183
  memory_error:
1184 1185
    VIR_FREE(cpuNums);
    VIR_FREE(cpuset);
1186
    virReportOOMError();
1187
    return -1;
1188 1189
}

1190

1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
/**
 * sexpr_to_domain:
 * @conn: an existing virtual connection block
 * @root: an S-Expression describing a domain
 *
 * Internal routine returning the associated virDomainPtr for this domain
 *
 * Returns the domain pointer or NULL in case of error.
 */
static virDomainPtr
1201
sexpr_to_domain(virConnectPtr conn, const struct sexpr *root)
1202
{
1203
    virDomainPtr ret = NULL;
1204
    unsigned char uuid[VIR_UUID_BUFLEN];
1205
    const char *name;
1206
    const char *tmp;
1207
    xenUnifiedPrivatePtr priv;
1208 1209

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

1212 1213
    priv = (xenUnifiedPrivatePtr) conn->privateData;

1214
    if (sexpr_uuid(uuid, root, "domain/uuid") < 0)
1215 1216 1217 1218 1219
        goto error;
    name = sexpr_node(root, "domain/name");
    if (name == NULL)
        goto error;

1220
    ret = virGetDomain(conn, name, uuid);
1221 1222
    if (ret == NULL) return NULL;

1223 1224 1225 1226
    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
     */
1227
    if (!tmp && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
1228 1229
        goto error;

1230
    if (tmp)
1231
        ret->id = sexpr_int(root, "domain/domid");
1232
    else
1233
        ret->id = -1; /* An inactive domain */
1234

1235
    return ret;
1236

1237
error:
1238 1239
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   "%s", _("failed to parse Xend domain information"));
1240
    virObjectUnref(ret);
1241
    return NULL;
1242
}
1243

1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265

/*****************************************************************
 ******
 ******
 ******
 ******
             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.
 */
1266
virDrvOpenStatus
1267 1268
xenDaemonOpen(virConnectPtr conn,
              virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
1269
              unsigned int flags)
1270
{
1271 1272
    char *port = NULL;
    int ret = VIR_DRV_OPEN_ERROR;
1273

E
Eric Blake 已提交
1274 1275
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1276 1277
    /* Switch on the scheme, which we expect to be NULL (file),
     * "http" or "xen".
1278
     */
1279
    if (conn->uri->scheme == NULL) {
1280
        /* It should be a file access */
1281
        if (conn->uri->path == NULL) {
1282
            virReportError(VIR_ERR_NO_CONNECT, __FUNCTION__);
1283 1284
            goto failed;
        }
1285 1286
        if (xenDaemonOpen_unix(conn, conn->uri->path) < 0 ||
            xend_detect_config_version(conn) == -1)
1287 1288
            goto failed;
    }
1289
    else if (STRCASEEQ (conn->uri->scheme, "xen")) {
1290
        /*
1291 1292
         * try first to open the unix socket
         */
1293 1294
        if (xenDaemonOpen_unix(conn, "/var/lib/xend/xend-socket") == 0 &&
            xend_detect_config_version(conn) != -1)
1295 1296 1297 1298 1299
            goto done;

        /*
         * try though http on port 8000
         */
1300 1301
        if (xenDaemonOpen_tcp(conn, "localhost", "8000") < 0 ||
            xend_detect_config_version(conn) == -1)
1302
            goto failed;
1303
    } else if (STRCASEEQ (conn->uri->scheme, "http")) {
1304
        if (conn->uri->port &&
1305
            virAsprintf(&port, "%d", conn->uri->port) == -1) {
1306
            virReportOOMError();
1307
            goto failed;
1308
        }
1309

1310 1311 1312
        if (xenDaemonOpen_tcp(conn,
                              conn->uri->server ? conn->uri->server : "localhost",
                              port ? port : "8000") < 0 ||
1313
            xend_detect_config_version(conn) == -1)
1314
            goto failed;
1315
    } else {
1316
        virReportError(VIR_ERR_NO_CONNECT, __FUNCTION__);
1317
        goto failed;
1318
    }
1319

1320
 done:
1321
    ret = VIR_DRV_OPEN_SUCCESS;
1322

1323
failed:
1324 1325
    VIR_FREE(port);
    return ret;
1326
}
1327

1328 1329 1330 1331 1332 1333 1334 1335 1336

/**
 * 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.
 *
1337
 * Returns 0 in case of success, -1 in case of error
1338 1339 1340 1341
 */
int
xenDaemonClose(virConnectPtr conn ATTRIBUTE_UNUSED)
{
1342
    return 0;
1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357
}

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

    if (domain->id < 0) {
1363 1364
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain %s isn't running."), domain->name);
1365
        return -1;
1366 1367
    }

1368 1369 1370 1371 1372
    return xend_op(domain->conn, domain->name, "op", "pause", NULL);
}

/**
 * xenDaemonDomainResume:
P
Philipp Hahn 已提交
1373
 * @xend: pointer to the Xen Daemon block
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
 * @name: name for the domain
 *
 * Resume the domain after xenDaemonDomainSuspend() has been called
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
xenDaemonDomainResume(virDomainPtr domain)
{
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
1384
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1385
        return -1;
1386
    }
1387 1388

    if (domain->id < 0) {
1389 1390
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain %s isn't running."), domain->name);
1391
        return -1;
1392 1393
    }

1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
    return xend_op(domain->conn, domain->name, "op", "unpause", NULL);
}

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

    if (domain->id < 0) {
1416 1417
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain %s isn't running."), domain->name);
1418
        return -1;
1419 1420
    }

1421
    return xend_op(domain->conn, domain->name, "op", "shutdown", "reason", "poweroff", NULL);
1422 1423
}

1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435
/**
 * xenDaemonDomainReboot:
 * @domain: pointer to the Domain block
 * @flags: extra flags for the reboot operation, not used yet
 *
 * Reboot the domain, the OS is requested to properly shutdown
 * and restart but the domain may ignore it.  It will return immediately
 * after queuing the request.
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
E
Eric Blake 已提交
1436
xenDaemonDomainReboot(virDomainPtr domain, unsigned int flags)
1437
{
E
Eric Blake 已提交
1438 1439
    virCheckFlags(0, -1);

1440
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
1441
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1442
        return -1;
1443
    }
1444 1445

    if (domain->id < 0) {
1446 1447
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain %s isn't running."), domain->name);
1448
        return -1;
1449 1450
    }

1451 1452 1453
    return xend_op(domain->conn, domain->name, "op", "shutdown", "reason", "reboot", NULL);
}

1454
/**
1455
 * xenDaemonDomainDestroyFlags:
1456
 * @domain: pointer to the Domain block
1457
 * @flags: an OR'ed set of virDomainDestroyFlagsValues
1458 1459 1460 1461 1462 1463 1464 1465
 *
 * 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).
 *
1466 1467 1468
 * Calling this function with no @flags set (equal to zero)
 * is equivalent to calling xenDaemonDomainDestroy.
 *
1469 1470 1471
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
1472 1473
xenDaemonDomainDestroyFlags(virDomainPtr domain,
                            unsigned int flags)
1474
{
1475 1476
    virCheckFlags(0, -1);

1477
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
1478
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1479
        return -1;
1480
    }
1481 1482

    if (domain->id < 0) {
1483 1484
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain %s isn't running."), domain->name);
1485
        return -1;
1486 1487
    }

1488 1489 1490
    return xend_op(domain->conn, domain->name, "op", "destroy", NULL);
}

1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507
/**
 * xenDaemonDomainGetOSType:
 * @domain: a domain object
 *
 * Get the type of domain operation system.
 *
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
static char *
xenDaemonDomainGetOSType(virDomainPtr domain)
{
    char *type;
    struct sexpr *root;
    xenUnifiedPrivatePtr priv;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
1508
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1509
        return NULL;
1510 1511 1512 1513
    }

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

1514
    if (domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
1515
        return NULL;
1516 1517 1518 1519

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

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

1528
    if (type == NULL)
1529
        virReportOOMError();
1530

1531 1532
    sexpr_free(root);

1533
    return type;
1534 1535
}

1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552
/**
 * xenDaemonDomainSave:
 * @domain: pointer to the Domain block
 * @filename: path for the output file
 *
 * This method will suspend a domain and save its memory contents to
 * a file on disk.  Use xenDaemonDomainRestore() to restore a domain after
 * saving.
 * Note that for remote Xen Daemon the file path will be interpreted in
 * the remote host.
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
xenDaemonDomainSave(virDomainPtr domain, const char *filename)
{
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
1553
        (filename == NULL)) {
1554
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1555
        return -1;
1556
    }
1557

1558
    if (domain->id < 0) {
1559 1560
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain %s isn't running."), domain->name);
1561
        return -1;
1562
    }
1563 1564 1565

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

1569 1570 1571
    return xend_op(domain->conn, domain->name, "op", "save", "file", filename, NULL);
}

D
Daniel Veillard 已提交
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583
/**
 * 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.
 */
1584
int
D
Daniel Veillard 已提交
1585
xenDaemonDomainCoreDump(virDomainPtr domain, const char *filename,
E
Eric Blake 已提交
1586
                        unsigned int flags)
D
Daniel Veillard 已提交
1587
{
E
Eric Blake 已提交
1588 1589
    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH, -1);

D
Daniel Veillard 已提交
1590 1591
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        (filename == NULL)) {
1592
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1593
        return -1;
D
Daniel Veillard 已提交
1594
    }
1595 1596

    if (domain->id < 0) {
1597 1598
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain %s isn't running."), domain->name);
1599
        return -1;
1600 1601
    }

1602
    return xend_op(domain->conn, domain->name,
J
Jiri Denemark 已提交
1603
                   "op", "dump", "file", filename,
P
Paolo Bonzini 已提交
1604
                   "live", (flags & VIR_DUMP_LIVE ? "1" : "0"),
1605 1606
                   "crash", (flags & VIR_DUMP_CRASH ? "1" : "0"),
                   NULL);
D
Daniel Veillard 已提交
1607 1608
}

1609 1610
/**
 * xenDaemonDomainRestore:
P
Philipp Hahn 已提交
1611
 * @conn: pointer to the Xen Daemon block
1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624
 * @filename: path for the output file
 *
 * This method will restore a domain saved to disk by xenDaemonDomainSave().
 * Note that for remote Xen Daemon the file path will be interpreted in
 * the remote host.
 *
 * Returns 0 in case of success, -1 (with errno) in case of error.
 */
int
xenDaemonDomainRestore(virConnectPtr conn, const char *filename)
{
    if ((conn == NULL) || (filename == NULL)) {
        /* this should be caught at the interface but ... */
1625
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1626
        return -1;
1627 1628 1629
    }
    return xend_op(conn, "", "op", "restore", "file", filename, NULL);
}
1630

1631

1632 1633 1634 1635 1636 1637 1638 1639
/**
 * 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.
 */
1640
unsigned long long
1641 1642
xenDaemonDomainGetMaxMemory(virDomainPtr domain)
{
1643
    unsigned long long ret = 0;
1644
    struct sexpr *root;
1645
    xenUnifiedPrivatePtr priv;
1646 1647

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
1648
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1649
        return 0;
1650
    }
1651 1652 1653

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

1654
    if (domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
1655
        return 0;
1656 1657 1658 1659

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

1662
    ret = sexpr_u64(root, "domain/memory") << 10;
1663 1664
    sexpr_free(root);

1665
    return ret;
1666 1667
}

1668

1669 1670 1671 1672 1673 1674 1675
/**
 * 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
1676
 * on its own.
1677 1678 1679 1680 1681 1682 1683
 *
 * Returns 0 for success; -1 (with errno) on error
 */
int
xenDaemonDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
{
    char buf[1024];
1684
    xenUnifiedPrivatePtr priv;
1685 1686

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
1687
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1688
        return -1;
1689
    }
1690 1691 1692

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

1693
    if (domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
1694
        return -1;
1695

1696
    snprintf(buf, sizeof(buf), "%lu", VIR_DIV_UP(memory, 1024));
1697 1698 1699 1700
    return xend_op(domain->conn, domain->name, "op", "maxmem_set", "memory",
                   buf, NULL);
}

1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720
/**
 * xenDaemonDomainSetMemory:
 * @domain: pointer to the Domain block
 * @memory: The target memory in kilobytes
 *
 * This method will set a target memory allocation for a given domain and
 * request that the guest meet this target.  The guest may or may not actually
 * achieve this target.  When this function returns, it does not signify that
 * the domain has actually reached that target.
 *
 * Memory for a domain can only be allocated up to the maximum memory setting.
 * There is no safe guard for allocations that are too small so be careful
 * when using this function to reduce a domain's memory usage.
 *
 * Returns 0 for success; -1 (with errno) on error
 */
int
xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory)
{
    char buf[1024];
1721
    xenUnifiedPrivatePtr priv;
1722 1723

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
1724
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1725
        return -1;
1726
    }
1727 1728 1729

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

1730
    if (domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
1731
        return -1;
1732

1733
    snprintf(buf, sizeof(buf), "%lu", VIR_DIV_UP(memory, 1024));
1734 1735 1736 1737
    return xend_op(domain->conn, domain->name, "op", "mem_target_set",
                   "target", buf, NULL);
}

1738

1739 1740 1741 1742 1743
virDomainDefPtr
xenDaemonDomainFetch(virConnectPtr conn,
                     int domid,
                     const char *name,
                     const char *cpus)
1744 1745
{
    struct sexpr *root;
1746
    xenUnifiedPrivatePtr priv;
1747
    virDomainDefPtr def;
1748 1749 1750
    int id;
    char * tty;
    int vncport;
1751

1752 1753 1754 1755
    if (name)
        root = sexpr_get(conn, "/xend/domain/%s?detail=1", name);
    else
        root = sexpr_get(conn, "/xend/domain/%d?detail=1", domid);
1756
    if (root == NULL)
1757
        return NULL;
1758

1759 1760
    priv = (xenUnifiedPrivatePtr) conn->privateData;

1761 1762
    id = xenGetDomIdFromSxpr(root, priv->xendConfigVersion);
    xenUnifiedLock(priv);
1763 1764 1765 1766
    if (sexpr_lookup(root, "domain/image/hvm"))
        tty = xenStoreDomainGetSerialConsolePath(conn, id);
    else
        tty = xenStoreDomainGetConsolePath(conn, id);
1767 1768
    vncport = xenStoreDomainGetVNCPort(conn, id);
    xenUnifiedUnlock(priv);
M
Markus Groß 已提交
1769 1770 1771 1772 1773
    if (!(def = xenParseSxpr(root,
                             priv->xendConfigVersion,
                             cpus,
                             tty,
                             vncport)))
1774 1775 1776
        goto cleanup;

cleanup:
1777 1778
    sexpr_free(root);

1779
    return def;
1780 1781 1782
}


1783
/**
1784
 * xenDaemonDomainGetXMLDesc:
D
Daniel Veillard 已提交
1785
 * @domain: a domain object
1786 1787
 * @flags: potential dump flags
 * @cpus: list of cpu the domain is pinned to.
D
Daniel Veillard 已提交
1788
 *
1789
 * Provide an XML description of the domain.
D
Daniel Veillard 已提交
1790 1791 1792 1793 1794
 *
 * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
 *         the caller must free() the returned value.
 */
char *
E
Eric Blake 已提交
1795 1796
xenDaemonDomainGetXMLDesc(virDomainPtr domain, unsigned int flags,
                          const char *cpus)
1797
{
1798
    xenUnifiedPrivatePtr priv;
1799 1800
    virDomainDefPtr def;
    char *xml;
1801

E
Eric Blake 已提交
1802 1803
    /* Flags checked by virDomainDefFormat */

1804
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
1805
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1806
        return NULL;
1807
    }
1808 1809
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;

1810
    if (domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
1811
        /* fall-through to the next driver to handle */
1812
        return NULL;
1813 1814
    }

1815 1816 1817 1818
    if (!(def = xenDaemonDomainFetch(domain->conn,
                                     domain->id,
                                     domain->name,
                                     cpus)))
1819
        return NULL;
1820

1821
    xml = virDomainDefFormat(def, flags);
1822 1823 1824 1825

    virDomainDefFree(def);

    return xml;
D
Daniel Veillard 已提交
1826
}
1827

1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843

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

1846 1847
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL) ||
        (info == NULL)) {
1848
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1849
        return -1;
1850
    }
1851 1852 1853

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

1854
    if (domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
1855
        return -1;
1856 1857 1858

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

1861
    ret = sexpr_to_xend_domain_info(domain, root, info);
1862
    sexpr_free(root);
1863
    return ret;
1864
}
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881


/**
 * xenDaemonDomainGetState:
 * @domain: a domain object
 * @state: returned domain's state
 * @reason: returned reason for the state
 * @flags: additional flags, 0 for now
 *
 * This method looks up domain state and reason.
 *
 * Returns 0 in case of success, -1 in case of error
 */
int
xenDaemonDomainGetState(virDomainPtr domain,
                        int *state,
                        int *reason,
E
Eric Blake 已提交
1882
                        unsigned int flags)
1883 1884 1885 1886
{
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
    struct sexpr *root;

E
Eric Blake 已提交
1887 1888
    virCheckFlags(0, -1);

1889
    if (domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902
        return -1;

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

    *state = sexpr_to_xend_domain_state(domain, root);
    if (reason)
        *reason = 0;

    sexpr_free(root);
    return 0;
}
1903

1904

1905
/**
1906
 * xenDaemonLookupByName:
1907 1908 1909 1910 1911 1912 1913 1914 1915 1916
 * @conn: A xend instance
 * @name: The name of the domain
 *
 * This method looks up information about a domain and returns
 * it in the form of a struct xend_domain.  This should be
 * free()'d when no longer needed.
 *
 * Returns domain info on success; NULL (with errno) on error
 */
virDomainPtr
1917
xenDaemonLookupByName(virConnectPtr conn, const char *domname)
1918 1919 1920 1921 1922
{
    struct sexpr *root;
    virDomainPtr ret = NULL;

    if ((conn == NULL) || (domname == NULL)) {
1923
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1924
        return NULL;
1925
    }
1926

1927 1928 1929 1930 1931 1932 1933 1934
    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);
1935
    return ret;
1936
}
1937

1938

1939 1940 1941 1942
/**
 * xenDaemonNodeGetInfo:
 * @conn: pointer to the Xen Daemon block
 * @info: pointer to a virNodeInfo structure allocated by the user
1943
 *
1944 1945 1946 1947
 * Extract hardware information about the node.
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
1948
int
1949 1950 1951 1952 1953
xenDaemonNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) {
    int ret = -1;
    struct sexpr *root;

    if (!VIR_IS_CONNECT(conn)) {
1954
        virReportError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1955
        return -1;
1956 1957
    }
    if (info == NULL) {
1958
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1959
        return -1;
1960 1961 1962 1963
    }

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

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

1971 1972 1973
/**
 * xenDaemonNodeGetTopology:
 * @conn: pointer to the Xen Daemon block
1974
 * @caps: capabilities info
1975 1976 1977 1978 1979 1980
 *
 * This method retrieves a node's topology information.
 *
 * Returns -1 in case of error, 0 otherwise.
 */
int
1981 1982
xenDaemonNodeGetTopology(virConnectPtr conn,
                         virCapsPtr caps) {
1983 1984 1985 1986
    int ret = -1;
    struct sexpr *root;

    if (!VIR_IS_CONNECT(conn)) {
1987
        virReportError(VIR_ERR_INVALID_CONN, __FUNCTION__);
1988
        return -1;
1989 1990
    }

1991
    if (caps == NULL) {
1992
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
1993
        return -1;
1994
    }
1995 1996 1997

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

2001
    ret = sexpr_to_xend_topology(root, caps);
2002
    sexpr_free(root);
2003
    return ret;
2004 2005
}

2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016
/**
 * xenDaemonGetVersion:
 * @conn: pointer to the Xen Daemon block
 * @hvVer: return value for the version of the running hypervisor (OUT)
 *
 * Get the version level of the Hypervisor running.
 *
 * Returns -1 in case of error, 0 otherwise. if the version can't be
 *    extracted by lack of capacities returns 0 and @hvVer is 0, otherwise
 *    @hvVer value is major * 1,000,000 + minor * 1,000 + release
 */
2017
int
2018 2019
xenDaemonGetVersion(virConnectPtr conn, unsigned long *hvVer)
{
2020
    struct sexpr *root;
2021
    int major, minor;
2022
    unsigned long version;
2023

2024
    if (!VIR_IS_CONNECT(conn)) {
2025
        virReportError(VIR_ERR_INVALID_CONN, __FUNCTION__);
2026
        return -1;
2027 2028
    }
    if (hvVer == NULL) {
2029
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2030
        return -1;
2031
    }
2032 2033
    root = sexpr_get(conn, "/xend/node/");
    if (root == NULL)
2034
        return -1;
2035 2036 2037 2038

    major = sexpr_int(root, "node/xen_major");
    minor = sexpr_int(root, "node/xen_minor");
    sexpr_free(root);
2039
    version = major * 1000000 + minor * 1000;
2040
    *hvVer = version;
2041
    return 0;
2042
}
2043

2044

2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056
/**
 * xenDaemonListDomains:
 * @conn: pointer to the hypervisor connection
 * @ids: array to collect the list of IDs of active domains
 * @maxids: size of @ids
 *
 * Collect the list of active domains, and store their ID in @maxids
 * TODO: this is quite expensive at the moment since there isn't one
 *       xend RPC providing both name and id for all domains.
 *
 * Returns the number of domain found or -1 in case of error
 */
2057
int
2058 2059 2060 2061 2062 2063 2064
xenDaemonListDomains(virConnectPtr conn, int *ids, int maxids)
{
    struct sexpr *root = NULL;
    int ret = -1;
    struct sexpr *_for_i, *node;
    long id;

2065
    if (maxids == 0)
2066
        return 0;
2067 2068

    if ((ids == NULL) || (maxids < 0))
2069 2070 2071 2072 2073 2074 2075
        goto error;
    root = sexpr_get(conn, "/xend/domain");
    if (root == NULL)
        goto error;

    ret = 0;

2076 2077
    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) {
2078 2079
        if (node->kind != SEXPR_VALUE)
            continue;
2080
        id = xenDaemonDomainLookupByName_ids(conn, node->u.value, NULL);
2081
        if (id >= 0)
2082 2083 2084
            ids[ret++] = (int) id;
        if (ret >= maxids)
            break;
2085 2086 2087
    }

error:
2088
    sexpr_free(root);
2089
    return ret;
2090 2091 2092 2093 2094 2095 2096 2097 2098 2099
}

/**
 * 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
 */
2100
int
2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112
xenDaemonNumOfDomains(virConnectPtr conn)
{
    struct sexpr *root = NULL;
    int ret = -1;
    struct sexpr *_for_i, *node;

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

    ret = 0;

2113 2114
    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) {
2115 2116
        if (node->kind != SEXPR_VALUE)
            continue;
2117
        ret++;
2118 2119 2120
    }

error:
2121
    sexpr_free(root);
2122
    return ret;
2123
}
2124

2125

2126 2127 2128 2129 2130 2131 2132 2133 2134
/**
 * xenDaemonLookupByID:
 * @conn: pointer to the hypervisor connection
 * @id: the domain ID number
 *
 * Try to find a domain based on the hypervisor ID number
 *
 * Returns a new domain object or NULL in case of failure
 */
2135
virDomainPtr
2136 2137
xenDaemonLookupByID(virConnectPtr conn, int id) {
    char *name = NULL;
2138
    unsigned char uuid[VIR_UUID_BUFLEN];
2139 2140
    virDomainPtr ret;

2141
    if (xenDaemonDomainLookupByID(conn, id, &name, uuid) < 0) {
2142
        goto error;
2143
    }
2144 2145

    ret = virGetDomain(conn, name, uuid);
2146
    if (ret == NULL) goto error;
2147

2148
    ret->id = id;
2149
    VIR_FREE(name);
2150
    return ret;
2151

2152
 error:
2153
    VIR_FREE(name);
2154
    return NULL;
2155 2156
}

2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175
/**
 * 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.
 *
 * Returns 0 on success, -1 if an error message was issued, and -2 if
 * the unified driver should keep trying.
 */
int
xenDaemonDomainSetVcpusFlags(virDomainPtr domain, unsigned int vcpus,
                             unsigned int flags)
{
    char buf[VIR_UUID_BUFLEN];
    xenUnifiedPrivatePtr priv;
    int max;

E
Eric Blake 已提交
2176 2177 2178 2179
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

2180 2181
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
        || (vcpus < 1)) {
2182
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2183
        return -1;
2184 2185 2186 2187
    }

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

2188
    if ((domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) ||
2189 2190 2191 2192 2193 2194
        (flags & VIR_DOMAIN_VCPU_MAXIMUM))
        return -2;

    /* With xendConfigVersion 2, only _LIVE is supported.  With
     * xendConfigVersion 3, only _LIVE|_CONFIG is supported for
     * running domains, or _CONFIG for inactive domains.  */
2195
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
2196
        if (flags & VIR_DOMAIN_VCPU_CONFIG) {
2197 2198 2199
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend version does not support modifying "
                             "persistent config"));
2200 2201 2202 2203
            return -1;
        }
    } else if (domain->id < 0) {
        if (flags & VIR_DOMAIN_VCPU_LIVE) {
2204 2205
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("domain not running"));
2206 2207 2208 2209 2210
            return -1;
        }
    } else {
        if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) !=
            (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) {
2211 2212 2213
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend only supports modifying both live and "
                             "persistent config"));
2214 2215 2216 2217 2218 2219 2220
        }
    }

    /* Unfortunately, xend_op does not validate whether this exceeds
     * the maximum.  */
    flags |= VIR_DOMAIN_VCPU_MAXIMUM;
    if ((max = xenDaemonDomainGetVcpusFlags(domain, flags)) < 0) {
2221 2222
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("could not determine max vcpus for the domain"));
2223 2224 2225
        return -1;
    }
    if (vcpus > max) {
2226 2227 2228
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), vcpus, max);
2229 2230 2231 2232 2233 2234 2235 2236
        return -1;
    }

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

2237 2238 2239 2240 2241 2242
/**
 * 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
2243
 *
2244
 * Dynamically change the real CPUs which can be allocated to a virtual CPU.
2245 2246 2247 2248 2249
 * 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
2250 2251 2252 2253 2254
 *
 * Returns 0 for success; -1 (with errno) on error
 */
int
xenDaemonDomainPinVcpu(virDomainPtr domain, unsigned int vcpu,
2255
                       unsigned char *cpumap, int maplen)
2256
{
2257
    char buf[VIR_UUID_BUFLEN], mapstr[sizeof(cpumap_t) * 64];
2258
    int i, j, ret;
2259
    xenUnifiedPrivatePtr priv;
2260
    virDomainDefPtr def = NULL;
2261 2262 2263

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
     || (cpumap == NULL) || (maplen < 1) || (maplen > (int)sizeof(cpumap_t))) {
2264
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2265
        return -1;
2266
    }
2267

2268
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
2269
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
H
Henrik Persson 已提交
2270 2271
        mapstr[0] = '[';
        mapstr[1] = 0;
2272
    } else {
H
Henrik Persson 已提交
2273
        mapstr[0] = 0;
2274 2275
    }

2276 2277 2278
    /* 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)) {
2279
        snprintf(buf, sizeof(buf), "%d,", (8 * i) + j);
2280 2281
        strcat(mapstr, buf);
    }
2282
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
2283 2284 2285 2286
        mapstr[strlen(mapstr) - 1] = ']';
    else
        mapstr[strlen(mapstr) - 1] = 0;

2287
    snprintf(buf, sizeof(buf), "%d", vcpu);
2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298

    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 已提交
2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310
        if (!def->cputune.vcpupin) {
            if (VIR_ALLOC(def->cputune.vcpupin) < 0) {
                virReportOOMError();
                goto cleanup;
            }
            def->cputune.nvcpupin = 0;
        }
        if (virDomainVcpuPinAdd(def->cputune.vcpupin,
                                &def->cputune.nvcpupin,
                                cpumap,
                                maplen,
                                vcpu) < 0) {
2311 2312
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("failed to add vcpupin xml entry"));
2313
            return -1;
2314 2315 2316 2317 2318 2319 2320 2321
        }
    }

    return ret;

cleanup:
    virDomainDefFree(def);
    return -1;
2322 2323
}

2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341
/**
 * 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
 * issued, and -2 if the unified driver should keep trying.

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

E
Eric Blake 已提交
2342 2343 2344 2345
    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

2346
    if (domain == NULL || domain->conn == NULL || domain->name == NULL) {
2347
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2348 2349 2350 2351 2352 2353 2354 2355
        return -1;
    }

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

    /* If xendConfigVersion is 2, then we can only report _LIVE (and
     * xm_internal reports _CONFIG).  If it is 3, then _LIVE and
     * _CONFIG are always in sync for a running system.  */
2356
    if (domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
2357 2358
        return -2;
    if (domain->id < 0 && (flags & VIR_DOMAIN_VCPU_LIVE)) {
2359 2360
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain not active"));
2361 2362 2363 2364 2365 2366 2367 2368 2369
        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)) {
2370
        int vcpus = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail"));
2371 2372 2373 2374 2375 2376 2377 2378 2379
        if (vcpus)
            ret = MIN(vcpus, ret);
    }
    if (!ret)
        ret = -2;
    sexpr_free(root);
    return ret;
}

2380 2381 2382 2383 2384
/**
 * 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 已提交
2385
 * @cpumaps: pointer to a bit map of real CPUs for all vcpus of this domain (in 8-bit bytes) (OUT)
D
Daniel Veillard 已提交
2386
 *	If cpumaps is NULL, then no cpumap information is returned by the API.
2387 2388 2389 2390 2391 2392
 *	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...).
2393
 *
2394
 * Extract information about virtual CPUs of domain, store it in info array
D
Daniel Veillard 已提交
2395
 * and also in cpumaps if this pointer isn't NULL.
2396 2397 2398 2399 2400
 *
 * Returns the number of info filled in case of success, -1 in case of failure.
 */
int
xenDaemonDomainGetVcpus(virDomainPtr domain, virVcpuInfoPtr info, int maxinfo,
2401
                        unsigned char *cpumaps, int maplen)
2402 2403 2404 2405 2406 2407 2408 2409
{
    struct sexpr *root, *s, *t;
    virVcpuInfoPtr ipt = info;
    int nbinfo = 0, oln;
    unsigned char *cpumap;
    int vcpu, cpu;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)
2410
        || (info == NULL) || (maxinfo < 1)) {
2411
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2412
        return -1;
2413 2414
    }
    if (cpumaps != NULL && maplen < 1) {
2415
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2416
        return -1;
2417
    }
2418

2419 2420
    root = sexpr_get(domain->conn, "/xend/domain/%s?op=vcpuinfo", domain->name);
    if (root == NULL)
2421
        return -1;
2422 2423

    if (cpumaps != NULL)
2424
        memset(cpumaps, 0, maxinfo * maplen);
2425 2426

    /* scan the sexprs from "(vcpu (number x)...)" and get parameter values */
2427 2428 2429
    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) &&
2430
            STREQ(s->u.s.car->u.s.car->u.value, "vcpu")) {
2431
            t = s->u.s.car;
2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447
            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
                 */
2448 2449 2450
                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) &&
2451
                        STREQ(t->u.s.car->u.s.car->u.value, "cpumap") &&
2452 2453
                        (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)
2454
                            if (t->u.s.car->kind == SEXPR_VALUE
2455
                                && virStrToLong_i(t->u.s.car->u.value, NULL, 10, &cpu) == 0
2456 2457 2458
                                && cpu >= 0
                                && (VIR_CPU_MAPLEN(cpu+1) <= maplen)) {
                                VIR_USE_CPU(cpumap, cpu);
2459 2460 2461
                            }
                        break;
                    }
2462 2463
            }

2464 2465 2466
            if (++nbinfo == maxinfo) break;
            ipt++;
        }
2467 2468
    }
    sexpr_free(root);
2469
    return nbinfo;
2470 2471
}

2472 2473 2474 2475 2476 2477 2478 2479 2480
/**
 * xenDaemonLookupByUUID:
 * @conn: pointer to the hypervisor connection
 * @uuid: the raw UUID for the domain
 *
 * Try to lookup a domain on xend based on its UUID.
 *
 * Returns a new domain object or NULL in case of failure
 */
2481
virDomainPtr
2482 2483 2484 2485 2486
xenDaemonLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
    virDomainPtr ret;
    char *name = NULL;
    int id = -1;
2487 2488
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;

2489
    /* Old approach for xen <= 3.0.3 */
2490
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
2491 2492 2493 2494 2495 2496
        char **names, **tmp;
        unsigned char ident[VIR_UUID_BUFLEN];
        names = xenDaemonListDomainsOld(conn);
        tmp = names;

        if (names == NULL) {
2497
            return NULL;
2498 2499 2500 2501 2502
        }
        while (*tmp != NULL) {
            id = xenDaemonDomainLookupByName_ids(conn, *tmp, &ident[0]);
            if (id >= 0) {
                if (!memcmp(uuid, ident, VIR_UUID_BUFLEN)) {
E
Eric Blake 已提交
2503
                    name = *tmp;
2504 2505
                    break;
                }
2506
            }
2507
            tmp++;
2508
        }
E
Eric Blake 已提交
2509 2510 2511 2512 2513 2514
        tmp = names;
        while (*tmp) {
            if (*tmp != name)
                VIR_FREE(*tmp);
            tmp++;
        }
2515
        VIR_FREE(names);
2516 2517 2518 2519 2520
    } else { /* New approach for xen >= 3.0.4 */
        char *domname = NULL;
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        struct sexpr *root = NULL;

2521
        virUUIDFormat(uuid, uuidstr);
2522 2523
        root = sexpr_get(conn, "/xend/domain/%s?detail=1", uuidstr);
        if (root == NULL)
2524
            return NULL;
2525 2526 2527 2528 2529
        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;
2530 2531 2532 2533 2534

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

            if (name == NULL)
2535
                virReportOOMError();
2536 2537
        }

2538
        sexpr_free(root);
2539 2540 2541
    }

    if (name == NULL)
2542
        return NULL;
2543 2544

    ret = virGetDomain(conn, name, uuid);
2545
    if (ret == NULL) goto cleanup;
2546

2547
    ret->id = id;
2548 2549

  cleanup:
2550
    VIR_FREE(name);
2551
    return ret;
2552
}
2553 2554

/**
2555
 * xenDaemonCreateXML:
2556 2557 2558 2559 2560 2561
 * @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()
2562
 * This function may requires privileged access to the hypervisor.
2563
 *
2564 2565
 * Returns a new domain object or NULL in case of failure
 */
2566
virDomainPtr
2567
xenDaemonCreateXML(virConnectPtr conn, const char *xmlDesc,
2568
                     unsigned int flags)
2569 2570 2571
{
    int ret;
    char *sexpr;
2572
    virDomainPtr dom = NULL;
2573
    xenUnifiedPrivatePtr priv;
2574
    virDomainDefPtr def;
2575

2576 2577
    virCheckFlags(0, NULL);

2578 2579
    priv = (xenUnifiedPrivatePtr) conn->privateData;

M
Matthias Bolte 已提交
2580 2581
    if (!(def = virDomainDefParseString(priv->caps, xmlDesc,
                                        1 << VIR_DOMAIN_VIRT_XEN,
2582
                                        VIR_DOMAIN_XML_INACTIVE)))
2583
        return NULL;
2584

M
Markus Groß 已提交
2585
    if (!(sexpr = xenFormatSxpr(conn, def, priv->xendConfigVersion))) {
2586
        virDomainDefFree(def);
2587
        return NULL;
2588 2589
    }

2590
    ret = xenDaemonDomainCreateXML(conn, sexpr);
2591
    VIR_FREE(sexpr);
2592 2593 2594 2595
    if (ret != 0) {
        goto error;
    }

2596 2597
    /* This comes before wait_for_devices, to ensure that latter
       cleanup will destroy the domain upon failure */
2598
    if (!(dom = virDomainLookupByName(conn, def->name)))
2599 2600
        goto error;

2601
    if (xend_wait_for_devices(conn, def->name) < 0)
2602 2603
        goto error;

2604
    if (xenDaemonDomainResume(dom) < 0)
2605 2606
        goto error;

2607
    virDomainDefFree(def);
2608
    return dom;
2609

2610
  error:
2611 2612
    /* Make sure we don't leave a still-born domain around */
    if (dom != NULL) {
2613
        xenDaemonDomainDestroyFlags(dom, 0);
2614
        virObjectUnref(dom);
2615
    }
2616
    virDomainDefFree(def);
2617
    return NULL;
2618
}
2619 2620

/**
2621
 * xenDaemonAttachDeviceFlags:
2622 2623
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
2624
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
2625
 *
2626 2627 2628 2629 2630 2631
 * Create a virtual device attachment to backend.
 * XML description is translated into S-expression.
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
2632 2633
xenDaemonAttachDeviceFlags(virDomainPtr domain, const char *xml,
                           unsigned int flags)
2634
{
2635
    xenUnifiedPrivatePtr priv;
2636 2637 2638 2639 2640
    char *sexpr = NULL;
    int ret = -1;
    virDomainDeviceDefPtr dev = NULL;
    virDomainDefPtr def = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2641
    char class[8], ref[80];
2642
    char *target = NULL;
2643

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

2646
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
2647
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2648
        return -1;
2649
    }
2650

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

2653
    if (domain->id < 0) {
2654 2655
        /* Cannot modify live config if domain is inactive */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
2656 2657
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Cannot modify live config if domain is inactive"));
2658 2659
            return -1;
        }
2660
        /* If xendConfigVersion < 3 only live config can be changed */
2661
        if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
2662 2663
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend version does not support modifying "
2664
                           "persistent config"));
2665 2666 2667 2668
            return -1;
        }
    } else {
        /* Only live config can be changed if xendConfigVersion < 3 */
2669
        if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4 &&
E
Eric Blake 已提交
2670
            (flags != VIR_DOMAIN_DEVICE_MODIFY_CURRENT &&
2671
             flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) {
2672 2673 2674
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend version does not support modifying "
                             "persistent config"));
2675 2676
            return -1;
        }
2677
        /* Xen only supports modifying both live and persistent config if
2678 2679
         * xendConfigVersion >= 3
         */
2680
        if (priv->xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4 &&
2681 2682
            (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                       VIR_DOMAIN_DEVICE_MODIFY_CONFIG))) {
2683 2684 2685
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend only supports modifying both live and "
                             "persistent config"));
2686 2687 2688
            return -1;
        }
    }
2689

2690 2691 2692 2693 2694 2695
    if (!(def = xenDaemonDomainFetch(domain->conn,
                                     domain->id,
                                     domain->name,
                                     NULL)))
        goto cleanup;

2696
    if (!(dev = virDomainDeviceDefParse(priv->caps,
G
Guido Günther 已提交
2697
                                        def, xml, VIR_DOMAIN_XML_INACTIVE)))
2698 2699 2700 2701 2702
        goto cleanup;


    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
2703 2704 2705 2706
        if (xenFormatSxprDisk(dev->data.disk,
                              &buf,
                              STREQ(def->os.type, "hvm") ? 1 : 0,
                              priv->xendConfigVersion, 1) < 0)
2707
            goto cleanup;
2708 2709 2710 2711 2712 2713 2714

        if (dev->data.disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
            if (!(target = strdup(dev->data.disk->dst))) {
                virReportOOMError();
                goto cleanup;
            }
        }
2715
        break;
2716 2717

    case VIR_DOMAIN_DEVICE_NET:
M
Markus Groß 已提交
2718 2719 2720 2721 2722
        if (xenFormatSxprNet(domain->conn,
                             dev->data.net,
                             &buf,
                             STREQ(def->os.type, "hvm") ? 1 : 0,
                             priv->xendConfigVersion, 1) < 0)
2723
            goto cleanup;
2724 2725

        char macStr[VIR_MAC_STRING_BUFLEN];
2726
        virMacAddrFormat(&dev->data.net->mac, macStr);
2727 2728 2729 2730 2731

        if (!(target = strdup(macStr))) {
            virReportOOMError();
            goto cleanup;
        }
2732
        break;
2733

2734 2735 2736
    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ß 已提交
2737
            if (xenFormatSxprOnePCI(dev->data.hostdev, &buf, 0) < 0)
2738
                goto cleanup;
2739

2740
            virDevicePCIAddress PCIAddr;
2741 2742 2743 2744 2745 2746 2747 2748 2749

            PCIAddr = dev->data.hostdev->source.subsys.u.pci;
            virAsprintf(&target, "PCI device: %.4x:%.2x:%.2x", PCIAddr.domain,
                                 PCIAddr.bus, PCIAddr.slot);

            if (target == NULL) {
                virReportOOMError();
                goto cleanup;
            }
2750
        } else {
2751 2752
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("unsupported device type"));
2753 2754 2755 2756
            goto cleanup;
        }
        break;

2757
    default:
2758 2759
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("unsupported device type"));
2760
        goto cleanup;
2761
    }
2762 2763 2764 2765

    sexpr = virBufferContentAndReset(&buf);

    if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref))) {
2766 2767
        /* device doesn't exist, define it */
        ret = xend_op(domain->conn, domain->name, "op", "device_create",
2768
                      "config", sexpr, NULL);
2769 2770
    } else {
        if (dev->data.disk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
2771 2772
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("target '%s' already exists"), target);
2773 2774 2775 2776 2777
        } else {
            /* device exists, attempt to modify it */
            ret = xend_op(domain->conn, domain->name, "op", "device_configure",
                          "config", sexpr, "dev", ref, NULL);
        }
2778
    }
2779 2780

cleanup:
2781
    VIR_FREE(sexpr);
2782 2783
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
2784
    VIR_FREE(target);
2785 2786 2787
    return ret;
}

2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798
/**
 * 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.
 */
2799
int
2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810
xenDaemonUpdateDeviceFlags(virDomainPtr domain, const char *xml,
                           unsigned int flags)
{
    xenUnifiedPrivatePtr priv;
    char *sexpr = NULL;
    int ret = -1;
    virDomainDeviceDefPtr dev = NULL;
    virDomainDefPtr def = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char class[8], ref[80];

E
Eric Blake 已提交
2811
    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
2812 2813
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

2814
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
2815
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2816 2817 2818 2819 2820 2821
        return -1;
    }

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

    if (domain->id < 0) {
2822 2823
        /* Cannot modify live config if domain is inactive */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
2824 2825
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Cannot modify live config if domain is inactive"));
2826 2827
            return -1;
        }
2828
        /* If xendConfigVersion < 3 only live config can be changed */
2829
        if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
2830 2831
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend version does not support modifying "
2832 2833 2834 2835 2836
                           "persistent config"));
            return -1;
        }
    } else {
        /* Only live config can be changed if xendConfigVersion < 3 */
2837
        if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4 &&
E
Eric Blake 已提交
2838
            (flags != VIR_DOMAIN_DEVICE_MODIFY_CURRENT &&
2839
             flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) {
2840 2841 2842
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend version does not support modifying "
                             "persistent config"));
2843 2844 2845 2846 2847
            return -1;
        }
        /* Xen only supports modifying both live and persistent config if
         * xendConfigVersion >= 3
         */
2848
        if (priv->xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4 &&
2849 2850
            (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                       VIR_DOMAIN_DEVICE_MODIFY_CONFIG))) {
2851 2852 2853
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend only supports modifying both live and "
                             "persistent config"));
2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870
            return -1;
        }
    }

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

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


    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
2871
        if (xenFormatSxprDisk(dev->data.disk,
M
Markus Groß 已提交
2872 2873 2874
                              &buf,
                              STREQ(def->os.type, "hvm") ? 1 : 0,
                              priv->xendConfigVersion, 1) < 0)
2875 2876 2877 2878
            goto cleanup;
        break;

    default:
2879 2880
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("unsupported device type"));
2881 2882 2883 2884 2885 2886
        goto cleanup;
    }

    sexpr = virBufferContentAndReset(&buf);

    if (virDomainXMLDevID(domain, dev, class, ref, sizeof(ref))) {
2887 2888
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("requested device does not exist"));
2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902
        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;
}

2903
/**
2904
 * xenDaemonDetachDeviceFlags:
2905 2906
 * @domain: pointer to domain object
 * @xml: pointer to XML description of device
2907
 * @flags: an OR'ed set of virDomainDeviceModifyFlags
2908
 *
2909 2910 2911 2912 2913
 * Destroy a virtual device attachment to backend.
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
static int
2914 2915
xenDaemonDetachDeviceFlags(virDomainPtr domain, const char *xml,
                           unsigned int flags)
2916
{
2917
    xenUnifiedPrivatePtr priv;
2918
    char class[8], ref[80];
2919 2920 2921
    virDomainDeviceDefPtr dev = NULL;
    virDomainDefPtr def = NULL;
    int ret = -1;
2922 2923
    char *xendev = NULL;
    virBuffer buf = VIR_BUFFER_INITIALIZER;
2924

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

2927
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
2928
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
2929
        return -1;
2930
    }
2931 2932 2933

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

2934
    if (domain->id < 0) {
2935 2936
        /* Cannot modify live config if domain is inactive */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
2937 2938
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Cannot modify live config if domain is inactive"));
2939 2940
            return -1;
        }
2941
        /* If xendConfigVersion < 3 only live config can be changed */
2942
        if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) {
2943 2944 2945
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend version does not support modifying "
                             "persistent config"));
2946 2947 2948 2949
            return -1;
        }
    } else {
        /* Only live config can be changed if xendConfigVersion < 3 */
2950
        if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4 &&
E
Eric Blake 已提交
2951
            (flags != VIR_DOMAIN_DEVICE_MODIFY_CURRENT &&
2952
             flags != VIR_DOMAIN_DEVICE_MODIFY_LIVE)) {
2953 2954 2955
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend version does not support modifying "
                             "persistent config"));
2956 2957
            return -1;
        }
2958
        /* Xen only supports modifying both live and persistent config if
2959 2960
         * xendConfigVersion >= 3
         */
2961
        if (priv->xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4 &&
2962 2963
            (flags != (VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                       VIR_DOMAIN_DEVICE_MODIFY_CONFIG))) {
2964 2965 2966
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Xend only supports modifying both live and "
                             "persistent config"));
2967 2968 2969
            return -1;
        }
    }
2970 2971 2972 2973 2974 2975 2976

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

2977
    if (!(dev = virDomainDeviceDefParse(priv->caps,
G
Guido Günther 已提交
2978
                                        def, xml, VIR_DOMAIN_XML_INACTIVE)))
2979 2980 2981 2982 2983
        goto cleanup;

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

2984 2985 2986
    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ß 已提交
2987
            if (xenFormatSxprOnePCI(dev->data.hostdev, &buf, 1) < 0)
2988 2989
                goto cleanup;
        } else {
2990 2991
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("unsupported device type"));
2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003
            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);
    }
3004 3005 3006 3007 3008 3009

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

    return ret;
3010
}
3011

3012 3013 3014 3015 3016 3017 3018 3019 3020
int
xenDaemonDomainGetAutostart(virDomainPtr domain,
                            int *autostart)
{
    struct sexpr *root;
    const char *tmp;
    xenUnifiedPrivatePtr priv;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3021
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3022
        return -1;
3023 3024 3025 3026 3027 3028
    }

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

    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL) {
3034 3035
        virReportError(VIR_ERR_XEN_CALL,
                       "%s", _("xenDaemonGetAutostart failed to find this domain"));
3036
        return -1;
3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054
    }

    *autostart = 0;

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

    sexpr_free(root);
    return 0;
}

int
xenDaemonDomainSetAutostart(virDomainPtr domain,
                            int autostart)
{
    struct sexpr *root, *autonode;
3055 3056
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
    char *content = NULL;
3057 3058 3059 3060
    int ret = -1;
    xenUnifiedPrivatePtr priv;

    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3061
        virReportError(VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
3062
        return -1;
3063 3064 3065 3066 3067 3068
    }

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

    root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name);
    if (root == NULL) {
3074 3075
        virReportError(VIR_ERR_XEN_CALL,
                       "%s", _("xenDaemonSetAutostart failed to find this domain"));
3076
        return -1;
3077 3078
    }

3079 3080 3081 3082
    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);
3083
        if (!val || (!STREQ(val, "ignore") && !STREQ(val, "start"))) {
3084 3085
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("unexpected value from on_xend_start"));
3086 3087 3088
            goto error;
        }

3089
        /* Change the autostart value in place, then define the new sexpr */
3090
        VIR_FREE(autonode->u.s.car->u.value);
3091 3092 3093
        autonode->u.s.car->u.value = (autostart ? strdup("start")
                                                : strdup("ignore"));
        if (!(autonode->u.s.car->u.value)) {
3094
            virReportOOMError();
3095 3096 3097
            goto error;
        }

3098
        if (sexpr2string(root, &buffer) < 0) {
3099 3100
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("sexpr2string failed"));
3101 3102
            goto error;
        }
3103 3104 3105 3106 3107 3108 3109 3110 3111

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

        content = virBufferContentAndReset(&buffer);

        if (xend_op(domain->conn, "", "op", "new", "config", content, NULL) != 0) {
3112 3113
            virReportError(VIR_ERR_XEN_CALL,
                           "%s", _("Failed to redefine sexpr"));
3114 3115 3116
            goto error;
        }
    } else {
3117 3118
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("on_xend_start not present in sexpr"));
3119 3120 3121 3122 3123
        goto error;
    }

    ret = 0;
  error:
3124 3125
    virBufferFreeAndReset(&buffer);
    VIR_FREE(content);
3126 3127 3128
    sexpr_free(root);
    return ret;
}
3129

3130 3131 3132 3133 3134 3135
int
xenDaemonDomainMigratePrepare (virConnectPtr dconn,
                               char **cookie ATTRIBUTE_UNUSED,
                               int *cookielen ATTRIBUTE_UNUSED,
                               const char *uri_in,
                               char **uri_out,
E
Eric Blake 已提交
3136
                               unsigned long flags,
3137 3138 3139
                               const char *dname ATTRIBUTE_UNUSED,
                               unsigned long resource ATTRIBUTE_UNUSED)
{
E
Eric Blake 已提交
3140 3141
    virCheckFlags(XEN_MIGRATION_FLAGS, -1);

3142 3143 3144 3145 3146
    /* 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) {
3147 3148
        *uri_out = virGetHostname(dconn);
        if (*uri_out == NULL)
3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173
            return -1;
    }

    return 0;
}

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

3174 3175
    int undefined_source = 0;

E
Eric Blake 已提交
3176 3177
    virCheckFlags(XEN_MIGRATION_FLAGS, -1);

3178 3179
    /* Xen doesn't support renaming domains during migration. */
    if (dname) {
3180 3181 3182
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("xenDaemonDomainMigrate: Xen does not support"
                               " renaming domains during migration"));
3183 3184 3185 3186 3187 3188 3189
        return -1;
    }

    /* Xen (at least up to 3.1.0) takes a resource parameter but
     * ignores it.
     */
    if (bandwidth) {
3190 3191 3192
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("xenDaemonDomainMigrate: Xen does not support"
                               " bandwidth limits during migration"));
3193 3194 3195
        return -1;
    }

3196 3197 3198
    /*
     * Check the flags.
     */
3199 3200 3201 3202
    if ((flags & VIR_MIGRATE_LIVE)) {
        strcpy (live, "1");
        flags &= ~VIR_MIGRATE_LIVE;
    }
3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213

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

3214 3215 3216 3217
    /* This is buggy in Xend, but could be supported in principle.  Give
     * a nice error message.
     */
    if (flags & VIR_MIGRATE_PAUSED) {
3218 3219
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("xenDaemonDomainMigrate: xend cannot migrate paused domains"));
3220 3221 3222
        return -1;
    }

3223 3224
    /* XXX we could easily do tunnelled & peer2peer migration too
       if we want to. support these... */
3225
    if (flags != 0) {
3226 3227
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("xenDaemonDomainMigrate: unsupported flag"));
3228 3229 3230 3231 3232 3233 3234 3235 3236
        return -1;
    }

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

3241
        if (uriptr->scheme && STRCASENEQ (uriptr->scheme, "xenmigr")) {
3242 3243 3244
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("xenDaemonDomainMigrate: only xenmigr://"
                                   " migrations are supported by Xen"));
3245
            virURIFree (uriptr);
3246 3247 3248
            return -1;
        }
        if (!uriptr->server) {
3249 3250 3251
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("xenDaemonDomainMigrate: a hostname must be"
                                   " specified in the URI"));
3252
            virURIFree (uriptr);
3253 3254 3255 3256
            return -1;
        }
        hostname = strdup (uriptr->server);
        if (!hostname) {
3257
            virReportOOMError();
3258
            virURIFree (uriptr);
3259 3260 3261
            return -1;
        }
        if (uriptr->port)
3262
            snprintf (port, sizeof(port), "%d", uriptr->port);
3263
        virURIFree (uriptr);
3264 3265 3266 3267
    }
    else if ((p = strrchr (uri, ':')) != NULL) { /* "hostname:port" */
        int port_nr, n;

3268
        if (virStrToLong_i(p+1, NULL, 10, &port_nr) < 0) {
3269 3270
            virReportError(VIR_ERR_INVALID_ARG,
                           "%s", _("xenDaemonDomainMigrate: invalid port number"));
3271 3272
            return -1;
        }
3273
        snprintf (port, sizeof(port), "%d", port_nr);
3274 3275 3276 3277 3278

        /* Get the hostname. */
        n = p - uri; /* n = Length of hostname in bytes. */
        hostname = strdup (uri);
        if (!hostname) {
3279
            virReportOOMError();
3280 3281 3282 3283 3284 3285 3286
            return -1;
        }
        hostname[n] = '\0';
    }
    else {                      /* "hostname" (or IP address) */
        hostname = strdup (uri);
        if (!hostname) {
3287
            virReportOOMError();
3288 3289 3290 3291
            return -1;
        }
    }

3292
    VIR_DEBUG("hostname = %s, port = %s", hostname, port);
3293

J
Jim Fehlig 已提交
3294 3295 3296 3297 3298 3299
    /* 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.
     */
3300 3301 3302 3303 3304
    ret = xend_op (domain->conn, domain->name,
                   "op", "migrate",
                   "destination", hostname,
                   "live", live,
                   "port", port,
J
Jim Fehlig 已提交
3305 3306 3307 3308
                   "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 */
3309
                   NULL);
3310
    VIR_FREE (hostname);
3311

3312 3313 3314
    if (ret == 0 && undefined_source)
        xenDaemonDomainUndefine (domain);

3315
    VIR_DEBUG("migration done");
3316 3317 3318 3319

    return ret;
}

3320 3321 3322 3323
virDomainPtr xenDaemonDomainDefineXML(virConnectPtr conn, const char *xmlDesc) {
    int ret;
    char *sexpr;
    virDomainPtr dom;
3324
    xenUnifiedPrivatePtr priv;
3325
    virDomainDefPtr def;
3326 3327 3328

    priv = (xenUnifiedPrivatePtr) conn->privateData;

3329
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
3330
        return NULL;
3331

3332
    if (!(def = virDomainDefParseString(priv->caps, xmlDesc,
M
Matthias Bolte 已提交
3333
                                        1 << VIR_DOMAIN_VIRT_XEN,
3334
                                        VIR_DOMAIN_XML_INACTIVE))) {
3335 3336
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("failed to parse domain description"));
3337
        return NULL;
3338 3339
    }

M
Markus Groß 已提交
3340
    if (!(sexpr = xenFormatSxpr(conn, def, priv->xendConfigVersion))) {
3341 3342
        virReportError(VIR_ERR_XML_ERROR,
                       "%s", _("failed to build sexpr"));
3343 3344 3345
        goto error;
    }

3346
    ret = xend_op(conn, "", "op", "new", "config", sexpr, NULL);
3347
    VIR_FREE(sexpr);
3348
    if (ret != 0) {
3349 3350
        virReportError(VIR_ERR_XEN_CALL,
                       _("Failed to create inactive domain %s"), def->name);
3351 3352 3353
        goto error;
    }

3354
    dom = virDomainLookupByName(conn, def->name);
3355 3356 3357
    if (dom == NULL) {
        goto error;
    }
3358
    virDomainDefFree(def);
3359
    return dom;
3360

3361
  error:
3362
    virDomainDefFree(def);
3363
    return NULL;
3364
}
3365 3366 3367
int xenDaemonDomainCreate(virDomainPtr domain)
{
    xenUnifiedPrivatePtr priv;
3368 3369
    int ret;
    virDomainPtr tmp;
3370

3371
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3372
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3373
        return -1;
3374
    }
3375 3376 3377

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

3378
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
3379
        return -1;
3380

3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391
    ret = xend_op(domain->conn, domain->name, "op", "start", NULL);

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

3394 3395 3396 3397
int xenDaemonDomainUndefine(virDomainPtr domain)
{
    xenUnifiedPrivatePtr priv;

3398
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3399
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3400
        return -1;
3401
    }
3402 3403 3404

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

3405
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
3406
        return -1;
3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424

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

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

3427 3428 3429
    /* xm_internal.c (the support for defined domains from /etc/xen
     * config files used by old Xen) will handle this.
     */
3430
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
3431
        return -1;
3432

3433 3434 3435 3436 3437 3438
    root = sexpr_get(conn, "/xend/domain?state=halted");
    if (root == NULL)
        goto error;

    ret = 0;

3439 3440
    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) {
3441 3442 3443 3444 3445 3446
        if (node->kind != SEXPR_VALUE)
            continue;
        ret++;
    }

error:
3447
    sexpr_free(root);
3448
    return ret;
3449 3450
}

3451 3452
static int
xenDaemonListDefinedDomains(virConnectPtr conn, char **const names, int maxnames) {
3453
    struct sexpr *root = NULL;
3454
    int i, ret = -1;
3455
    struct sexpr *_for_i, *node;
3456
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
3457

3458
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
3459
        return -1;
3460

3461
    if ((names == NULL) || (maxnames < 0))
3462
        goto error;
3463
    if (maxnames == 0)
3464
        return 0;
3465

3466 3467 3468 3469 3470 3471
    root = sexpr_get(conn, "/xend/domain?state=halted");
    if (root == NULL)
        goto error;

    ret = 0;

3472 3473
    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) {
3474 3475 3476
        if (node->kind != SEXPR_VALUE)
            continue;

3477
        if ((names[ret++] = strdup(node->u.value)) == NULL) {
3478
            virReportOOMError();
3479 3480 3481
            goto error;
        }

3482 3483 3484 3485
        if (ret >= maxnames)
            break;
    }

3486 3487
cleanup:
    sexpr_free(root);
3488
    return ret;
3489

3490
error:
3491 3492 3493
    for (i = 0; i < ret; ++i)
        VIR_FREE(names[i]);

3494 3495 3496
    ret = -1;

    goto cleanup;
3497 3498
}

3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516
/**
 * xenDaemonGetSchedulerType:
 * @domain: pointer to the Domain block
 * @nparams: give a number of scheduler parameters
 *
 * Get the scheduler type of Xen
 *
 * Returns a scheduler name (credit or sedf) which must be freed by the
 * caller or NULL in case of failure
 */
static char *
xenDaemonGetSchedulerType(virDomainPtr domain, int *nparams)
{
    xenUnifiedPrivatePtr priv;
    struct sexpr *root;
    const char *ret = NULL;
    char *schedulertype = NULL;

3517
    if (domain->conn == NULL || domain->name == NULL) {
3518
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3519 3520 3521 3522 3523
        return NULL;
    }

    /* Support only xendConfigVersion >=4 */
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
3524
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
3525 3526
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("unsupported in xendConfigVersion < 4"));
3527 3528 3529 3530 3531 3532 3533 3534 3535 3536
        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){
3537 3538
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("node information incomplete, missing scheduler name"));
3539 3540 3541 3542 3543
        goto error;
    }
    if (STREQ (ret, "credit")) {
        schedulertype = strdup("credit");
        if (schedulertype == NULL){
3544
            virReportOOMError();
3545 3546
            goto error;
        }
3547 3548
        if (nparams)
            *nparams = XEN_SCHED_CRED_NPARAM;
3549 3550 3551
    } else if (STREQ (ret, "sedf")) {
        schedulertype = strdup("sedf");
        if (schedulertype == NULL){
3552
            virReportOOMError();
3553 3554
            goto error;
        }
3555 3556
        if (nparams)
            *nparams = XEN_SCHED_SEDF_NPARAM;
3557
    } else {
3558
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581
        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
 */
static int
xenDaemonGetSchedulerParameters(virDomainPtr domain,
3582
                                virTypedParameterPtr params, int *nparams)
3583 3584 3585 3586 3587 3588 3589
{
    xenUnifiedPrivatePtr priv;
    struct sexpr *root;
    char *sched_type = NULL;
    int sched_nparam = 0;
    int ret = -1;

3590
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3591
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3592
        return -1;
3593 3594 3595 3596
    }

    /* Support only xendConfigVersion >=4 */
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
3597
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
3598 3599
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("unsupported in xendConfigVersion < 4"));
3600
        return -1;
3601 3602 3603 3604 3605
    }

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

    /* get the scheduler type */
    sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
    if (sched_type == NULL) {
3611 3612
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Failed to get a scheduler name"));
3613 3614 3615 3616 3617
        goto error;
    }

    switch (sched_nparam){
        case XEN_SCHED_SEDF_NPARAM:
3618
            if (*nparams < XEN_SCHED_SEDF_NPARAM) {
3619 3620
                virReportError(VIR_ERR_INVALID_ARG,
                               "%s", _("Invalid parameter count"));
3621 3622 3623
                goto error;
            }

3624 3625 3626 3627 3628 3629
            /* 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) {
3630 3631
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("domain information incomplete, missing cpu_weight"));
3632 3633 3634
                goto error;
            }
            if (sexpr_node(root, "domain/cpu_cap") == NULL) {
3635 3636
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("domain information incomplete, missing cpu_cap"));
3637 3638 3639
                goto error;
            }

3640 3641
            if (virStrcpyStatic(params[0].field,
                                VIR_DOMAIN_SCHEDULER_WEIGHT) == NULL) {
3642 3643 3644
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Weight %s too big for destination"),
                               VIR_DOMAIN_SCHEDULER_WEIGHT);
C
Chris Lalancette 已提交
3645 3646
                goto error;
            }
3647
            params[0].type = VIR_TYPED_PARAM_UINT;
3648 3649
            params[0].value.ui = sexpr_int(root, "domain/cpu_weight");

3650 3651 3652
            if (*nparams > 1) {
                if (virStrcpyStatic(params[1].field,
                                    VIR_DOMAIN_SCHEDULER_CAP) == NULL) {
3653 3654 3655
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Cap %s too big for destination"),
                                   VIR_DOMAIN_SCHEDULER_CAP);
3656 3657 3658 3659
                    goto error;
                }
                params[1].type = VIR_TYPED_PARAM_UINT;
                params[1].value.ui = sexpr_int(root, "domain/cpu_cap");
C
Chris Lalancette 已提交
3660
            }
3661 3662 3663

            if (*nparams > XEN_SCHED_CRED_NPARAM)
                *nparams = XEN_SCHED_CRED_NPARAM;
3664 3665 3666
            ret = 0;
            break;
        default:
3667
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
3668 3669 3670 3671 3672
            goto error;
    }

error:
    sexpr_free(root);
3673
    VIR_FREE(sched_type);
3674
    return ret;
3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688
}

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

3698
    if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) {
3699
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3700
        return -1;
3701 3702 3703 3704
    }

    /* Support only xendConfigVersion >=4 and active domains */
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
3705
    if (priv->xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
3706 3707
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("unsupported in xendConfigVersion < 4"));
3708
        return -1;
3709 3710 3711 3712 3713
    }

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

    /* get the scheduler type */
    sched_type = xenDaemonGetSchedulerType(domain, &sched_nparam);
    if (sched_type == NULL) {
3719 3720
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Failed to get a scheduler name"));
3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738
        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++) {
3739
                if (STREQ (params[i].field, VIR_DOMAIN_SCHEDULER_WEIGHT) &&
3740
                    params[i].type == VIR_TYPED_PARAM_UINT) {
3741
                    snprintf(buf_weight, sizeof(buf_weight), "%u", params[i].value.ui);
3742
                } else if (STREQ (params[i].field, VIR_DOMAIN_SCHEDULER_CAP) &&
3743
                    params[i].type == VIR_TYPED_PARAM_UINT) {
3744 3745
                    snprintf(buf_cap, sizeof(buf_cap), "%u", params[i].value.ui);
                } else {
3746
                    virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
3747 3748 3749 3750 3751 3752 3753 3754
                    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) {
3755 3756
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("domain information incomplete, missing cpu_weight"));
3757 3758 3759 3760 3761 3762 3763
                    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) {
3764 3765
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("domain information incomplete, missing cpu_cap"));
3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776
                    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:
3777
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Unknown scheduler"));
3778 3779 3780 3781 3782
            goto error;
    }

error:
    sexpr_free(root);
3783
    VIR_FREE(sched_type);
3784
    return ret;
3785 3786
}

R
Richard W.M. Jones 已提交
3787 3788
/**
 * xenDaemonDomainBlockPeek:
P
Philipp Hahn 已提交
3789
 * @domain: domain object
R
Richard W.M. Jones 已提交
3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802
 * @path: path to the file or device
 * @offset: offset
 * @size: size
 * @buffer: return buffer
 *
 * Returns 0 if successful, -1 if error, -2 if declined.
 */
int
xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path,
                          unsigned long long offset, size_t size,
                          void *buffer)
{
    xenUnifiedPrivatePtr priv;
3803 3804 3805
    struct sexpr *root = NULL;
    int fd = -1, ret = -1;
    virDomainDefPtr def;
3806 3807 3808
    int id;
    char * tty;
    int vncport;
3809
    const char *actual;
R
Richard W.M. Jones 已提交
3810 3811 3812

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

3813
    if (domain->id < 0 && priv->xendConfigVersion < XEND_CONFIG_VERSION_3_0_4)
R
Richard W.M. Jones 已提交
3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824
        return -2;              /* Decline, allow XM to handle it. */

    /* Security check: The path must correspond to a block device. */
    if (domain->id > 0)
        root = sexpr_get (domain->conn, "/xend/domain/%d?detail=1",
                          domain->id);
    else if (domain->id < 0)
        root = sexpr_get (domain->conn, "/xend/domain/%s?detail=1",
                          domain->name);
    else {
        /* This call always fails for dom0. */
3825 3826
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domainBlockPeek is not supported for dom0"));
R
Richard W.M. Jones 已提交
3827 3828 3829 3830
        return -1;
    }

    if (!root) {
3831
        virReportError(VIR_ERR_XEN_CALL, __FUNCTION__);
R
Richard W.M. Jones 已提交
3832 3833 3834
        return -1;
    }

3835 3836 3837 3838 3839 3840
    id = xenGetDomIdFromSxpr(root, priv->xendConfigVersion);
    xenUnifiedLock(priv);
    tty = xenStoreDomainGetConsolePath(domain->conn, id);
    vncport = xenStoreDomainGetVNCPort(domain->conn, id);
    xenUnifiedUnlock(priv);

M
Markus Groß 已提交
3841 3842
    if (!(def = xenParseSxpr(root, priv->xendConfigVersion, NULL, tty,
                             vncport)))
3843
        goto cleanup;
R
Richard W.M. Jones 已提交
3844

3845
    if (!(actual = virDomainDiskPathByName(def, path))) {
3846 3847
        virReportError(VIR_ERR_INVALID_ARG,
                       _("%s: invalid path"), path);
3848
        goto cleanup;
R
Richard W.M. Jones 已提交
3849
    }
3850
    path = actual;
R
Richard W.M. Jones 已提交
3851 3852 3853

    /* The path is correct, now try to open it and get its size. */
    fd = open (path, O_RDONLY);
3854
    if (fd == -1) {
3855
        virReportSystemError(errno,
3856 3857
                             _("failed to open for reading: %s"),
                             path);
3858
        goto cleanup;
R
Richard W.M. Jones 已提交
3859 3860 3861 3862 3863 3864 3865 3866
    }

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

    ret = 0;
3874
 cleanup:
3875
    VIR_FORCE_CLOSE(fd);
3876 3877
    sexpr_free(root);
    virDomainDefFree(def);
R
Richard W.M. Jones 已提交
3878 3879 3880
    return ret;
}

3881
struct xenUnifiedDriver xenDaemonDriver = {
E
Eric Blake 已提交
3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905
    .xenClose = xenDaemonClose,
    .xenVersion = xenDaemonGetVersion,
    .xenDomainSuspend = xenDaemonDomainSuspend,
    .xenDomainResume = xenDaemonDomainResume,
    .xenDomainShutdown = xenDaemonDomainShutdown,
    .xenDomainReboot = xenDaemonDomainReboot,
    .xenDomainDestroyFlags = xenDaemonDomainDestroyFlags,
    .xenDomainGetOSType = xenDaemonDomainGetOSType,
    .xenDomainGetMaxMemory = xenDaemonDomainGetMaxMemory,
    .xenDomainSetMaxMemory = xenDaemonDomainSetMaxMemory,
    .xenDomainSetMemory = xenDaemonDomainSetMemory,
    .xenDomainGetInfo = xenDaemonDomainGetInfo,
    .xenDomainPinVcpu = xenDaemonDomainPinVcpu,
    .xenDomainGetVcpus = xenDaemonDomainGetVcpus,
    .xenListDefinedDomains = xenDaemonListDefinedDomains,
    .xenNumOfDefinedDomains = xenDaemonNumOfDefinedDomains,
    .xenDomainCreate = xenDaemonDomainCreate,
    .xenDomainDefineXML = xenDaemonDomainDefineXML,
    .xenDomainUndefine = xenDaemonDomainUndefine,
    .xenDomainAttachDeviceFlags = xenDaemonAttachDeviceFlags,
    .xenDomainDetachDeviceFlags = xenDaemonDetachDeviceFlags,
    .xenDomainGetSchedulerType = xenDaemonGetSchedulerType,
    .xenDomainGetSchedulerParameters = xenDaemonGetSchedulerParameters,
    .xenDomainSetSchedulerParameters = xenDaemonSetSchedulerParameters,
3906 3907
};

3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919

/**
 * 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.
3920 3921
 *  - if pci, get BDF from description, scan XenStore and
 *    copy in ref the corresponding dev number.
3922 3923 3924 3925 3926 3927 3928 3929 3930 3931
 *
 * 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 已提交
3932
    xenUnifiedPrivatePtr priv = domain->conn->privateData;
3933
    char *xref;
C
Chris Lalancette 已提交
3934
    char *tmp;
3935 3936

    if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
3937 3938 3939
        if (dev->data.disk->driverName &&
            STREQ(dev->data.disk->driverName, "tap"))
            strcpy(class, "tap");
J
Jim Fehlig 已提交
3940 3941 3942
        else if (dev->data.disk->driverName &&
            STREQ(dev->data.disk->driverName, "tap2"))
            strcpy(class, "tap2");
3943 3944 3945
        else
            strcpy(class, "vbd");

3946 3947
        if (dev->data.disk->dst == NULL)
            return -1;
D
Daniel P. Berrange 已提交
3948
        xenUnifiedLock(priv);
3949 3950
        xref = xenStoreDomainGetDiskID(domain->conn, domain->id,
                                       dev->data.disk->dst);
D
Daniel P. Berrange 已提交
3951
        xenUnifiedUnlock(priv);
3952 3953 3954
        if (xref == NULL)
            return -1;

C
Chris Lalancette 已提交
3955
        tmp = virStrcpy(ref, xref, ref_len);
3956
        VIR_FREE(xref);
C
Chris Lalancette 已提交
3957 3958
        if (tmp == NULL)
            return -1;
3959 3960 3961 3962
    } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
        char mac[30];
        virDomainNetDefPtr def = dev->data.net;
        snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
3963 3964
                 def->mac.addr[0], def->mac.addr[1], def->mac.addr[2],
                 def->mac.addr[3], def->mac.addr[4], def->mac.addr[5]);
3965 3966 3967

        strcpy(class, "vif");

D
Daniel P. Berrange 已提交
3968
        xenUnifiedLock(priv);
3969 3970
        xref = xenStoreDomainGetNetworkID(domain->conn, domain->id,
                                          mac);
D
Daniel P. Berrange 已提交
3971
        xenUnifiedUnlock(priv);
3972 3973 3974
        if (xref == NULL)
            return -1;

C
Chris Lalancette 已提交
3975
        tmp = virStrcpy(ref, xref, ref_len);
3976
        VIR_FREE(xref);
C
Chris Lalancette 已提交
3977 3978
        if (tmp == NULL)
            return -1;
3979 3980 3981
    } 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) {
3982 3983 3984 3985 3986 3987 3988 3989
        char *bdf;
        virDomainHostdevDefPtr def = dev->data.hostdev;

        if (virAsprintf(&bdf, "%04x:%02x:%02x.%0x",
                        def->source.subsys.u.pci.domain,
                        def->source.subsys.u.pci.bus,
                        def->source.subsys.u.pci.slot,
                        def->source.subsys.u.pci.function) < 0) {
3990
            virReportOOMError();
3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006
            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;
4007
    } else {
4008 4009
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("hotplug of device type not supported"));
4010 4011 4012 4013 4014
        return -1;
    }

    return 0;
}