libvirt.c 38.2 KB
Newer Older
D
Daniel Veillard 已提交
1
/*
2
 * libvirt.c: Main interfaces for the libvirt library to handle virtualization
D
Daniel Veillard 已提交
3 4
 *           domains from a process running in domain 0
 *
5
 * Copyright (C) 2005,2006 Red Hat, Inc.
D
Daniel Veillard 已提交
6 7 8 9 10 11
 *
 * See COPYING.LIB for the License of this software
 *
 * Daniel Veillard <veillard@redhat.com>
 */

12
#include "libvirt.h"
D
Daniel Veillard 已提交
13

14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17 18 19
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
20
#include <xs.h>
D
Daniel Veillard 已提交
21
#include "internal.h"
22
#include "driver.h"
23
#include "xen_internal.h"
24
#include "xend_internal.h"
25
#include "hash.h"
26
#include "xml.h"
27

D
Daniel Veillard 已提交
28 29 30 31 32

/*
 * TODO:
 * - use lock to protect against concurrent accesses ?
 * - use reference counting to garantee coherent pointer state ?
33 34
 * - error reporting layer
 * - memory wrappers for malloc/free ?
D
Daniel Veillard 已提交
35 36
 */

D
Daniel Veillard 已提交
37 38 39 40 41 42 43 44 45
/**
 * virLibConnError:
 * @conn: the connection if available
 * @error: the error noumber
 * @info: extra information string
 *
 * Handle an error at the connection level
 */
static void
46 47
virLibConnError(virConnectPtr conn, virErrorNumber error, const char *info)
{
D
Daniel Veillard 已提交
48
    const char *errmsg;
49

D
Daniel Veillard 已提交
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
    if (error == VIR_ERR_OK)
        return;

    errmsg = __virErrorMsg(error, info);
    __virRaiseError(conn, NULL, VIR_FROM_NONE, error, VIR_ERR_ERROR,
                    errmsg, info, NULL, 0, 0, errmsg, info);
}

/**
 * virLibConnError:
 * @conn: the connection if available
 * @error: the error noumber
 * @info: extra information string
 *
 * Handle an error at the connection level
 */
static void
67 68 69
virLibDomainError(virDomainPtr domain, virErrorNumber error,
                  const char *info)
{
D
Daniel Veillard 已提交
70 71
    virConnectPtr conn = NULL;
    const char *errmsg;
72

D
Daniel Veillard 已提交
73 74 75 76 77 78 79 80 81 82 83
    if (error == VIR_ERR_OK)
        return;

    errmsg = __virErrorMsg(error, info);
    if (error != VIR_ERR_INVALID_DOMAIN) {
        conn = domain->conn;
    }
    __virRaiseError(conn, domain, VIR_FROM_DOM, error, VIR_ERR_ERROR,
                    errmsg, info, NULL, 0, 0, errmsg, info);
}

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
/**
 * virGetVersion:
 * @libVer: return value for the library version (OUT)
 * @type: hypervisor type
 * @typeVer: return value for the version of the hypervisor (OUT)
 *
 * Provides two information back, @libVer is the version of the library
 * while @typeVer will be the version of the hypervisor type @type against
 * which the library was compiled. If @type is NULL, "Xen" is assumed, if
 * @type is unknown or not availble, an error code will be returned and 
 * @typeVer will be 0.
 *
 * Returns -1 in case of failure, 0 otherwise, and values for @libVer and
 *       @typeVer have the format major * 1,000,000 + minor * 1,000 + release.
 */
int
100 101 102
virGetVersion(unsigned long *libVer, const char *type,
              unsigned long *typeVer)
{
103
    if (libVer == NULL)
104
        return (-1);
105 106 107
    *libVer = LIBVIR_VERSION_NUMBER;

    if (typeVer != NULL) {
108 109 110
        if ((type == NULL) || (!strcasecmp(type, "Xen"))) {
            if ((DOM0_INTERFACE_VERSION & 0xFFFF0000) == (0xAAAA0000)) {
                /* one time glitch hopefully ! */
111
                *typeVer = 2 * 1000000 +
112 113 114 115 116 117 118 119 120 121 122 123 124 125
                    ((DOM0_INTERFACE_VERSION >> 8) & 0xFF) * 1000 +
                    (DOM0_INTERFACE_VERSION & 0xFF);
            } else {
                *typeVer = (DOM0_INTERFACE_VERSION >> 24) * 1000000 +
                    ((DOM0_INTERFACE_VERSION >> 16) & 0xFF) * 1000 +
                    (DOM0_INTERFACE_VERSION & 0xFFFF);
            }
        } else {
            *typeVer = 0;
            virLibConnError(NULL, VIR_ERR_NO_SUPPORT, "type");
            return (-1);
        }
    }
    return (0);
126 127
}

D
Daniel Veillard 已提交
128
/**
129
 * virConnectOpen:
D
Daniel Veillard 已提交
130 131 132
 * @name: optional argument currently unused, pass NULL
 *
 * This function should be called first to get a connection to the 
133
 * Hypervisor and xen store
D
Daniel Veillard 已提交
134 135 136
 *
 * Returns a pointer to the hypervisor connection or NULL in case of error
 */
137
virConnectPtr
138 139
virConnectOpen(const char *name)
{
140
    virConnectPtr ret = NULL;
141
    int res;
142 143 144
    struct xs_handle *xshandle = NULL;

    /* we can only talk to the local Xen supervisor ATM */
D
Daniel Veillard 已提交
145
    if (name != NULL) {
146 147
        virLibConnError(NULL, VIR_ERR_NO_SUPPORT, name);
        return (NULL);
D
Daniel Veillard 已提交
148
    }
149

150 151 152 153 154 155 156 157 158 159
    ret = (virConnectPtr) malloc(sizeof(virConnect));
    if (ret == NULL) {
        virLibConnError(NULL, VIR_ERR_NO_MEMORY, "Allocating connection");
        goto failed;
    }
    memset(ret, 0, sizeof(virConnect));
    ret->magic = VIR_CONNECT_MAGIC;

    res = xenHypervisorOpen(ret, name, 0);
    if (res < 0) {
160
        goto failed;
D
Daniel Veillard 已提交
161
    }
162
    xshandle = xs_daemon_open();
D
Daniel Veillard 已提交
163
    if (xshandle == NULL) {
164
        virLibConnError(NULL, VIR_ERR_NO_CONNECT, "XenStore");
165
        goto failed;
D
Daniel Veillard 已提交
166
    }
167 168

    ret->xshandle = xshandle;
169
    if (xenDaemonOpen(ret, name, 0) < 0)
170
        goto failed;
171
    ret->domains = virHashCreate(20);
172
    ret->flags = 0;
173 174
    if (ret->domains == NULL)
        goto failed;
175

176 177
    return (ret);
  failed:
178
    xenHypervisorClose(ret);
179
    if (xshandle != NULL)
180
        xs_daemon_close(xshandle);
181 182
    if (ret != NULL)
        free(ret);
183
    return (NULL);
184 185 186
}

/**
187
 * virConnectOpenReadOnly:
188 189
 * @name: optional argument currently unused, pass NULL
 *
190 191 192
 * This function should be called first to get a restricted connection to the 
 * libbrary functionalities. The set of APIs usable are then restricted
 * on the available methods to control the domains.
193 194 195
 *
 * Returns a pointer to the hypervisor connection or NULL in case of error
 */
196
virConnectPtr
197 198
virConnectOpenReadOnly(const char *name)
{
199
    int method = 0;
200
    int res;
201
    virConnectPtr ret = NULL;
202 203 204
    struct xs_handle *xshandle = NULL;

    /* we can only talk to the local Xen supervisor ATM */
D
Daniel Veillard 已提交
205
    if (name != NULL) {
206 207
        virLibConnError(NULL, VIR_ERR_NO_SUPPORT, name);
        return (NULL);
D
Daniel Veillard 已提交
208
    }
209

210
    ret = (virConnectPtr) malloc(sizeof(virConnect));
D
Daniel Veillard 已提交
211 212
    if (ret == NULL) {
        virLibConnError(NULL, VIR_ERR_NO_MEMORY, "Allocating connection");
213
        goto failed;
D
Daniel Veillard 已提交
214
    }
215
    memset(ret, 0, sizeof(virConnect));
216
    ret->magic = VIR_CONNECT_MAGIC;
217 218 219 220 221 222 223 224 225

    res = xenHypervisorOpen(ret, name, VIR_DRV_OPEN_QUIET | VIR_DRV_OPEN_RO);
    if (res >= 0)
        method++;

    xshandle = xs_daemon_open_readonly();
    if (xshandle != NULL)
        method++;

226
    ret->xshandle = xshandle;
227
    if (xenDaemonOpen(ret, name, VIR_DRV_OPEN_QUIET | VIR_DRV_OPEN_RO) == 0)
228
        method++;
229
    ret->domains = virHashCreate(20);
D
Daniel Veillard 已提交
230 231
    if (ret->domains == NULL)
        goto failed;
232
    ret->flags = VIR_CONNECT_RO;
D
Daniel Veillard 已提交
233 234
    if (method == 0) {
        virLibConnError(NULL, VIR_ERR_NO_CONNECT,
235
                        "could not connect to Xen Daemon nor Xen Store");
236
        goto failed;
D
Daniel Veillard 已提交
237
    }
238

239 240
    return (ret);
  failed:
241
    xenHypervisorClose(ret);
242 243
    if (xshandle != NULL)
        xs_daemon_close(xshandle);
244 245
    if (ret != NULL) {
        if (ret->domains != NULL)
246
            virHashFree(ret->domains, NULL);
247
        free(ret);
248
    }
249
    return (NULL);
D
Daniel Veillard 已提交
250 251
}

252 253 254 255 256 257 258 259 260 261 262
/**
 * virConnectCheckStoreID:
 * @conn: pointer to the hypervisor connection
 * @id: the id number as returned from Xenstore
 *
 * the xenstore sometimes list non-running domains, double check
 * from the hypervisor if we have direct access
 *
 * Returns -1 if the check failed, 0 if successful or not possible to check
 */
static int
263 264
virConnectCheckStoreID(virConnectPtr conn, int id)
{
265
    if (conn->handle >= 0) {
266 267
	TODO
	/*
268 269
        dom0_getdomaininfo_t dominfo;
        int tmp;
270

271 272 273 274
        dominfo.domain = id;
        tmp = xenHypervisorGetDomainInfo(conn->handle, id, &dominfo);
        if (tmp < 0)
            return (-1);
275
	 */
276
    }
277
    return (0);
278 279
}

280
/**
281
 * virDomainFreeName:
282 283 284 285 286 287 288
 * @domain: a domain object
 *
 * Destroy the domain object, this is just used by the domain hash callback.
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
static int
289 290 291
virDomainFreeName(virDomainPtr domain, const char *name ATTRIBUTE_UNUSED)
{
    return (virDomainFree(domain));
292 293
}

D
Daniel Veillard 已提交
294
/**
295
 * virConnectClose:
D
Daniel Veillard 已提交
296 297 298 299 300 301 302 303 304 305
 * @conn: pointer to the hypervisor connection
 *
 * This function closes the connection to the Hypervisor. This should
 * not be called if further interaction with the Hypervisor are needed
 * especially if there is running domain which need further monitoring by
 * the application.
 *
 * Returns 0 in case of success or -1 in case of error.
 */
int
306 307
virConnectClose(virConnectPtr conn)
{
308
    xenDaemonClose(conn);
K
Karel Zak 已提交
309
    if (!VIR_IS_CONNECT(conn))
310
        return (-1);
311
    virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName);
D
Daniel Veillard 已提交
312
    conn->magic = -1;
313
    if (conn->xshandle != NULL)
314
        xs_daemon_close(conn->xshandle);
315
    conn->xshandle = NULL;
316
    xenHypervisorClose(conn);
317
    conn->handle = -1;
D
Daniel Veillard 已提交
318
    free(conn);
319
    return (0);
D
Daniel Veillard 已提交
320 321
}

322 323 324 325 326 327 328 329 330
/**
 * virConnectGetType:
 * @conn: pointer to the hypervisor connection
 *
 * Get the name of the Hypervisor software used.
 *
 * Returns NULL in case of error, a static zero terminated string otherwise.
 */
const char *
331 332
virConnectGetType(virConnectPtr conn)
{
D
Daniel Veillard 已提交
333
    if (!VIR_IS_CONNECT(conn)) {
334 335 336
        virLibConnError(conn, VIR_ERR_INVALID_CONN,
                        "in virConnectGetType");
        return (NULL);
D
Daniel Veillard 已提交
337
    }
338
    return ("Xen");
339 340
}

D
Daniel Veillard 已提交
341
/**
342
 * virConnectGetVersion:
D
Daniel Veillard 已提交
343
 * @conn: pointer to the hypervisor connection
344
 * @hvVer: return value for the version of the running hypervisor (OUT)
D
Daniel Veillard 已提交
345
 *
346 347 348
 * Get the version level of the Hypervisor running. This may work only with 
 * hypervisor call, i.e. with priviledged access to the hypervisor, not
 * with a Read-Only connection.
D
Daniel Veillard 已提交
349
 *
350 351 352
 * Returns -1 in case of error, 0 otherwise. if the version can't be
 *    extracted by lack of capacities returns 0 and @hvVer is 0, otherwise
 *    @hvVer value is major * 1,000,000 + minor * 1,000 + release
D
Daniel Veillard 已提交
353
 */
354
int
355 356
virConnectGetVersion(virConnectPtr conn, unsigned long *hvVer)
{
357
    unsigned long ver;
358

D
Daniel Veillard 已提交
359 360
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
361
        return (-1);
D
Daniel Veillard 已提交
362
    }
363

D
Daniel Veillard 已提交
364 365
    if (hvVer == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
366
        return (-1);
D
Daniel Veillard 已提交
367
    }
368

369
    /* this can't be extracted from the Xenstore */
370 371
    if (conn->handle < 0) {
        *hvVer = 0;
372
        return (0);
373
    }
374

375
    ver = xenHypervisorGetVersion(conn, hvVer);
376
    return (0);
377 378 379
}

/**
380
 * virConnectListDomains:
381 382 383 384 385 386 387 388 389
 * @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
390 391
virConnectListDomains(virConnectPtr conn, int *ids, int maxids)
{
392 393 394 395 396
    int ret = -1;
    unsigned int num, i;
    long id;
    char **idlist = NULL, *endptr;

D
Daniel Veillard 已提交
397 398
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
399
        return (-1);
D
Daniel Veillard 已提交
400
    }
401

D
Daniel Veillard 已提交
402 403
    if ((ids == NULL) || (maxids <= 0)) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
404
        return (-1);
D
Daniel Veillard 已提交
405
    }
406

407
    idlist = xenDaemonListDomains(conn);
408
    if (idlist != NULL) {
409
        for (ret = 0, i = 0; (idlist[i] != NULL) && (ret < maxids); i++) {
410
            id = xenDaemonDomainLookupByName_ids(conn, idlist[i], NULL);
411 412 413 414
            if (id >= 0)
                ids[ret++] = (int) id;
        }
        goto done;
415 416
    }
    if (conn->xshandle != NULL) {
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
        idlist = xs_directory(conn->xshandle, 0, "/local/domain", &num);
        if (idlist == NULL)
            goto done;

        for (ret = 0, i = 0; (i < num) && (ret < maxids); i++) {
            id = strtol(idlist[i], &endptr, 10);
            if ((endptr == idlist[i]) || (*endptr != 0)) {
                ret = -1;
                goto done;
            }
            if (virConnectCheckStoreID(conn, (int) id) < 0)
                continue;
            ids[ret++] = (int) id;
        }
    }

  done:
434 435 436
    if (idlist != NULL)
        free(idlist);

437
    return (ret);
D
Daniel Veillard 已提交
438 439
}

K
 
Karel Zak 已提交
440 441 442 443
/**
 * virConnectNumOfDomains:
 * @conn: pointer to the hypervisor connection
 *
444 445
 * Provides the number of active domains.
 *
K
 
Karel Zak 已提交
446 447 448
 * Returns the number of domain found or -1 in case of error
 */
int
449 450
virConnectNumOfDomains(virConnectPtr conn)
{
K
 
Karel Zak 已提交
451 452 453 454
    int ret = -1;
    unsigned int num;
    char **idlist = NULL;

D
Daniel Veillard 已提交
455 456
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
457
        return (-1);
D
Daniel Veillard 已提交
458
    }
K
Karel Zak 已提交
459

460 461 462
    /* 
     * try first with Xend interface
     */
463
    idlist = xenDaemonListDomains(conn);
464 465 466 467 468
    if (idlist != NULL) {
        char **tmp = idlist;

        ret = 0;
        while (*tmp != NULL) {
469 470 471 472
            tmp++;
            ret++;
        }

473
    } else if (conn->xshandle != NULL) {
474
        idlist = xs_directory(conn->xshandle, 0, "/local/domain", &num);
475 476 477 478
        if (idlist) {
            free(idlist);
            ret = num;
        }
K
 
Karel Zak 已提交
479
    }
480
    return (ret);
K
 
Karel Zak 已提交
481 482
}

D
Daniel Veillard 已提交
483
/**
484
 * virDomainCreateLinux:
D
Daniel Veillard 已提交
485
 * @conn: pointer to the hypervisor connection
486
 * @xmlDesc: an XML description of the domain
487
 * @flags: an optional set of virDomainFlags
D
Daniel Veillard 已提交
488
 *
489 490 491
 * Launch a new Linux guest domain, based on an XML description similar
 * to the one returned by virDomainGetXMLDesc()
 * This function may requires priviledged access to the hypervisor.
D
Daniel Veillard 已提交
492 493 494
 * 
 * Returns a new domain object or NULL in case of failure
 */
495
virDomainPtr
496
virDomainCreateLinux(virConnectPtr conn,
497
                     const char *xmlDesc,
498 499
                     unsigned int flags ATTRIBUTE_UNUSED)
{
500 501 502 503
    int ret;
    char *sexpr;
    char *name = NULL;
    virDomainPtr dom;
K
Karel Zak 已提交
504

D
Daniel Veillard 已提交
505 506
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
507
        return (NULL);
D
Daniel Veillard 已提交
508 509 510
    }
    if (xmlDesc == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
511
        return (NULL);
D
Daniel Veillard 已提交
512 513
    }

514 515 516
    sexpr = virDomainParseXMLDesc(xmlDesc, &name);
    if ((sexpr == NULL) || (name == NULL)) {
        if (sexpr != NULL)
517
            free(sexpr);
518
        if (name != NULL)
519
            free(name);
520

521
        return (NULL);
522 523
    }

524
    ret = xenDaemonDomainCreateLinux(conn, sexpr);
525 526 527
    free(sexpr);
    if (ret != 0) {
        fprintf(stderr, "Failed to create domain %s\n", name);
528
        goto error;
529 530 531 532 533
    }

    ret = xend_wait_for_devices(conn, name);
    if (ret != 0) {
        fprintf(stderr, "Failed to get devices for domain %s\n", name);
534
        goto error;
535 536
    }

537 538 539 540 541 542
    dom = virDomainLookupByName(conn, name);
    if (dom == NULL) {
        goto error;
    }

    ret = xenDaemonDomainResume(dom);
543 544
    if (ret != 0) {
        fprintf(stderr, "Failed to resume new domain %s\n", name);
545
        xenDaemonDomainDestroy(dom);
546
        goto error;
547 548 549 550 551
    }

    dom = virDomainLookupByName(conn, name);
    free(name);

552 553
    return (dom);
  error:
554 555
    if (name != NULL)
        free(name);
556
    return (NULL);
D
Daniel Veillard 已提交
557 558
}

559 560 561 562 563 564 565 566 567 568 569
/**
 * 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 **
570 571 572
virConnectDoStoreList(virConnectPtr conn, const char *path,
                      unsigned int *nb)
{
573 574
    if ((conn == NULL) || (conn->xshandle == NULL) || (path == NULL) ||
        (nb == NULL))
575
        return (NULL);
576

577
    return xs_directory(conn->xshandle, 0, path, nb);
578 579 580
}

/**
581
 * virDomainDoStoreQuery:
582 583 584 585 586 587 588 589
 * @domain: a domain object
 * @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 *
590 591
virDomainDoStoreQuery(virDomainPtr domain, const char *path)
{
592 593
    char s[256];
    unsigned int len = 0;
594

K
Karel Zak 已提交
595
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
596
        return (NULL);
597
    if (domain->conn->xshandle == NULL)
598
        return (NULL);
599 600 601 602

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

603
    return xs_read(domain->conn->xshandle, 0, &s[0], &len);
604 605
}

606

607 608 609 610 611 612 613 614 615 616 617 618
/**
 * 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,
619 620
                      const char *value)
{
621 622 623 624
    char s[256];

    int ret = -1;

K
Karel Zak 已提交
625
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
626
        return (-1);
627
    if (domain->conn->xshandle == NULL)
628
        return (-1);
K
Karel Zak 已提交
629
    if (domain->conn->flags & VIR_CONNECT_RO)
630
        return (-1);
631 632 633 634

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

635
    if (xs_write(domain->conn->xshandle, 0, &s[0], value, strlen(value)))
636 637
        ret = 0;

638
    return (ret);
639 640
}

641 642 643 644 645 646 647 648 649 650 651 652 653 654
/**
 * virDomainGetVM:
 * @domain: a domain object
 *
 * Internal API extracting a xenstore vm path.
 *
 * Returns the new string or NULL in case of error
 */
char *
virDomainGetVM(virDomainPtr domain)
{
    char *vm;
    char query[200];
    unsigned int len;
655

K
Karel Zak 已提交
656
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
657
        return (NULL);
658
    if (domain->conn->xshandle == NULL)
659 660 661
        return (NULL);

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

664
    vm = xs_read(domain->conn->xshandle, 0, &query[0], &len);
665

666
    return (vm);
667 668 669 670 671 672 673 674 675 676 677 678 679 680
}

/**
 * virDomainGetVMInfo:
 * @domain: a domain object
 * @vm: the xenstore vm path
 * @name: the value's path
 *
 * Internal API extracting one information the device used 
 * by the domain from xensttore
 *
 * Returns the new string or NULL in case of error
 */
char *
681 682
virDomainGetVMInfo(virDomainPtr domain, const char *vm, const char *name)
{
683 684 685
    char s[256];
    char *ret = NULL;
    unsigned int len = 0;
686

K
Karel Zak 已提交
687
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
688 689 690 691
        return (NULL);
    if (domain->conn->xshandle == NULL)
        return (NULL);

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

695
    ret = xs_read(domain->conn->xshandle, 0, &s[0], &len);
696

697
    return (ret);
698 699
}

700
/**
701
 * virDomainLookupByID:
702 703 704 705 706 707 708
 * @conn: pointer to the hypervisor connection
 * @id: the domain ID number
 *
 * Try to find a domain based on the hypervisor ID number
 *
 * Returns a new domain object or NULL in case of failure
 */
709
virDomainPtr
710 711
virDomainLookupByID(virConnectPtr conn, int id)
{
712
    char *path = NULL;
713
    virDomainPtr ret;
714
    char *name = NULL;
715
    unsigned char uuid[16];
716

D
Daniel Veillard 已提交
717 718
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
719
        return (NULL);
D
Daniel Veillard 已提交
720 721 722
    }
    if (id < 0) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
723
        return (NULL);
D
Daniel Veillard 已提交
724
    }
725

726 727
    /* lookup is easier with the Xen store so try it first */
    if (conn->xshandle != NULL) {
728
        path = xs_get_domain_path(conn->xshandle, (unsigned int) id);
729 730
    }
    /* fallback to xend API then */
731
    if (path == NULL) {
732
        char **names = xenDaemonListDomains(conn);
733 734 735 736 737
        char **tmp = names;
        int ident;

        if (names != NULL) {
            while (*tmp != NULL) {
738
                ident = xenDaemonDomainLookupByName_ids(conn, *tmp, &uuid[0]);
739 740 741 742 743 744 745 746
                if (ident == id) {
                    name = strdup(*tmp);
                    break;
                }
                tmp++;
            }
            free(names);
        }
747
    }
748

749
    ret = (virDomainPtr) malloc(sizeof(virDomain));
750
    if (ret == NULL) {
751
        goto error;
752
    }
753
    memset(ret, 0, sizeof(virDomain));
754
    ret->magic = VIR_DOMAIN_MAGIC;
755 756
    ret->conn = conn;
    ret->handle = id;
757
    ret->path = path;
758
    if (name == NULL) {
759
        ret->name = virDomainDoStoreQuery(ret, "name");
760
    } else {
761
        ret->name = name;
762 763
        memcpy(&ret->uuid[0], uuid, 16);
    }
764
    if (ret->name == NULL) {
765 766 767
        goto error;
    }

768 769
    return (ret);
  error:
770
    if (ret != NULL)
771
        free(path);
772
    if (path != NULL)
773
        free(path);
774
    if (path != NULL)
775 776
        free(path);
    return (NULL);
777 778 779 780 781 782 783 784 785 786 787 788
}

/**
 * virDomainLookupByUUID:
 * @conn: pointer to the hypervisor connection
 * @uuid: the UUID string for the domain
 *
 * Try to lookup a domain on the given hypervisor based on its UUID.
 *
 * Returns a new domain object or NULL in case of failure
 */
virDomainPtr
789 790
virDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
791 792 793 794 795
    virDomainPtr ret;
    char *name = NULL;
    char **names;
    char **tmp;
    unsigned char ident[16];
796
    int id = -1;
797

D
Daniel Veillard 已提交
798 799
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
800
        return (NULL);
D
Daniel Veillard 已提交
801 802 803
    }
    if (uuid == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
804
        return (NULL);
D
Daniel Veillard 已提交
805
    }
806
    names = xenDaemonListDomains(conn);
807 808 809
    tmp = names;

    if (names == NULL) {
810 811
        TODO                    /* try to fallback to xenstore lookup */
            return (NULL);
812
    }
813
    while (*tmp != NULL) {
814
        id = xenDaemonDomainLookupByName_ids(conn, *tmp, &ident[0]);
815 816 817 818 819 820 821
        if (id >= 0) {
            if (!memcmp(uuid, ident, 16)) {
                name = strdup(*tmp);
                break;
            }
        }
        tmp++;
822 823 824 825
    }
    free(names);

    if (name == NULL)
826
        return (NULL);
827 828 829 830

    ret = (virDomainPtr) malloc(sizeof(virDomain));
    if (ret == NULL) {
        if (name != NULL)
831 832
            free(name);
        return (NULL);
833
    }
834
    memset(ret, 0, sizeof(virDomain));
835 836 837 838
    ret->magic = VIR_DOMAIN_MAGIC;
    ret->conn = conn;
    ret->handle = id;
    ret->name = name;
839
    ret->path = 0;
840
    memcpy(ret->uuid, uuid, 16);
841

842
    return (ret);
843 844
}

845 846 847 848 849
/**
 * virDomainLookupByName:
 * @conn: pointer to the hypervisor connection
 * @name: name for the domain
 *
850
 * Try to lookup a domain on the given hypervisor based on its name.
851 852 853 854
 *
 * Returns a new domain object or NULL in case of failure
 */
virDomainPtr
855 856
virDomainLookupByName(virConnectPtr conn, const char *name)
{
857 858
    virDomainPtr ret = NULL;
    unsigned int num, i, len;
859
    long id = -1;
860
    char **idlist = NULL, *endptr;
861 862
    char prop[200], *tmp, *path = NULL;
    unsigned char *uuid = NULL;
863
    int found = 0;
864
    struct xend_domain *xenddomain = NULL;
865

D
Daniel Veillard 已提交
866 867
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
868
        return (NULL);
D
Daniel Veillard 已提交
869 870 871
    }
    if (name == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
872
        return (NULL);
D
Daniel Veillard 已提交
873
    }
874

875
    /* try first though Xend */
876
    xenddomain = xenDaemonDomainLookupByName(conn, name);
877 878
    if (xenddomain != NULL) {
        id = xenddomain->live->id;
879 880 881
        uuid = xenddomain->uuid;
        found = 1;
        goto do_found;
882 883 884
    }

    /* then though the XenStore */
885
    if (conn->xshandle != NULL) {
886
        idlist = xs_directory(conn->xshandle, 0, "/local/domain", &num);
887 888 889
        if (idlist == NULL)
            goto done;

890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905
        for (i = 0; i < num; i++) {
            id = strtol(idlist[i], &endptr, 10);
            if ((endptr == idlist[i]) || (*endptr != 0)) {
                goto done;
            }
            if (virConnectCheckStoreID(conn, (int) id) < 0)
                continue;
            snprintf(prop, 199, "/local/domain/%s/name", idlist[i]);
            prop[199] = 0;
            tmp = xs_read(conn->xshandle, 0, prop, &len);
            if (tmp != NULL) {
                found = !strcmp(name, tmp);
                free(tmp);
                if (found)
                    break;
            }
906 907
        }
        path = xs_get_domain_path(conn->xshandle, (unsigned int) id);
908
    }
909

910
  do_found:
911

912
    if (found) {
913 914 915 916 917 918 919 920 921 922 923 924 925 926
        ret = (virDomainPtr) malloc(sizeof(virDomain));
        if (ret == NULL)
            goto done;
        memset(ret, 0, sizeof(virDomain));
        ret->magic = VIR_DOMAIN_MAGIC;
        ret->conn = conn;
        ret->handle = id;
        ret->path = path;
        if (uuid != NULL)
            memcpy(ret->uuid, uuid, 16);
        ret->name = strdup(name);
    }

  done:
927
    if (xenddomain != NULL)
928
        free(xenddomain);
929 930 931
    if (idlist != NULL)
        free(idlist);

932
    return (ret);
933 934
}

D
Daniel Veillard 已提交
935
/**
936
 * virDomainDestroy:
D
Daniel Veillard 已提交
937 938 939 940
 * @domain: a domain object
 *
 * Destroy the domain object. The running instance is shutdown if not down
 * already and all resources used by it are given back to the hypervisor.
941 942
 * The data structure is freed and should not be used thereafter if the
 * call does not return an error.
943
 * This function may requires priviledged access
D
Daniel Veillard 已提交
944 945
 *
 * Returns 0 in case of success and -1 in case of failure.
946
 */
D
Daniel Veillard 已提交
947
int
948 949
virDomainDestroy(virDomainPtr domain)
{
950 951
    int ret;

D
Daniel Veillard 已提交
952 953
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
954
        return (-1);
D
Daniel Veillard 已提交
955
    }
956 957 958 959

    /*
     * try first with the xend method
     */
960
    ret = xenDaemonDomainDestroy(domain);
961 962
    if (ret == 0) {
        virDomainFree(domain);
963
        return (0);
964 965
    }

966
    ret = xenHypervisorDestroyDomain(domain);
967
    if (ret < 0)
968 969
        return (-1);

970
    virDomainFree(domain);
971
    return (0);
972 973 974 975 976 977 978 979 980 981 982 983
}

/**
 * virDomainFree:
 * @domain: a domain object
 *
 * Free the domain object. The running instance is kept alive.
 * The data structure is freed and should not be used thereafter.
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
984 985
virDomainFree(virDomainPtr domain)
{
D
Daniel Veillard 已提交
986 987
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
988
        return (-1);
D
Daniel Veillard 已提交
989
    }
990 991 992 993 994 995 996
    domain->magic = -1;
    domain->handle = -1;
    if (domain->path != NULL)
        free(domain->path);
    if (domain->name)
        free(domain->name);
    free(domain);
997
    return (0);
D
Daniel Veillard 已提交
998 999 1000
}

/**
1001
 * virDomainSuspend:
D
Daniel Veillard 已提交
1002 1003 1004 1005
 * @domain: a domain object
 *
 * Suspends an active domain, the process is frozen without further access
 * to CPU resources and I/O but the memory used by the domain at the 
1006
 * hypervisor level will stay allocated. Use virDomainResume() to reactivate
D
Daniel Veillard 已提交
1007
 * the domain.
1008
 * This function may requires priviledged access.
D
Daniel Veillard 已提交
1009 1010 1011 1012
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
1013 1014
virDomainSuspend(virDomainPtr domain)
{
1015 1016
    int ret;

D
Daniel Veillard 已提交
1017 1018
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1019
        return (-1);
D
Daniel Veillard 已提交
1020 1021
    }

1022
    /* first try though the Xen daemon */
1023
    ret = xenDaemonDomainSuspend(domain);
1024
    if (ret == 0)
1025
        return (0);
1026 1027

    /* then try a direct hypervisor access */
1028
    return (xenHypervisorPauseDomain(domain));
D
Daniel Veillard 已提交
1029 1030 1031
}

/**
1032
 * virDomainResume:
D
Daniel Veillard 已提交
1033 1034 1035
 * @domain: a domain object
 *
 * Resume an suspended domain, the process is restarted from the state where
1036
 * it was frozen by calling virSuspendDomain().
1037
 * This function may requires priviledged access
D
Daniel Veillard 已提交
1038 1039 1040 1041
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
1042 1043
virDomainResume(virDomainPtr domain)
{
1044 1045
    int ret;

D
Daniel Veillard 已提交
1046 1047
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1048
        return (-1);
D
Daniel Veillard 已提交
1049 1050
    }

1051
    /* first try though the Xen daemon */
1052
    ret = xenDaemonDomainResume(domain);
1053
    if (ret == 0)
1054
        return (0);
1055 1056

    /* then try a direct hypervisor access */
1057
    return (xenHypervisorResumeDomain(domain));
D
Daniel Veillard 已提交
1058 1059
}

1060 1061 1062 1063 1064 1065
/**
 * virDomainSave:
 * @domain: a domain object
 * @to: path for the output file
 *
 * This method will suspend a domain and save its memory contents to
1066 1067 1068
 * a file on disk. After the call, if successful, the domain is not
 * listed as running anymore (this may be a problem).
 * Use virDomainRestore() to restore a domain after saving.
1069 1070 1071 1072
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
1073 1074
virDomainSave(virDomainPtr domain, const char *to)
{
1075
    int ret;
1076
    char filepath[4096];
1077

D
Daniel Veillard 已提交
1078 1079
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1080
        return (-1);
D
Daniel Veillard 已提交
1081 1082 1083
    }
    if (to == NULL) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1084
        return (-1);
D
Daniel Veillard 已提交
1085
    }
1086

1087 1088 1089 1090 1091
    /*
     * We must absolutize the file path as the save is done out of process
     * TODO: check for URI when libxml2 is linked in.
     */
    if (to[0] != '/') {
1092
        unsigned int len, t;
1093

1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
        t = strlen(to);
        if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL)
            return (-1);
        len = strlen(filepath);
        /* that should be covered by getcwd() semantic, but be 100% sure */
        if (len > sizeof(filepath) - (t + 3))
            return (-1);
        filepath[len] = '/';
        strcpy(&filepath[len + 1], to);
        to = &filepath[0];
1104 1105 1106

    }

1107
    ret = xenDaemonDomainSave(domain, to);
1108
    return (ret);
1109 1110 1111 1112
}

/**
 * virDomainRestore:
1113
 * @conn: pointer to the hypervisor connection
1114 1115 1116 1117 1118 1119 1120
 * @from: path to the 
 *
 * This method will restore a domain saved to disk by virDomainSave().
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
1121 1122
virDomainRestore(virConnectPtr conn, const char *from)
{
1123
    int ret;
1124
    char filepath[4096];
1125

D
Daniel Veillard 已提交
1126 1127
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
1128
        return (-1);
D
Daniel Veillard 已提交
1129 1130 1131
    }
    if (from == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
1132
        return (-1);
D
Daniel Veillard 已提交
1133 1134
    }

1135 1136 1137 1138 1139
    /*
     * We must absolutize the file path as the restore is done out of process
     * TODO: check for URI when libxml2 is linked in.
     */
    if (from[0] != '/') {
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
        unsigned int len, t;

        t = strlen(from);
        if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL)
            return (-1);
        len = strlen(filepath);
        /* that should be covered by getcwd() semantic, but be 100% sure */
        if (len > sizeof(filepath) - (t + 3))
            return (-1);
        filepath[len] = '/';
        strcpy(&filepath[len + 1], from);
        from = &filepath[0];
    }

1154
    ret = xenDaemonDomainRestore(conn, from);
1155
    return (ret);
1156 1157
}

1158 1159 1160 1161 1162
/**
 * virDomainShutdown:
 * @domain: a domain object
 *
 * Shutdown a domain, the domain object is still usable there after but
1163 1164
 * the domain OS is being stopped. Note that the guest OS may ignore the
 * request.
1165 1166 1167 1168 1169 1170 1171
 *
 * TODO: should we add an option for reboot, knowing it may not be doable
 *       in the general case ?
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
1172 1173
virDomainShutdown(virDomainPtr domain)
{
1174 1175
    int ret;

D
Daniel Veillard 已提交
1176 1177
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1178
        return (-1);
D
Daniel Veillard 已提交
1179
    }
1180

1181 1182 1183
    /*
     * try first with the xend daemon
     */
1184
    ret = xenDaemonDomainShutdown(domain);
1185
    if (ret == 0)
1186
        return (0);
1187

1188
    /*
1189 1190 1191 1192 1193 1194 1195
     * this is very hackish, the domU kernel probes for a special 
     * node in the xenstore and launch the shutdown command if found.
     */
    ret = virDomainDoStoreWrite(domain, "control/shutdown", "halt");
    if (ret == 0) {
        domain->flags |= DOMAIN_IS_SHUTDOWN;
    }
1196
    return (ret);
1197 1198
}

1199
/**
1200
 * virDomainGetName:
1201 1202 1203 1204 1205 1206 1207 1208
 * @domain: a domain object
 *
 * Get the public name for that domain
 *
 * Returns a pointer to the name or NULL, the string need not be deallocated
 * its lifetime will be the same as the domain object.
 */
const char *
1209 1210
virDomainGetName(virDomainPtr domain)
{
D
Daniel Veillard 已提交
1211 1212
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1213
        return (NULL);
D
Daniel Veillard 已提交
1214
    }
1215
    return (domain->name);
1216 1217
}

1218 1219 1220 1221 1222 1223 1224 1225 1226 1227
/**
 * virDomainGetUUID:
 * @domain: a domain object
 * @uuid: pointer to a 16 bytes array
 *
 * Get the UUID for a domain
 *
 * Returns -1 in case of error, 0 in case of success
 */
int
1228 1229
virDomainGetUUID(virDomainPtr domain, unsigned char *uuid)
{
D
Daniel Veillard 已提交
1230 1231
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1232
        return (-1);
D
Daniel Veillard 已提交
1233 1234 1235
    }
    if (uuid == NULL) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1236
        return (-1);
D
Daniel Veillard 已提交
1237 1238 1239
    }

    if (domain->handle == 0) {
1240
        memset(uuid, 0, 16);
D
Daniel Veillard 已提交
1241
    } else {
1242 1243 1244 1245 1246 1247 1248 1249
        if ((domain->uuid[0] == 0) && (domain->uuid[1] == 0) &&
            (domain->uuid[2] == 0) && (domain->uuid[3] == 0) &&
            (domain->uuid[4] == 0) && (domain->uuid[5] == 0) &&
            (domain->uuid[6] == 0) && (domain->uuid[7] == 0) &&
            (domain->uuid[8] == 0) && (domain->uuid[9] == 0) &&
            (domain->uuid[10] == 0) && (domain->uuid[11] == 0) &&
            (domain->uuid[12] == 0) && (domain->uuid[13] == 0) &&
            (domain->uuid[14] == 0) && (domain->uuid[15] == 0))
1250
            xenDaemonDomainLookupByName_ids(domain->conn, domain->name,
1251 1252 1253 1254
                                &domain->uuid[0]);
        memcpy(uuid, &domain->uuid[0], 16);
    }
    return (0);
1255 1256
}

1257
/**
1258
 * virDomainGetID:
1259 1260 1261 1262 1263 1264 1265
 * @domain: a domain object
 *
 * Get the hypervisor ID number for the domain
 *
 * Returns the domain ID number or (unsigned int) -1 in case of error
 */
unsigned int
1266 1267
virDomainGetID(virDomainPtr domain)
{
D
Daniel Veillard 已提交
1268 1269
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1270
        return ((unsigned int) -1);
D
Daniel Veillard 已提交
1271
    }
1272
    return (domain->handle);
1273 1274
}

1275 1276 1277 1278 1279 1280
/**
 * virDomainGetOSType:
 * @domain: a domain object
 *
 * Get the type of domain operation system.
 *
1281 1282
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
1283 1284
 */
char *
1285 1286
virDomainGetOSType(virDomainPtr domain)
{
1287
    char *vm, *str = NULL;
1288

D
Daniel Veillard 已提交
1289 1290
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1291
        return (NULL);
D
Daniel Veillard 已提交
1292
    }
1293

1294 1295
    vm = virDomainGetVM(domain);
    if (vm) {
1296 1297
        str = virDomainGetVMInfo(domain, vm, "image/ostype");
        free(vm);
1298
    }
1299 1300 1301
    if (str == NULL)
        str = strdup("linux");

1302
    return (str);
1303 1304
}

1305
/**
1306
 * virDomainGetMaxMemory:
1307 1308 1309 1310 1311 1312 1313 1314 1315
 * @domain: a domain object or NULL
 * 
 * Retrieve the maximum amount of physical memory allocated to a
 * domain. If domain is NULL, then this get the amount of memory reserved
 * to Domain0 i.e. the domain where the application runs.
 *
 * Returns the memory size in kilobytes or 0 in case of error.
 */
unsigned long
1316 1317
virDomainGetMaxMemory(virDomainPtr domain)
{
1318 1319
    unsigned long ret = 0;

D
Daniel Veillard 已提交
1320 1321
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1322
        return (0);
D
Daniel Veillard 已提交
1323
    }
1324

1325 1326 1327
    if (domain->conn->flags & VIR_CONNECT_RO) {
        char *tmp;

1328 1329 1330 1331 1332
        tmp = virDomainDoStoreQuery(domain, "memory/target");
        if (tmp != NULL) {
            ret = (unsigned long) atol(tmp);
            free(tmp);
        }
1333
    } else {
1334
        virDomainInfo dominfo;
1335
        int tmp;
1336

1337
        tmp = xenHypervisorGetDomainInfo(domain, &dominfo);
1338
        if (tmp >= 0)
1339
            ret = dominfo.maxMem;
1340
    }
1341
    return (ret);
1342 1343
}

D
Daniel Veillard 已提交
1344
/**
1345
 * virDomainSetMaxMemory:
D
Daniel Veillard 已提交
1346 1347 1348 1349 1350 1351
 * @domain: a domain object or NULL
 * @memory: the memory size in kilobytes
 * 
 * Dynamically change the maximum amount of physical memory allocated to a
 * domain. If domain is NULL, then this change the amount of memory reserved
 * to Domain0 i.e. the domain where the application runs.
1352
 * This function requires priviledged access to the hypervisor.
D
Daniel Veillard 已提交
1353 1354 1355 1356
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
1357 1358
virDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
{
1359 1360
    int ret;
    char s[256], v[30];
1361

D
Daniel Veillard 已提交
1362 1363
    if (memory < 4096) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1364
        return (-1);
D
Daniel Veillard 已提交
1365
    }
1366 1367 1368 1369 1370 1371
    if (domain == NULL) {
        TODO
	return (-1);
    }
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1372
        return (-1);
1373 1374
    }
    if (domain->conn->flags & VIR_CONNECT_RO)
1375
        return (-1);
1376 1377 1378 1379 1380

    ret = xenDaemonDomainSetMaxMemory(domain, memory);
    if (ret == 0)
        return(0);

1381
    ret = xenHypervisorSetMaxMemory(domain, memory);
1382
    if (ret < 0)
1383
        return (-1);
1384

1385 1386 1387 1388 1389 1390 1391 1392 1393 1394
    if (domain->conn->xshandle != NULL) {
	/*
	 * try to update at the Xenstore level too
	 * Failing to do so should not be considered fatal though as long
	 * as the hypervisor call succeeded
	 */
	snprintf(s, 255, "/local/domain/%d/memory/target", domain->handle);
	s[255] = 0;
	snprintf(v, 29, "%lu", memory);
	v[30] = 0;
1395

1396 1397 1398
	if (!xs_write(domain->conn->xshandle, 0, &s[0], &v[0], strlen(v)))
	    ret = -1;
    }
1399

1400
    return (ret);
D
Daniel Veillard 已提交
1401 1402
}

1403 1404
/**
 * virDomainGetInfo:
1405
 * @domain: a domain object
1406 1407 1408 1409 1410 1411 1412 1413 1414
 * @info: pointer to a virDomainInfo structure allocated by the user
 * 
 * Extract information about a domain. Note that if the connection
 * used to get the domain is limited only a partial set of the informations
 * can be extracted.
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
1415 1416
virDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
1417
    int ret;
1418 1419 1420 1421
    char *tmp, **tmp2;
    unsigned int nb_vcpus;
    char request[200];

1422

D
Daniel Veillard 已提交
1423 1424
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1425
        return (-1);
D
Daniel Veillard 已提交
1426 1427 1428
    }
    if (info == NULL) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1429
        return (-1);
D
Daniel Veillard 已提交
1430
    }
1431

1432
    memset(info, 0, sizeof(virDomainInfo));
1433

1434 1435 1436 1437
    /*
     * if we have direct access though the hypervisor do a direct call
     */
    if (domain->conn->handle >= 0) {
1438
        ret = xenHypervisorGetDomainInfo(domain, info);
1439 1440
        if (ret == 0)
	    return (0);
1441 1442 1443 1444 1445
    }

    /*
     * try to extract the informations though access to the Xen Daemon
     */
1446
    if (xenDaemonDomainGetInfo(domain, info) == 0)
1447
        return (0);
1448 1449 1450 1451 1452 1453 1454

    /*
     * last fallback, try to get the inforamtions from the Xen store
     */

    tmp = virDomainDoStoreQuery(domain, "running");
    if (tmp != NULL) {
1455 1456 1457
        if (tmp[0] == '1')
            info->state = VIR_DOMAIN_RUNNING;
        free(tmp);
1458
    } else {
1459
        info->state = VIR_DOMAIN_NONE;
1460 1461 1462
    }
    tmp = virDomainDoStoreQuery(domain, "memory/target");
    if (tmp != NULL) {
1463 1464 1465
        info->memory = atol(tmp);
        info->maxMem = atol(tmp);
        free(tmp);
1466
    } else {
1467 1468
        info->memory = 0;
        info->maxMem = 0;
1469 1470 1471 1472 1473
    }
#if 0
    /* doesn't seems to work */
    tmp = virDomainDoStoreQuery(domain, "cpu_time");
    if (tmp != NULL) {
1474 1475
        info->cpuTime = atol(tmp);
        free(tmp);
1476
    } else {
1477
        info->cpuTime = 0;
1478 1479 1480 1481 1482 1483
    }
#endif
    snprintf(request, 199, "/local/domain/%d/cpu", domain->handle);
    request[199] = 0;
    tmp2 = virConnectDoStoreList(domain->conn, request, &nb_vcpus);
    if (tmp2 != NULL) {
1484 1485
        info->nrVirtCpu = nb_vcpus;
        free(tmp2);
1486
    }
1487
    return (0);
1488
}
1489

1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501
/**
 * virDomainGetXMLDesc:
 * @domain: a domain object
 * @flags: and OR'ed set of extraction flags, not used yet
 *
 * Provide an XML description of the domain. The description may be reused
 * later to relaunch the domain with virDomainCreateLinux().
 *
 * Returns a 0 terminated UTF-8 encoded XML instance, or NULL in case of error.
 *         the caller must free() the returned value.
 */
char *
1502 1503
virDomainGetXMLDesc(virDomainPtr domain, int flags)
{
D
Daniel Veillard 已提交
1504 1505
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1506
        return (NULL);
D
Daniel Veillard 已提交
1507 1508 1509
    }
    if (flags != 0) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1510
        return (NULL);
D
Daniel Veillard 已提交
1511
    }
1512

1513
    return (xenDaemonDomainDumpXML(domain));
1514
}