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

23
#include <config.h>
J
Jim Meyering 已提交
24

25 26 27 28 29 30 31 32 33 34
#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>

35
#include <xen/dom0_ops.h>
36 37
#include <xen/version.h>

38 39 40 41 42
#if HAVE_XENSTORE_H
# include <xenstore.h>
#else
# include <xs.h>
#endif
43

44
#include "virterror_internal.h"
45
#include "datatypes.h"
46
#include "driver.h"
47
#include "viralloc.h"
48
#include "virlog.h"
49
#include "uuid.h"
50
#include "xen_driver.h"
51
#include "xs_internal.h"
52
#include "xen_hypervisor.h"
53

54 55
#define VIR_FROM_THIS VIR_FROM_XEN

56
static char *xenStoreDomainGetOSType(virDomainPtr domain);
D
Daniel P. Berrange 已提交
57 58
static void xenStoreWatchEvent(int watch, int fd, int events, void *data);
static void xenStoreWatchListFree(xenStoreWatchListPtr list);
59

60
struct xenUnifiedDriver xenStoreDriver = {
E
Eric Blake 已提交
61 62 63 64 65 66 67
    .xenClose = xenStoreClose,
    .xenDomainShutdown = xenStoreDomainShutdown,
    .xenDomainReboot = xenStoreDomainReboot,
    .xenDomainGetOSType = xenStoreDomainGetOSType,
    .xenDomainGetMaxMemory = xenStoreDomainGetMaxMemory,
    .xenDomainSetMemory = xenStoreDomainSetMemory,
    .xenDomainGetInfo = xenStoreGetDomainInfo,
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
};

/************************************************************************
 *									*
 *		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)
{
89 90 91 92 93 94 95
    xenUnifiedPrivatePtr priv;

    if (conn == NULL)
        return NULL;

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

98
    return xs_directory(priv->xshandle, 0, path, nb);
99 100 101 102
}

/**
 * virDomainDoStoreQuery:
103 104
 * @conn: pointer to the hypervisor connection
 * @domid: id of the domain
105 106 107 108 109 110 111
 * @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 *
112
virDomainDoStoreQuery(virConnectPtr conn, int domid, const char *path)
113 114 115
{
    char s[256];
    unsigned int len = 0;
116 117 118 119
    xenUnifiedPrivatePtr priv;

    if (!conn)
        return NULL;
120

121 122
    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
123
        return NULL;
124

125
    snprintf(s, 255, "/local/domain/%d/%s", domid, path);
126 127
    s[255] = 0;

128
    return xs_read(priv->xshandle, 0, &s[0], &len);
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
}

/**
 * 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];
146
    xenUnifiedPrivatePtr priv;
147 148 149
    int ret = -1;

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
150
        return -1;
151 152 153

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
154
        return -1;
155
    if (domain->conn->flags & VIR_CONNECT_RO)
156
        return -1;
157

158
    snprintf(s, 255, "/local/domain/%d/%s", domain->id, path);
159 160
    s[255] = 0;

161
    if (xs_write(priv->xshandle, 0, &s[0], value, strlen(value)))
162 163
        ret = 0;

164
    return ret;
165 166 167 168 169 170 171 172 173 174
}

/**
 * virDomainGetVM:
 * @domain: a domain object
 *
 * Internal API extracting a xenstore vm path.
 *
 * Returns the new string or NULL in case of error
 */
175
static char *
176 177 178 179 180
virDomainGetVM(virDomainPtr domain)
{
    char *vm;
    char query[200];
    unsigned int len;
181
    xenUnifiedPrivatePtr priv;
182 183

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
184
        return NULL;
185 186 187

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
188
        return NULL;
189 190 191 192

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

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

195
    return vm;
196 197 198 199 200 201 202 203
}

/**
 * virDomainGetVMInfo:
 * @domain: a domain object
 * @vm: the xenstore vm path
 * @name: the value's path
 *
204
 * Internal API extracting one information the device used
205 206 207 208
 * by the domain from xensttore
 *
 * Returns the new string or NULL in case of error
 */
209
static char *
210 211 212 213 214
virDomainGetVMInfo(virDomainPtr domain, const char *vm, const char *name)
{
    char s[256];
    char *ret = NULL;
    unsigned int len = 0;
215
    xenUnifiedPrivatePtr priv;
216 217

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
218
        return NULL;
219 220 221

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
222
        return NULL;
223 224 225 226

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

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

229
    return ret;
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
}


/************************************************************************
 *									*
 *		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.
 */
248
virDrvOpenStatus
249
xenStoreOpen(virConnectPtr conn,
250
             virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
251
             unsigned int flags)
252
{
253
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
254

E
Eric Blake 已提交
255 256
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

257
    if (flags & VIR_CONNECT_RO)
258
        priv->xshandle = xs_daemon_open_readonly();
259
    else
260
        priv->xshandle = xs_daemon_open();
261

262
    if (priv->xshandle == NULL) {
263
        /*
J
John Levon 已提交
264 265
         * not being able to connect via the socket as an unprivileged
         * user is rather normal, this should fallback to the proxy (or
266
         * remote) mechanism.
267
         */
J
John Levon 已提交
268
        if (xenHavePrivilege()) {
269 270
            virReportError(VIR_ERR_NO_XEN,
                           "%s", _("failed to connect to Xen Store"));
271
        }
272
        return -1;
273
    }
274 275

    /* Init activeDomainList */
276
    if (VIR_ALLOC(priv->activeDomainList) < 0) {
277
        virReportOOMError();
278 279 280 281 282 283
        return -1;
    }

    /* Init watch list before filling in domInfoList,
       so we can know if it is the first time through
       when the callback fires */
284
    if (VIR_ALLOC(priv->xsWatchList) < 0) {
285
        virReportOOMError();
286 287 288 289
        return -1;
    }

    /* This will get called once at start */
290 291
    if (xenStoreAddWatch(conn, "@releaseDomain",
                         "releaseDomain", xenStoreDomainReleased, priv) < 0)
292
    {
293 294
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("adding watch @releaseDomain"));
295 296 297 298
        return -1;
    }

    /* The initial call of this will fill domInfoList */
299 300
    if (xenStoreAddWatch(conn, "@introduceDomain",
                         "introduceDomain", xenStoreDomainIntroduced, priv) < 0)
301
    {
302 303
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("adding watch @introduceDomain"));
304 305 306 307 308 309 310 311 312
        return -1;
    }

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

    return 0;
316 317 318 319 320 321 322 323 324 325 326 327 328
}

/**
 * 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)
{
329 330
    xenUnifiedPrivatePtr priv;

331
    if (conn == NULL) {
332
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
333
        return -1;
334 335
    }

336
    priv = (xenUnifiedPrivatePtr) conn->privateData;
337 338

    if (xenStoreRemoveWatch(conn, "@introduceDomain", "introduceDomain") < 0) {
339
        VIR_DEBUG("Warning, could not remove @introduceDomain watch");
340 341 342 343
        /* not fatal */
    }

    if (xenStoreRemoveWatch(conn, "@releaseDomain", "releaseDomain") < 0) {
344
        VIR_DEBUG("Warning, could not remove @releaseDomain watch");
345 346 347 348
        /* not fatal */
    }

    xenStoreWatchListFree(priv->xsWatchList);
J
John Levon 已提交
349
    priv->xsWatchList = NULL;
350 351
    xenUnifiedDomainInfoListFree(priv->activeDomainList);
    priv->activeDomainList = NULL;
352

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

356 357
    if (priv->xsWatch != -1)
        virEventRemoveHandle(priv->xsWatch);
358

359
    xs_daemon_close(priv->xshandle);
360 361
    priv->xshandle = NULL;

362
    return 0;
363 364 365 366 367
}

/**
 * xenStoreGetDomainInfo:
 * @domain: pointer to the domain block
368
 * @info: the place where information should be stored
369
 *
E
Eric Blake 已提交
370
 * Do a hypervisor call to get the related set of domain information.
371 372 373 374 375 376 377 378 379
 *
 * 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];
380
    xenUnifiedPrivatePtr priv;
381

382
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
383
        return -1;
384

385
    if ((domain == NULL) || (domain->conn == NULL) || (info == NULL)) {
386
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
387
        return -1;
388
    }
389 390 391

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

394
    if (domain->id == -1)
395
        return -1;
396

397
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "running");
398 399 400
    if (tmp != NULL) {
        if (tmp[0] == '1')
            info->state = VIR_DOMAIN_RUNNING;
401
        VIR_FREE(tmp);
402
    } else {
403
        info->state = VIR_DOMAIN_NOSTATE;
404
    }
405
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
406 407 408
    if (tmp != NULL) {
        info->memory = atol(tmp);
        info->maxMem = atol(tmp);
409
        VIR_FREE(tmp);
410 411 412 413
    } else {
        info->memory = 0;
        info->maxMem = 0;
    }
414
#if 0
415
    /* doesn't seems to work */
416
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "cpu_time");
417 418
    if (tmp != NULL) {
        info->cpuTime = atol(tmp);
419
        VIR_FREE(tmp);
420 421 422
    } else {
        info->cpuTime = 0;
    }
423
#endif
424
    snprintf(request, 199, "/local/domain/%d/cpu", domain->id);
425 426 427 428
    request[199] = 0;
    tmp2 = virConnectDoStoreList(domain->conn, request, &nb_vcpus);
    if (tmp2 != NULL) {
        info->nrVirtCpu = nb_vcpus;
429
        VIR_FREE(tmp2);
430
    }
431
    return 0;
432 433
}

434 435 436 437 438 439 440 441 442 443 444 445 446
/**
 * 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 已提交
447
                       unsigned int flags)
448 449 450
{
    char *running;

E
Eric Blake 已提交
451 452
    virCheckFlags(0, -1);

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
    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;
}

470
/**
471
 * xenStoreDomainSetMemory:
472 473 474 475 476 477 478 479
 * @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
480
xenStoreDomainSetMemory(virDomainPtr domain, unsigned long memory)
481 482 483 484
{
    int ret;
    char value[20];

D
Daniel Veillard 已提交
485 486
    if ((domain == NULL) || (domain->conn == NULL) ||
        (memory < 1024 * MIN_XEN_GUEST_SIZE)) {
487
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
488
        return -1;
489
    }
490
    if (domain->id == -1)
491
        return -1;
D
Daniel Veillard 已提交
492
    if ((domain->id == 0) && (memory < (2 * MIN_XEN_GUEST_SIZE * 1024)))
493
        return -1;
494 495 496 497
    snprintf(value, 19, "%lu", memory);
    value[19] = 0;
    ret = virDomainDoStoreWrite(domain, "memory/target", &value[0]);
    if (ret < 0)
498 499
        return -1;
    return 0;
500 501 502 503 504 505 506 507 508 509
}

/**
 * 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.
 */
510
unsigned long long
511 512 513
xenStoreDomainGetMaxMemory(virDomainPtr domain)
{
    char *tmp;
514
    unsigned long long ret = 0;
D
Daniel P. Berrange 已提交
515
    xenUnifiedPrivatePtr priv;
516

517
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
518
        return ret;
519
    if (domain->id == -1)
520
        return 0;
521

D
Daniel P. Berrange 已提交
522 523
    priv = domain->conn->privateData;
    xenUnifiedLock(priv);
524
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
525
    if (tmp != NULL) {
526
        ret = atol(tmp);
D
Daniel P. Berrange 已提交
527
        VIR_FREE(tmp);
528
    }
D
Daniel P. Berrange 已提交
529
    xenUnifiedUnlock(priv);
530
    return ret;
531 532 533 534 535 536 537 538 539 540 541 542 543 544
}

/**
 * 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;
545 546 547
    char **idlist = NULL, *endptr;
    int i, ret = -1, realnum = 0;
    long id;
548
    xenUnifiedPrivatePtr priv;
549

550
    if (conn == NULL) {
551
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
552
        return -1;
553
    }
554 555 556

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL) {
557
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
558
        return -1;
559
    }
560

561
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
562
    if (idlist) {
563 564 565 566 567 568 569 570 571 572 573
        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:
574
        VIR_FREE(idlist);
575
        ret = realnum;
576
    }
577
    return ret;
578 579 580
}

/**
581
 * xenStoreDoListDomains:
582 583 584 585
 * @conn: pointer to the hypervisor connection
 * @ids: array to collect the list of IDs of active domains
 * @maxids: size of @ids
 *
586 587
 * Internal API: collect the list of active domains, and store
 * their ID in @maxids. The driver lock must be held.
588 589 590
 *
 * Returns the number of domain found or -1 in case of error
 */
591
static int
592
xenStoreDoListDomains(virConnectPtr conn, xenUnifiedPrivatePtr priv, int *ids, int maxids)
593 594 595
{
    char **idlist = NULL, *endptr;
    unsigned int num, i;
596
    int ret = -1;
597
    long id;
D
Daniel P. Berrange 已提交
598

599
    if (priv->xshandle == NULL)
600
        goto out;
601

602
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
603
    if (idlist == NULL)
604
        goto out;
605 606

    for (ret = 0, i = 0; (i < num) && (ret < maxids); i++) {
607
        id = strtol(idlist[i], &endptr, 10);
608 609
        if ((endptr == idlist[i]) || (*endptr != 0))
            goto out;
610 611 612 613 614

        /* Sometimes xenstore has stale domain IDs, so filter
           against the hypervisor's info */
        if (xenHypervisorHasDomain(conn, (int)id))
            ids[ret++] = (int) id;
615
    }
616 617

out:
618
    VIR_FREE(idlist);
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638
    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)) {
639
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
640
        return -1;
641 642 643 644 645
    }

    priv = (xenUnifiedPrivatePtr) conn->privateData;

    xenUnifiedLock(priv);
646
    ret = xenStoreDoListDomains(conn, priv, ids, maxids);
D
Daniel P. Berrange 已提交
647
    xenUnifiedUnlock(priv);
648

649
    return ret;
650 651 652
}

/**
653
 * xenStoreLookupByName:
654 655 656 657 658 659 660 661
 * @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
662
xenStoreLookupByName(virConnectPtr conn, const char *name)
663 664 665 666 667
{
    virDomainPtr ret = NULL;
    unsigned int num, i, len;
    long id = -1;
    char **idlist = NULL, *endptr;
668
    char prop[200], *tmp;
669 670
    int found = 0;
    struct xend_domain *xenddomain = NULL;
671
    xenUnifiedPrivatePtr priv;
672 673

    if ((conn == NULL) || (name == NULL)) {
674
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
675
        return NULL;
676
    }
677 678 679

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

682
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
683
    if (idlist == NULL)
684
        goto done;
685 686

    for (i = 0; i < num; i++) {
687 688 689 690
        id = strtol(idlist[i], &endptr, 10);
        if ((endptr == idlist[i]) || (*endptr != 0)) {
            goto done;
        }
691
#if 0
692 693
        if (virConnectCheckStoreID(conn, (int) id) < 0)
            continue;
694
#endif
695 696 697 698
        snprintf(prop, 199, "/local/domain/%s/name", idlist[i]);
        prop[199] = 0;
        tmp = xs_read(priv->xshandle, 0, prop, &len);
        if (tmp != NULL) {
699
            found = STREQ(name, tmp);
700
            VIR_FREE(tmp);
701 702 703
            if (found)
                break;
        }
704 705
    }
    if (!found)
706
        goto done;
707

708
    ret = virGetDomain(conn, name, NULL);
709
    if (ret == NULL)
710
        goto done;
711

712
    ret->id = id;
713 714

done:
715 716
    VIR_FREE(xenddomain);
    VIR_FREE(idlist);
717

718
    return ret;
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
}

/**
 * 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 已提交
734 735 736
    int ret;
    xenUnifiedPrivatePtr priv;

737
    if ((domain == NULL) || (domain->conn == NULL)) {
738
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
739
        return -1;
740
    }
741
    if (domain->id == -1 || domain->id == 0)
742
        return -1;
743
    /*
744
     * this is very hackish, the domU kernel probes for a special
745 746
     * node in the xenstore and launch the shutdown command if found.
     */
D
Daniel P. Berrange 已提交
747 748 749 750 751
    priv = domain->conn->privateData;
    xenUnifiedLock(priv);
    ret = virDomainDoStoreWrite(domain, "control/shutdown", "poweroff");
    xenUnifiedUnlock(priv);
    return ret;
752 753
}

754 755 756 757 758 759 760 761 762 763 764 765
/**
 * 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 已提交
766
xenStoreDomainReboot(virDomainPtr domain, unsigned int flags)
767
{
D
Daniel P. Berrange 已提交
768 769 770
    int ret;
    xenUnifiedPrivatePtr priv;

E
Eric Blake 已提交
771 772
    virCheckFlags(0, -1);

773
    if ((domain == NULL) || (domain->conn == NULL)) {
774
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
775
        return -1;
776
    }
777
    if (domain->id == -1 || domain->id == 0)
778
        return -1;
779
    /*
780
     * this is very hackish, the domU kernel probes for a special
781 782
     * node in the xenstore and launch the shutdown command if found.
     */
D
Daniel P. Berrange 已提交
783 784 785 786 787
    priv = domain->conn->privateData;
    xenUnifiedLock(priv);
    ret = virDomainDoStoreWrite(domain, "control/shutdown", "reboot");
    xenUnifiedUnlock(priv);
    return ret;
788
}
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803

/*
 * 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)) {
804
        virReportError(VIR_ERR_INVALID_ARG, __FUNCTION__);
805
        return NULL;
806 807 808 809
    }

    vm = virDomainGetVM(domain);
    if (vm) {
D
Daniel P. Berrange 已提交
810 811
        xenUnifiedPrivatePtr priv = domain->conn->privateData;
        xenUnifiedLock(priv);
812
        str = virDomainGetVMInfo(domain, vm, "image/ostype");
D
Daniel P. Berrange 已提交
813 814
        xenUnifiedUnlock(priv);
        VIR_FREE(vm);
815 816
    }

817
    return str;
818
}
819

820 821
/**
 * xenStoreDomainGetVNCPort:
822 823
 * @conn: the hypervisor connection
 * @domid: id of the domain
824 825
 *
 * Return the port number on which the domain is listening for VNC
826
 * connections.
827
 *
D
Daniel P. Berrange 已提交
828 829 830
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
831 832
 * Returns the port number, -1 in case of error
 */
833
int             xenStoreDomainGetVNCPort(virConnectPtr conn, int domid) {
834 835 836
    char *tmp;
    int ret = -1;

837
    tmp = virDomainDoStoreQuery(conn, domid, "console/vnc-port");
838 839 840 841 842
    if (tmp != NULL) {
        char *end;
        ret = strtol(tmp, &end, 10);
        if (ret == 0 && end == tmp)
            ret = -1;
843
        VIR_FREE(tmp);
844
    }
845
    return ret;
846 847 848 849
}

/**
 * xenStoreDomainGetConsolePath:
850 851
 * @conn: the hypervisor connection
 * @domid: id of the domain
852
 *
853
 * Return the path to the pseudo TTY on which the guest domain's
854 855 856 857 858
 * 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 已提交
859 860 861
 *
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
862
 */
863 864
char *          xenStoreDomainGetConsolePath(virConnectPtr conn, int domid) {
  return virDomainDoStoreQuery(conn, domid, "console/tty");
865
}
866

867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
/**
 * 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");
}

886 887 888 889 890 891 892 893 894 895

/*
 * 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 已提交
896 897 898
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
899 900 901 902 903 904
 * 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;
905
    unsigned int len, i, num;
906
    char *ret = NULL;
907
    xenUnifiedPrivatePtr priv;
908 909

    if (id < 0)
910
        return NULL;
911 912 913

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
914
        return NULL;
915
    if (mac == NULL)
916
        return NULL;
917

918
    snprintf(dir, sizeof(dir), "/local/domain/0/backend/vif/%d", id);
919
    list = xs_directory(priv->xshandle, 0, dir, &num);
920
    if (list == NULL)
921
        return NULL;
922
    for (i = 0; i < num; i++) {
923
        snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "mac");
924
        if ((val = xs_read(priv->xshandle, 0, path, &len)) == NULL)
925
            break;
926 927 928 929 930 931

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

        VIR_FREE(val);

        if (match) {
932
            ret = strdup(list[i]);
933 934

            if (ret == NULL)
935
                virReportOOMError();
936

937 938
            break;
        }
939
    }
940 941

    VIR_FREE(list);
942
    return ret;
943
}
944

945 946 947 948 949 950 951 952 953
/*
 * 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 已提交
954 955 956
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 *
957 958 959 960 961 962 963 964 965 966 967
 * 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)
968
        return NULL;
969 970 971

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
972
        return NULL;
973
    if (dev == NULL)
974
        return NULL;
975 976
    devlen = strlen(dev);
    if (devlen <= 0)
977
        return NULL;
978 979 980

    snprintf(dir, sizeof(dir), "/local/domain/0/backend/vbd/%d", id);
    list = xs_directory(priv->xshandle, 0, dir, &num);
981 982 983 984 985 986 987
    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)) {
988
                VIR_FREE(val);
989 990
            } else {
                ret = strdup(list[i]);
991 992

                if (ret == NULL)
993
                    virReportOOMError();
994

995 996
                VIR_FREE(val);
                VIR_FREE(list);
997
                return ret;
998
            }
999
        }
1000
        VIR_FREE(list);
1001
    }
1002 1003 1004 1005 1006 1007 1008 1009 1010
    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)) {
1011
                VIR_FREE(val);
1012 1013
            } else {
                ret = strdup(list[i]);
1014 1015

                if (ret == NULL)
1016
                    virReportOOMError();
1017

1018 1019
                VIR_FREE(val);
                VIR_FREE(list);
1020
                return ret;
1021 1022
            }
        }
1023
        VIR_FREE(list);
1024
    }
1025
    return NULL;
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
/*
 * 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)
1052
        return NULL;
1053 1054 1055

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
1056
        return NULL;
1057
    if (bdf == NULL)
1058
        return NULL;
1059 1060 1061 1062

    snprintf(dir, sizeof(dir), "/local/domain/0/backend/pci/%d", id);
    list = xs_directory(priv->xshandle, 0, dir, &num);
    if (list == NULL)
1063
        return NULL;
1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
    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);
1080
    return ret;
1081 1082
}

D
Daniel P. Berrange 已提交
1083 1084 1085 1086
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1087 1088 1089 1090 1091 1092 1093 1094
char *xenStoreDomainGetName(virConnectPtr conn,
                            int id) {
    char prop[200];
    xenUnifiedPrivatePtr priv;
    unsigned int len;

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
1095
        return NULL;
1096 1097 1098 1099 1100 1101

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

D
Daniel P. Berrange 已提交
1102 1103 1104 1105
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120
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;
1121
    /* This will return something like
1122
     * /vm/00000000-0000-0000-0000-000000000000[-*] */
1123
    uuidstr = xs_read(priv->xshandle, 0, prop, &len);
1124 1125 1126
    /* Strip optional version suffix when VM was renamed */
    if (len > 40) /* strlen('/vm/') + VIR_UUID_STRING_BUFLEN - sizeof('\0') */
        uuidstr[40] = '\0';
1127

1128
    /* remove "/vm/" */
1129 1130 1131 1132 1133 1134 1135
    ret = virUUIDParse(uuidstr + 4, uuid);

    VIR_FREE(uuidstr);

    return ret;
}

D
Daniel P. Berrange 已提交
1136 1137
static void
xenStoreWatchListFree(xenStoreWatchListPtr list)
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
{
    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 已提交
1148 1149 1150 1151
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1152 1153 1154 1155 1156 1157
int xenStoreAddWatch(virConnectPtr conn,
                     const char *path,
                     const char *token,
                     xenStoreWatchCallback cb,
                     void *opaque)
{
1158
    xenStoreWatchPtr watch = NULL;
1159 1160 1161 1162 1163 1164 1165 1166
    int n;
    xenStoreWatchListPtr list;
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;

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

    list = priv->xsWatchList;
1167
    if (!list)
1168 1169 1170 1171
        return -1;

    /* check if we already have this callback on our list */
    for (n=0; n < list->count; n++) {
1172
        if (STREQ(list->watches[n]->path, path) &&
1173
            STREQ(list->watches[n]->token, token)) {
1174 1175
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("watch already tracked"));
1176 1177 1178 1179 1180
            return -1;
        }
    }

    if (VIR_ALLOC(watch) < 0)
1181 1182
        goto no_memory;

1183 1184 1185 1186 1187
    watch->path   = strdup(path);
    watch->token  = strdup(token);
    watch->cb     = cb;
    watch->opaque = opaque;

1188 1189 1190 1191
    if (watch->path == NULL || watch->token == NULL) {
        goto no_memory;
    }

1192 1193 1194
    /* Make space on list */
    n = list->count;
    if (VIR_REALLOC_N(list->watches, n + 1) < 0) {
1195
        goto no_memory;
1196 1197 1198 1199 1200 1201
    }

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

    return xs_watch(priv->xshandle, watch->path, watch->token);
1202 1203 1204 1205 1206 1207 1208 1209

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

1210
    virReportOOMError();
1211 1212

    return -1;
1213 1214
}

D
Daniel P. Berrange 已提交
1215 1216 1217 1218
/*
 * The caller must hold the lock on the privateData
 * associated with the 'conn' parameter.
 */
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230
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;
1231
    if (!list)
1232 1233 1234
        return -1;

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

            if (!xs_unwatch(priv->xshandle,
                       list->watches[i]->path,
1240
                       list->watches[i]->token))
1241
            {
1242
                VIR_DEBUG("WARNING: Could not remove watch");
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
                /* 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 已提交
1267 1268 1269 1270
static xenStoreWatchPtr
xenStoreFindWatch(xenStoreWatchListPtr list,
                  const char *path,
                  const char *token)
1271 1272 1273
{
    int i;
    for (i = 0 ; i < list->count ; i++)
1274 1275
        if (STREQ(path, list->watches[i]->path) &&
            STREQ(token, list->watches[i]->token))
1276 1277 1278 1279 1280
            return list->watches[i];

    return NULL;
}

D
Daniel P. Berrange 已提交
1281 1282 1283
static void
xenStoreWatchEvent(int watch ATTRIBUTE_UNUSED,
                   int fd ATTRIBUTE_UNUSED,
1284
                   int events,
D
Daniel P. Berrange 已提交
1285
                   void *data)
1286 1287 1288 1289 1290 1291 1292 1293 1294
{
    char		 **event;
    char		 *path;
    char		 *token;
    unsigned int	 stringCount;
    xenStoreWatchPtr     sw;

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

1296
    if (!priv) return;
D
Daniel P. Berrange 已提交
1297

1298 1299 1300
    /* only set a watch on read and write events */
    if (events & (VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP)) return;

D
Daniel P. Berrange 已提交
1301 1302
    xenUnifiedLock(priv);

1303
    if (!priv->xshandle)
D
Daniel P. Berrange 已提交
1304
        goto cleanup;
1305 1306 1307

    event = xs_read_watch(priv->xshandle, &stringCount);
    if (!event)
D
Daniel P. Berrange 已提交
1308
        goto cleanup;
1309 1310 1311 1312 1313

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

    sw = xenStoreFindWatch(priv->xsWatchList, path, token);
1314
    if (sw)
1315 1316
        sw->cb(conn, path, token, sw->opaque);
    VIR_FREE(event);
D
Daniel P. Berrange 已提交
1317 1318 1319

cleanup:
    xenUnifiedUnlock(priv);
1320 1321
}

D
Daniel P. Berrange 已提交
1322 1323 1324 1325 1326 1327

/*
 * The domain callback for the @introduceDomain watch
 *
 * The lock on 'priv' is held when calling this
 */
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
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;

1338
    xenUnifiedPrivatePtr priv = opaque;
1339 1340 1341

retry:
    new_domain_cnt = xenStoreNumOfDomains(conn);
1342 1343 1344
    if (new_domain_cnt < 0)
        return -1;

1345
    if (VIR_ALLOC_N(new_domids,new_domain_cnt) < 0) {
1346
        virReportOOMError();
1347 1348
        return -1;
    }
1349
    nread = xenStoreDoListDomains(conn, priv, new_domids, new_domain_cnt);
1350
    if (nread != new_domain_cnt) {
1351
        /* mismatch. retry this read */
1352 1353 1354 1355 1356 1357 1358
        VIR_FREE(new_domids);
        goto retry;
    }

    missing = 0;
    for (i=0 ; i < new_domain_cnt ; i++) {
        found = 0;
1359 1360
        for (j = 0 ; j < priv->activeDomainList->count ; j++) {
            if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
1361 1362 1363 1364 1365 1366
                found = 1;
                break;
            }
        }

        if (!found) {
1367
            virDomainEventPtr event;
1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
            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;
            }

1381 1382 1383 1384 1385
            event = virDomainEventNew(new_domids[i], name, uuid,
                                      VIR_DOMAIN_EVENT_STARTED,
                                      VIR_DOMAIN_EVENT_STARTED_BOOTED);
            if (event)
                xenUnifiedDomainEventDispatch(priv, event);
1386

1387
            /* Add to the list */
1388
            xenUnifiedAddDomainInfo(priv->activeDomainList,
1389
                                    new_domids[i], name, uuid);
1390 1391 1392 1393 1394 1395 1396

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

    if (missing && retries--) {
1397
        VIR_DEBUG("Some domains were missing, trying again");
1398 1399 1400 1401 1402 1403
        usleep(100 * 1000);
        goto retry;
    }
    return 0;
}

D
Daniel P. Berrange 已提交
1404 1405 1406 1407 1408
/*
 * The domain callback for the @destroyDomain watch
 *
 * The lock on 'priv' is held when calling this
 */
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420
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;

1421
    if (!priv->activeDomainList->count) return 0;
1422 1423 1424

retry:
    new_domain_cnt = xenStoreNumOfDomains(conn);
1425 1426
    if (new_domain_cnt < 0)
        return -1;
1427

1428
    if (VIR_ALLOC_N(new_domids,new_domain_cnt) < 0) {
1429
        virReportOOMError();
1430 1431
        return -1;
    }
1432
    nread = xenStoreDoListDomains(conn, priv, new_domids, new_domain_cnt);
1433
    if (nread != new_domain_cnt) {
1434
        /* mismatch. retry this read */
1435 1436 1437 1438 1439
        VIR_FREE(new_domids);
        goto retry;
    }

    removed = 0;
1440
    for (j=0 ; j < priv->activeDomainList->count ; j++) {
1441 1442
        found = 0;
        for (i=0 ; i < new_domain_cnt ; i++) {
1443
            if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
1444 1445 1446 1447 1448 1449
                found = 1;
                break;
            }
        }

        if (!found) {
1450 1451
            virDomainEventPtr event =
                virDomainEventNew(-1,
1452 1453
                                  priv->activeDomainList->doms[j]->name,
                                  priv->activeDomainList->doms[j]->uuid,
1454 1455 1456 1457 1458 1459
                                  VIR_DOMAIN_EVENT_STOPPED,
                                  VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
            if (event)
                xenUnifiedDomainEventDispatch(priv, event);

            /* Remove from the list */
1460 1461 1462 1463
            xenUnifiedRemoveDomainInfo(priv->activeDomainList,
                                       priv->activeDomainList->doms[j]->id,
                                       priv->activeDomainList->doms[j]->name,
                                       priv->activeDomainList->doms[j]->uuid);
1464 1465

            removed = 1;
1466 1467 1468 1469 1470 1471
        }
    }

    VIR_FREE(new_domids);

    if (!removed && retries--) {
1472
        VIR_DEBUG("No domains removed, retrying");
1473 1474 1475 1476 1477
        usleep(100 * 1000);
        goto retry;
    }
    return 0;
}