libvirt.c 32.4 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

21
#include <xs.h>
22

D
Daniel Veillard 已提交
23
#include "internal.h"
24
#include "driver.h"
25
#include "xen_internal.h"
26
#include "xend_internal.h"
27
#include "xs_internal.h"
28
#include "hash.h"
29
#include "xml.h"
30

D
Daniel Veillard 已提交
31 32 33 34 35

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

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
#define MAX_DRIVERS 5
static virDriverPtr virDriverTab[MAX_DRIVERS];
static int initialized = 0;

/**
 * virInitialize:
 *
 * Initialize the library. It's better to call this routine at startup
 * in multithreaded applications to avoid potential race when initializing
 * the library.
 *
 * Returns 0 in case of success, -1 in case of error
 */
int
virInitialize(void)
{
    int i;

    if (initialized)
        return(0);

    /*
     * should not be needed but...
     */
    for (i = 0;i < MAX_DRIVERS;i++) 
         virDriverTab[i] = NULL;

    /*
     * Note that the order is important the first ones have a higher priority
     */
    xenHypervisorRegister();
    xenDaemonRegister();
    xenStoreRegister();
    initialized = 1;
    return(0);
}



D
Daniel Veillard 已提交
79 80 81 82 83 84 85 86 87
/**
 * virLibConnError:
 * @conn: the connection if available
 * @error: the error noumber
 * @info: extra information string
 *
 * Handle an error at the connection level
 */
static void
88 89
virLibConnError(virConnectPtr conn, virErrorNumber error, const char *info)
{
D
Daniel Veillard 已提交
90
    const char *errmsg;
91

D
Daniel Veillard 已提交
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
    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
109 110 111
virLibDomainError(virDomainPtr domain, virErrorNumber error,
                  const char *info)
{
D
Daniel Veillard 已提交
112 113
    virConnectPtr conn = NULL;
    const char *errmsg;
114

D
Daniel Veillard 已提交
115 116 117 118 119 120 121 122 123 124 125
    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);
}

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
/**
 * virRegisterDriver:
 * @driver: pointer to a driver block
 *
 * Register a virtualization driver
 *
 * Returns the driver priority or -1 in case of error.
 */
int
virRegisterDriver(virDriverPtr driver)
{
    int i;

    if (driver == NULL) {
        virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
	return(-1);
    }
    for (i = 0;i < MAX_DRIVERS;i++) {
        if (virDriverTab[i] == driver)
	    return(i);
    }
    for (i = 0;i < MAX_DRIVERS;i++) {
        if (virDriverTab[i] == NULL) {
	    virDriverTab[i] = driver;
	    return(i);
	}
    }
    virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__);
    return(-1);
}

157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
/**
 * 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
173 174 175
virGetVersion(unsigned long *libVer, const char *type,
              unsigned long *typeVer)
{
176
    if (libVer == NULL)
177
        return (-1);
178 179 180
    *libVer = LIBVIR_VERSION_NUMBER;

    if (typeVer != NULL) {
181 182 183
        if ((type == NULL) || (!strcasecmp(type, "Xen"))) {
            if ((DOM0_INTERFACE_VERSION & 0xFFFF0000) == (0xAAAA0000)) {
                /* one time glitch hopefully ! */
184
                *typeVer = 2 * 1000000 +
185 186 187 188 189 190 191 192 193 194 195 196 197 198
                    ((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);
199 200
}

D
Daniel Veillard 已提交
201
/**
202
 * virConnectOpen:
D
Daniel Veillard 已提交
203 204 205
 * @name: optional argument currently unused, pass NULL
 *
 * This function should be called first to get a connection to the 
206
 * Hypervisor and xen store
D
Daniel Veillard 已提交
207 208 209
 *
 * Returns a pointer to the hypervisor connection or NULL in case of error
 */
210
virConnectPtr
211 212
virConnectOpen(const char *name)
{
213
    virConnectPtr ret = NULL;
214 215

    /* we can only talk to the local Xen supervisor ATM */
D
Daniel Veillard 已提交
216
    if (name != NULL) {
217 218
        virLibConnError(NULL, VIR_ERR_NO_SUPPORT, name);
        return (NULL);
D
Daniel Veillard 已提交
219
    }
220

221 222 223 224 225 226 227 228
    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;

229 230 231 232
    /*
     * open connections to the hypervisor, store and daemon
     */
    if (xenHypervisorOpen(ret, name, 0) < 0)
233
        goto failed;
234
    if (xenStoreOpen(ret, name, 0) < 0)
235
        goto failed;
236
    if (xenDaemonOpen(ret, name, 0) < 0)
237
        goto failed;
238

239
    ret->domains = virHashCreate(20);
240 241
    if (ret->domains == NULL)
        goto failed;
242
    ret->flags = 0;
243

244
    return (ret);
245 246 247 248 249 250

failed:
    if (ret != NULL) {
	xenHypervisorClose(ret);
	xenStoreClose(ret);
	xenDaemonClose(ret);
251
        free(ret);
252
    }
253
    return (NULL);
254 255 256
}

/**
257
 * virConnectOpenReadOnly:
258 259
 * @name: optional argument currently unused, pass NULL
 *
260 261 262
 * 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.
263 264 265
 *
 * Returns a pointer to the hypervisor connection or NULL in case of error
 */
266
virConnectPtr
267 268
virConnectOpenReadOnly(const char *name)
{
269
    int method = 0;
270
    int res;
271
    virConnectPtr ret = NULL;
272 273

    /* we can only talk to the local Xen supervisor ATM */
D
Daniel Veillard 已提交
274
    if (name != NULL) {
275 276
        virLibConnError(NULL, VIR_ERR_NO_SUPPORT, name);
        return (NULL);
D
Daniel Veillard 已提交
277
    }
278

279
    ret = (virConnectPtr) malloc(sizeof(virConnect));
D
Daniel Veillard 已提交
280 281
    if (ret == NULL) {
        virLibConnError(NULL, VIR_ERR_NO_MEMORY, "Allocating connection");
282
        goto failed;
D
Daniel Veillard 已提交
283
    }
284
    memset(ret, 0, sizeof(virConnect));
285
    ret->magic = VIR_CONNECT_MAGIC;
286 287 288 289 290

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

291 292
    res = xenStoreOpen(ret, name, VIR_DRV_OPEN_QUIET | VIR_DRV_OPEN_RO);
    if (res >= 0)
293 294
        method++;

295
    if (xenDaemonOpen(ret, name, VIR_DRV_OPEN_QUIET | VIR_DRV_OPEN_RO) == 0)
296
        method++;
297

D
Daniel Veillard 已提交
298 299
    if (method == 0) {
        virLibConnError(NULL, VIR_ERR_NO_CONNECT,
300
                        "could not connect to Xen Daemon nor Xen Store");
301
        goto failed;
D
Daniel Veillard 已提交
302
    }
303

304 305 306 307 308
    ret->domains = virHashCreate(20);
    if (ret->domains == NULL)
        goto failed;
    ret->flags = VIR_CONNECT_RO;

309
    return (ret);
310 311

failed:
312
    if (ret != NULL) {
313 314 315
	xenHypervisorClose(ret);
	xenStoreClose(ret);
	xenDaemonClose(ret);
316
        free(ret);
317
    }
318
    return (NULL);
D
Daniel Veillard 已提交
319 320
}

321
/**
322
 * virDomainFreeName:
323 324 325 326 327 328 329
 * @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
330 331 332
virDomainFreeName(virDomainPtr domain, const char *name ATTRIBUTE_UNUSED)
{
    return (virDomainFree(domain));
333 334
}

D
Daniel Veillard 已提交
335
/**
336
 * virConnectClose:
D
Daniel Veillard 已提交
337 338 339 340 341 342 343 344 345 346
 * @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
347 348
virConnectClose(virConnectPtr conn)
{
349
    xenDaemonClose(conn);
K
Karel Zak 已提交
350
    if (!VIR_IS_CONNECT(conn))
351
        return (-1);
352
    virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName);
353 354 355
    conn->domains = NULL;
    xenDaemonClose(conn);
    xenStoreClose(conn);
356
    xenHypervisorClose(conn);
357
    conn->magic = -1;
D
Daniel Veillard 已提交
358
    free(conn);
359
    return (0);
D
Daniel Veillard 已提交
360 361
}

362 363 364 365 366 367 368 369 370
/**
 * 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 *
371 372
virConnectGetType(virConnectPtr conn)
{
D
Daniel Veillard 已提交
373
    if (!VIR_IS_CONNECT(conn)) {
374 375 376
        virLibConnError(conn, VIR_ERR_INVALID_CONN,
                        "in virConnectGetType");
        return (NULL);
D
Daniel Veillard 已提交
377
    }
378
    return ("Xen");
379 380
}

D
Daniel Veillard 已提交
381
/**
382
 * virConnectGetVersion:
D
Daniel Veillard 已提交
383
 * @conn: pointer to the hypervisor connection
384
 * @hvVer: return value for the version of the running hypervisor (OUT)
D
Daniel Veillard 已提交
385
 *
386 387 388
 * 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 已提交
389
 *
390 391 392
 * 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 已提交
393
 */
394
int
395 396
virConnectGetVersion(virConnectPtr conn, unsigned long *hvVer)
{
397
    unsigned long ver;
398

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

D
Daniel Veillard 已提交
404 405
    if (hvVer == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
406
        return (-1);
D
Daniel Veillard 已提交
407
    }
408

409
    /* this can't be extracted from the Xenstore */
410 411
    if (conn->handle < 0) {
        *hvVer = 0;
412
        return (0);
413
    }
414

415
    ver = xenHypervisorGetVersion(conn, hvVer);
416
    return (0);
417 418 419
}

/**
420
 * virConnectListDomains:
421 422 423 424 425 426 427 428 429
 * @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
430 431
virConnectListDomains(virConnectPtr conn, int *ids, int maxids)
{
432
    int ret = -1;
433
    unsigned int i;
434
    long id;
435
    char **idlist = NULL;
436

D
Daniel Veillard 已提交
437 438
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
439
        return (-1);
D
Daniel Veillard 已提交
440
    }
441

D
Daniel Veillard 已提交
442 443
    if ((ids == NULL) || (maxids <= 0)) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
444
        return (-1);
D
Daniel Veillard 已提交
445
    }
446

447 448 449
    /*
     * try first though the Xen Daemon
     */
450
    idlist = xenDaemonListDomains(conn);
451
    if (idlist != NULL) {
452
        for (ret = 0, i = 0; (idlist[i] != NULL) && (ret < maxids); i++) {
453
            id = xenDaemonDomainLookupByName_ids(conn, idlist[i], NULL);
454 455 456
            if (id >= 0)
                ids[ret++] = (int) id;
        }
457 458
	free(idlist);
        return(ret);
459
    }
460

461 462 463 464
    /*
     * Then fallback to the XenStore
     */
    ret = xenStoreListDomains(conn, ids, maxids);
465
    return (ret);
D
Daniel Veillard 已提交
466 467
}

K
 
Karel Zak 已提交
468 469 470 471
/**
 * virConnectNumOfDomains:
 * @conn: pointer to the hypervisor connection
 *
472 473
 * Provides the number of active domains.
 *
K
 
Karel Zak 已提交
474 475 476
 * Returns the number of domain found or -1 in case of error
 */
int
477 478
virConnectNumOfDomains(virConnectPtr conn)
{
K
 
Karel Zak 已提交
479 480 481
    int ret = -1;
    char **idlist = NULL;

D
Daniel Veillard 已提交
482 483
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
484
        return (-1);
D
Daniel Veillard 已提交
485
    }
K
Karel Zak 已提交
486

487
    /* TODO: there must be a way to do that with an hypervisor call too ! */
488 489 490
    /* 
     * try first with Xend interface
     */
491
    idlist = xenDaemonListDomains(conn);
492 493 494 495 496
    if (idlist != NULL) {
        char **tmp = idlist;

        ret = 0;
        while (*tmp != NULL) {
497 498 499
            tmp++;
            ret++;
        }
500 501
	free(idlist);
	return(ret);
K
 
Karel Zak 已提交
502
    }
503 504
    /* Then Xen Store */
    return(xenStoreNumOfDomains(conn));
K
 
Karel Zak 已提交
505 506
}

D
Daniel Veillard 已提交
507
/**
508
 * virDomainCreateLinux:
D
Daniel Veillard 已提交
509
 * @conn: pointer to the hypervisor connection
510
 * @xmlDesc: an XML description of the domain
511
 * @flags: an optional set of virDomainFlags
D
Daniel Veillard 已提交
512
 *
513 514 515
 * 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 已提交
516 517 518
 * 
 * Returns a new domain object or NULL in case of failure
 */
519
virDomainPtr
520
virDomainCreateLinux(virConnectPtr conn,
521
                     const char *xmlDesc,
522 523
                     unsigned int flags ATTRIBUTE_UNUSED)
{
524 525 526 527
    int ret;
    char *sexpr;
    char *name = NULL;
    virDomainPtr dom;
K
Karel Zak 已提交
528

D
Daniel Veillard 已提交
529 530
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
531
        return (NULL);
D
Daniel Veillard 已提交
532 533 534
    }
    if (xmlDesc == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
535
        return (NULL);
D
Daniel Veillard 已提交
536 537
    }

538 539 540
    sexpr = virDomainParseXMLDesc(xmlDesc, &name);
    if ((sexpr == NULL) || (name == NULL)) {
        if (sexpr != NULL)
541
            free(sexpr);
542
        if (name != NULL)
543
            free(name);
544

545
        return (NULL);
546 547
    }

548
    ret = xenDaemonDomainCreateLinux(conn, sexpr);
549 550 551
    free(sexpr);
    if (ret != 0) {
        fprintf(stderr, "Failed to create domain %s\n", name);
552
        goto error;
553 554 555 556 557
    }

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

561 562 563 564 565 566
    dom = virDomainLookupByName(conn, name);
    if (dom == NULL) {
        goto error;
    }

    ret = xenDaemonDomainResume(dom);
567 568
    if (ret != 0) {
        fprintf(stderr, "Failed to resume new domain %s\n", name);
569
        xenDaemonDomainDestroy(dom);
570
        goto error;
571 572 573 574 575
    }

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

576 577
    return (dom);
  error:
578 579
    if (name != NULL)
        free(name);
580
    return (NULL);
D
Daniel Veillard 已提交
581 582
}

583

584
/**
585
 * virDomainLookupByID:
586 587 588 589 590 591 592
 * @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
 */
593
virDomainPtr
594 595
virDomainLookupByID(virConnectPtr conn, int id)
{
596
    char *path = NULL;
597
    virDomainPtr ret;
598
    char *name = NULL;
599
    unsigned char uuid[16];
600

D
Daniel Veillard 已提交
601 602
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
603
        return (NULL);
D
Daniel Veillard 已提交
604 605 606
    }
    if (id < 0) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
607
        return (NULL);
D
Daniel Veillard 已提交
608
    }
609

610 611
    /* lookup is easier with the Xen store so try it first */
    if (conn->xshandle != NULL) {
612
        path = xs_get_domain_path(conn->xshandle, (unsigned int) id);
613 614
    }
    /* fallback to xend API then */
615
    if (path == NULL) {
616
        char **names = xenDaemonListDomains(conn);
617 618 619 620 621
        char **tmp = names;
        int ident;

        if (names != NULL) {
            while (*tmp != NULL) {
622
                ident = xenDaemonDomainLookupByName_ids(conn, *tmp, &uuid[0]);
623 624 625 626 627 628 629 630
                if (ident == id) {
                    name = strdup(*tmp);
                    break;
                }
                tmp++;
            }
            free(names);
        }
631
    }
632

633
    ret = (virDomainPtr) malloc(sizeof(virDomain));
634
    if (ret == NULL) {
635
        goto error;
636
    }
637
    memset(ret, 0, sizeof(virDomain));
638
    ret->magic = VIR_DOMAIN_MAGIC;
639 640
    ret->conn = conn;
    ret->handle = id;
641
    ret->path = path;
642 643
    ret->name = name;
    memcpy(&ret->uuid[0], uuid, 16);
644
    if (ret->name == NULL) {
645 646 647
        goto error;
    }

648 649
    return (ret);
  error:
650
    if (ret != NULL)
651
        free(path);
652
    if (path != NULL)
653
        free(path);
654
    if (path != NULL)
655 656
        free(path);
    return (NULL);
657 658 659 660 661 662 663 664 665 666 667 668
}

/**
 * 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
669 670
virDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
671 672 673 674 675
    virDomainPtr ret;
    char *name = NULL;
    char **names;
    char **tmp;
    unsigned char ident[16];
676
    int id = -1;
677

D
Daniel Veillard 已提交
678 679
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
680
        return (NULL);
D
Daniel Veillard 已提交
681 682 683
    }
    if (uuid == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
684
        return (NULL);
D
Daniel Veillard 已提交
685
    }
686
    names = xenDaemonListDomains(conn);
687 688 689
    tmp = names;

    if (names == NULL) {
690 691
        TODO                    /* try to fallback to xenstore lookup */
            return (NULL);
692
    }
693
    while (*tmp != NULL) {
694
        id = xenDaemonDomainLookupByName_ids(conn, *tmp, &ident[0]);
695 696 697 698 699 700 701
        if (id >= 0) {
            if (!memcmp(uuid, ident, 16)) {
                name = strdup(*tmp);
                break;
            }
        }
        tmp++;
702 703 704 705
    }
    free(names);

    if (name == NULL)
706
        return (NULL);
707 708 709 710

    ret = (virDomainPtr) malloc(sizeof(virDomain));
    if (ret == NULL) {
        if (name != NULL)
711 712
            free(name);
        return (NULL);
713
    }
714
    memset(ret, 0, sizeof(virDomain));
715 716 717 718
    ret->magic = VIR_DOMAIN_MAGIC;
    ret->conn = conn;
    ret->handle = id;
    ret->name = name;
719
    ret->path = 0;
720
    memcpy(ret->uuid, uuid, 16);
721

722
    return (ret);
723 724
}

725 726 727 728 729
/**
 * virDomainLookupByName:
 * @conn: pointer to the hypervisor connection
 * @name: name for the domain
 *
730
 * Try to lookup a domain on the given hypervisor based on its name.
731 732 733 734
 *
 * Returns a new domain object or NULL in case of failure
 */
virDomainPtr
735 736
virDomainLookupByName(virConnectPtr conn, const char *name)
{
737 738
    virDomainPtr ret = NULL;

D
Daniel Veillard 已提交
739 740
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
741
        return (NULL);
D
Daniel Veillard 已提交
742 743 744
    }
    if (name == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
745
        return (NULL);
D
Daniel Veillard 已提交
746
    }
747

748
    /* try first though Xend */
749 750 751
    ret = xenDaemonDomainLookupByName(conn, name);
    if (ret != NULL) {
        return(ret);
752 753 754
    }

    /* then though the XenStore */
755 756 757
    ret = xenStoreDomainLookupByName(conn, name);
    if (ret != NULL) {
        return(ret);
758 759 760
    }

    return (ret);
761 762
}

D
Daniel Veillard 已提交
763
/**
764
 * virDomainDestroy:
D
Daniel Veillard 已提交
765 766 767 768
 * @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.
769 770
 * The data structure is freed and should not be used thereafter if the
 * call does not return an error.
771
 * This function may requires priviledged access
D
Daniel Veillard 已提交
772 773
 *
 * Returns 0 in case of success and -1 in case of failure.
774
 */
D
Daniel Veillard 已提交
775
int
776 777
virDomainDestroy(virDomainPtr domain)
{
778 779
    int ret;

D
Daniel Veillard 已提交
780 781
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
782
        return (-1);
D
Daniel Veillard 已提交
783
    }
784 785 786 787

    /*
     * try first with the xend method
     */
788
    ret = xenDaemonDomainDestroy(domain);
789 790
    if (ret == 0) {
        virDomainFree(domain);
791
        return (0);
792 793
    }

794
    ret = xenHypervisorDestroyDomain(domain);
795
    if (ret < 0)
796 797
        return (-1);

798
    virDomainFree(domain);
799
    return (0);
800 801 802 803 804 805 806 807 808 809 810 811
}

/**
 * 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
812 813
virDomainFree(virDomainPtr domain)
{
D
Daniel Veillard 已提交
814 815
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
816
        return (-1);
D
Daniel Veillard 已提交
817
    }
818 819 820 821 822 823 824
    domain->magic = -1;
    domain->handle = -1;
    if (domain->path != NULL)
        free(domain->path);
    if (domain->name)
        free(domain->name);
    free(domain);
825
    return (0);
D
Daniel Veillard 已提交
826 827 828
}

/**
829
 * virDomainSuspend:
D
Daniel Veillard 已提交
830 831 832 833
 * @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 
834
 * hypervisor level will stay allocated. Use virDomainResume() to reactivate
D
Daniel Veillard 已提交
835
 * the domain.
836
 * This function may requires priviledged access.
D
Daniel Veillard 已提交
837 838 839 840
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
841 842
virDomainSuspend(virDomainPtr domain)
{
843 844
    int ret;

D
Daniel Veillard 已提交
845 846
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
847
        return (-1);
D
Daniel Veillard 已提交
848 849
    }

850
    /* first try though the Xen daemon */
851
    ret = xenDaemonDomainSuspend(domain);
852
    if (ret == 0)
853
        return (0);
854 855

    /* then try a direct hypervisor access */
856
    return (xenHypervisorPauseDomain(domain));
D
Daniel Veillard 已提交
857 858 859
}

/**
860
 * virDomainResume:
D
Daniel Veillard 已提交
861 862 863
 * @domain: a domain object
 *
 * Resume an suspended domain, the process is restarted from the state where
864
 * it was frozen by calling virSuspendDomain().
865
 * This function may requires priviledged access
D
Daniel Veillard 已提交
866 867 868 869
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
870 871
virDomainResume(virDomainPtr domain)
{
872 873
    int ret;

D
Daniel Veillard 已提交
874 875
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
876
        return (-1);
D
Daniel Veillard 已提交
877 878
    }

879
    /* first try though the Xen daemon */
880
    ret = xenDaemonDomainResume(domain);
881
    if (ret == 0)
882
        return (0);
883 884

    /* then try a direct hypervisor access */
885
    return (xenHypervisorResumeDomain(domain));
D
Daniel Veillard 已提交
886 887
}

888 889 890 891 892 893
/**
 * virDomainSave:
 * @domain: a domain object
 * @to: path for the output file
 *
 * This method will suspend a domain and save its memory contents to
894 895 896
 * 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.
897 898 899 900
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
901 902
virDomainSave(virDomainPtr domain, const char *to)
{
903
    int ret;
904
    char filepath[4096];
905

D
Daniel Veillard 已提交
906 907
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
908
        return (-1);
D
Daniel Veillard 已提交
909 910 911
    }
    if (to == NULL) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
912
        return (-1);
D
Daniel Veillard 已提交
913
    }
914

915 916 917 918 919
    /*
     * 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] != '/') {
920
        unsigned int len, t;
921

922 923 924 925 926 927 928 929 930 931
        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];
932 933 934

    }

935
    ret = xenDaemonDomainSave(domain, to);
936
    return (ret);
937 938 939 940
}

/**
 * virDomainRestore:
941
 * @conn: pointer to the hypervisor connection
942 943 944 945 946 947 948
 * @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
949 950
virDomainRestore(virConnectPtr conn, const char *from)
{
951
    int ret;
952
    char filepath[4096];
953

D
Daniel Veillard 已提交
954 955
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
956
        return (-1);
D
Daniel Veillard 已提交
957 958 959
    }
    if (from == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
960
        return (-1);
D
Daniel Veillard 已提交
961 962
    }

963 964 965 966 967
    /*
     * 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] != '/') {
968 969 970 971 972 973 974 975 976 977 978 979 980 981
        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];
    }

982
    ret = xenDaemonDomainRestore(conn, from);
983
    return (ret);
984 985
}

986 987 988 989 990
/**
 * virDomainShutdown:
 * @domain: a domain object
 *
 * Shutdown a domain, the domain object is still usable there after but
991 992
 * the domain OS is being stopped. Note that the guest OS may ignore the
 * request.
993 994 995 996 997 998 999
 *
 * 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
1000 1001
virDomainShutdown(virDomainPtr domain)
{
1002 1003
    int ret;

D
Daniel Veillard 已提交
1004 1005
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1006
        return (-1);
D
Daniel Veillard 已提交
1007
    }
1008

1009 1010 1011
    /*
     * try first with the xend daemon
     */
1012
    ret = xenDaemonDomainShutdown(domain);
1013 1014
    if (ret == 0) {
        domain->flags |= DOMAIN_IS_SHUTDOWN;
1015
        return (0);
1016
    }
1017

1018
    /*
1019 1020 1021
     * this is very hackish, the domU kernel probes for a special 
     * node in the xenstore and launch the shutdown command if found.
     */
1022
    ret = xenDaemonDomainShutdown(domain);
1023 1024 1025
    if (ret == 0) {
        domain->flags |= DOMAIN_IS_SHUTDOWN;
    }
1026
    return (ret);
1027 1028
}

1029
/**
1030
 * virDomainGetName:
1031 1032 1033 1034 1035 1036 1037 1038
 * @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 *
1039 1040
virDomainGetName(virDomainPtr domain)
{
D
Daniel Veillard 已提交
1041 1042
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1043
        return (NULL);
D
Daniel Veillard 已提交
1044
    }
1045
    return (domain->name);
1046 1047
}

1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
/**
 * 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
1058 1059
virDomainGetUUID(virDomainPtr domain, unsigned char *uuid)
{
D
Daniel Veillard 已提交
1060 1061
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1062
        return (-1);
D
Daniel Veillard 已提交
1063 1064 1065
    }
    if (uuid == NULL) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1066
        return (-1);
D
Daniel Veillard 已提交
1067 1068 1069
    }

    if (domain->handle == 0) {
1070
        memset(uuid, 0, 16);
D
Daniel Veillard 已提交
1071
    } else {
1072 1073 1074 1075 1076 1077 1078 1079
        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))
1080
            xenDaemonDomainLookupByName_ids(domain->conn, domain->name,
1081 1082 1083 1084
                                &domain->uuid[0]);
        memcpy(uuid, &domain->uuid[0], 16);
    }
    return (0);
1085 1086
}

1087
/**
1088
 * virDomainGetID:
1089 1090 1091 1092 1093 1094 1095
 * @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
1096 1097
virDomainGetID(virDomainPtr domain)
{
D
Daniel Veillard 已提交
1098 1099
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1100
        return ((unsigned int) -1);
D
Daniel Veillard 已提交
1101
    }
1102
    return (domain->handle);
1103 1104
}

1105 1106 1107 1108 1109 1110
/**
 * virDomainGetOSType:
 * @domain: a domain object
 *
 * Get the type of domain operation system.
 *
1111 1112
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
1113 1114
 */
char *
1115 1116
virDomainGetOSType(virDomainPtr domain)
{
1117
    char *vm, *str = NULL;
1118

D
Daniel Veillard 已提交
1119 1120
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1121
        return (NULL);
D
Daniel Veillard 已提交
1122
    }
1123

1124 1125
    vm = virDomainGetVM(domain);
    if (vm) {
1126 1127
        str = virDomainGetVMInfo(domain, vm, "image/ostype");
        free(vm);
1128
    }
1129 1130 1131
    if (str == NULL)
        str = strdup("linux");

1132
    return (str);
1133 1134
}

1135
/**
1136
 * virDomainGetMaxMemory:
1137 1138 1139 1140 1141 1142 1143 1144 1145
 * @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
1146 1147
virDomainGetMaxMemory(virDomainPtr domain)
{
1148 1149
    unsigned long ret = 0;

D
Daniel Veillard 已提交
1150 1151
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1152
        return (0);
D
Daniel Veillard 已提交
1153
    }
1154

1155 1156 1157 1158
    /*
     * try first with the hypervisor if available
     */
    if (!(domain->conn->flags & VIR_CONNECT_RO)) {
1159
        virDomainInfo dominfo;
1160
        int tmp;
1161

1162
        tmp = xenHypervisorGetDomainInfo(domain, &dominfo);
1163
        if (tmp >= 0)
1164
	    return(dominfo.maxMem);
1165
    }
1166 1167 1168 1169
    ret = xenStoreDomainGetMaxMemory(domain);
    if (ret > 0)
        return(ret);
    ret = xenDaemonDomainGetMaxMemory(domain);
1170
    return (ret);
1171 1172
}

D
Daniel Veillard 已提交
1173
/**
1174
 * virDomainSetMaxMemory:
D
Daniel Veillard 已提交
1175 1176 1177 1178 1179 1180
 * @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.
1181
 * This function requires priviledged access to the hypervisor.
D
Daniel Veillard 已提交
1182 1183 1184 1185
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
1186 1187
virDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
{
1188 1189
    int ret;
    char s[256], v[30];
1190

D
Daniel Veillard 已提交
1191 1192
    if (memory < 4096) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1193
        return (-1);
D
Daniel Veillard 已提交
1194
    }
1195 1196 1197 1198 1199 1200
    if (domain == NULL) {
        TODO
	return (-1);
    }
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1201
        return (-1);
1202 1203
    }
    if (domain->conn->flags & VIR_CONNECT_RO)
1204
        return (-1);
1205 1206 1207 1208 1209

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

1210
    ret = xenHypervisorSetMaxMemory(domain, memory);
1211
    if (ret < 0)
1212
        return (-1);
1213

1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
    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;
1224

1225 1226 1227
	if (!xs_write(domain->conn->xshandle, 0, &s[0], &v[0], strlen(v)))
	    ret = -1;
    }
1228

1229
    return (ret);
D
Daniel Veillard 已提交
1230 1231
}

1232 1233
/**
 * virDomainGetInfo:
1234
 * @domain: a domain object
1235 1236 1237 1238 1239 1240 1241 1242 1243
 * @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
1244 1245
virDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
1246 1247
    int ret;

D
Daniel Veillard 已提交
1248 1249
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1250
        return (-1);
D
Daniel Veillard 已提交
1251 1252 1253
    }
    if (info == NULL) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1254
        return (-1);
D
Daniel Veillard 已提交
1255
    }
1256

1257
    memset(info, 0, sizeof(virDomainInfo));
1258

1259 1260 1261 1262
    /*
     * if we have direct access though the hypervisor do a direct call
     */
    if (domain->conn->handle >= 0) {
1263
        ret = xenHypervisorGetDomainInfo(domain, info);
1264 1265
        if (ret == 0)
	    return (0);
1266 1267 1268 1269 1270
    }

    /*
     * try to extract the informations though access to the Xen Daemon
     */
1271
    if (xenDaemonDomainGetInfo(domain, info) == 0)
1272
        return (0);
1273 1274

    /*
1275
     * last fallback, try to get the informations from the Xen store
1276
     */
1277 1278
    if (xenStoreGetDomainInfo(domain, info) == 0)
        return (0);
1279

1280
    return (-1);
1281
}
1282

1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
/**
 * 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 *
1295 1296
virDomainGetXMLDesc(virDomainPtr domain, int flags)
{
D
Daniel Veillard 已提交
1297 1298
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1299
        return (NULL);
D
Daniel Veillard 已提交
1300 1301 1302
    }
    if (flags != 0) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1303
        return (NULL);
D
Daniel Veillard 已提交
1304
    }
1305

1306
    return (xenDaemonDomainDumpXML(domain));
1307
}