xs_internal.c 37.8 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
        return NULL;
85

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
        return NULL;
112

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
    int ret = -1;

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

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

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
        ret = 0;

152
    return ret;
153 154 155 156 157 158 159 160 161 162
}

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

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

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

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

181
    vm = xs_read(priv->xshandle, 0, &query[0], &len);
182

183
    return vm;
184 185 186 187 188 189 190 191
}

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

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

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

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

215
    ret = xs_read(priv->xshandle, 0, &s[0], &len);
216

217
    return ret;
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
}


/************************************************************************
 *									*
 *		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
        return -1;
261
    }
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
    if (priv->xshandle == NULL)
342
        return -1;
343

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

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

350
    return 0;
351 352 353 354 355
}

/**
 * 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
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
371
        return -1;
372

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
    return 0;
420 421
}

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
    snprintf(value, 19, "%lu", memory);
    value[19] = 0;
    ret = virDomainDoStoreWrite(domain, "memory/target", &value[0]);
    if (ret < 0)
486 487
        return -1;
    return 0;
488 489 490 491 492 493 494 495 496 497
}

/**
 * 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
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
506
        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
    return ret;
519 520 521 522 523 524 525 526 527 528 529 530 531 532
}

/**
 * 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
        return -1;
547
    }
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
    return ret;
566 567 568
}

/**
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
        return -1;
629 630 631 632 633
    }

    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
        return NULL;
669

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
    return ret;
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
}

/**
 * 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
        return -1;
728
    }
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
        return -1;
764
    }
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
        return NULL;
794 795 796 797
    }

    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
    return str;
806
}
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
    return ret;
834 835 836 837
}

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

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

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

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
    return ret;
931
}
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
 * 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)
956
        return NULL;
957 958 959

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
960
        return NULL;
961
    if (dev == NULL)
962
        return NULL;
963 964
    devlen = strlen(dev);
    if (devlen <= 0)
965
        return NULL;
966 967 968

    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
                return ret;
986
            }
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
                return ret;
1009 1010
            }
        }
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
/*
 * 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)
1040
        return NULL;
1041 1042 1043

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
1044
        return NULL;
1045
    if (bdf == NULL)
1046
        return NULL;
1047 1048 1049 1050

    snprintf(dir, sizeof(dir), "/local/domain/0/backend/pci/%d", id);
    list = xs_directory(priv->xshandle, 0, dir, &num);
    if (list == NULL)
1051
        return NULL;
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
    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);
1068
    return ret;
1069 1070
}

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
char *xenStoreDomainGetName(virConnectPtr conn,
                            int id) {
    char prop[200];
    xenUnifiedPrivatePtr priv;
    unsigned int len;

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
1083
        return NULL;
1084 1085 1086 1087 1088 1089

    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;
}