libvirt.c 33.3 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 "xml.h"
29

D
Daniel Veillard 已提交
30 31 32 33 34

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

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
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);
57
    initialized = 1;
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

    /*
     * 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();
    return(0);
}



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

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

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

123 124 125 126 127 128 129 130 131 132 133 134 135
/**
 * 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;

136 137 138
    if (!initialized)
        virInitialize();

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
    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 177 178
    if (!initialized)
        virInitialize();

179
    if (libVer == NULL)
180
        return (-1);
181 182 183
    *libVer = LIBVIR_VERSION_NUMBER;

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

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

219 220 221
    if (!initialized)
        virInitialize();

222
    ret = virGetConnect();
223 224 225 226 227
    if (ret == NULL) {
        virLibConnError(NULL, VIR_ERR_NO_MEMORY, "Allocating connection");
        goto failed;
    }

228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    for (i = 0;i < MAX_DRIVERS;i++) {
        if ((virDriverTab[i] != NULL) && (virDriverTab[i]->open != NULL)) {
	    res = virDriverTab[i]->open(ret, name, 0);
	    /*
	     * For a default connect to Xen make sure we manage to contact
	     * all related drivers.
	     */
	    if ((res < 0) && (name == NULL) &&
	        (!strcmp(virDriverTab[i]->name, "Xen")))
		goto failed;
	    if (res == 0)
	        ret->drivers[ret->nb_drivers++] = virDriverTab[i];
	}
    }

    if (ret->nb_drivers == 0) {
	/* we failed to find an adequate driver */
	virLibConnError(NULL, VIR_ERR_NO_SUPPORT, name);
	goto failed;
    }
248

249
    return (ret);
250 251 252

failed:
    if (ret != NULL) {
253 254 255 256
	for (i = 0;i < ret->nb_drivers;i++) {
	    if ((ret->drivers[i] != NULL) && (ret->drivers[i]->close != NULL))
	        ret->drivers[i]->close(ret);
	}
257
	virFreeConnect(ret);
258
    }
259
    return (NULL);
260 261 262
}

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

278 279 280
    if (!initialized)
        virInitialize();

281
    ret = virGetConnect();
D
Daniel Veillard 已提交
282 283
    if (ret == NULL) {
        virLibConnError(NULL, VIR_ERR_NO_MEMORY, "Allocating connection");
284
        goto failed;
D
Daniel Veillard 已提交
285
    }
286

287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
    for (i = 0;i < MAX_DRIVERS;i++) {
        if ((virDriverTab[i] != NULL) && (virDriverTab[i]->open != NULL)) {
	    res = virDriverTab[i]->open(ret, name,
	                                VIR_DRV_OPEN_QUIET | VIR_DRV_OPEN_RO);
	    if (res == 0)
	        ret->drivers[ret->nb_drivers++] = virDriverTab[i];
	}
    }
    if (ret->nb_drivers == 0) {
	if (name == NULL)
	    virLibConnError(NULL, VIR_ERR_NO_CONNECT,
			    "could not connect to Xen Daemon nor Xen Store");
	else
	    /* we failed to find an adequate driver */
	    virLibConnError(NULL, VIR_ERR_NO_SUPPORT, name);
	goto failed;
D
Daniel Veillard 已提交
303
    }
304 305
    ret->flags = VIR_CONNECT_RO;

306
    return (ret);
307 308

failed:
309
    if (ret != NULL) {
310 311 312 313
	for (i = 0;i < ret->nb_drivers;i++) {
	    if ((ret->drivers[i] != NULL) && (ret->drivers[i]->close != NULL))
	        ret->drivers[i]->close(ret);
	}
314
	virFreeConnect(ret);
315
    }
316
    return (NULL);
D
Daniel Veillard 已提交
317 318 319
}

/**
320
 * virConnectClose:
D
Daniel Veillard 已提交
321 322 323 324 325 326 327 328 329 330
 * @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
331 332
virConnectClose(virConnectPtr conn)
{
K
Karel Zak 已提交
333
    if (!VIR_IS_CONNECT(conn))
334
        return (-1);
335 336
    if (virFreeConnect(conn) < 0)
        return (-1);
337
    return (0);
D
Daniel Veillard 已提交
338 339
}

340 341 342 343 344 345 346 347 348
/**
 * 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 *
349 350
virConnectGetType(virConnectPtr conn)
{
D
Daniel Veillard 已提交
351
    if (!VIR_IS_CONNECT(conn)) {
352
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
353
        return (NULL);
D
Daniel Veillard 已提交
354
    }
355
    return ("Xen");
356 357
}

D
Daniel Veillard 已提交
358
/**
359
 * virConnectGetVersion:
D
Daniel Veillard 已提交
360
 * @conn: pointer to the hypervisor connection
361
 * @hvVer: return value for the version of the running hypervisor (OUT)
D
Daniel Veillard 已提交
362
 *
363 364 365
 * 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 已提交
366
 *
367 368 369
 * 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 已提交
370
 */
371
int
372 373
virConnectGetVersion(virConnectPtr conn, unsigned long *hvVer)
{
374
    unsigned long ver;
375

D
Daniel Veillard 已提交
376 377
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
378
        return (-1);
D
Daniel Veillard 已提交
379
    }
380

D
Daniel Veillard 已提交
381 382
    if (hvVer == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
383
        return (-1);
D
Daniel Veillard 已提交
384
    }
385

386
    /* this can't be extracted from the Xenstore */
387 388
    if (conn->handle < 0) {
        *hvVer = 0;
389
        return (0);
390
    }
391

392
    ver = xenHypervisorGetVersion(conn, hvVer);
393
    return (0);
394 395 396
}

/**
397
 * virConnectListDomains:
398 399 400 401 402 403 404 405 406
 * @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
407 408
virConnectListDomains(virConnectPtr conn, int *ids, int maxids)
{
409
    int ret = -1;
410
    unsigned int i;
411
    long id;
412
    char **idlist = NULL;
413

D
Daniel Veillard 已提交
414 415
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
416
        return (-1);
D
Daniel Veillard 已提交
417
    }
418

D
Daniel Veillard 已提交
419 420
    if ((ids == NULL) || (maxids <= 0)) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
421
        return (-1);
D
Daniel Veillard 已提交
422
    }
423

424 425 426
    /*
     * try first though the Xen Daemon
     */
427
    idlist = xenDaemonListDomains(conn);
428
    if (idlist != NULL) {
429
        for (ret = 0, i = 0; (idlist[i] != NULL) && (ret < maxids); i++) {
430
            id = xenDaemonDomainLookupByName_ids(conn, idlist[i], NULL);
431 432 433
            if (id >= 0)
                ids[ret++] = (int) id;
        }
434 435
	free(idlist);
        return(ret);
436
    }
437

438 439 440 441
    /*
     * Then fallback to the XenStore
     */
    ret = xenStoreListDomains(conn, ids, maxids);
442
    return (ret);
D
Daniel Veillard 已提交
443 444
}

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

D
Daniel Veillard 已提交
459 460
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
461
        return (-1);
D
Daniel Veillard 已提交
462
    }
K
Karel Zak 已提交
463

464
    /* TODO: there must be a way to do that with an hypervisor call too ! */
465 466 467
    /* 
     * try first with Xend interface
     */
468
    idlist = xenDaemonListDomains(conn);
469 470 471 472 473
    if (idlist != NULL) {
        char **tmp = idlist;

        ret = 0;
        while (*tmp != NULL) {
474 475 476
            tmp++;
            ret++;
        }
477 478
	free(idlist);
	return(ret);
K
 
Karel Zak 已提交
479
    }
480 481
    /* Then Xen Store */
    return(xenStoreNumOfDomains(conn));
K
 
Karel Zak 已提交
482 483
}

D
Daniel Veillard 已提交
484
/**
485
 * virDomainCreateLinux:
D
Daniel Veillard 已提交
486
 * @conn: pointer to the hypervisor connection
487
 * @xmlDesc: an XML description of the domain
488
 * @flags: an optional set of virDomainFlags
D
Daniel Veillard 已提交
489
 *
490 491 492
 * 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 已提交
493 494 495
 * 
 * Returns a new domain object or NULL in case of failure
 */
496
virDomainPtr
497
virDomainCreateLinux(virConnectPtr conn,
498
                     const char *xmlDesc,
499 500
                     unsigned int flags ATTRIBUTE_UNUSED)
{
501 502 503 504
    int ret;
    char *sexpr;
    char *name = NULL;
    virDomainPtr dom;
K
Karel Zak 已提交
505

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

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

522
        return (NULL);
523 524
    }

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

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

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

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

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

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

560

561
/**
562
 * virDomainLookupByID:
563 564 565 566 567 568 569
 * @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
 */
570
virDomainPtr
571 572
virDomainLookupByID(virConnectPtr conn, int id)
{
573
    char *path = NULL;
D
Daniel Veillard 已提交
574 575 576
    char **names;
    char **tmp;
    int ident;
577
    virDomainPtr ret;
578
    char *name = NULL;
579
    unsigned char uuid[16];
580

D
Daniel Veillard 已提交
581 582
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
583
        return (NULL);
D
Daniel Veillard 已提交
584 585 586
    }
    if (id < 0) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
587
        return (NULL);
D
Daniel Veillard 已提交
588
    }
589

D
Daniel Veillard 已提交
590
    /* retrieve home path of the domain */
591
    if (conn->xshandle != NULL) {
592
        path = xs_get_domain_path(conn->xshandle, (unsigned int) id);
593
    }
D
Daniel Veillard 已提交
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608

    /* path does not contain name, use xend API to retrieve name */
    names = xenDaemonListDomains(conn);
    tmp = names;

    if (names != NULL) {
       while (*tmp != NULL) {
          ident = xenDaemonDomainLookupByName_ids(conn, *tmp, &uuid[0]);
          if (ident == id) {
             name = strdup(*tmp);
             break;
          }
          tmp++;
       }
       free(names);
609
    }
610 611
    if (name == NULL)
        goto error;
612

613
    ret = virGetDomain(conn, name, &uuid[0]);
614
    if (ret == NULL) {
615
        virLibConnError(conn, VIR_ERR_NO_MEMORY, "Allocating domain");
616
        goto error;
617 618
    }
    ret->handle = id;
619
    ret->path = path;
620 621
    if (name != NULL)
        free(name);
622

623
    return (ret);
624 625 626
error:
    if (name != NULL)
        free(name);
627
    if (path != NULL)
628 629
        free(path);
    return (NULL);
630 631 632 633 634 635 636 637 638 639 640 641
}

/**
 * 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
642 643
virDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
644 645 646 647 648
    virDomainPtr ret;
    char *name = NULL;
    char **names;
    char **tmp;
    unsigned char ident[16];
649
    int id = -1;
650

D
Daniel Veillard 已提交
651 652
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
653
        return (NULL);
D
Daniel Veillard 已提交
654 655 656
    }
    if (uuid == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
657
        return (NULL);
D
Daniel Veillard 已提交
658
    }
659
    names = xenDaemonListDomains(conn);
660 661 662
    tmp = names;

    if (names == NULL) {
663 664
        TODO                    /* try to fallback to xenstore lookup */
            return (NULL);
665
    }
666
    while (*tmp != NULL) {
667
        id = xenDaemonDomainLookupByName_ids(conn, *tmp, &ident[0]);
668 669 670 671 672 673 674
        if (id >= 0) {
            if (!memcmp(uuid, ident, 16)) {
                name = strdup(*tmp);
                break;
            }
        }
        tmp++;
675 676 677 678
    }
    free(names);

    if (name == NULL)
679
        return (NULL);
680

681
    ret = virGetDomain(conn, name, &uuid[0]);
682 683
    if (ret == NULL) {
        if (name != NULL)
684 685
            free(name);
        return (NULL);
686 687
    }
    ret->handle = id;
688

689
    return (ret);
690 691
}

692 693 694 695 696
/**
 * virDomainLookupByName:
 * @conn: pointer to the hypervisor connection
 * @name: name for the domain
 *
697
 * Try to lookup a domain on the given hypervisor based on its name.
698 699 700 701
 *
 * Returns a new domain object or NULL in case of failure
 */
virDomainPtr
702 703
virDomainLookupByName(virConnectPtr conn, const char *name)
{
704 705
    virDomainPtr ret = NULL;

D
Daniel Veillard 已提交
706 707
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
708
        return (NULL);
D
Daniel Veillard 已提交
709 710 711
    }
    if (name == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
712
        return (NULL);
D
Daniel Veillard 已提交
713
    }
714

715
    /* try first though Xend */
716 717 718
    ret = xenDaemonDomainLookupByName(conn, name);
    if (ret != NULL) {
        return(ret);
719 720 721
    }

    /* then though the XenStore */
722 723 724
    ret = xenStoreDomainLookupByName(conn, name);
    if (ret != NULL) {
        return(ret);
725 726 727
    }

    return (ret);
728 729
}

D
Daniel Veillard 已提交
730
/**
731
 * virDomainDestroy:
D
Daniel Veillard 已提交
732 733 734 735
 * @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.
736 737
 * The data structure is freed and should not be used thereafter if the
 * call does not return an error.
738
 * This function may requires priviledged access
D
Daniel Veillard 已提交
739 740
 *
 * Returns 0 in case of success and -1 in case of failure.
741
 */
D
Daniel Veillard 已提交
742
int
743 744
virDomainDestroy(virDomainPtr domain)
{
745 746
    int ret;

D
Daniel Veillard 已提交
747 748
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
749
        return (-1);
D
Daniel Veillard 已提交
750
    }
751 752 753 754

    /*
     * try first with the xend method
     */
755
    ret = xenDaemonDomainDestroy(domain);
756 757
    if (ret == 0) {
        virDomainFree(domain);
758
        return (0);
759 760
    }

761
    ret = xenHypervisorDestroyDomain(domain);
762
    if (ret < 0)
763 764
        return (-1);

765
    virDomainFree(domain);
766
    return (0);
767 768 769 770 771 772 773 774 775 776 777 778
}

/**
 * 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
779 780
virDomainFree(virDomainPtr domain)
{
D
Daniel Veillard 已提交
781 782
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
783
        return (-1);
D
Daniel Veillard 已提交
784
    }
785 786 787
    if (virFreeDomain(domain->conn, domain) < 0)
        return (-1);
    return(0);
D
Daniel Veillard 已提交
788 789 790
}

/**
791
 * virDomainSuspend:
D
Daniel Veillard 已提交
792 793 794 795
 * @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 
796
 * hypervisor level will stay allocated. Use virDomainResume() to reactivate
D
Daniel Veillard 已提交
797
 * the domain.
798
 * This function may requires priviledged access.
D
Daniel Veillard 已提交
799 800 801 802
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
803 804
virDomainSuspend(virDomainPtr domain)
{
805 806
    int ret;

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

812
    /* first try though the Xen daemon */
813
    ret = xenDaemonDomainSuspend(domain);
814
    if (ret == 0)
815
        return (0);
816 817

    /* then try a direct hypervisor access */
818
    return (xenHypervisorPauseDomain(domain));
D
Daniel Veillard 已提交
819 820 821
}

/**
822
 * virDomainResume:
D
Daniel Veillard 已提交
823 824 825
 * @domain: a domain object
 *
 * Resume an suspended domain, the process is restarted from the state where
826
 * it was frozen by calling virSuspendDomain().
827
 * This function may requires priviledged access
D
Daniel Veillard 已提交
828 829 830 831
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
832 833
virDomainResume(virDomainPtr domain)
{
834 835
    int ret;

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
    /* first try though the Xen daemon */
842
    ret = xenDaemonDomainResume(domain);
843
    if (ret == 0)
844
        return (0);
845 846

    /* then try a direct hypervisor access */
847
    return (xenHypervisorResumeDomain(domain));
D
Daniel Veillard 已提交
848 849
}

850 851 852 853 854 855
/**
 * virDomainSave:
 * @domain: a domain object
 * @to: path for the output file
 *
 * This method will suspend a domain and save its memory contents to
856 857 858
 * 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.
859 860 861 862
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
863 864
virDomainSave(virDomainPtr domain, const char *to)
{
865
    int ret;
866
    char filepath[4096];
867

D
Daniel Veillard 已提交
868 869
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
870
        return (-1);
D
Daniel Veillard 已提交
871 872 873
    }
    if (to == NULL) {
        virLibDomainError(domain, VIR_ERR_INVALID_ARG, __FUNCTION__);
874
        return (-1);
D
Daniel Veillard 已提交
875
    }
876

877 878 879 880 881
    /*
     * 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] != '/') {
882
        unsigned int len, t;
883

884 885 886 887 888 889 890 891 892 893
        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];
894 895 896

    }

897
    ret = xenDaemonDomainSave(domain, to);
898
    return (ret);
899 900 901 902
}

/**
 * virDomainRestore:
903
 * @conn: pointer to the hypervisor connection
904 905 906 907 908 909 910
 * @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
911 912
virDomainRestore(virConnectPtr conn, const char *from)
{
913
    int ret;
914
    char filepath[4096];
915

D
Daniel Veillard 已提交
916 917
    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
918
        return (-1);
D
Daniel Veillard 已提交
919 920 921
    }
    if (from == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
922
        return (-1);
D
Daniel Veillard 已提交
923 924
    }

925 926 927 928 929
    /*
     * 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] != '/') {
930 931 932 933 934 935 936 937 938 939 940 941 942 943
        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];
    }

944
    ret = xenDaemonDomainRestore(conn, from);
945
    return (ret);
946 947
}

948 949 950 951 952
/**
 * virDomainShutdown:
 * @domain: a domain object
 *
 * Shutdown a domain, the domain object is still usable there after but
953 954
 * the domain OS is being stopped. Note that the guest OS may ignore the
 * request.
955 956 957 958 959 960 961
 *
 * 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
962 963
virDomainShutdown(virDomainPtr domain)
{
964 965
    int ret;

D
Daniel Veillard 已提交
966 967
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
968
        return (-1);
D
Daniel Veillard 已提交
969
    }
970

971 972 973
    /*
     * try first with the xend daemon
     */
974
    ret = xenDaemonDomainShutdown(domain);
975 976
    if (ret == 0) {
        domain->flags |= DOMAIN_IS_SHUTDOWN;
977
        return (0);
978
    }
979

980
    /*
981 982 983
     * this is very hackish, the domU kernel probes for a special 
     * node in the xenstore and launch the shutdown command if found.
     */
984
    ret = xenDaemonDomainShutdown(domain);
985 986 987
    if (ret == 0) {
        domain->flags |= DOMAIN_IS_SHUTDOWN;
    }
988
    return (ret);
989 990
}

991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
/**
 * virDomainReboot:
 * @domain: a domain object
 * @flags: extra flags for the reboot operation, not used yet
 *
 * Reboot a domain, the domain object is still usable there after but
 * the domain OS is being stopped for a restart.
 * Note that the guest OS may ignore the request.
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
virDomainReboot(virDomainPtr domain, unsigned int flags)
{
    int ret;

    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
        return (-1);
    }

    /*
     * try first with the xend daemon
     */
    ret = xenDaemonDomainReboot(domain, flags);
    if (ret == 0) {
        domain->flags |= DOMAIN_IS_SHUTDOWN;
        return (0);
    }

    /*
     * this is very hackish, the domU kernel probes for a special 
     * node in the xenstore and launch the shutdown command if found.
     */
    ret = xenDaemonDomainReboot(domain, flags);
    if (ret == 0) {
        domain->flags |= DOMAIN_IS_SHUTDOWN;
    }
    return (ret);
}

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

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

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

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

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

D
Daniel Veillard 已提交
1122 1123
    if (!VIR_IS_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1124
        return (NULL);
D
Daniel Veillard 已提交
1125
    }
1126

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

1135
    return (str);
1136 1137
}

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

D
Daniel Veillard 已提交
1153 1154
    if (!VIR_IS_CONNECTED_DOMAIN(domain)) {
        virLibDomainError(domain, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
1155
        return (0);
D
Daniel Veillard 已提交
1156
    }
1157

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

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

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

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

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

1213
    ret = xenHypervisorSetMaxMemory(domain, memory);
1214
    if (ret < 0)
1215
        return (-1);
1216

1217 1218 1219 1220 1221 1222 1223 1224 1225 1226
    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;
1227

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

1232
    return (ret);
D
Daniel Veillard 已提交
1233 1234
}

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

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

1260
    memset(info, 0, sizeof(virDomainInfo));
1261

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

    /*
     * try to extract the informations though access to the Xen Daemon
     */
1274
    if (xenDaemonDomainGetInfo(domain, info) == 0)
1275
        return (0);
1276 1277

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

1283
    return (-1);
1284
}
1285

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

1309
    return (xenDaemonDomainDumpXML(domain));
1310
}
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348

/**
 * virNodeGetInfo:
 * @conn: pointer to the hypervisor connection
 * @info: pointer to a virNodeInfo structure allocated by the user
 * 
 * Extract hardware information about the node.
 *
 * Returns 0 in case of success and -1 in case of failure.
 */
int
virNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) {
    int i;
    int ret = -1;

    if (!VIR_IS_CONNECT(conn)) {
        virLibConnError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
        return (-1);
    }
    if (info == NULL) {
        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
        return (-1);
    }

    for (i = 0;i < conn->nb_drivers;i++) {
	if ((conn->drivers[i] != NULL) &&
	    (conn->drivers[i]->nodeGetInfo != NULL)) {
	    ret = conn->drivers[i]->nodeGetInfo(conn, info);
	    if (ret == 0)
	        break;
	}
    }
    if (ret != 0) {
        virLibConnError(conn, VIR_ERR_CALL_FAILED, __FUNCTION__);
        return (-1);
    }
    return(0);
}