~serge-hallyn/ubuntu/raring/libvirt/libvirt-hugepages

« back to all changes in this revision

Viewing changes to src/xs_internal.c

  • Committer: James Westby
  • Author(s): Jamie Strandboge
  • Date: 2009-12-02 14:22:21 UTC
  • mfrom: (1.2.3 upstream) (3.4.9 squeeze)
  • Revision ID: james.westby@canonical.com-20091202142221-ltkr0to6h52mla1y
Tags: 0.7.2-4ubuntu1
* Merge from debian testing. Remaining changes:
  - debian/control:
    + Don't build-depend on QEmu
    + Bump bridge-utils, dnsmasq-base, netcat-openbsd, and iptables
      to Depends of libvirt-bin
    + Recommends qemu-kvm (>= 0.11.0-0ubuntu6)
    + Add versioned Conflicts/Replaces to libvirt0 for libvirt0-dbg,
      since we used to ship them as such
    + We call libxen-dev libxen3-dev, so change all references
    + Build-Depends on libxml2-utils
    + Build-Depends on open-iscsi-utils instead of open-iscsi due to
      LP: #414986
  - debian/postinst:
    + rename the libvirt group to libvirtd
    + add each admin user to the libvirtd group
  - debian/libvirt-bin.postrm: rename the libvirt group to libvirtd
  - debian/rules: add DEB_MAKE_CHECK_TARGET := check
  - debian/patches/900[0-7]: updated/refreshed for new paths in 0.7.2
  - debian/patches/series: don't apply 0002-qemu-disable-network.diff.patch
  - AppArmor integration:
    + debian/control: Build-Depends on libapparmor-dev and Suggests
      apparmor (>= 2.3+1289-0ubuntu14)
    + debian/libvirt-bin.dirs: add /etc/apparmor.d/abstractions,
      /etc/apparmor.d/force-complain, /etc/apparmor.d/libvirt,
      /etc/cron.daily and /usr/share/apport/package-hooks
    + add debian/libvirt-bin.cron.daily (LP: #438165)
    + add debian/libvirt-bin.apport
    + debian/libvirt-bin.install: install apparmor profiles, abstractions
      and apport hook
    + debian/postinst: reload apparmor profiles
    + debian/libvirt-bin.postrm: remove apparmor symlinks on purge
    + debian/libvirt-bin.preinst: added to force complain on certain
      upgrades
    + debian/README.Debian: add AppArmor section based on the upstream
      documentation
    + debian/rules: use --with-apparmor and copy apparmor and apport hook to
      debian/tmp
  - Dropped the following patches now included upstream:
    + 0005-Close-logfile-fd-after-spawning-qemu.patch
    + 9090-reenable-nonfile-labels.patch
    + 9091-apparmor.patch
    + 9092-apparmor-autoreconf.patch
* AppArmor integration updates:
  - debian/apparmor/usr.sbin.libvirtd: allow libvirtd access to
    /usr/lib/libvirt/* (LP: #480478)
  - debian/apparmor/libvirt-qemu: allow guests access to
    /etc/pki/libvirt-vnc/** (LP: #484562)
  - debian/libvirt-bin.postinst: 0.7.2 moved /usr/bin/virt-aa-helper to
    /usr/lib/libvirt, so the profile changed from usr.bin.virt-aa-helper
    to usr.lib.libvirt.virt-aa-helper and needs to be migrated. If the user
    made no changes to the old profile, remove it, otherwise, update the
    paths, preserving the shipped usr.lib.libvirt.virt-aa-helper
  - update to 0.7.4 version of the sVirt AppArmor driver (can be dropped in
    0.7.4):
    + debian/patches/9008-apparmor-caps-mockup.patch
    + debian/patches/9009-apparmor-lp453335.patch
    + debian/patches/9010-apparmor-lp460271.patch
    + debian/patches/9011-apparmor-code-cleanups.patch
  - add virt-aa-helper-test and examples/apparmor that were omitted from the
    upstream tarball (can be dropped in 0.7.5):
    + debian/patches/9012-apparmor-add-virt-aa-helper-test.patch
    + debian/patches/9013-apparmor-examples.patch
    + debian/rules: add post-patches target to make virt-aa-helper-test
      executable
* debian/patches/0005-Fix-SELinux-linking-issues.patch: updated to work
  when both apparmor and selinux are available. This patch should be
  dropped in 0.7.4.
* debian/patches/9007-default-config-test-case.patch: updated to not fail
  if building in a deep directory
* debian/patches/9014-event-fuzz.patch: add a little fuzz to not be quite
  so precise with expected expiry time. Fixes FTBFS with HZ=100 kernels.
  Can be dropped in 0.7.5.
* debian/patches/9015-hal-startup-failure-is-nonfatal.patch: disable hal
  driver if hald is not running instead of dying. Can be dropped in
  0.7.4.
* debian/control: temporarily remove Build-Depends on libcap-ng-dev, which
  isn't available in Ubuntu main yet
* revert change to new source format 3.0 (quilt) since Launchpad can't
  handle it yet (see LP: #293106)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * xs_internal.c: access to Xen Store
3
 
 *
4
 
 * Copyright (C) 2006, 2009 Red Hat, Inc.
5
 
 *
6
 
 * See COPYING.LIB for the License of this software
7
 
 *
8
 
 * Daniel Veillard <veillard@redhat.com>
9
 
 */
10
 
 
11
 
#include <config.h>
12
 
 
13
 
#include <stdio.h>
14
 
#include <string.h>
15
 
#include <unistd.h>
16
 
#include <stdlib.h>
17
 
#include <fcntl.h>
18
 
#include <sys/mman.h>
19
 
#include <sys/ioctl.h>
20
 
 
21
 
#include <stdint.h>
22
 
 
23
 
#include <xen/dom0_ops.h>
24
 
#include <xen/version.h>
25
 
#include <xen/xen.h>
26
 
 
27
 
#include <xs.h>
28
 
 
29
 
#include "virterror_internal.h"
30
 
#include "datatypes.h"
31
 
#include "driver.h"
32
 
#include "memory.h"
33
 
#include "event.h"
34
 
#include "logging.h"
35
 
#include "uuid.h"
36
 
#include "xen_unified.h"
37
 
#include "xs_internal.h"
38
 
#include "xen_internal.h"
39
 
 
40
 
#define VIR_FROM_THIS VIR_FROM_XEN
41
 
 
42
 
#ifndef PROXY
43
 
static char *xenStoreDomainGetOSType(virDomainPtr domain);
44
 
static void xenStoreWatchEvent(int watch, int fd, int events, void *data);
45
 
static void xenStoreWatchListFree(xenStoreWatchListPtr list);
46
 
 
47
 
struct xenUnifiedDriver xenStoreDriver = {
48
 
    xenStoreOpen, /* open */
49
 
    xenStoreClose, /* close */
50
 
    NULL, /* version */
51
 
    NULL, /* hostname */
52
 
    NULL, /* nodeGetInfo */
53
 
    NULL, /* getCapabilities */
54
 
    xenStoreListDomains, /* listDomains */
55
 
    NULL, /* numOfDomains */
56
 
    NULL, /* domainCreateXML */
57
 
    NULL, /* domainSuspend */
58
 
    NULL, /* domainResume */
59
 
    xenStoreDomainShutdown, /* domainShutdown */
60
 
    xenStoreDomainReboot, /* domainReboot */
61
 
    NULL, /* domainDestroy */
62
 
    xenStoreDomainGetOSType, /* domainGetOSType */
63
 
    xenStoreDomainGetMaxMemory, /* domainGetMaxMemory */
64
 
    NULL, /* domainSetMaxMemory */
65
 
    xenStoreDomainSetMemory, /* domainSetMemory */
66
 
    xenStoreGetDomainInfo, /* domainGetInfo */
67
 
    NULL, /* domainSave */
68
 
    NULL, /* domainRestore */
69
 
    NULL, /* domainCoreDump */
70
 
    NULL, /* domainSetVcpus */
71
 
    NULL, /* domainPinVcpu */
72
 
    NULL, /* domainGetVcpus */
73
 
    NULL, /* domainGetMaxVcpus */
74
 
    NULL, /* listDefinedDomains */
75
 
    NULL, /* numOfDefinedDomains */
76
 
    NULL, /* domainCreate */
77
 
    NULL, /* domainDefineXML */
78
 
    NULL, /* domainUndefine */
79
 
    NULL, /* domainAttachDevice */
80
 
    NULL, /* domainDetachDevice */
81
 
    NULL, /* domainGetAutostart */
82
 
    NULL, /* domainSetAutostart */
83
 
    NULL, /* domainGetSchedulerType */
84
 
    NULL, /* domainGetSchedulerParameters */
85
 
    NULL, /* domainSetSchedulerParameters */
86
 
};
87
 
 
88
 
#endif /* ! PROXY */
89
 
 
90
 
#define virXenStoreError(conn, code, fmt...)                                 \
91
 
        virReportErrorHelper(NULL, VIR_FROM_XENSTORE, code, __FILE__,      \
92
 
                               __FUNCTION__, __LINE__, fmt)
93
 
 
94
 
/************************************************************************
95
 
 *                                                                      *
96
 
 *              Helper internal APIs                                    *
97
 
 *                                                                      *
98
 
 ************************************************************************/
99
 
#ifndef PROXY
100
 
/**
101
 
 * virConnectDoStoreList:
102
 
 * @conn: pointer to the hypervisor connection
103
 
 * @path: the absolute path of the directory in the store to list
104
 
 * @nb: OUT pointer to the number of items found
105
 
 *
106
 
 * Internal API querying the Xenstore for a list
107
 
 *
108
 
 * Returns a string which must be freed by the caller or NULL in case of error
109
 
 */
110
 
static char **
111
 
virConnectDoStoreList(virConnectPtr conn, const char *path,
112
 
                      unsigned int *nb)
113
 
{
114
 
    xenUnifiedPrivatePtr priv;
115
 
 
116
 
    if (conn == NULL)
117
 
        return NULL;
118
 
 
119
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
120
 
    if (priv->xshandle == NULL || path == NULL || nb == NULL)
121
 
        return (NULL);
122
 
 
123
 
    return xs_directory (priv->xshandle, 0, path, nb);
124
 
}
125
 
#endif /* ! PROXY */
126
 
 
127
 
/**
128
 
 * virDomainDoStoreQuery:
129
 
 * @conn: pointer to the hypervisor connection
130
 
 * @domid: id of the domain
131
 
 * @path: the relative path of the data in the store to retrieve
132
 
 *
133
 
 * Internal API querying the Xenstore for a string value.
134
 
 *
135
 
 * Returns a string which must be freed by the caller or NULL in case of error
136
 
 */
137
 
static char *
138
 
virDomainDoStoreQuery(virConnectPtr conn, int domid, const char *path)
139
 
{
140
 
    char s[256];
141
 
    unsigned int len = 0;
142
 
    xenUnifiedPrivatePtr priv;
143
 
 
144
 
    if (!conn)
145
 
        return NULL;
146
 
 
147
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
148
 
    if (priv->xshandle == NULL)
149
 
        return (NULL);
150
 
 
151
 
    snprintf(s, 255, "/local/domain/%d/%s", domid, path);
152
 
    s[255] = 0;
153
 
 
154
 
    return xs_read(priv->xshandle, 0, &s[0], &len);
155
 
}
156
 
 
157
 
#ifndef PROXY
158
 
/**
159
 
 * virDomainDoStoreWrite:
160
 
 * @domain: a domain object
161
 
 * @path: the relative path of the data in the store to retrieve
162
 
 *
163
 
 * Internal API setting up a string value in the Xenstore
164
 
 * Requires write access to the XenStore
165
 
 *
166
 
 * Returns 0 in case of success, -1 in case of failure
167
 
 */
168
 
static int
169
 
virDomainDoStoreWrite(virDomainPtr domain, const char *path,
170
 
                      const char *value)
171
 
{
172
 
    char s[256];
173
 
    xenUnifiedPrivatePtr priv;
174
 
    int ret = -1;
175
 
 
176
 
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
177
 
        return (-1);
178
 
 
179
 
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
180
 
    if (priv->xshandle == NULL)
181
 
        return (-1);
182
 
    if (domain->conn->flags & VIR_CONNECT_RO)
183
 
        return (-1);
184
 
 
185
 
    snprintf(s, 255, "/local/domain/%d/%s", domain->id, path);
186
 
    s[255] = 0;
187
 
 
188
 
    if (xs_write(priv->xshandle, 0, &s[0], value, strlen(value)))
189
 
        ret = 0;
190
 
 
191
 
    return (ret);
192
 
}
193
 
 
194
 
/**
195
 
 * virDomainGetVM:
196
 
 * @domain: a domain object
197
 
 *
198
 
 * Internal API extracting a xenstore vm path.
199
 
 *
200
 
 * Returns the new string or NULL in case of error
201
 
 */
202
 
static char *
203
 
virDomainGetVM(virDomainPtr domain)
204
 
{
205
 
    char *vm;
206
 
    char query[200];
207
 
    unsigned int len;
208
 
    xenUnifiedPrivatePtr priv;
209
 
 
210
 
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
211
 
        return (NULL);
212
 
 
213
 
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
214
 
    if (priv->xshandle == NULL)
215
 
        return (NULL);
216
 
 
217
 
    snprintf(query, 199, "/local/domain/%d/vm", virDomainGetID(domain));
218
 
    query[199] = 0;
219
 
 
220
 
    vm = xs_read(priv->xshandle, 0, &query[0], &len);
221
 
 
222
 
    return (vm);
223
 
}
224
 
 
225
 
/**
226
 
 * virDomainGetVMInfo:
227
 
 * @domain: a domain object
228
 
 * @vm: the xenstore vm path
229
 
 * @name: the value's path
230
 
 *
231
 
 * Internal API extracting one information the device used
232
 
 * by the domain from xensttore
233
 
 *
234
 
 * Returns the new string or NULL in case of error
235
 
 */
236
 
static char *
237
 
virDomainGetVMInfo(virDomainPtr domain, const char *vm, const char *name)
238
 
{
239
 
    char s[256];
240
 
    char *ret = NULL;
241
 
    unsigned int len = 0;
242
 
    xenUnifiedPrivatePtr priv;
243
 
 
244
 
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
245
 
        return (NULL);
246
 
 
247
 
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
248
 
    if (priv->xshandle == NULL)
249
 
        return (NULL);
250
 
 
251
 
    snprintf(s, 255, "%s/%s", vm, name);
252
 
    s[255] = 0;
253
 
 
254
 
    ret = xs_read(priv->xshandle, 0, &s[0], &len);
255
 
 
256
 
    return (ret);
257
 
}
258
 
 
259
 
#endif /* ! PROXY */
260
 
 
261
 
/************************************************************************
262
 
 *                                                                      *
263
 
 *              Canonical internal APIs                                 *
264
 
 *                                                                      *
265
 
 ************************************************************************/
266
 
/**
267
 
 * xenStoreOpen:
268
 
 * @conn: pointer to the connection block
269
 
 * @name: URL for the target, NULL for local
270
 
 * @flags: combination of virDrvOpenFlag(s)
271
 
 *
272
 
 * Connects to the Xen hypervisor.
273
 
 *
274
 
 * Returns 0 or -1 in case of error.
275
 
 */
276
 
virDrvOpenStatus
277
 
xenStoreOpen(virConnectPtr conn,
278
 
             virConnectAuthPtr auth ATTRIBUTE_UNUSED,
279
 
             int flags ATTRIBUTE_UNUSED)
280
 
{
281
 
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
282
 
 
283
 
#ifdef PROXY
284
 
    priv->xshandle = xs_daemon_open_readonly();
285
 
#else
286
 
    if (flags & VIR_CONNECT_RO)
287
 
        priv->xshandle = xs_daemon_open_readonly();
288
 
    else
289
 
        priv->xshandle = xs_daemon_open();
290
 
#endif /* ! PROXY */
291
 
 
292
 
    if (priv->xshandle == NULL) {
293
 
        /*
294
 
         * not being able to connect via the socket as an unprivileged
295
 
         * user is rather normal, this should fallback to the proxy (or
296
 
         * remote) mechanism.
297
 
         */
298
 
        if (xenHavePrivilege()) {
299
 
            virXenStoreError(NULL, VIR_ERR_NO_XEN,
300
 
                                 "%s", _("failed to connect to Xen Store"));
301
 
        }
302
 
        return (-1);
303
 
    }
304
 
 
305
 
#ifndef PROXY
306
 
    /* Init activeDomainList */
307
 
    if (VIR_ALLOC(priv->activeDomainList) < 0) {
308
 
        virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
309
 
                                 "%s", _("failed to allocate activeDomainList"));
310
 
        return -1;
311
 
    }
312
 
 
313
 
    /* Init watch list before filling in domInfoList,
314
 
       so we can know if it is the first time through
315
 
       when the callback fires */
316
 
    if ( VIR_ALLOC(priv->xsWatchList) < 0 ) {
317
 
        virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
318
 
                                 "%s", _("failed to allocate xsWatchList"));
319
 
        return -1;
320
 
    }
321
 
 
322
 
    /* This will get called once at start */
323
 
    if ( xenStoreAddWatch(conn, "@releaseDomain",
324
 
                     "releaseDomain", xenStoreDomainReleased, priv) < 0 )
325
 
    {
326
 
        virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
327
 
                                 "%s", _("adding watch @releaseDomain"));
328
 
        return -1;
329
 
    }
330
 
 
331
 
    /* The initial call of this will fill domInfoList */
332
 
    if( xenStoreAddWatch(conn, "@introduceDomain",
333
 
                     "introduceDomain", xenStoreDomainIntroduced, priv) < 0 )
334
 
    {
335
 
        virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
336
 
                                 "%s", _("adding watch @introduceDomain"));
337
 
        return -1;
338
 
    }
339
 
 
340
 
    /* Add an event handle */
341
 
    if ((priv->xsWatch = virEventAddHandle(xs_fileno(priv->xshandle),
342
 
                                           VIR_EVENT_HANDLE_READABLE,
343
 
                                           xenStoreWatchEvent,
344
 
                                           conn,
345
 
                                           NULL)) < 0)
346
 
        DEBUG0("Failed to add event handle, disabling events\n");
347
 
 
348
 
#endif //PROXY
349
 
    return 0;
350
 
}
351
 
 
352
 
/**
353
 
 * xenStoreClose:
354
 
 * @conn: pointer to the connection block
355
 
 *
356
 
 * Close the connection to the Xen hypervisor.
357
 
 *
358
 
 * Returns 0 in case of success or -1 in case of error.
359
 
 */
360
 
int
361
 
xenStoreClose(virConnectPtr conn)
362
 
{
363
 
    xenUnifiedPrivatePtr priv;
364
 
 
365
 
    if (conn == NULL) {
366
 
        virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
367
 
        return(-1);
368
 
    }
369
 
 
370
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
371
 
 
372
 
#ifndef PROXY
373
 
    if (xenStoreRemoveWatch(conn, "@introduceDomain", "introduceDomain") < 0) {
374
 
        DEBUG0("Warning, could not remove @introduceDomain watch");
375
 
        /* not fatal */
376
 
    }
377
 
 
378
 
    if (xenStoreRemoveWatch(conn, "@releaseDomain", "releaseDomain") < 0) {
379
 
        DEBUG0("Warning, could not remove @releaseDomain watch");
380
 
        /* not fatal */
381
 
    }
382
 
 
383
 
    xenStoreWatchListFree(priv->xsWatchList);
384
 
    priv->xsWatchList = NULL;
385
 
    xenUnifiedDomainInfoListFree(priv->activeDomainList);
386
 
    priv->activeDomainList = NULL;
387
 
#endif
388
 
    if (priv->xshandle == NULL)
389
 
        return(-1);
390
 
 
391
 
    if (priv->xsWatch != -1)
392
 
        virEventRemoveHandle(priv->xsWatch);
393
 
    xs_daemon_close(priv->xshandle);
394
 
    priv->xshandle = NULL;
395
 
 
396
 
    return (0);
397
 
}
398
 
 
399
 
#ifndef PROXY
400
 
/**
401
 
 * xenStoreGetDomainInfo:
402
 
 * @domain: pointer to the domain block
403
 
 * @info: the place where information should be stored
404
 
 *
405
 
 * Do an hypervisor call to get the related set of domain information.
406
 
 *
407
 
 * Returns 0 in case of success, -1 in case of error.
408
 
 */
409
 
int
410
 
xenStoreGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
411
 
{
412
 
    char *tmp, **tmp2;
413
 
    unsigned int nb_vcpus;
414
 
    char request[200];
415
 
    xenUnifiedPrivatePtr priv;
416
 
 
417
 
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
418
 
        return (-1);
419
 
 
420
 
    if ((domain == NULL) || (domain->conn == NULL) || (info == NULL)) {
421
 
        virXenStoreError(domain ? domain->conn : NULL, VIR_ERR_INVALID_ARG,
422
 
                         __FUNCTION__);
423
 
        return(-1);
424
 
    }
425
 
 
426
 
    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
427
 
    if (priv->xshandle == NULL)
428
 
        return(-1);
429
 
 
430
 
    if (domain->id == -1)
431
 
        return(-1);
432
 
 
433
 
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "running");
434
 
    if (tmp != NULL) {
435
 
        if (tmp[0] == '1')
436
 
            info->state = VIR_DOMAIN_RUNNING;
437
 
        free(tmp);
438
 
    } else {
439
 
        info->state = VIR_DOMAIN_NOSTATE;
440
 
    }
441
 
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
442
 
    if (tmp != NULL) {
443
 
        info->memory = atol(tmp);
444
 
        info->maxMem = atol(tmp);
445
 
        free(tmp);
446
 
    } else {
447
 
        info->memory = 0;
448
 
        info->maxMem = 0;
449
 
    }
450
 
#if 0
451
 
    /* doesn't seems to work */
452
 
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "cpu_time");
453
 
    if (tmp != NULL) {
454
 
        info->cpuTime = atol(tmp);
455
 
        free(tmp);
456
 
    } else {
457
 
        info->cpuTime = 0;
458
 
    }
459
 
#endif
460
 
    snprintf(request, 199, "/local/domain/%d/cpu", domain->id);
461
 
    request[199] = 0;
462
 
    tmp2 = virConnectDoStoreList(domain->conn, request, &nb_vcpus);
463
 
    if (tmp2 != NULL) {
464
 
        info->nrVirtCpu = nb_vcpus;
465
 
        free(tmp2);
466
 
    }
467
 
    return (0);
468
 
}
469
 
 
470
 
/**
471
 
 * xenStoreDomainSetMemory:
472
 
 * @domain: pointer to the domain block
473
 
 * @memory: the max memory size in kilobytes.
474
 
 *
475
 
 * Change the maximum amount of memory allowed in the xen store
476
 
 *
477
 
 * Returns 0 in case of success, -1 in case of error.
478
 
 */
479
 
int
480
 
xenStoreDomainSetMemory(virDomainPtr domain, unsigned long memory)
481
 
{
482
 
    int ret;
483
 
    char value[20];
484
 
 
485
 
    if ((domain == NULL) || (domain->conn == NULL) ||
486
 
        (memory < 1024 * MIN_XEN_GUEST_SIZE)) {
487
 
        virXenStoreError(domain ? domain->conn : NULL, VIR_ERR_INVALID_ARG,
488
 
                         __FUNCTION__);
489
 
        return(-1);
490
 
    }
491
 
    if (domain->id == -1)
492
 
        return(-1);
493
 
    if ((domain->id == 0) && (memory < (2 * MIN_XEN_GUEST_SIZE * 1024)))
494
 
        return(-1);
495
 
    snprintf(value, 19, "%lu", memory);
496
 
    value[19] = 0;
497
 
    ret = virDomainDoStoreWrite(domain, "memory/target", &value[0]);
498
 
    if (ret < 0)
499
 
        return (-1);
500
 
    return (0);
501
 
}
502
 
 
503
 
/**
504
 
 * xenStoreDomainGetMaxMemory:
505
 
 * @domain: pointer to the domain block
506
 
 *
507
 
 * Ask the xenstore for the maximum memory allowed for a domain
508
 
 *
509
 
 * Returns the memory size in kilobytes or 0 in case of error.
510
 
 */
511
 
unsigned long
512
 
xenStoreDomainGetMaxMemory(virDomainPtr domain)
513
 
{
514
 
    char *tmp;
515
 
    unsigned long ret = 0;
516
 
    xenUnifiedPrivatePtr priv;
517
 
 
518
 
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
519
 
        return (ret);
520
 
    if (domain->id == -1)
521
 
        return(-1);
522
 
 
523
 
    priv = domain->conn->privateData;
524
 
    xenUnifiedLock(priv);
525
 
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
526
 
    if (tmp != NULL) {
527
 
        ret = (unsigned long) atol(tmp);
528
 
        VIR_FREE(tmp);
529
 
    }
530
 
    xenUnifiedUnlock(priv);
531
 
    return(ret);
532
 
}
533
 
 
534
 
/**
535
 
 * xenStoreNumOfDomains:
536
 
 * @conn: pointer to the hypervisor connection
537
 
 *
538
 
 * Provides the number of active domains.
539
 
 *
540
 
 * Returns the number of domain found or -1 in case of error
541
 
 */
542
 
int
543
 
xenStoreNumOfDomains(virConnectPtr conn)
544
 
{
545
 
    unsigned int num;
546
 
    char **idlist;
547
 
    int ret = -1;
548
 
    xenUnifiedPrivatePtr priv;
549
 
 
550
 
    if (conn == NULL) {
551
 
        virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
552
 
        return -1;
553
 
    }
554
 
 
555
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
556
 
    if (priv->xshandle == NULL) {
557
 
        virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
558
 
        return(-1);
559
 
    }
560
 
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
561
 
    if (idlist) {
562
 
        free(idlist);
563
 
        ret = num;
564
 
    }
565
 
    return(ret);
566
 
}
567
 
 
568
 
/**
569
 
 * xenStoreDoListDomains:
570
 
 * @conn: pointer to the hypervisor connection
571
 
 * @ids: array to collect the list of IDs of active domains
572
 
 * @maxids: size of @ids
573
 
 *
574
 
 * Internal API: collect the list of active domains, and store
575
 
 * their ID in @maxids. The driver lock must be held.
576
 
 *
577
 
 * Returns the number of domain found or -1 in case of error
578
 
 */
579
 
static int
580
 
xenStoreDoListDomains(xenUnifiedPrivatePtr priv, int *ids, int maxids)
581
 
{
582
 
    char **idlist = NULL, *endptr;
583
 
    unsigned int num, i;
584
 
    int ret = -1;
585
 
    long id;
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
 
        if ((endptr == idlist[i]) || (*endptr != 0))
597
 
            goto out;
598
 
        ids[ret++] = (int) id;
599
 
    }
600
 
 
601
 
out:
602
 
    VIR_FREE (idlist);
603
 
    return ret;
604
 
}
605
 
 
606
 
/**
607
 
 * xenStoreListDomains:
608
 
 * @conn: pointer to the hypervisor connection
609
 
 * @ids: array to collect the list of IDs of active domains
610
 
 * @maxids: size of @ids
611
 
 *
612
 
 * Collect the list of active domains, and store their ID in @maxids
613
 
 *
614
 
 * Returns the number of domain found or -1 in case of error
615
 
 */
616
 
int
617
 
xenStoreListDomains(virConnectPtr conn, int *ids, int maxids)
618
 
{
619
 
    xenUnifiedPrivatePtr priv;
620
 
    int ret;
621
 
 
622
 
    if ((conn == NULL) || (ids == NULL)) {
623
 
        virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
624
 
        return(-1);
625
 
    }
626
 
 
627
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
628
 
 
629
 
    xenUnifiedLock(priv);
630
 
    ret = xenStoreDoListDomains(priv, ids, maxids);
631
 
    xenUnifiedUnlock(priv);
632
 
 
633
 
    return(ret);
634
 
}
635
 
 
636
 
/**
637
 
 * xenStoreLookupByName:
638
 
 * @conn: A xend instance
639
 
 * @name: The name of the domain
640
 
 *
641
 
 * Try to lookup a domain on the Xen Store based on its name.
642
 
 *
643
 
 * Returns a new domain object or NULL in case of failure
644
 
 */
645
 
virDomainPtr
646
 
xenStoreLookupByName(virConnectPtr conn, const char *name)
647
 
{
648
 
    virDomainPtr ret = NULL;
649
 
    unsigned int num, i, len;
650
 
    long id = -1;
651
 
    char **idlist = NULL, *endptr;
652
 
    char prop[200], *tmp;
653
 
    int found = 0;
654
 
    struct xend_domain *xenddomain = NULL;
655
 
    xenUnifiedPrivatePtr priv;
656
 
 
657
 
    if ((conn == NULL) || (name == NULL)) {
658
 
        virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
659
 
        return(NULL);
660
 
    }
661
 
 
662
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
663
 
    if (priv->xshandle == NULL)
664
 
        return(NULL);
665
 
 
666
 
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
667
 
    if (idlist == NULL)
668
 
        goto done;
669
 
 
670
 
    for (i = 0; i < num; i++) {
671
 
        id = strtol(idlist[i], &endptr, 10);
672
 
        if ((endptr == idlist[i]) || (*endptr != 0)) {
673
 
            goto done;
674
 
        }
675
 
#if 0
676
 
        if (virConnectCheckStoreID(conn, (int) id) < 0)
677
 
            continue;
678
 
#endif
679
 
        snprintf(prop, 199, "/local/domain/%s/name", idlist[i]);
680
 
        prop[199] = 0;
681
 
        tmp = xs_read(priv->xshandle, 0, prop, &len);
682
 
        if (tmp != NULL) {
683
 
            found = STREQ (name, tmp);
684
 
            free(tmp);
685
 
            if (found)
686
 
                break;
687
 
        }
688
 
    }
689
 
    if (!found)
690
 
        goto done;
691
 
 
692
 
    ret = virGetDomain(conn, name, NULL);
693
 
    if (ret == NULL)
694
 
        goto done;
695
 
 
696
 
    ret->id = id;
697
 
 
698
 
done:
699
 
        free(xenddomain);
700
 
        free(idlist);
701
 
 
702
 
    return(ret);
703
 
}
704
 
 
705
 
/**
706
 
 * xenStoreDomainShutdown:
707
 
 * @domain: pointer to the Domain block
708
 
 *
709
 
 * Shutdown the domain, the OS is requested to properly shutdown
710
 
 * and the domain may ignore it.  It will return immediately
711
 
 * after queuing the request.
712
 
 *
713
 
 * Returns 0 in case of success, -1 in case of error.
714
 
 */
715
 
int
716
 
xenStoreDomainShutdown(virDomainPtr domain)
717
 
{
718
 
    int ret;
719
 
    xenUnifiedPrivatePtr priv;
720
 
 
721
 
    if ((domain == NULL) || (domain->conn == NULL)) {
722
 
        virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
723
 
                         __FUNCTION__);
724
 
        return(-1);
725
 
    }
726
 
    if (domain->id == -1 || domain->id == 0)
727
 
        return(-1);
728
 
    /*
729
 
     * this is very hackish, the domU kernel probes for a special
730
 
     * node in the xenstore and launch the shutdown command if found.
731
 
     */
732
 
    priv = domain->conn->privateData;
733
 
    xenUnifiedLock(priv);
734
 
    ret = virDomainDoStoreWrite(domain, "control/shutdown", "poweroff");
735
 
    xenUnifiedUnlock(priv);
736
 
    return ret;
737
 
}
738
 
 
739
 
/**
740
 
 * xenStoreDomainReboot:
741
 
 * @domain: pointer to the Domain block
742
 
 * @flags: extra flags for the reboot operation, not used yet
743
 
 *
744
 
 * Reboot the domain, the OS is requested to properly shutdown
745
 
 * and reboot but the domain may ignore it.  It will return immediately
746
 
 * after queuing the request.
747
 
 *
748
 
 * Returns 0 in case of success, -1 in case of error.
749
 
 */
750
 
int
751
 
xenStoreDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
752
 
{
753
 
    int ret;
754
 
    xenUnifiedPrivatePtr priv;
755
 
 
756
 
    if ((domain == NULL) || (domain->conn == NULL)) {
757
 
        virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
758
 
                         __FUNCTION__);
759
 
        return(-1);
760
 
    }
761
 
    if (domain->id == -1 || domain->id == 0)
762
 
        return(-1);
763
 
    /*
764
 
     * this is very hackish, the domU kernel probes for a special
765
 
     * node in the xenstore and launch the shutdown command if found.
766
 
     */
767
 
    priv = domain->conn->privateData;
768
 
    xenUnifiedLock(priv);
769
 
    ret = virDomainDoStoreWrite(domain, "control/shutdown", "reboot");
770
 
    xenUnifiedUnlock(priv);
771
 
    return ret;
772
 
}
773
 
 
774
 
/*
775
 
 * xenStoreDomainGetOSType:
776
 
 * @domain: a domain object
777
 
 *
778
 
 * Get the type of domain operation system.
779
 
 *
780
 
 * Returns the new string or NULL in case of error, the string must be
781
 
 *         freed by the caller.
782
 
 */
783
 
static char *
784
 
xenStoreDomainGetOSType(virDomainPtr domain) {
785
 
    char *vm, *str = NULL;
786
 
 
787
 
    if ((domain == NULL) || (domain->conn == NULL)) {
788
 
        virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
789
 
                         __FUNCTION__);
790
 
        return(NULL);
791
 
    }
792
 
 
793
 
    vm = virDomainGetVM(domain);
794
 
    if (vm) {
795
 
        xenUnifiedPrivatePtr priv = domain->conn->privateData;
796
 
        xenUnifiedLock(priv);
797
 
        str = virDomainGetVMInfo(domain, vm, "image/ostype");
798
 
        xenUnifiedUnlock(priv);
799
 
        VIR_FREE(vm);
800
 
    }
801
 
 
802
 
    return (str);
803
 
}
804
 
#endif /* ! PROXY */
805
 
 
806
 
/**
807
 
 * xenStoreDomainGetVNCPort:
808
 
 * @conn: the hypervisor connection
809
 
 * @domid: id of the domain
810
 
 *
811
 
 * Return the port number on which the domain is listening for VNC
812
 
 * connections.
813
 
 *
814
 
 * The caller must hold the lock on the privateData
815
 
 * associated with the 'conn' parameter.
816
 
 *
817
 
 * Returns the port number, -1 in case of error
818
 
 */
819
 
int             xenStoreDomainGetVNCPort(virConnectPtr conn, int domid) {
820
 
    char *tmp;
821
 
    int ret = -1;
822
 
 
823
 
    tmp = virDomainDoStoreQuery(conn, domid, "console/vnc-port");
824
 
    if (tmp != NULL) {
825
 
        char *end;
826
 
        ret = strtol(tmp, &end, 10);
827
 
        if (ret == 0 && end == tmp)
828
 
            ret = -1;
829
 
        free(tmp);
830
 
    }
831
 
    return(ret);
832
 
}
833
 
 
834
 
/**
835
 
 * xenStoreDomainGetConsolePath:
836
 
 * @conn: the hypervisor connection
837
 
 * @domid: id of the domain
838
 
 *
839
 
 * Return the path to the psuedo TTY on which the guest domain's
840
 
 * serial console is attached.
841
 
 *
842
 
 * Returns the path to the serial console. It is the callers
843
 
 * responsibilty to free() the return string. Returns NULL
844
 
 * on error
845
 
 *
846
 
 * The caller must hold the lock on the privateData
847
 
 * associated with the 'conn' parameter.
848
 
 */
849
 
char *          xenStoreDomainGetConsolePath(virConnectPtr conn, int domid) {
850
 
  return virDomainDoStoreQuery(conn, domid, "console/tty");
851
 
}
852
 
 
853
 
#ifdef PROXY
854
 
/*
855
 
 * xenStoreDomainGetOSTypeID:
856
 
 * @conn: pointer to the connection.
857
 
 * @id: the domain id
858
 
 *
859
 
 * Get the type of domain operation system.
860
 
 *
861
 
 * The caller must hold the lock on the privateData
862
 
 * associated with the 'conn' parameter.
863
 
 *
864
 
 * Returns the new string or NULL in case of error, the string must be
865
 
 *         freed by the caller.
866
 
 */
867
 
char *
868
 
xenStoreDomainGetOSTypeID(virConnectPtr conn, int id) {
869
 
    char *vm, *str = NULL;
870
 
    char query[200];
871
 
    unsigned int len;
872
 
    xenUnifiedPrivatePtr priv;
873
 
 
874
 
    if (id < 0)
875
 
        return(NULL);
876
 
 
877
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
878
 
    if (priv->xshandle == NULL)
879
 
        return (NULL);
880
 
 
881
 
    snprintf(query, 199, "/local/domain/%d/vm", id);
882
 
    query[199] = 0;
883
 
 
884
 
    vm = xs_read(priv->xshandle, 0, &query[0], &len);
885
 
 
886
 
    if (vm) {
887
 
        snprintf(query, 199, "%s/image/ostype", vm);
888
 
        str = xs_read(priv->xshandle, 0, &query[0], &len);
889
 
        free(vm);
890
 
    }
891
 
    if (str == NULL)
892
 
        str = strdup("linux");
893
 
 
894
 
 
895
 
    return (str);
896
 
}
897
 
#endif /* PROXY */
898
 
 
899
 
/*
900
 
 * xenStoreDomainGetNetworkID:
901
 
 * @conn: pointer to the connection.
902
 
 * @id: the domain id
903
 
 * @mac: the mac address
904
 
 *
905
 
 * Get the reference (i.e. the string number) for the device on that domain
906
 
 * which uses the given mac address
907
 
 *
908
 
 * The caller must hold the lock on the privateData
909
 
 * associated with the 'conn' parameter.
910
 
 *
911
 
 * Returns the new string or NULL in case of error, the string must be
912
 
 *         freed by the caller.
913
 
 */
914
 
char *
915
 
xenStoreDomainGetNetworkID(virConnectPtr conn, int id, const char *mac) {
916
 
    char dir[80], path[128], **list = NULL, *val = NULL;
917
 
    unsigned int len, i, num;
918
 
    char *ret = NULL;
919
 
    xenUnifiedPrivatePtr priv;
920
 
 
921
 
    if (id < 0)
922
 
        return(NULL);
923
 
 
924
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
925
 
    if (priv->xshandle == NULL)
926
 
        return (NULL);
927
 
    if (mac == NULL)
928
 
        return (NULL);
929
 
 
930
 
    snprintf(dir, sizeof(dir), "/local/domain/0/backend/vif/%d", id);
931
 
    list = xs_directory(priv->xshandle, 0, dir, &num);
932
 
    if (list == NULL)
933
 
        return(NULL);
934
 
    for (i = 0; i < num; i++) {
935
 
        snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "mac");
936
 
        if ((val = xs_read(priv->xshandle, 0, path, &len)) == NULL)
937
 
            break;
938
 
 
939
 
        bool match = (virMacAddrCompare(val, mac) == 0);
940
 
 
941
 
        VIR_FREE(val);
942
 
 
943
 
        if (match) {
944
 
            ret = strdup(list[i]);
945
 
            break;
946
 
        }
947
 
    }
948
 
 
949
 
    VIR_FREE(list);
950
 
    return(ret);
951
 
}
952
 
 
953
 
/*
954
 
 * xenStoreDomainGetDiskID:
955
 
 * @conn: pointer to the connection.
956
 
 * @id: the domain id
957
 
 * @dev: the virtual block device name
958
 
 *
959
 
 * Get the reference (i.e. the string number) for the device on that domain
960
 
 * which uses the given virtual block device name
961
 
 *
962
 
 * The caller must hold the lock on the privateData
963
 
 * associated with the 'conn' parameter.
964
 
 *
965
 
 * Returns the new string or NULL in case of error, the string must be
966
 
 *         freed by the caller.
967
 
 */
968
 
char *
969
 
xenStoreDomainGetDiskID(virConnectPtr conn, int id, const char *dev) {
970
 
    char dir[80], path[128], **list = NULL, *val = NULL;
971
 
    unsigned int devlen, len, i, num;
972
 
    char *ret = NULL;
973
 
    xenUnifiedPrivatePtr priv;
974
 
 
975
 
    if (id < 0)
976
 
        return(NULL);
977
 
 
978
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
979
 
    if (priv->xshandle == NULL)
980
 
        return (NULL);
981
 
    if (dev == NULL)
982
 
        return (NULL);
983
 
    devlen = strlen(dev);
984
 
    if (devlen <= 0)
985
 
        return (NULL);
986
 
 
987
 
    snprintf(dir, sizeof(dir), "/local/domain/0/backend/vbd/%d", id);
988
 
    list = xs_directory(priv->xshandle, 0, dir, &num);
989
 
    if (list != NULL) {
990
 
        for (i = 0; i < num; i++) {
991
 
            snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
992
 
            val = xs_read(priv->xshandle, 0, path, &len);
993
 
            if (val == NULL)
994
 
                break;
995
 
            if ((devlen != len) || memcmp(val, dev, len)) {
996
 
                free (val);
997
 
            } else {
998
 
                ret = strdup(list[i]);
999
 
                free (val);
1000
 
                free (list);
1001
 
                return (ret);
1002
 
            }
1003
 
        }
1004
 
        free (list);
1005
 
    }
1006
 
    snprintf(dir, sizeof(dir), "/local/domain/0/backend/tap/%d", id);
1007
 
    list = xs_directory(priv->xshandle, 0, dir, &num);
1008
 
    if (list != NULL) {
1009
 
        for (i = 0; i < num; i++) {
1010
 
            snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "dev");
1011
 
            val = xs_read(priv->xshandle, 0, path, &len);
1012
 
            if (val == NULL)
1013
 
                break;
1014
 
            if ((devlen != len) || memcmp(val, dev, len)) {
1015
 
                free (val);
1016
 
            } else {
1017
 
                ret = strdup(list[i]);
1018
 
                free (val);
1019
 
                free (list);
1020
 
                return (ret);
1021
 
            }
1022
 
        }
1023
 
        free (list);
1024
 
    }
1025
 
    return (NULL);
1026
 
}
1027
 
 
1028
 
/*
1029
 
 * The caller must hold the lock on the privateData
1030
 
 * associated with the 'conn' parameter.
1031
 
 */
1032
 
char *xenStoreDomainGetName(virConnectPtr conn,
1033
 
                            int id) {
1034
 
    char prop[200];
1035
 
    xenUnifiedPrivatePtr priv;
1036
 
    unsigned int len;
1037
 
 
1038
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
1039
 
    if (priv->xshandle == NULL)
1040
 
        return(NULL);
1041
 
 
1042
 
    snprintf(prop, 199, "/local/domain/%d/name", id);
1043
 
    prop[199] = 0;
1044
 
    return xs_read(priv->xshandle, 0, prop, &len);
1045
 
}
1046
 
 
1047
 
#ifndef PROXY
1048
 
/*
1049
 
 * The caller must hold the lock on the privateData
1050
 
 * associated with the 'conn' parameter.
1051
 
 */
1052
 
int xenStoreDomainGetUUID(virConnectPtr conn,
1053
 
                          int id,
1054
 
                          unsigned char *uuid) {
1055
 
    char prop[200];
1056
 
    xenUnifiedPrivatePtr priv;
1057
 
    unsigned int len;
1058
 
    char *uuidstr;
1059
 
    int ret = 0;
1060
 
 
1061
 
    priv = (xenUnifiedPrivatePtr) conn->privateData;
1062
 
    if (priv->xshandle == NULL)
1063
 
        return -1;
1064
 
 
1065
 
    snprintf(prop, 199, "/local/domain/%d/vm", id);
1066
 
    prop[199] = 0;
1067
 
    // This will return something like
1068
 
    // /vm/00000000-0000-0000-0000-000000000000
1069
 
    uuidstr = xs_read(priv->xshandle, 0, prop, &len);
1070
 
 
1071
 
    // remove "/vm/"
1072
 
    ret = virUUIDParse(uuidstr + 4, uuid);
1073
 
 
1074
 
    VIR_FREE(uuidstr);
1075
 
 
1076
 
    return ret;
1077
 
}
1078
 
 
1079
 
static void
1080
 
xenStoreWatchListFree(xenStoreWatchListPtr list)
1081
 
{
1082
 
    int i;
1083
 
    for (i=0; i<list->count; i++) {
1084
 
        VIR_FREE(list->watches[i]->path);
1085
 
        VIR_FREE(list->watches[i]->token);
1086
 
        VIR_FREE(list->watches[i]);
1087
 
    }
1088
 
    VIR_FREE(list);
1089
 
}
1090
 
 
1091
 
/*
1092
 
 * The caller must hold the lock on the privateData
1093
 
 * associated with the 'conn' parameter.
1094
 
 */
1095
 
int xenStoreAddWatch(virConnectPtr conn,
1096
 
                     const char *path,
1097
 
                     const char *token,
1098
 
                     xenStoreWatchCallback cb,
1099
 
                     void *opaque)
1100
 
{
1101
 
    xenStoreWatchPtr watch;
1102
 
    int n;
1103
 
    xenStoreWatchListPtr list;
1104
 
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
1105
 
 
1106
 
    if (priv->xshandle == NULL)
1107
 
        return -1;
1108
 
 
1109
 
    list = priv->xsWatchList;
1110
 
    if(!list)
1111
 
        return -1;
1112
 
 
1113
 
    /* check if we already have this callback on our list */
1114
 
    for (n=0; n < list->count; n++) {
1115
 
        if( STREQ(list->watches[n]->path, path) &&
1116
 
            STREQ(list->watches[n]->token, token)) {
1117
 
            virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
1118
 
                                 "%s", _("watch already tracked"));
1119
 
            return -1;
1120
 
        }
1121
 
    }
1122
 
 
1123
 
    if (VIR_ALLOC(watch) < 0)
1124
 
        return -1;
1125
 
    watch->path   = strdup(path);
1126
 
    watch->token  = strdup(token);
1127
 
    watch->cb     = cb;
1128
 
    watch->opaque = opaque;
1129
 
 
1130
 
    /* Make space on list */
1131
 
    n = list->count;
1132
 
    if (VIR_REALLOC_N(list->watches, n + 1) < 0) {
1133
 
        virXenStoreError(NULL, VIR_ERR_INTERNAL_ERROR,
1134
 
                                 "%s", _("reallocating list"));
1135
 
        VIR_FREE(watch);
1136
 
        return -1;
1137
 
    }
1138
 
 
1139
 
    list->watches[n] = watch;
1140
 
    list->count++;
1141
 
 
1142
 
    conn->refs++;
1143
 
 
1144
 
    return xs_watch(priv->xshandle, watch->path, watch->token);
1145
 
}
1146
 
 
1147
 
/*
1148
 
 * The caller must hold the lock on the privateData
1149
 
 * associated with the 'conn' parameter.
1150
 
 */
1151
 
int xenStoreRemoveWatch(virConnectPtr conn,
1152
 
                        const char *path,
1153
 
                        const char *token)
1154
 
{
1155
 
    int i;
1156
 
    xenStoreWatchListPtr list;
1157
 
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
1158
 
 
1159
 
    if (priv->xshandle == NULL)
1160
 
        return -1;
1161
 
 
1162
 
    list = priv->xsWatchList;
1163
 
    if(!list)
1164
 
        return -1;
1165
 
 
1166
 
    for (i = 0 ; i < list->count ; i++) {
1167
 
        if( STREQ(list->watches[i]->path, path) &&
1168
 
            STREQ(list->watches[i]->token, token)) {
1169
 
 
1170
 
            if (!xs_unwatch(priv->xshandle,
1171
 
                       list->watches[i]->path,
1172
 
                       list->watches[i]->token))
1173
 
            {
1174
 
                DEBUG0("WARNING: Could not remove watch");
1175
 
                /* Not fatal, continue */
1176
 
            }
1177
 
 
1178
 
            VIR_FREE(list->watches[i]->path);
1179
 
            VIR_FREE(list->watches[i]->token);
1180
 
            VIR_FREE(list->watches[i]);
1181
 
 
1182
 
            if (i < (list->count - 1))
1183
 
                memmove(list->watches + i,
1184
 
                        list->watches + i + 1,
1185
 
                        sizeof(*(list->watches)) *
1186
 
                                (list->count - (i + 1)));
1187
 
 
1188
 
            if (VIR_REALLOC_N(list->watches,
1189
 
                              list->count - 1) < 0) {
1190
 
                ; /* Failure to reduce memory allocation isn't fatal */
1191
 
            }
1192
 
            list->count--;
1193
 
            virUnrefConnect(conn);
1194
 
            return 0;
1195
 
        }
1196
 
    }
1197
 
    return -1;
1198
 
}
1199
 
 
1200
 
static xenStoreWatchPtr
1201
 
xenStoreFindWatch(xenStoreWatchListPtr list,
1202
 
                  const char *path,
1203
 
                  const char *token)
1204
 
{
1205
 
    int i;
1206
 
    for (i = 0 ; i < list->count ; i++)
1207
 
        if( STREQ(path, list->watches[i]->path) &&
1208
 
            STREQ(token, list->watches[i]->token) )
1209
 
            return list->watches[i];
1210
 
 
1211
 
    return NULL;
1212
 
}
1213
 
 
1214
 
static void
1215
 
xenStoreWatchEvent(int watch ATTRIBUTE_UNUSED,
1216
 
                   int fd ATTRIBUTE_UNUSED,
1217
 
                   int events,
1218
 
                   void *data)
1219
 
{
1220
 
    char                 **event;
1221
 
    char                 *path;
1222
 
    char                 *token;
1223
 
    unsigned int         stringCount;
1224
 
    xenStoreWatchPtr     sw;
1225
 
 
1226
 
    virConnectPtr        conn = data;
1227
 
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
1228
 
 
1229
 
    if(!priv) return;
1230
 
 
1231
 
    /* only set a watch on read and write events */
1232
 
    if (events & (VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_HANGUP)) return;
1233
 
 
1234
 
    xenUnifiedLock(priv);
1235
 
 
1236
 
    if(!priv->xshandle)
1237
 
        goto cleanup;
1238
 
 
1239
 
    event = xs_read_watch(priv->xshandle, &stringCount);
1240
 
    if (!event)
1241
 
        goto cleanup;
1242
 
 
1243
 
    path  = event[XS_WATCH_PATH];
1244
 
    token = event[XS_WATCH_TOKEN];
1245
 
 
1246
 
    sw = xenStoreFindWatch(priv->xsWatchList, path, token);
1247
 
    if( sw )
1248
 
        sw->cb(conn, path, token, sw->opaque);
1249
 
    VIR_FREE(event);
1250
 
 
1251
 
cleanup:
1252
 
    xenUnifiedUnlock(priv);
1253
 
}
1254
 
 
1255
 
 
1256
 
/*
1257
 
 * The domain callback for the @introduceDomain watch
1258
 
 *
1259
 
 * The lock on 'priv' is held when calling this
1260
 
 */
1261
 
int xenStoreDomainIntroduced(virConnectPtr conn,
1262
 
                             const char *path ATTRIBUTE_UNUSED,
1263
 
                             const char *token ATTRIBUTE_UNUSED,
1264
 
                             void *opaque)
1265
 
{
1266
 
    int i, j, found, missing = 0, retries = 20;
1267
 
    int new_domain_cnt;
1268
 
    int *new_domids;
1269
 
    int nread;
1270
 
 
1271
 
    xenUnifiedPrivatePtr priv = opaque;
1272
 
 
1273
 
retry:
1274
 
    new_domain_cnt = xenStoreNumOfDomains(conn);
1275
 
    if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
1276
 
        virReportOOMError(NULL);
1277
 
        return -1;
1278
 
    }
1279
 
    nread = xenStoreDoListDomains(priv, new_domids, new_domain_cnt);
1280
 
    if (nread != new_domain_cnt) {
1281
 
        // mismatch. retry this read
1282
 
        VIR_FREE(new_domids);
1283
 
        goto retry;
1284
 
    }
1285
 
 
1286
 
    missing = 0;
1287
 
    for (i=0 ; i < new_domain_cnt ; i++) {
1288
 
        found = 0;
1289
 
        for (j = 0 ; j < priv->activeDomainList->count ; j++) {
1290
 
            if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
1291
 
                found = 1;
1292
 
                break;
1293
 
            }
1294
 
        }
1295
 
 
1296
 
        if (!found) {
1297
 
            virDomainEventPtr event;
1298
 
            char *name;
1299
 
            unsigned char uuid[VIR_UUID_BUFLEN];
1300
 
 
1301
 
            if (!(name = xenStoreDomainGetName(conn, new_domids[i]))) {
1302
 
                missing = 1;
1303
 
                continue;
1304
 
            }
1305
 
            if (xenStoreDomainGetUUID(conn, new_domids[i], uuid) < 0) {
1306
 
                missing = 1;
1307
 
                VIR_FREE(name);
1308
 
                continue;
1309
 
            }
1310
 
 
1311
 
            event = virDomainEventNew(new_domids[i], name, uuid,
1312
 
                                      VIR_DOMAIN_EVENT_STARTED,
1313
 
                                      VIR_DOMAIN_EVENT_STARTED_BOOTED);
1314
 
            if (event)
1315
 
                xenUnifiedDomainEventDispatch(priv, event);
1316
 
 
1317
 
            /* Add to the list */
1318
 
            xenUnifiedAddDomainInfo(priv->activeDomainList,
1319
 
                                    new_domids[i], name, uuid);
1320
 
 
1321
 
            VIR_FREE(name);
1322
 
        }
1323
 
    }
1324
 
    VIR_FREE(new_domids);
1325
 
 
1326
 
    if (missing && retries--) {
1327
 
        DEBUG0("Some domains were missing, trying again");
1328
 
        usleep(100 * 1000);
1329
 
        goto retry;
1330
 
    }
1331
 
    return 0;
1332
 
}
1333
 
 
1334
 
/*
1335
 
 * The domain callback for the @destroyDomain watch
1336
 
 *
1337
 
 * The lock on 'priv' is held when calling this
1338
 
 */
1339
 
int xenStoreDomainReleased(virConnectPtr conn,
1340
 
                            const char *path  ATTRIBUTE_UNUSED,
1341
 
                            const char *token ATTRIBUTE_UNUSED,
1342
 
                            void *opaque)
1343
 
{
1344
 
    int i, j, found, removed, retries = 20;
1345
 
    int new_domain_cnt;
1346
 
    int *new_domids;
1347
 
    int nread;
1348
 
 
1349
 
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) opaque;
1350
 
 
1351
 
    if(!priv->activeDomainList->count) return 0;
1352
 
 
1353
 
retry:
1354
 
    new_domain_cnt = xenStoreNumOfDomains(conn);
1355
 
 
1356
 
    if( VIR_ALLOC_N(new_domids,new_domain_cnt) < 0 ) {
1357
 
        virReportOOMError(NULL);
1358
 
        return -1;
1359
 
    }
1360
 
    nread = xenStoreDoListDomains(priv, new_domids, new_domain_cnt);
1361
 
    if (nread != new_domain_cnt) {
1362
 
        // mismatch. retry this read
1363
 
        VIR_FREE(new_domids);
1364
 
        goto retry;
1365
 
    }
1366
 
 
1367
 
    removed = 0;
1368
 
    for (j=0 ; j < priv->activeDomainList->count ; j++) {
1369
 
        found = 0;
1370
 
        for (i=0 ; i < new_domain_cnt ; i++) {
1371
 
            if (priv->activeDomainList->doms[j]->id == new_domids[i]) {
1372
 
                found = 1;
1373
 
                break;
1374
 
            }
1375
 
        }
1376
 
 
1377
 
        if (!found) {
1378
 
            virDomainEventPtr event =
1379
 
                virDomainEventNew(-1,
1380
 
                                  priv->activeDomainList->doms[j]->name,
1381
 
                                  priv->activeDomainList->doms[j]->uuid,
1382
 
                                  VIR_DOMAIN_EVENT_STOPPED,
1383
 
                                  VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
1384
 
            if (event)
1385
 
                xenUnifiedDomainEventDispatch(priv, event);
1386
 
 
1387
 
            /* Remove from the list */
1388
 
            xenUnifiedRemoveDomainInfo(priv->activeDomainList,
1389
 
                                       priv->activeDomainList->doms[j]->id,
1390
 
                                       priv->activeDomainList->doms[j]->name,
1391
 
                                       priv->activeDomainList->doms[j]->uuid);
1392
 
 
1393
 
            removed = 1;
1394
 
        }
1395
 
    }
1396
 
 
1397
 
    VIR_FREE(new_domids);
1398
 
 
1399
 
    if (!removed && retries--) {
1400
 
        DEBUG0("No domains removed, retrying");
1401
 
        usleep(100 * 1000);
1402
 
        goto retry;
1403
 
    }
1404
 
    return 0;
1405
 
}
1406
 
 
1407
 
#endif //PROXY