xs_internal.c 37.9 KB
Newer Older
1 2 3
/*
 * xs_internal.c: access to Xen Store
 *
4
 * Copyright (C) 2006, 2009-2012 Red Hat, Inc.
5 6 7 8 9 10
 *
 * See COPYING.LIB for the License of this software
 *
 * Daniel Veillard <veillard@redhat.com>
 */

11
#include <config.h>
J
Jim Meyering 已提交
12

13 14 15 16 17 18 19 20 21 22
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <stdint.h>

23
#include <xen/dom0_ops.h>
24 25 26 27
#include <xen/version.h>

#include <xs.h>

28
#include "virterror_internal.h"
29
#include "datatypes.h"
30
#include "driver.h"
31 32 33
#include "memory.h"
#include "logging.h"
#include "uuid.h"
34
#include "xen_driver.h"
35
#include "xs_internal.h"
36
#include "xen_hypervisor.h"
37

38 39
#define VIR_FROM_THIS VIR_FROM_XEN

40
static char *xenStoreDomainGetOSType(virDomainPtr domain);
D
Daniel P. Berrange 已提交
41 42
static void xenStoreWatchEvent(int watch, int fd, int events, void *data);
static void xenStoreWatchListFree(xenStoreWatchListPtr list);
43

44
struct xenUnifiedDriver xenStoreDriver = {
E
Eric Blake 已提交
45 46 47 48 49 50 51
    .xenClose = xenStoreClose,
    .xenDomainShutdown = xenStoreDomainShutdown,
    .xenDomainReboot = xenStoreDomainReboot,
    .xenDomainGetOSType = xenStoreDomainGetOSType,
    .xenDomainGetMaxMemory = xenStoreDomainGetMaxMemory,
    .xenDomainSetMemory = xenStoreDomainSetMemory,
    .xenDomainGetInfo = xenStoreGetDomainInfo,
52 53
};

54
#define virXenStoreError(code, ...)                                  \
55
        virReportErrorHelper(VIR_FROM_XENSTORE, code, __FILE__,      \
56
                             __FUNCTION__, __LINE__, __VA_ARGS__)
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76

/************************************************************************
 *									*
 *		Helper internal APIs					*
 *									*
 ************************************************************************/
/**
 * virConnectDoStoreList:
 * @conn: pointer to the hypervisor connection
 * @path: the absolute path of the directory in the store to list
 * @nb: OUT pointer to the number of items found
 *
 * Internal API querying the Xenstore for a list
 *
 * Returns a string which must be freed by the caller or NULL in case of error
 */
static char **
virConnectDoStoreList(virConnectPtr conn, const char *path,
                      unsigned int *nb)
{
77 78 79 80 81 82 83
    xenUnifiedPrivatePtr priv;

    if (conn == NULL)
        return NULL;

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL || path == NULL || nb == NULL)
84 85
        return (NULL);

86
    return xs_directory (priv->xshandle, 0, path, nb);
87 88 89 90
}

/**
 * virDomainDoStoreQuery:
91 92
 * @conn: pointer to the hypervisor connection
 * @domid: id of the domain
93 94 95 96 97 98 99
 * @path: the relative path of the data in the store to retrieve
 *
 * Internal API querying the Xenstore for a string value.
 *
 * Returns a string which must be freed by the caller or NULL in case of error
 */
static char *
100
virDomainDoStoreQuery(virConnectPtr conn, int domid, const char *path)
101 102 103
{
    char s[256];
    unsigned int len = 0;
104 105 106 107
    xenUnifiedPrivatePtr priv;

    if (!conn)
        return NULL;
108

109 110
    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
111 112
        return (NULL);

113
    snprintf(s, 255, "/local/domain/%d/%s", domid, path);
114 115
    s[255] = 0;

116
    return xs_read(priv->xshandle, 0, &s[0], &len);
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
}

/**
 * virDomainDoStoreWrite:
 * @domain: a domain object
 * @path: the relative path of the data in the store to retrieve
 *
 * Internal API setting up a string value in the Xenstore
 * Requires write access to the XenStore
 *
 * Returns 0 in case of success, -1 in case of failure
 */
static int
virDomainDoStoreWrite(virDomainPtr domain, const char *path,
                      const char *value)
{
    char s[256];
134
    xenUnifiedPrivatePtr priv;
135 136 137 138
    int ret = -1;

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
        return (-1);
139 140 141

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
142 143 144 145
        return (-1);
    if (domain->conn->flags & VIR_CONNECT_RO)
        return (-1);

146
    snprintf(s, 255, "/local/domain/%d/%s", domain->id, path);
147 148
    s[255] = 0;

149
    if (xs_write(priv->xshandle, 0, &s[0], value, strlen(value)))
150 151 152 153 154 155 156 157 158 159 160 161 162
        ret = 0;

    return (ret);
}

/**
 * virDomainGetVM:
 * @domain: a domain object
 *
 * Internal API extracting a xenstore vm path.
 *
 * Returns the new string or NULL in case of error
 */
163
static char *
164 165 166 167 168
virDomainGetVM(virDomainPtr domain)
{
    char *vm;
    char query[200];
    unsigned int len;
169
    xenUnifiedPrivatePtr priv;
170 171 172

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
        return (NULL);
173 174 175

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
176 177 178 179 180
        return (NULL);

    snprintf(query, 199, "/local/domain/%d/vm", virDomainGetID(domain));
    query[199] = 0;

181
    vm = xs_read(priv->xshandle, 0, &query[0], &len);
182 183 184 185 186 187 188 189 190 191

    return (vm);
}

/**
 * virDomainGetVMInfo:
 * @domain: a domain object
 * @vm: the xenstore vm path
 * @name: the value's path
 *
192
 * Internal API extracting one information the device used
193 194 195 196
 * by the domain from xensttore
 *
 * Returns the new string or NULL in case of error
 */
197
static char *
198 199 200 201 202
virDomainGetVMInfo(virDomainPtr domain, const char *vm, const char *name)
{
    char s[256];
    char *ret = NULL;
    unsigned int len = 0;
203
    xenUnifiedPrivatePtr priv;
204 205 206

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
        return (NULL);
207 208 209

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
210 211 212 213 214
        return (NULL);

    snprintf(s, 255, "%s/%s", vm, name);
    s[255] = 0;

215
    ret = xs_read(priv->xshandle, 0, &s[0], &len);
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

    return (ret);
}


/************************************************************************
 *									*
 *		Canonical internal APIs					*
 *									*
 ************************************************************************/
/**
 * xenStoreOpen:
 * @conn: pointer to the connection block
 * @name: URL for the target, NULL for local
 * @flags: combination of virDrvOpenFlag(s)
 *
 * Connects to the Xen hypervisor.
 *
 * Returns 0 or -1 in case of error.
 */
236
virDrvOpenStatus
237
xenStoreOpen(virConnectPtr conn,
238
             virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
239
             unsigned int flags)
240
{
241
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
242

E
Eric Blake 已提交
243 244
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

245
    if (flags & VIR_CONNECT_RO)
246
        priv->xshandle = xs_daemon_open_readonly();
247
    else
248
        priv->xshandle = xs_daemon_open();
249

250
    if (priv->xshandle == NULL) {
251
        /*
J
John Levon 已提交
252 253
         * not being able to connect via the socket as an unprivileged
         * user is rather normal, this should fallback to the proxy (or
254
         * remote) mechanism.
255
         */
J
John Levon 已提交
256
        if (xenHavePrivilege()) {
257 258
            virXenStoreError(VIR_ERR_NO_XEN,
                             "%s", _("failed to connect to Xen Store"));
259
        }
260 261
        return (-1);
    }
262 263

    /* Init activeDomainList */
264
    if (VIR_ALLOC(priv->activeDomainList) < 0) {
265
        virReportOOMError();
266 267 268 269 270 271
        return -1;
    }

    /* Init watch list before filling in domInfoList,
       so we can know if it is the first time through
       when the callback fires */
272
    if (VIR_ALLOC(priv->xsWatchList) < 0) {
273
        virReportOOMError();
274 275 276 277 278 279 280
        return -1;
    }

    /* This will get called once at start */
    if ( xenStoreAddWatch(conn, "@releaseDomain",
                     "releaseDomain", xenStoreDomainReleased, priv) < 0 )
    {
281 282
        virXenStoreError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("adding watch @releaseDomain"));
283 284 285 286 287 288 289
        return -1;
    }

    /* The initial call of this will fill domInfoList */
    if( xenStoreAddWatch(conn, "@introduceDomain",
                     "introduceDomain", xenStoreDomainIntroduced, priv) < 0 )
    {
290 291
        virXenStoreError(VIR_ERR_INTERNAL_ERROR,
                         "%s", _("adding watch @introduceDomain"));
292 293 294 295 296 297 298 299 300
        return -1;
    }

    /* Add an event handle */
    if ((priv->xsWatch = virEventAddHandle(xs_fileno(priv->xshandle),
                                           VIR_EVENT_HANDLE_READABLE,
                                           xenStoreWatchEvent,
                                           conn,
                                           NULL)) < 0)
301
        VIR_DEBUG("Failed to add event handle, disabling events");
302 303

    return 0;
304 305 306 307 308 309 310 311 312 313 314 315 316
}

/**
 * xenStoreClose:
 * @conn: pointer to the connection block
 *
 * Close the connection to the Xen hypervisor.
 *
 * Returns 0 in case of success or -1 in case of error.
 */
int
xenStoreClose(virConnectPtr conn)
{
317 318
    xenUnifiedPrivatePtr priv;

319
    if (conn == NULL) {
320
        virXenStoreError(VIR_ERR_INVALID_ARG, __FUNCTION__);
321
        return(-1);
322 323
    }

324
    priv = (xenUnifiedPrivatePtr) conn->privateData;
325 326

    if (xenStoreRemoveWatch(conn, "@introduceDomain", "introduceDomain") < 0) {
327
        VIR_DEBUG("Warning, could not remove @introduceDomain watch");
328 329 330 331
        /* not fatal */
    }

    if (xenStoreRemoveWatch(conn, "@releaseDomain", "releaseDomain") < 0) {
332
        VIR_DEBUG("Warning, could not remove @releaseDomain watch");
333 334 335 336
        /* not fatal */
    }

    xenStoreWatchListFree(priv->xsWatchList);
J
John Levon 已提交
337
    priv->xsWatchList = NULL;
338 339
    xenUnifiedDomainInfoListFree(priv->activeDomainList);
    priv->activeDomainList = NULL;
340

341 342 343
    if (priv->xshandle == NULL)
        return(-1);

344 345
    if (priv->xsWatch != -1)
        virEventRemoveHandle(priv->xsWatch);
346

347
    xs_daemon_close(priv->xshandle);
348 349
    priv->xshandle = NULL;

350 351 352 353 354 355
    return (0);
}

/**
 * xenStoreGetDomainInfo:
 * @domain: pointer to the domain block
356
 * @info: the place where information should be stored
357
 *
E
Eric Blake 已提交
358
 * Do a hypervisor call to get the related set of domain information.
359 360 361 362 363 364 365 366 367
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
xenStoreGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
{
    char *tmp, **tmp2;
    unsigned int nb_vcpus;
    char request[200];
368
    xenUnifiedPrivatePtr priv;
369

370 371 372
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
        return (-1);

373
    if ((domain == NULL) || (domain->conn == NULL) || (info == NULL)) {
374
        virXenStoreError(VIR_ERR_INVALID_ARG, __FUNCTION__);
375
        return(-1);
376
    }
377 378 379

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
380
        return(-1);
381

382
    if (domain->id == -1)
383
        return(-1);
384

385
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "running");
386 387 388
    if (tmp != NULL) {
        if (tmp[0] == '1')
            info->state = VIR_DOMAIN_RUNNING;
389
        VIR_FREE(tmp);
390
    } else {
391
        info->state = VIR_DOMAIN_NOSTATE;
392
    }
393
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
394 395 396
    if (tmp != NULL) {
        info->memory = atol(tmp);
        info->maxMem = atol(tmp);
397
        VIR_FREE(tmp);
398 399 400 401
    } else {
        info->memory = 0;
        info->maxMem = 0;
    }
402
#if 0
403
    /* doesn't seems to work */
404
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "cpu_time");
405 406
    if (tmp != NULL) {
        info->cpuTime = atol(tmp);
407
        VIR_FREE(tmp);
408 409 410
    } else {
        info->cpuTime = 0;
    }
411
#endif
412
    snprintf(request, 199, "/local/domain/%d/cpu", domain->id);
413 414 415 416
    request[199] = 0;
    tmp2 = virConnectDoStoreList(domain->conn, request, &nb_vcpus);
    if (tmp2 != NULL) {
        info->nrVirtCpu = nb_vcpus;
417
        VIR_FREE(tmp2);
418 419 420 421
    }
    return (0);
}

422 423 424 425 426 427 428 429 430 431 432 433 434
/**
 * xenStoreDomainGetState:
 * @domain: pointer to the domain block
 * @state: returned domain's state
 * @reason: returned state reason
 * @flags: additional flags, 0 for now
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
xenStoreDomainGetState(virDomainPtr domain,
                       int *state,
                       int *reason,
E
Eric Blake 已提交
435
                       unsigned int flags)
436 437 438
{
    char *running;

E
Eric Blake 已提交
439 440
    virCheckFlags(0, -1);

441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
    if (domain->id == -1)
        return -1;

    running = virDomainDoStoreQuery(domain->conn, domain->id, "running");

    if (running && *running == '1')
        *state = VIR_DOMAIN_RUNNING;
    else
        *state = VIR_DOMAIN_NOSTATE;
    if (reason)
        *reason = 0;

    VIR_FREE(running);

    return 0;
}

458
/**
459
 * xenStoreDomainSetMemory:
460 461 462 463 464 465 466 467
 * @domain: pointer to the domain block
 * @memory: the max memory size in kilobytes.
 *
 * Change the maximum amount of memory allowed in the xen store
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
468
xenStoreDomainSetMemory(virDomainPtr domain, unsigned long memory)
469 470 471 472
{
    int ret;
    char value[20];

D
Daniel Veillard 已提交
473 474
    if ((domain == NULL) || (domain->conn == NULL) ||
        (memory < 1024 * MIN_XEN_GUEST_SIZE)) {
475
        virXenStoreError(VIR_ERR_INVALID_ARG, __FUNCTION__);
476
        return(-1);
477
    }
478
    if (domain->id == -1)
479
        return(-1);
D
Daniel Veillard 已提交
480
    if ((domain->id == 0) && (memory < (2 * MIN_XEN_GUEST_SIZE * 1024)))
481
        return(-1);
482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
    snprintf(value, 19, "%lu", memory);
    value[19] = 0;
    ret = virDomainDoStoreWrite(domain, "memory/target", &value[0]);
    if (ret < 0)
        return (-1);
    return (0);
}

/**
 * xenStoreDomainGetMaxMemory:
 * @domain: pointer to the domain block
 *
 * Ask the xenstore for the maximum memory allowed for a domain
 *
 * Returns the memory size in kilobytes or 0 in case of error.
 */
498
unsigned long long
499 500 501
xenStoreDomainGetMaxMemory(virDomainPtr domain)
{
    char *tmp;
502
    unsigned long long ret = 0;
D
Daniel P. Berrange 已提交
503
    xenUnifiedPrivatePtr priv;
504

505 506
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
        return (ret);
507
    if (domain->id == -1)
508
        return 0;
509

D
Daniel P. Berrange 已提交
510 511
    priv = domain->conn->privateData;
    xenUnifiedLock(priv);
512
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
513
    if (tmp != NULL) {
514
        ret = atol(tmp);
D
Daniel P. Berrange 已提交
515
        VIR_FREE(tmp);
516
    }
D
Daniel P. Berrange 已提交
517
    xenUnifiedUnlock(priv);
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
    return(ret);
}

/**
 * xenStoreNumOfDomains:
 * @conn: pointer to the hypervisor connection
 *
 * Provides the number of active domains.
 *
 * Returns the number of domain found or -1 in case of error
 */
int
xenStoreNumOfDomains(virConnectPtr conn)
{
    unsigned int num;
533 534 535
    char **idlist = NULL, *endptr;
    int i, ret = -1, realnum = 0;
    long id;
536
    xenUnifiedPrivatePtr priv;
537

538
    if (conn == NULL) {
539
        virXenStoreError(VIR_ERR_INVALID_ARG, __FUNCTION__);
540
        return -1;
541
    }
542 543 544

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL) {
545
        virXenStoreError(VIR_ERR_INVALID_ARG, __FUNCTION__);
546 547
        return(-1);
    }
548

549
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
550
    if (idlist) {
551 552 553 554 555 556 557 558 559 560 561 562 563
        for (i = 0; i < num; i++) {
            id = strtol(idlist[i], &endptr, 10);
            if ((endptr == idlist[i]) || (*endptr != 0))
                goto out;

            /* Sometimes xenstore has stale domain IDs, so filter
               against the hypervisor's info */
            if (xenHypervisorHasDomain(conn, (int)id))
                realnum++;
        }
out:
        VIR_FREE (idlist);
        ret = realnum;
564 565 566 567 568
    }
    return(ret);
}

/**
569
 * xenStoreDoListDomains:
570 571 572 573
 * @conn: pointer to the hypervisor connection
 * @ids: array to collect the list of IDs of active domains
 * @maxids: size of @ids
 *
574 575
 * Internal API: collect the list of active domains, and store
 * their ID in @maxids. The driver lock must be held.
576 577 578
 *
 * Returns the number of domain found or -1 in case of error
 */
579
static int
580
xenStoreDoListDomains(virConnectPtr conn, xenUnifiedPrivatePtr priv, int *ids, int maxids)
581 582 583
{
    char **idlist = NULL, *endptr;
    unsigned int num, i;
584
    int ret = -1;
585
    long id;
D
Daniel P. Berrange 已提交
586

587
    if (priv->xshandle == NULL)
588
        goto out;
589

590
    idlist = xs_directory (priv->xshandle, 0, "/local/domain", &num);
591
    if (idlist == NULL)
592
        goto out;
593 594

    for (ret = 0, i = 0; (i < num) && (ret < maxids); i++) {
595
        id = strtol(idlist[i], &endptr, 10);
596 597
        if ((endptr == idlist[i]) || (*endptr != 0))
            goto out;
598 599 600 601 602

        /* Sometimes xenstore has stale domain IDs, so filter
           against the hypervisor's info */
        if (xenHypervisorHasDomain(conn, (int)id))
            ids[ret++] = (int) id;
603
    }
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626

out:
    VIR_FREE (idlist);
    return ret;
}

/**
 * xenStoreListDomains:
 * @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
 *
 * Returns the number of domain found or -1 in case of error
 */
int
xenStoreListDomains(virConnectPtr conn, int *ids, int maxids)
{
    xenUnifiedPrivatePtr priv;
    int ret;

    if ((conn == NULL) || (ids == NULL)) {
627
        virXenStoreError(VIR_ERR_INVALID_ARG, __FUNCTION__);
628 629 630 631 632 633
        return(-1);
    }

    priv = (xenUnifiedPrivatePtr) conn->privateData;

    xenUnifiedLock(priv);
634
    ret = xenStoreDoListDomains(conn, priv, ids, maxids);
D
Daniel P. Berrange 已提交
635
    xenUnifiedUnlock(priv);
636 637

    return(ret);
638 639 640
}

/**
641
 * xenStoreLookupByName:
642 643 644 645 646 647 648 649
 * @conn: A xend instance
 * @name: The name of the domain
 *
 * Try to lookup a domain on the Xen Store based on its name.
 *
 * Returns a new domain object or NULL in case of failure
 */
virDomainPtr
650
xenStoreLookupByName(virConnectPtr conn, const char *name)
651 652 653 654 655
{
    virDomainPtr ret = NULL;
    unsigned int num, i, len;
    long id = -1;
    char **idlist = NULL, *endptr;
656
    char prop[200], *tmp;
657 658
    int found = 0;
    struct xend_domain *xenddomain = NULL;
659
    xenUnifiedPrivatePtr priv;
660 661

    if ((conn == NULL) || (name == NULL)) {
662
        virXenStoreError(VIR_ERR_INVALID_ARG, __FUNCTION__);
663
        return(NULL);
664
    }
665 666 667

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
668 669
        return(NULL);

670
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
671
    if (idlist == NULL)
672
        goto done;
673 674

    for (i = 0; i < num; i++) {
675 676 677 678
        id = strtol(idlist[i], &endptr, 10);
        if ((endptr == idlist[i]) || (*endptr != 0)) {
            goto done;
        }
679
#if 0
680 681
        if (virConnectCheckStoreID(conn, (int) id) < 0)
            continue;
682
#endif
683 684 685 686 687
        snprintf(prop, 199, "/local/domain/%s/name", idlist[i]);
        prop[199] = 0;
        tmp = xs_read(priv->xshandle, 0, prop, &len);
        if (tmp != NULL) {
            found = STREQ (name, tmp);
688
            VIR_FREE(tmp);
689 690 691
            if (found)
                break;
        }
692 693
    }
    if (!found)
694
        goto done;
695

696
    ret = virGetDomain(conn, name, NULL);
697
    if (ret == NULL)
698
        goto done;
699

700
    ret->id = id;
701 702

done:
703 704
    VIR_FREE(xenddomain);
    VIR_FREE(idlist);
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721

    return(ret);
}

/**
 * xenStoreDomainShutdown:
 * @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 in case of error.
 */
int
xenStoreDomainShutdown(virDomainPtr domain)
{
D
Daniel P. Berrange 已提交
722 723 724
    int ret;
    xenUnifiedPrivatePtr priv;

725
    if ((domain == NULL) || (domain->conn == NULL)) {
726
        virXenStoreError(VIR_ERR_INVALID_ARG, __FUNCTION__);
727 728
        return(-1);
    }
729
    if (domain->id == -1 || domain->id == 0)
730
        return(-1);
731
    /*
732
     * this is very hackish, the domU kernel probes for a special
733 734
     * node in the xenstore and launch the shutdown command if found.
     */
D
Daniel P. Berrange 已提交
735 736 737 738 739
    priv = domain->conn->privateData;
    xenUnifiedLock(priv);
    ret = virDomainDoStoreWrite(domain, "control/shutdown", "poweroff");
    xenUnifiedUnlock(priv);
    return ret;
740 741
}

742 743 744 745 746 747 748 749 750 751 752 753
/**
 * xenStoreDomainReboot:
 * @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 reboot but the domain may ignore it.  It will return immediately
 * after queuing the request.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
E
Eric Blake 已提交
754
xenStoreDomainReboot(virDomainPtr domain, unsigned int flags)
755
{
D
Daniel P. Berrange 已提交
756 757 758
    int ret;
    xenUnifiedPrivatePtr priv;

E
Eric Blake 已提交
759 760
    virCheckFlags(0, -1);

761
    if ((domain == NULL) || (domain->conn == NULL)) {
762
        virXenStoreError(VIR_ERR_INVALID_ARG, __FUNCTION__);
763 764
        return(-1);
    }
765
    if (domain->id == -1 || domain->id == 0)
766
        return(-1);
767
    /*
768
     * this is very hackish, the domU kernel probes for a special
769 770
     * node in the xenstore and launch the shutdown command if found.
     */
D
Daniel P. Berrange 已提交
771 772 773 774 775
    priv = domain->conn->privateData;
    xenUnifiedLock(priv);
    ret = virDomainDoStoreWrite(domain, "control/shutdown", "reboot");
    xenUnifiedUnlock(priv);
    return ret;
776
}
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791

/*
 * xenStoreDomainGetOSType:
 * @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 *
xenStoreDomainGetOSType(virDomainPtr domain) {
    char *vm, *str = NULL;

    if ((domain == NULL) || (domain->conn == NULL)) {
792
        virXenStoreError(VIR_ERR_INVALID_ARG, __FUNCTION__);
793 794 795 796 797
        return(NULL);
    }

    vm = virDomainGetVM(domain);
    if (vm) {
D
Daniel P. Berrange 已提交
798 799
        xenUnifiedPrivatePtr priv = domain->conn->privateData;
        xenUnifiedLock(priv);
800
        str = virDomainGetVMInfo(domain, vm, "image/ostype");
D
Daniel P. Berrange 已提交
801 802
        xenUnifiedUnlock(priv);
        VIR_FREE(vm);
803 804 805 806
    }

    return (str);
}
807

808 809
/**
 * xenStoreDomainGetVNCPort:
810 811
 * @conn: the hypervisor connection
 * @domid: id of the domain
812 813
 *
 * Return the port number on which the domain is listening for VNC
814
 * connections.
815
 *
D
Daniel P. Berrange 已提交
816 817 818
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
819 820
 * Returns the port number, -1 in case of error
 */
821
int             xenStoreDomainGetVNCPort(virConnectPtr conn, int domid) {
822 823 824
    char *tmp;
    int ret = -1;

825
    tmp = virDomainDoStoreQuery(conn, domid, "console/vnc-port");
826 827 828 829 830
    if (tmp != NULL) {
        char *end;
        ret = strtol(tmp, &end, 10);
        if (ret == 0 && end == tmp)
            ret = -1;
831
        VIR_FREE(tmp);
832 833 834 835 836 837
    }
    return(ret);
}

/**
 * xenStoreDomainGetConsolePath:
838 839
 * @conn: the hypervisor connection
 * @domid: id of the domain
840
 *
841
 * Return the path to the pseudo TTY on which the guest domain's
842 843 844 845 846
 * serial console is attached.
 *
 * Returns the path to the serial console. It is the callers
 * responsibilty to free() the return string. Returns NULL
 * on error
D
Daniel P. Berrange 已提交
847 848 849
 *
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
850
 */
851 852
char *          xenStoreDomainGetConsolePath(virConnectPtr conn, int domid) {
  return virDomainDoStoreQuery(conn, domid, "console/tty");
853
}
854

855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873
/**
 * xenStoreDomainGetSerailConsolePath:
 * @conn: the hypervisor connection
 * @domid: id of the domain
 *
 * Return the path to the pseudo TTY on which the guest domain's
 * serial console is attached.
 *
 * Returns the path to the serial console. It is the callers
 * responsibilty to free() the return string. Returns NULL
 * on error
 *
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
char * xenStoreDomainGetSerialConsolePath(virConnectPtr conn, int domid) {
    return virDomainDoStoreQuery(conn, domid, "serial/0/tty");
}

874 875 876 877 878 879 880 881 882 883

/*
 * xenStoreDomainGetNetworkID:
 * @conn: pointer to the connection.
 * @id: the domain id
 * @mac: the mac address
 *
 * Get the reference (i.e. the string number) for the device on that domain
 * which uses the given mac address
 *
D
Daniel P. Berrange 已提交
884 885 886
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
887 888 889 890 891 892
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
char *
xenStoreDomainGetNetworkID(virConnectPtr conn, int id, const char *mac) {
    char dir[80], path[128], **list = NULL, *val = NULL;
893
    unsigned int len, i, num;
894
    char *ret = NULL;
895
    xenUnifiedPrivatePtr priv;
896 897 898

    if (id < 0)
        return(NULL);
899 900 901

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
902 903 904 905
        return (NULL);
    if (mac == NULL)
        return (NULL);

906
    snprintf(dir, sizeof(dir), "/local/domain/0/backend/vif/%d", id);
907
    list = xs_directory(priv->xshandle, 0, dir, &num);
908
    if (list == NULL)
909
        return(NULL);
910
    for (i = 0; i < num; i++) {
911
        snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "mac");
912
        if ((val = xs_read(priv->xshandle, 0, path, &len)) == NULL)
913
            break;
914 915 916 917 918 919

        bool match = (virMacAddrCompare(val, mac) == 0);

        VIR_FREE(val);

        if (match) {
920
            ret = strdup(list[i]);
921 922

            if (ret == NULL)
923
                virReportOOMError();
924

925 926
            break;
        }
927
    }
928 929

    VIR_FREE(list);
930 931
    return(ret);
}
932

933 934 935 936 937 938 939 940 941
/*
 * xenStoreDomainGetDiskID:
 * @conn: pointer to the connection.
 * @id: the domain id
 * @dev: the virtual block device name
 *
 * Get the reference (i.e. the string number) for the device on that domain
 * which uses the given virtual block device name
 *
D
Daniel P. Berrange 已提交
942 943 944
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
char *
xenStoreDomainGetDiskID(virConnectPtr conn, int id, const char *dev) {
    char dir[80], path[128], **list = NULL, *val = NULL;
    unsigned int devlen, len, i, num;
    char *ret = NULL;
    xenUnifiedPrivatePtr priv;

    if (id < 0)
        return(NULL);

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
        return (NULL);
    if (dev == NULL)
        return (NULL);
    devlen = strlen(dev);
    if (devlen <= 0)
        return (NULL);

    snprintf(dir, sizeof(dir), "/local/domain/0/backend/vbd/%d", id);
    list = xs_directory(priv->xshandle, 0, dir, &num);
969 970 971 972 973 974 975
    if (list != NULL) {
        for (i = 0; i < num; i++) {
            snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
            val = xs_read(priv->xshandle, 0, path, &len);
            if (val == NULL)
                break;
            if ((devlen != len) || memcmp(val, dev, len)) {
976
                VIR_FREE (val);
977 978
            } else {
                ret = strdup(list[i]);
979 980

                if (ret == NULL)
981
                    virReportOOMError();
982 983 984

                VIR_FREE (val);
                VIR_FREE (list);
985 986
                return (ret);
            }
987
        }
988
        VIR_FREE (list);
989
    }
990 991 992 993 994 995 996 997 998
    snprintf(dir, sizeof(dir), "/local/domain/0/backend/tap/%d", id);
    list = xs_directory(priv->xshandle, 0, dir, &num);
    if (list != NULL) {
        for (i = 0; i < num; i++) {
            snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
            val = xs_read(priv->xshandle, 0, path, &len);
            if (val == NULL)
                break;
            if ((devlen != len) || memcmp(val, dev, len)) {
999
                VIR_FREE (val);
1000 1001
            } else {
                ret = strdup(list[i]);
1002 1003

                if (ret == NULL)
1004
                    virReportOOMError();
1005 1006 1007

                VIR_FREE (val);
                VIR_FREE (list);
1008 1009 1010
                return (ret);
            }
        }
1011
        VIR_FREE (list);
1012 1013
    }
    return (NULL);
1014 1015
}

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
/*
 * xenStoreDomainGetPCIID:
 * @conn: pointer to the connection.
 * @id: the domain id
 * @bdf: the PCI BDF
 *
 * Get the reference (i.e. the string number) for the device on that domain
 * which uses the given PCI address
 *
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
char *
xenStoreDomainGetPCIID(virConnectPtr conn, int id, const char *bdf)
{
    char dir[80], path[128], **list = NULL, *val = NULL;
    unsigned int len, i, num;
    char *ret = NULL;
    xenUnifiedPrivatePtr priv;

    if (id < 0)
        return(NULL);

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
        return (NULL);
    if (bdf == NULL)
        return (NULL);

    snprintf(dir, sizeof(dir), "/local/domain/0/backend/pci/%d", id);
    list = xs_directory(priv->xshandle, 0, dir, &num);
    if (list == NULL)
        return(NULL);
    for (i = 0; i < num; i++) {
        snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev-0");
        if ((val = xs_read(priv->xshandle, 0, path, &len)) == NULL)
            break;

        bool match = STREQ(val, bdf);

        VIR_FREE(val);

        if (match) {
            ret = strdup(list[i]);
            break;
        }
    }

    VIR_FREE(list);
    return(ret);
}

D
Daniel P. Berrange 已提交
1071 1072 1073 1074
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089
char *xenStoreDomainGetName(virConnectPtr conn,
                            int id) {
    char prop[200];
    xenUnifiedPrivatePtr priv;
    unsigned int len;

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
        return(NULL);

    snprintf(prop, 199, "/local/domain/%d/name", id);
    prop[199] = 0;
    return xs_read(priv->xshandle, 0, prop, &len);
}

D
Daniel P. Berrange 已提交
1090 1091 1092 1093
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
int xenStoreDomainGetUUID(virConnectPtr conn,
                          int id,
                          unsigned char *uuid) {
    char prop[200];
    xenUnifiedPrivatePtr priv;
    unsigned int len;
    char *uuidstr;
    int ret = 0;

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
        return -1;

    snprintf(prop, 199, "/local/domain/%d/vm", id);
    prop[199] = 0;
1109 1110
    /* This will return something like
     * /vm/00000000-0000-0000-0000-000000000000 */
1111 1112
    uuidstr = xs_read(priv->xshandle, 0, prop, &len);

1113
    /* remove "/vm/" */
1114 1115 1116 1117 1118 1119 1120
    ret = virUUIDParse(uuidstr + 4, uuid);

    VIR_FREE(uuidstr);

    return ret;
}

D
Daniel P. Berrange 已提交
1121 1122
static void
xenStoreWatchListFree(xenStoreWatchListPtr list)
1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
{
    int i;
    for (i=0; i<list->count; i++) {
        VIR_FREE(list->watches[i]->path);
        VIR_FREE(list->watches[i]->token);
        VIR_FREE(list->watches[i]);
    }
    VIR_FREE(list);
}

D
Daniel P. Berrange 已提交
1133 1134 1135 1136
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1137 1138 1139 1140 1141 1142
int xenStoreAddWatch(virConnectPtr conn,
                     const char *path,
                     const char *token,
                     xenStoreWatchCallback cb,
                     void *opaque)
{
1143
    xenStoreWatchPtr watch = NULL;
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
    int n;
    xenStoreWatchListPtr list;
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;

    if (priv->xshandle == NULL)
        return -1;

    list = priv->xsWatchList;
    if(!list)
        return -1;

    /* check if we already have this callback on our list */
    for (n=0; n < list->count; n++) {
        if( STREQ(list->watches[n]->path, path) &&
            STREQ(list->watches[n]->token, token)) {
1159 1160
            virXenStoreError(VIR_ERR_INTERNAL_ERROR,
                             "%s", _("watch already tracked"));
1161 1162 1163 1164 1165
            return -1;
        }
    }

    if (VIR_ALLOC(watch) < 0)
1166 1167
        goto no_memory;

1168 1169 1170 1171 1172
    watch->path   = strdup(path);
    watch->token  = strdup(token);
    watch->cb     = cb;
    watch->opaque = opaque;

1173 1174 1175 1176
    if (watch->path == NULL || watch->token == NULL) {
        goto no_memory;
    }

1177 1178 1179
    /* Make space on list */
    n = list->count;
    if (VIR_REALLOC_N(list->watches, n + 1) < 0) {
1180
        goto no_memory;
1181 1182 1183 1184 1185 1186
    }

    list->watches[n] = watch;
    list->count++;

    return xs_watch(priv->xshandle, watch->path, watch->token);
1187 1188 1189 1190 1191 1192 1193 1194

  no_memory:
    if (watch) {
        VIR_FREE(watch->path);
        VIR_FREE(watch->token);
        VIR_FREE(watch);
    }

1195
    virReportOOMError();
1196 1197

    return -1;
1198 1199
}

D
Daniel P. Berrange 已提交
1200 1201 1202 1203
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
int xenStoreRemoveWatch(virConnectPtr conn,
                        const char *path,
                        const char *token)
{
    int i;
    xenStoreWatchListPtr list;
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;

    if (priv->xshandle == NULL)
        return -1;

    list = priv->xsWatchList;
    if(!list)
        return -1;

    for (i = 0 ; i < list->count ; i++) {
        if( STREQ(list->watches[i]->path, path) &&
            STREQ(list->watches[i]->token, token)) {

            if (!xs_unwatch(priv->xshandle,
                       list->watches[i]->path,
1225
                       list->watches[i]->token))
1226
            {
1227
                VIR_DEBUG("WARNING: Could not remove watch");
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
                /* Not fatal, continue */
            }

            VIR_FREE(list->watches[i]->path);
            VIR_FREE(list->watches[i]->token);
            VIR_FREE(list->watches[i]);

            if (i < (list->count - 1))
                memmove(list->watches + i,
                        list->watches + i + 1,
                        sizeof(*(list->watches)) *
                                (list->count - (i + 1)));

            if (VIR_REALLOC_N(list->watches,
                              list->count - 1) < 0) {
                ; /* Failure to reduce memory allocation isn't fatal */
            }
            list->count--;
            return 0;
        }
    }
    return -1;
}

D
Daniel P. Berrange 已提交
1252 1253 1254 1255
static xenStoreWatchPtr
xenStoreFindWatch(xenStoreWatchListPtr list,
                  const char *path,
                  const char *token)
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
{
    int i;
    for (i = 0 ; i < list->count ; i++)
        if( STREQ(path, list->watches[i]->path) &&
            STREQ(token, list->watches[i]->token) )
            return list->watches[i];

    return NULL;
}

D
Daniel P. Berrange 已提交
1266 1267 1268
static void
xenStoreWatchEvent(int watch ATTRIBUTE_UNUSED,
                   int fd ATTRIBUTE_UNUSED,
1269
                   int events,
D
Daniel P. Berrange 已提交
1270
                   void *data)
1271 1272 1273 1274 1275 1276 1277 1278 1279
{
    char		 **event;
    char		 *path;
    char		 *token;
    unsigned int	 stringCount;
    xenStoreWatchPtr     sw;

    virConnectPtr        conn = data;
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
1280

1281
    if(!priv) return;
D
Daniel P. Berrange 已提交
1282

1283 1284 1285
    /* only set a watch on read and write events */
    if (events & (VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP)) return;

D
Daniel P. Berrange 已提交
1286 1287 1288 1289
    xenUnifiedLock(priv);

    if(!priv->xshandle)
        goto cleanup;
1290 1291 1292

    event = xs_read_watch(priv->xshandle, &stringCount);
    if (!event)
D
Daniel P. Berrange 已提交
1293
        goto cleanup;
1294 1295 1296 1297 1298 1299 1300 1301

    path  = event[XS_WATCH_PATH];
    token = event[XS_WATCH_TOKEN];

    sw = xenStoreFindWatch(priv->xsWatchList, path, token);
    if( sw )
        sw->cb(conn, path, token, sw->opaque);
    VIR_FREE(event);
D
Daniel P. Berrange 已提交
1302 1303 1304

cleanup:
    xenUnifiedUnlock(priv);
1305 1306
}

D
Daniel P. Berrange 已提交
1307 1308 1309 1310 1311 1312

/*
 * The domain callback for the @introduceDomain watch
 *
 * The lock on 'priv' is held when calling this
 */
1313 1314 1315 1316 1317 1318 1319 1320 1321 1322
int xenStoreDomainIntroduced(virConnectPtr conn,
                             const char *path ATTRIBUTE_UNUSED,
                             const char *token ATTRIBUTE_UNUSED,
                             void *opaque)
{
    int i, j, found, missing = 0, retries = 20;
    int new_domain_cnt;
    int *new_domids;
    int nread;

1323
    xenUnifiedPrivatePtr priv = opaque;
1324 1325 1326

retry:
    new_domain_cnt = xenStoreNumOfDomains(conn);
1327 1328 1329
    if (new_domain_cnt < 0)
        return -1;

1330
    if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
1331
        virReportOOMError();
1332 1333
        return -1;
    }
1334
    nread = xenStoreDoListDomains(conn, priv, new_domids, new_domain_cnt);
1335
    if (nread != new_domain_cnt) {
1336
        /* mismatch. retry this read */
1337 1338 1339 1340 1341 1342 1343
        VIR_FREE(new_domids);
        goto retry;
    }

    missing = 0;
    for (i=0 ; i < new_domain_cnt ; i++) {
        found = 0;
1344 1345
        for (j = 0 ; j < priv->activeDomainList->count ; j++) {
            if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
1346 1347 1348 1349 1350 1351
                found = 1;
                break;
            }
        }

        if (!found) {
1352
            virDomainEventPtr event;
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365
            char *name;
            unsigned char uuid[VIR_UUID_BUFLEN];

            if (!(name = xenStoreDomainGetName(conn, new_domids[i]))) {
                missing = 1;
                continue;
            }
            if (xenStoreDomainGetUUID(conn, new_domids[i], uuid) < 0) {
                missing = 1;
                VIR_FREE(name);
                continue;
            }

1366 1367 1368 1369 1370
            event = virDomainEventNew(new_domids[i], name, uuid,
                                      VIR_DOMAIN_EVENT_STARTED,
                                      VIR_DOMAIN_EVENT_STARTED_BOOTED);
            if (event)
                xenUnifiedDomainEventDispatch(priv, event);
1371

1372
            /* Add to the list */
1373
            xenUnifiedAddDomainInfo(priv->activeDomainList,
1374
                                    new_domids[i], name, uuid);
1375 1376 1377 1378 1379 1380 1381

            VIR_FREE(name);
        }
    }
    VIR_FREE(new_domids);

    if (missing && retries--) {
1382
        VIR_DEBUG("Some domains were missing, trying again");
1383 1384 1385 1386 1387 1388
        usleep(100 * 1000);
        goto retry;
    }
    return 0;
}

D
Daniel P. Berrange 已提交
1389 1390 1391 1392 1393
/*
 * The domain callback for the @destroyDomain watch
 *
 * The lock on 'priv' is held when calling this
 */
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405
int xenStoreDomainReleased(virConnectPtr conn,
                            const char *path  ATTRIBUTE_UNUSED,
                            const char *token ATTRIBUTE_UNUSED,
                            void *opaque)
{
    int i, j, found, removed, retries = 20;
    int new_domain_cnt;
    int *new_domids;
    int nread;

    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) opaque;

1406
    if(!priv->activeDomainList->count) return 0;
1407 1408 1409

retry:
    new_domain_cnt = xenStoreNumOfDomains(conn);
1410 1411
    if (new_domain_cnt < 0)
        return -1;
1412 1413

    if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
1414
        virReportOOMError();
1415 1416
        return -1;
    }
1417
    nread = xenStoreDoListDomains(conn, priv, new_domids, new_domain_cnt);
1418
    if (nread != new_domain_cnt) {
1419
        /* mismatch. retry this read */
1420 1421 1422 1423 1424
        VIR_FREE(new_domids);
        goto retry;
    }

    removed = 0;
1425
    for (j=0 ; j < priv->activeDomainList->count ; j++) {
1426 1427
        found = 0;
        for (i=0 ; i < new_domain_cnt ; i++) {
1428
            if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
1429 1430 1431 1432 1433 1434
                found = 1;
                break;
            }
        }

        if (!found) {
1435 1436
            virDomainEventPtr event =
                virDomainEventNew(-1,
1437 1438
                                  priv->activeDomainList->doms[j]->name,
                                  priv->activeDomainList->doms[j]->uuid,
1439 1440 1441 1442 1443 1444
                                  VIR_DOMAIN_EVENT_STOPPED,
                                  VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
            if (event)
                xenUnifiedDomainEventDispatch(priv, event);

            /* Remove from the list */
1445 1446 1447 1448
            xenUnifiedRemoveDomainInfo(priv->activeDomainList,
                                       priv->activeDomainList->doms[j]->id,
                                       priv->activeDomainList->doms[j]->name,
                                       priv->activeDomainList->doms[j]->uuid);
1449 1450

            removed = 1;
1451 1452 1453 1454 1455 1456
        }
    }

    VIR_FREE(new_domids);

    if (!removed && retries--) {
1457
        VIR_DEBUG("No domains removed, retrying");
1458 1459 1460 1461 1462
        usleep(100 * 1000);
        goto retry;
    }
    return 0;
}