libvirt.c 31.0 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
 */

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

D
Daniel Veillard 已提交
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
    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
70 71 72
virLibDomainError(virDomainPtr domain, virErrorNumber error,
                  const char *info)
{
D
Daniel Veillard 已提交
73 74
    virConnectPtr conn = NULL;
    const char *errmsg;
75

D
Daniel Veillard 已提交
76 77 78 79 80 81 82 83 84 85 86
    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);
}

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
/**
 * 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
103 104 105
virGetVersion(unsigned long *libVer, const char *type,
              unsigned long *typeVer)
{
106
    if (libVer == NULL)
107
        return (-1);
108 109 110
    *libVer = LIBVIR_VERSION_NUMBER;

    if (typeVer != NULL) {
111 112 113
        if ((type == NULL) || (!strcasecmp(type, "Xen"))) {
            if ((DOM0_INTERFACE_VERSION & 0xFFFF0000) == (0xAAAA0000)) {
                /* one time glitch hopefully ! */
114
                *typeVer = 2 * 1000000 +
115 116 117 118 119 120 121 122 123 124 125 126 127 128
                    ((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);
129 130
}

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

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

151 152 153 154 155 156 157 158
    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;

159 160 161 162
    /*
     * open connections to the hypervisor, store and daemon
     */
    if (xenHypervisorOpen(ret, name, 0) < 0)
163
        goto failed;
164
    if (xenStoreOpen(ret, name, 0) < 0)
165
        goto failed;
166
    if (xenDaemonOpen(ret, name, 0) < 0)
167
        goto failed;
168

169
    ret->domains = virHashCreate(20);
170 171
    if (ret->domains == NULL)
        goto failed;
172
    ret->flags = 0;
173

174
    return (ret);
175 176 177 178 179 180

failed:
    if (ret != NULL) {
	xenHypervisorClose(ret);
	xenStoreClose(ret);
	xenDaemonClose(ret);
181
        free(ret);
182
    }
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

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

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

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

221 222
    res = xenStoreOpen(ret, name, VIR_DRV_OPEN_QUIET | VIR_DRV_OPEN_RO);
    if (res >= 0)
223 224
        method++;

225
    if (xenDaemonOpen(ret, name, VIR_DRV_OPEN_QUIET | VIR_DRV_OPEN_RO) == 0)
226
        method++;
227

D
Daniel Veillard 已提交
228 229
    if (method == 0) {
        virLibConnError(NULL, VIR_ERR_NO_CONNECT,
230
                        "could not connect to Xen Daemon nor Xen Store");
231
        goto failed;
D
Daniel Veillard 已提交
232
    }
233

234 235 236 237 238
    ret->domains = virHashCreate(20);
    if (ret->domains == NULL)
        goto failed;
    ret->flags = VIR_CONNECT_RO;

239
    return (ret);
240 241

failed:
242
    if (ret != NULL) {
243 244 245
	xenHypervisorClose(ret);
	xenStoreClose(ret);
	xenDaemonClose(ret);
246
        free(ret);
247
    }
248
    return (NULL);
D
Daniel Veillard 已提交
249 250
}

251
/**
252
 * virDomainFreeName:
253 254 255 256 257 258 259
 * @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
260 261 262
virDomainFreeName(virDomainPtr domain, const char *name ATTRIBUTE_UNUSED)
{
    return (virDomainFree(domain));
263 264
}

D
Daniel Veillard 已提交
265
/**
266
 * virConnectClose:
D
Daniel Veillard 已提交
267 268 269 270 271 272 273 274 275 276
 * @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
277 278
virConnectClose(virConnectPtr conn)
{
279
    xenDaemonClose(conn);
K
Karel Zak 已提交
280
    if (!VIR_IS_CONNECT(conn))
281
        return (-1);
282
    virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName);
283 284 285
    conn->domains = NULL;
    xenDaemonClose(conn);
    xenStoreClose(conn);
286
    xenHypervisorClose(conn);
287
    conn->magic = -1;
D
Daniel Veillard 已提交
288
    free(conn);
289
    return (0);
D
Daniel Veillard 已提交
290 291
}

292 293 294 295 296 297 298 299 300
/**
 * 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 *
301 302
virConnectGetType(virConnectPtr conn)
{
D
Daniel Veillard 已提交
303
    if (!VIR_IS_CONNECT(conn)) {
304 305 306
        virLibConnError(conn, VIR_ERR_INVALID_CONN,
                        "in virConnectGetType");
        return (NULL);
D
Daniel Veillard 已提交
307
    }
308
    return ("Xen");
309 310
}

D
Daniel Veillard 已提交
311
/**
312
 * virConnectGetVersion:
D
Daniel Veillard 已提交
313
 * @conn: pointer to the hypervisor connection
314
 * @hvVer: return value for the version of the running hypervisor (OUT)
D
Daniel Veillard 已提交
315
 *
316 317 318
 * 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 已提交
319
 *
320 321 322
 * 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 已提交
323
 */
324
int
325 326
virConnectGetVersion(virConnectPtr conn, unsigned long *hvVer)
{
327
    unsigned long ver;
328

D
Daniel Veillard 已提交
329 330
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
331
        return (-1);
D
Daniel Veillard 已提交
332
    }
333

D
Daniel Veillard 已提交
334 335
    if (hvVer == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
336
        return (-1);
D
Daniel Veillard 已提交
337
    }
338

339
    /* this can't be extracted from the Xenstore */
340 341
    if (conn->handle < 0) {
        *hvVer = 0;
342
        return (0);
343
    }
344

345
    ver = xenHypervisorGetVersion(conn, hvVer);
346
    return (0);
347 348 349
}

/**
350
 * virConnectListDomains:
351 352 353 354 355 356 357 358 359
 * @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
360 361
virConnectListDomains(virConnectPtr conn, int *ids, int maxids)
{
362
    int ret = -1;
363
    unsigned int i;
364
    long id;
365
    char **idlist = NULL;
366

D
Daniel Veillard 已提交
367 368
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
369
        return (-1);
D
Daniel Veillard 已提交
370
    }
371

D
Daniel Veillard 已提交
372 373
    if ((ids == NULL) || (maxids <= 0)) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
374
        return (-1);
D
Daniel Veillard 已提交
375
    }
376

377 378 379
    /*
     * try first though the Xen Daemon
     */
380
    idlist = xenDaemonListDomains(conn);
381
    if (idlist != NULL) {
382
        for (ret = 0, i = 0; (idlist[i] != NULL) && (ret < maxids); i++) {
383
            id = xenDaemonDomainLookupByName_ids(conn, idlist[i], NULL);
384 385 386
            if (id >= 0)
                ids[ret++] = (int) id;
        }
387 388
	free(idlist);
        return(ret);
389
    }
390

391 392 393 394
    /*
     * Then fallback to the XenStore
     */
    ret = xenStoreListDomains(conn, ids, maxids);
395
    return (ret);
D
Daniel Veillard 已提交
396 397
}

K
 
Karel Zak 已提交
398 399 400 401
/**
 * virConnectNumOfDomains:
 * @conn: pointer to the hypervisor connection
 *
402 403
 * Provides the number of active domains.
 *
K
 
Karel Zak 已提交
404 405 406
 * Returns the number of domain found or -1 in case of error
 */
int
407 408
virConnectNumOfDomains(virConnectPtr conn)
{
K
 
Karel Zak 已提交
409 410 411
    int ret = -1;
    char **idlist = NULL;

D
Daniel Veillard 已提交
412 413
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
414
        return (-1);
D
Daniel Veillard 已提交
415
    }
K
Karel Zak 已提交
416

417
    /* TODO: there must be a way to do that with an hypervisor call too ! */
418 419 420
    /* 
     * try first with Xend interface
     */
421
    idlist = xenDaemonListDomains(conn);
422 423 424 425 426
    if (idlist != NULL) {
        char **tmp = idlist;

        ret = 0;
        while (*tmp != NULL) {
427 428 429
            tmp++;
            ret++;
        }
430 431
	free(idlist);
	return(ret);
K
 
Karel Zak 已提交
432
    }
433 434
    /* Then Xen Store */
    return(xenStoreNumOfDomains(conn));
K
 
Karel Zak 已提交
435 436
}

D
Daniel Veillard 已提交
437
/**
438
 * virDomainCreateLinux:
D
Daniel Veillard 已提交
439
 * @conn: pointer to the hypervisor connection
440
 * @xmlDesc: an XML description of the domain
441
 * @flags: an optional set of virDomainFlags
D
Daniel Veillard 已提交
442
 *
443 444 445
 * 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 已提交
446 447 448
 * 
 * Returns a new domain object or NULL in case of failure
 */
449
virDomainPtr
450
virDomainCreateLinux(virConnectPtr conn,
451
                     const char *xmlDesc,
452 453
                     unsigned int flags ATTRIBUTE_UNUSED)
{
454 455 456 457
    int ret;
    char *sexpr;
    char *name = NULL;
    virDomainPtr dom;
K
Karel Zak 已提交
458

D
Daniel Veillard 已提交
459 460
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
461
        return (NULL);
D
Daniel Veillard 已提交
462 463 464
    }
    if (xmlDesc == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
465
        return (NULL);
D
Daniel Veillard 已提交
466 467
    }

468 469 470
    sexpr = virDomainParseXMLDesc(xmlDesc, &name);
    if ((sexpr == NULL) || (name == NULL)) {
        if (sexpr != NULL)
471
            free(sexpr);
472
        if (name != NULL)
473
            free(name);
474

475
        return (NULL);
476 477
    }

478
    ret = xenDaemonDomainCreateLinux(conn, sexpr);
479 480 481
    free(sexpr);
    if (ret != 0) {
        fprintf(stderr, "Failed to create domain %s\n", name);
482
        goto error;
483 484 485 486 487
    }

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

491 492 493 494 495 496
    dom = virDomainLookupByName(conn, name);
    if (dom == NULL) {
        goto error;
    }

    ret = xenDaemonDomainResume(dom);
497 498
    if (ret != 0) {
        fprintf(stderr, "Failed to resume new domain %s\n", name);
499
        xenDaemonDomainDestroy(dom);
500
        goto error;
501 502 503 504 505
    }

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

506 507
    return (dom);
  error:
508 509
    if (name != NULL)
        free(name);
510
    return (NULL);
D
Daniel Veillard 已提交
511 512
}

513

514
/**
515
 * virDomainLookupByID:
516 517 518 519 520 521 522
 * @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
 */
523
virDomainPtr
524 525
virDomainLookupByID(virConnectPtr conn, int id)
{
526
    char *path = NULL;
527
    virDomainPtr ret;
528
    char *name = NULL;
529
    unsigned char uuid[16];
530

D
Daniel Veillard 已提交
531 532
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
533
        return (NULL);
D
Daniel Veillard 已提交
534 535 536
    }
    if (id < 0) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
537
        return (NULL);
D
Daniel Veillard 已提交
538
    }
539

540 541
    /* lookup is easier with the Xen store so try it first */
    if (conn->xshandle != NULL) {
542
        path = xs_get_domain_path(conn->xshandle, (unsigned int) id);
543 544
    }
    /* fallback to xend API then */
545
    if (path == NULL) {
546
        char **names = xenDaemonListDomains(conn);
547 548 549 550 551
        char **tmp = names;
        int ident;

        if (names != NULL) {
            while (*tmp != NULL) {
552
                ident = xenDaemonDomainLookupByName_ids(conn, *tmp, &uuid[0]);
553 554 555 556 557 558 559 560
                if (ident == id) {
                    name = strdup(*tmp);
                    break;
                }
                tmp++;
            }
            free(names);
        }
561
    }
562

563
    ret = (virDomainPtr) malloc(sizeof(virDomain));
564
    if (ret == NULL) {
565
        goto error;
566
    }
567
    memset(ret, 0, sizeof(virDomain));
568
    ret->magic = VIR_DOMAIN_MAGIC;
569 570
    ret->conn = conn;
    ret->handle = id;
571
    ret->path = path;
572 573
    ret->name = name;
    memcpy(&ret->uuid[0], uuid, 16);
574
    if (ret->name == NULL) {
575 576 577
        goto error;
    }

578 579
    return (ret);
  error:
580
    if (ret != NULL)
581
        free(path);
582
    if (path != NULL)
583
        free(path);
584
    if (path != NULL)
585 586
        free(path);
    return (NULL);
587 588 589 590 591 592 593 594 595 596 597 598
}

/**
 * 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
599 600
virDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
601 602 603 604 605
    virDomainPtr ret;
    char *name = NULL;
    char **names;
    char **tmp;
    unsigned char ident[16];
606
    int id = -1;
607

D
Daniel Veillard 已提交
608 609
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
610
        return (NULL);
D
Daniel Veillard 已提交
611 612 613
    }
    if (uuid == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
614
        return (NULL);
D
Daniel Veillard 已提交
615
    }
616
    names = xenDaemonListDomains(conn);
617 618 619
    tmp = names;

    if (names == NULL) {
620 621
        TODO                    /* try to fallback to xenstore lookup */
            return (NULL);
622
    }
623
    while (*tmp != NULL) {
624
        id = xenDaemonDomainLookupByName_ids(conn, *tmp, &ident[0]);
625 626 627 628 629 630 631
        if (id >= 0) {
            if (!memcmp(uuid, ident, 16)) {
                name = strdup(*tmp);
                break;
            }
        }
        tmp++;
632 633 634 635
    }
    free(names);

    if (name == NULL)
636
        return (NULL);
637 638 639 640

    ret = (virDomainPtr) malloc(sizeof(virDomain));
    if (ret == NULL) {
        if (name != NULL)
641 642
            free(name);
        return (NULL);
643
    }
644
    memset(ret, 0, sizeof(virDomain));
645 646 647 648
    ret->magic = VIR_DOMAIN_MAGIC;
    ret->conn = conn;
    ret->handle = id;
    ret->name = name;
649
    ret->path = 0;
650
    memcpy(ret->uuid, uuid, 16);
651

652
    return (ret);
653 654
}

655 656 657 658 659
/**
 * virDomainLookupByName:
 * @conn: pointer to the hypervisor connection
 * @name: name for the domain
 *
660
 * Try to lookup a domain on the given hypervisor based on its name.
661 662 663 664
 *
 * Returns a new domain object or NULL in case of failure
 */
virDomainPtr
665 666
virDomainLookupByName(virConnectPtr conn, const char *name)
{
667 668
    virDomainPtr ret = NULL;

D
Daniel Veillard 已提交
669 670
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
671
        return (NULL);
D
Daniel Veillard 已提交
672 673 674
    }
    if (name == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
675
        return (NULL);
D
Daniel Veillard 已提交
676
    }
677

678
    /* try first though Xend */
679 680 681
    ret = xenDaemonDomainLookupByName(conn, name);
    if (ret != NULL) {
        return(ret);
682 683 684
    }

    /* then though the XenStore */
685 686 687
    ret = xenStoreDomainLookupByName(conn, name);
    if (ret != NULL) {
        return(ret);
688 689 690
    }

    return (ret);
691 692
}

D
Daniel Veillard 已提交
693
/**
694
 * virDomainDestroy:
D
Daniel Veillard 已提交
695 696 697 698
 * @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.
699 700
 * The data structure is freed and should not be used thereafter if the
 * call does not return an error.
701
 * This function may requires priviledged access
D
Daniel Veillard 已提交
702 703
 *
 * Returns 0 in case of success and -1 in case of failure.
704
 */
D
Daniel Veillard 已提交
705
int
706 707
virDomainDestroy(virDomainPtr domain)
{
708 709
    int ret;

D
Daniel Veillard 已提交
710 711
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
712
        return (-1);
D
Daniel Veillard 已提交
713
    }
714 715 716 717

    /*
     * try first with the xend method
     */
718
    ret = xenDaemonDomainDestroy(domain);
719 720
    if (ret == 0) {
        virDomainFree(domain);
721
        return (0);
722 723
    }

724
    ret = xenHypervisorDestroyDomain(domain);
725
    if (ret < 0)
726 727
        return (-1);

728
    virDomainFree(domain);
729
    return (0);
730 731 732 733 734 735 736 737 738 739 740 741
}

/**
 * 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
742 743
virDomainFree(virDomainPtr domain)
{
D
Daniel Veillard 已提交
744 745
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
746
        return (-1);
D
Daniel Veillard 已提交
747
    }
748 749 750 751 752 753 754
    domain->magic = -1;
    domain->handle = -1;
    if (domain->path != NULL)
        free(domain->path);
    if (domain->name)
        free(domain->name);
    free(domain);
755
    return (0);
D
Daniel Veillard 已提交
756 757 758
}

/**
759
 * virDomainSuspend:
D
Daniel Veillard 已提交
760 761 762 763
 * @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 
764
 * hypervisor level will stay allocated. Use virDomainResume() to reactivate
D
Daniel Veillard 已提交
765
 * the domain.
766
 * This function may requires priviledged access.
D
Daniel Veillard 已提交
767 768 769 770
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
771 772
virDomainSuspend(virDomainPtr domain)
{
773 774
    int ret;

D
Daniel Veillard 已提交
775 776
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
777
        return (-1);
D
Daniel Veillard 已提交
778 779
    }

780
    /* first try though the Xen daemon */
781
    ret = xenDaemonDomainSuspend(domain);
782
    if (ret == 0)
783
        return (0);
784 785

    /* then try a direct hypervisor access */
786
    return (xenHypervisorPauseDomain(domain));
D
Daniel Veillard 已提交
787 788 789
}

/**
790
 * virDomainResume:
D
Daniel Veillard 已提交
791 792 793
 * @domain: a domain object
 *
 * Resume an suspended domain, the process is restarted from the state where
794
 * it was frozen by calling virSuspendDomain().
795
 * This function may requires priviledged access
D
Daniel Veillard 已提交
796 797 798 799
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
800 801
virDomainResume(virDomainPtr domain)
{
802 803
    int ret;

D
Daniel Veillard 已提交
804 805
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
806
        return (-1);
D
Daniel Veillard 已提交
807 808
    }

809
    /* first try though the Xen daemon */
810
    ret = xenDaemonDomainResume(domain);
811
    if (ret == 0)
812
        return (0);
813 814

    /* then try a direct hypervisor access */
815
    return (xenHypervisorResumeDomain(domain));
D
Daniel Veillard 已提交
816 817
}

818 819 820 821 822 823
/**
 * virDomainSave:
 * @domain: a domain object
 * @to: path for the output file
 *
 * This method will suspend a domain and save its memory contents to
824 825 826
 * 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.
827 828 829 830
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
831 832
virDomainSave(virDomainPtr domain, const char *to)
{
833
    int ret;
834
    char filepath[4096];
835

D
Daniel Veillard 已提交
836 837
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
838
        return (-1);
D
Daniel Veillard 已提交
839 840 841
    }
    if (to == NULL) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
842
        return (-1);
D
Daniel Veillard 已提交
843
    }
844

845 846 847 848 849
    /*
     * 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] != '/') {
850
        unsigned int len, t;
851

852 853 854 855 856 857 858 859 860 861
        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];
862 863 864

    }

865
    ret = xenDaemonDomainSave(domain, to);
866
    return (ret);
867 868 869 870
}

/**
 * virDomainRestore:
871
 * @conn: pointer to the hypervisor connection
872 873 874 875 876 877 878
 * @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
879 880
virDomainRestore(virConnectPtr conn, const char *from)
{
881
    int ret;
882
    char filepath[4096];
883

D
Daniel Veillard 已提交
884 885
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
886
        return (-1);
D
Daniel Veillard 已提交
887 888 889
    }
    if (from == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
890
        return (-1);
D
Daniel Veillard 已提交
891 892
    }

893 894 895 896 897
    /*
     * 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] != '/') {
898 899 900 901 902 903 904 905 906 907 908 909 910 911
        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];
    }

912
    ret = xenDaemonDomainRestore(conn, from);
913
    return (ret);
914 915
}

916 917 918 919 920
/**
 * virDomainShutdown:
 * @domain: a domain object
 *
 * Shutdown a domain, the domain object is still usable there after but
921 922
 * the domain OS is being stopped. Note that the guest OS may ignore the
 * request.
923 924 925 926 927 928 929
 *
 * 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
930 931
virDomainShutdown(virDomainPtr domain)
{
932 933
    int ret;

D
Daniel Veillard 已提交
934 935
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
936
        return (-1);
D
Daniel Veillard 已提交
937
    }
938

939 940 941
    /*
     * try first with the xend daemon
     */
942
    ret = xenDaemonDomainShutdown(domain);
943 944
    if (ret == 0) {
        domain->flags |= DOMAIN_IS_SHUTDOWN;
945
        return (0);
946
    }
947

948
    /*
949 950 951
     * this is very hackish, the domU kernel probes for a special 
     * node in the xenstore and launch the shutdown command if found.
     */
952
    ret = xenDaemonDomainShutdown(domain);
953 954 955
    if (ret == 0) {
        domain->flags |= DOMAIN_IS_SHUTDOWN;
    }
956
    return (ret);
957 958
}

959
/**
960
 * virDomainGetName:
961 962 963 964 965 966 967 968
 * @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 *
969 970
virDomainGetName(virDomainPtr domain)
{
D
Daniel Veillard 已提交
971 972
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
973
        return (NULL);
D
Daniel Veillard 已提交
974
    }
975
    return (domain->name);
976 977
}

978 979 980 981 982 983 984 985 986 987
/**
 * 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
988 989
virDomainGetUUID(virDomainPtr domain, unsigned char *uuid)
{
D
Daniel Veillard 已提交
990 991
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
992
        return (-1);
D
Daniel Veillard 已提交
993 994 995
    }
    if (uuid == NULL) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
996
        return (-1);
D
Daniel Veillard 已提交
997 998 999
    }

    if (domain->handle == 0) {
1000
        memset(uuid, 0, 16);
D
Daniel Veillard 已提交
1001
    } else {
1002 1003 1004 1005 1006 1007 1008 1009
        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))
1010
            xenDaemonDomainLookupByName_ids(domain->conn, domain->name,
1011 1012 1013 1014
                                &domain->uuid[0]);
        memcpy(uuid, &domain->uuid[0], 16);
    }
    return (0);
1015 1016
}

1017
/**
1018
 * virDomainGetID:
1019 1020 1021 1022 1023 1024 1025
 * @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
1026 1027
virDomainGetID(virDomainPtr domain)
{
D
Daniel Veillard 已提交
1028 1029
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1030
        return ((unsigned int) -1);
D
Daniel Veillard 已提交
1031
    }
1032
    return (domain->handle);
1033 1034
}

1035 1036 1037 1038 1039 1040
/**
 * virDomainGetOSType:
 * @domain: a domain object
 *
 * Get the type of domain operation system.
 *
1041 1042
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
1043 1044
 */
char *
1045 1046
virDomainGetOSType(virDomainPtr domain)
{
1047
    char *vm, *str = NULL;
1048

D
Daniel Veillard 已提交
1049 1050
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1051
        return (NULL);
D
Daniel Veillard 已提交
1052
    }
1053

1054 1055
    vm = virDomainGetVM(domain);
    if (vm) {
1056 1057
        str = virDomainGetVMInfo(domain, vm, "image/ostype");
        free(vm);
1058
    }
1059 1060 1061
    if (str == NULL)
        str = strdup("linux");

1062
    return (str);
1063 1064
}

1065
/**
1066
 * virDomainGetMaxMemory:
1067 1068 1069 1070 1071 1072 1073 1074 1075
 * @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
1076 1077
virDomainGetMaxMemory(virDomainPtr domain)
{
1078 1079
    unsigned long ret = 0;

D
Daniel Veillard 已提交
1080 1081
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1082
        return (0);
D
Daniel Veillard 已提交
1083
    }
1084

1085 1086 1087 1088
    /*
     * try first with the hypervisor if available
     */
    if (!(domain->conn->flags & VIR_CONNECT_RO)) {
1089
        virDomainInfo dominfo;
1090
        int tmp;
1091

1092
        tmp = xenHypervisorGetDomainInfo(domain, &dominfo);
1093
        if (tmp >= 0)
1094
	    return(dominfo.maxMem);
1095
    }
1096 1097 1098 1099
    ret = xenStoreDomainGetMaxMemory(domain);
    if (ret > 0)
        return(ret);
    ret = xenDaemonDomainGetMaxMemory(domain);
1100
    return (ret);
1101 1102
}

D
Daniel Veillard 已提交
1103
/**
1104
 * virDomainSetMaxMemory:
D
Daniel Veillard 已提交
1105 1106 1107 1108 1109 1110
 * @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.
1111
 * This function requires priviledged access to the hypervisor.
D
Daniel Veillard 已提交
1112 1113 1114 1115
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
1116 1117
virDomainSetMaxMemory(virDomainPtr domain, unsigned long memory)
{
1118 1119
    int ret;
    char s[256], v[30];
1120

D
Daniel Veillard 已提交
1121 1122
    if (memory < 4096) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1123
        return (-1);
D
Daniel Veillard 已提交
1124
    }
1125 1126 1127 1128 1129 1130
    if (domain == NULL) {
        TODO
	return (-1);
    }
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1131
        return (-1);
1132 1133
    }
    if (domain->conn->flags & VIR_CONNECT_RO)
1134
        return (-1);
1135 1136 1137 1138 1139

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

1140
    ret = xenHypervisorSetMaxMemory(domain, memory);
1141
    if (ret < 0)
1142
        return (-1);
1143

1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
    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;
1154

1155 1156 1157
	if (!xs_write(domain->conn->xshandle, 0, &s[0], &v[0], strlen(v)))
	    ret = -1;
    }
1158

1159
    return (ret);
D
Daniel Veillard 已提交
1160 1161
}

1162 1163
/**
 * virDomainGetInfo:
1164
 * @domain: a domain object
1165 1166 1167 1168 1169 1170 1171 1172 1173
 * @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
1174 1175
virDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
1176 1177
    int ret;

D
Daniel Veillard 已提交
1178 1179
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1180
        return (-1);
D
Daniel Veillard 已提交
1181 1182 1183
    }
    if (info == NULL) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1184
        return (-1);
D
Daniel Veillard 已提交
1185
    }
1186

1187
    memset(info, 0, sizeof(virDomainInfo));
1188

1189 1190 1191 1192
    /*
     * if we have direct access though the hypervisor do a direct call
     */
    if (domain->conn->handle >= 0) {
1193
        ret = xenHypervisorGetDomainInfo(domain, info);
1194 1195
        if (ret == 0)
	    return (0);
1196 1197 1198 1199 1200
    }

    /*
     * try to extract the informations though access to the Xen Daemon
     */
1201
    if (xenDaemonDomainGetInfo(domain, info) == 0)
1202
        return (0);
1203 1204

    /*
1205
     * last fallback, try to get the informations from the Xen store
1206
     */
1207 1208
    if (xenStoreGetDomainInfo(domain, info) == 0)
        return (0);
1209

1210
    return (-1);
1211
}
1212

1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
/**
 * 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 *
1225 1226
virDomainGetXMLDesc(virDomainPtr domain, int flags)
{
D
Daniel Veillard 已提交
1227 1228
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1229
        return (NULL);
D
Daniel Veillard 已提交
1230 1231 1232
    }
    if (flags != 0) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
1233
        return (NULL);
D
Daniel Veillard 已提交
1234
    }
1235

1236
    return (xenDaemonDomainDumpXML(domain));
1237
}