xs_internal.c 21.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 * xs_internal.c: access to Xen Store
 *
 * Copyright (C) 2006 Red Hat, Inc.
 *
 * See COPYING.LIB for the License of this software
 *
 * Daniel Veillard <veillard@redhat.com>
 */

11
#ifdef WITH_XEN
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <stdint.h>

#include <xen/dom0_ops.h>
#include <xen/version.h>
#include <xen/xen.h>

#include <xs.h>

#include "internal.h"
#include "driver.h"
30
#include "xen_unified.h"
31
#include "xs_internal.h"
32
#include "xen_internal.h" /* for xenHypervisorCheckID */
33 34 35

#define XEN_HYPERVISOR_SOCKET "/proc/xen/privcmd"

36
#ifndef PROXY
37 38
static char *xenStoreDomainGetOSType(virDomainPtr domain);

39 40
virDriver xenStoreDriver = {
    -1,
41
    "XenStore",
42 43 44
    (DOM0_INTERFACE_VERSION >> 24) * 1000000 +
    ((DOM0_INTERFACE_VERSION >> 16) & 0xFF) * 1000 +
    (DOM0_INTERFACE_VERSION & 0xFFFF),
45 46 47 48
    xenStoreOpen, /* open */
    xenStoreClose, /* close */
    NULL, /* type */
    NULL, /* version */
49
    NULL, /* getMaxVcpus */
50
    NULL, /* nodeGetInfo */
51
    NULL, /* getCapabilities */
52 53 54 55 56
    xenStoreListDomains, /* listDomains */
    NULL, /* numOfDomains */
    NULL, /* domainCreateLinux */
    NULL, /* domainLookupByID */
    NULL, /* domainLookupByUUID */
57
    xenStoreDomainLookupByName, /* domainLookupByName */
58 59
    NULL, /* domainSuspend */
    NULL, /* domainResume */
60 61
    xenStoreDomainShutdown, /* domainShutdown */
    xenStoreDomainReboot, /* domainReboot */
62
    NULL, /* domainDestroy */
63
    xenStoreDomainGetOSType, /* domainGetOSType */
64
    xenStoreDomainGetMaxMemory, /* domainGetMaxMemory */
65 66
    NULL, /* domainSetMaxMemory */
    xenStoreDomainSetMemory, /* domainSetMemory */
67 68
    xenStoreGetDomainInfo, /* domainGetInfo */
    NULL, /* domainSave */
69
    NULL, /* domainRestore */
D
Daniel Veillard 已提交
70
    NULL, /* domainCoreDump */
71 72
    NULL, /* domainSetVcpus */
    NULL, /* domainPinVcpu */
73
    NULL, /* domainGetVcpus */
74
    NULL, /* domainGetMaxVcpus */
75
    NULL, /* domainDumpXML */
76 77 78 79 80
    NULL, /* listDefinedDomains */
    NULL, /* numOfDefinedDomains */
    NULL, /* domainCreate */
    NULL, /* domainDefineXML */
    NULL, /* domainUndefine */
81 82
    NULL, /* domainAttachDevice */
    NULL, /* domainDetachDevice */
83 84
    NULL, /* domainGetAutostart */
    NULL, /* domainSetAutostart */
85 86 87
    NULL, /* domainGetSchedulerType */
    NULL, /* domainGetSchedulerParameters */
    NULL, /* domainSetSchedulerParameters */
88 89
};

90
/**
91
 * xenStoreInit:
92
 *
93
 * Initialisation.
94
 */
95 96
int
xenStoreInit ()
97
{
98
    return 0;
99
}
100
#endif /* ! PROXY */
101

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
/**
 * virXenStoreError:
 * @conn: the connection if available
 * @error: the error number
 * @info: extra information string
 *
 * Handle an error at the xend store interface
 */
static void
virXenStoreError(virConnectPtr conn, virErrorNumber error, const char *info)
{
    const char *errmsg;

    if (error == VIR_ERR_OK)
        return;

    errmsg = __virErrorMsg(error, info);
119
    __virRaiseError(conn, NULL, NULL, VIR_FROM_XENSTORE, error, VIR_ERR_ERROR,
120 121 122 123 124 125 126 127
                    errmsg, info, NULL, 0, 0, errmsg, info);
}

/************************************************************************
 *									*
 *		Helper internal APIs					*
 *									*
 ************************************************************************/
128
#ifndef PROXY
129 130 131 132 133 134 135 136 137 138 139 140 141 142
/**
 * virConnectDoStoreList:
 * @conn: pointer to the hypervisor connection
 * @path: the absolute path of the directory in the store to list
 * @nb: OUT pointer to the number of items found
 *
 * Internal API querying the Xenstore for a list
 *
 * Returns a string which must be freed by the caller or NULL in case of error
 */
static char **
virConnectDoStoreList(virConnectPtr conn, const char *path,
                      unsigned int *nb)
{
143 144 145 146 147 148 149
    xenUnifiedPrivatePtr priv;

    if (conn == NULL)
        return NULL;

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL || path == NULL || nb == NULL)
150 151
        return (NULL);

152
    return xs_directory (priv->xshandle, 0, path, nb);
153
}
154
#endif /* ! PROXY */
155 156 157

/**
 * virDomainDoStoreQuery:
158 159
 * @conn: pointer to the hypervisor connection
 * @domid: id of the domain
160 161 162 163 164 165 166
 * @path: the relative path of the data in the store to retrieve
 *
 * Internal API querying the Xenstore for a string value.
 *
 * Returns a string which must be freed by the caller or NULL in case of error
 */
static char *
167
virDomainDoStoreQuery(virConnectPtr conn, int domid, const char *path)
168 169 170
{
    char s[256];
    unsigned int len = 0;
171 172 173 174
    xenUnifiedPrivatePtr priv;

    if (!conn)
        return NULL;
175

176 177
    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
178 179
        return (NULL);

180
    snprintf(s, 255, "/local/domain/%d/%s", domid, path);
181 182
    s[255] = 0;

183
    return xs_read(priv->xshandle, 0, &s[0], &len);
184 185
}

186
#ifndef PROXY
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
/**
 * virDomainDoStoreWrite:
 * @domain: a domain object
 * @path: the relative path of the data in the store to retrieve
 *
 * Internal API setting up a string value in the Xenstore
 * Requires write access to the XenStore
 *
 * Returns 0 in case of success, -1 in case of failure
 */
static int
virDomainDoStoreWrite(virDomainPtr domain, const char *path,
                      const char *value)
{
    char s[256];
202
    xenUnifiedPrivatePtr priv;
203 204 205 206
    int ret = -1;

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
        return (-1);
207 208 209

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
210 211 212 213
        return (-1);
    if (domain->conn->flags & VIR_CONNECT_RO)
        return (-1);

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

217
    if (xs_write(priv->xshandle, 0, &s[0], value, strlen(value)))
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
        ret = 0;

    return (ret);
}

/**
 * virDomainGetVM:
 * @domain: a domain object
 *
 * Internal API extracting a xenstore vm path.
 *
 * Returns the new string or NULL in case of error
 */
char *
virDomainGetVM(virDomainPtr domain)
{
    char *vm;
    char query[200];
    unsigned int len;
237
    xenUnifiedPrivatePtr priv;
238 239 240

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
        return (NULL);
241 242 243

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
244 245 246 247 248
        return (NULL);

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

249
    vm = xs_read(priv->xshandle, 0, &query[0], &len);
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

    return (vm);
}

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

    if (!VIR_IS_CONNECTED_DOMAIN(domain))
        return (NULL);
275 276 277

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
278 279 280 281 282
        return (NULL);

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

283
    ret = xs_read(priv->xshandle, 0, &s[0], &len);
284 285 286 287

    return (ret);
}

288
#if 0
289 290 291 292 293 294 295 296 297 298 299 300 301
/**
 * virConnectCheckStoreID:
 * @conn: pointer to the hypervisor connection
 * @id: the id number as returned from Xenstore
 *
 * the xenstore sometimes list non-running domains, double check
 * from the hypervisor if we have direct access
 *
 * Returns -1 if the check failed, 0 if successful or not possible to check
 */
static int
virConnectCheckStoreID(virConnectPtr conn, int id)
{
302
    if (conn->id >= 0) {
303 304
        int tmp;

305
        tmp = xenHypervisorCheckID(conn, id);
306 307 308 309 310
        if (tmp < 0)
            return (-1);
    }
    return (0);
}
311
#endif
312
#endif /* ! PROXY */
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

/************************************************************************
 *									*
 *		Canonical internal APIs					*
 *									*
 ************************************************************************/
/**
 * xenStoreOpen:
 * @conn: pointer to the connection block
 * @name: URL for the target, NULL for local
 * @flags: combination of virDrvOpenFlag(s)
 *
 * Connects to the Xen hypervisor.
 *
 * Returns 0 or -1 in case of error.
 */
int
330
xenStoreOpen(virConnectPtr conn,
331 332
             const char *name ATTRIBUTE_UNUSED,
             int flags ATTRIBUTE_UNUSED)
333
{
334
    xenUnifiedPrivatePtr priv = (xenUnifiedPrivatePtr) conn->privateData;
335

336
#ifdef PROXY
337
    priv->xshandle = xs_daemon_open_readonly();
338
#else
339
    if (flags & VIR_DRV_OPEN_RO)
340
	priv->xshandle = xs_daemon_open_readonly();
341
    else
342
	priv->xshandle = xs_daemon_open();
343
#endif /* ! PROXY */
344

345
    if (priv->xshandle == NULL) {
346
        virXenStoreError(NULL, VIR_ERR_NO_XEN, 
347
	                     _("failed to connect to Xen Store"));
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
        return (-1);
    }
    return (0);
}

/**
 * xenStoreClose:
 * @conn: pointer to the connection block
 *
 * Close the connection to the Xen hypervisor.
 *
 * Returns 0 in case of success or -1 in case of error.
 */
int
xenStoreClose(virConnectPtr conn)
{
364 365
    xenUnifiedPrivatePtr priv;

366 367
    if (conn == NULL) {
        virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
368
        return(-1);
369 370
    }

371 372 373 374 375
    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
        return(-1);

    xs_daemon_close(priv->xshandle);
376 377 378
    return (0);
}

379
#ifndef PROXY
380 381 382
/**
 * xenStoreGetDomainInfo:
 * @domain: pointer to the domain block
383
 * @info: the place where information should be stored
384
 *
385
 * Do an hypervisor call to get the related set of domain information.
386 387 388 389 390 391 392 393 394
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
xenStoreGetDomainInfo(virDomainPtr domain, virDomainInfoPtr info)
{
    char *tmp, **tmp2;
    unsigned int nb_vcpus;
    char request[200];
395
    xenUnifiedPrivatePtr priv;
396

397 398 399
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
        return (-1);

400 401 402 403 404
    if ((domain == NULL) || (domain->conn == NULL) || (info == NULL)) {
        virXenStoreError(domain ? domain->conn : NULL, VIR_ERR_INVALID_ARG,
	                 __FUNCTION__);
	return(-1);
    }
405 406 407

    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
    if (priv->xshandle == NULL)
408
        return(-1);
409

410
    if (domain->id == -1)
411
        return(-1);
412

413
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "running");
414 415 416 417 418 419 420
    if (tmp != NULL) {
        if (tmp[0] == '1')
            info->state = VIR_DOMAIN_RUNNING;
        free(tmp);
    } else {
        info->state = VIR_DOMAIN_NONE;
    }
421
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
422 423 424 425 426 427 428 429 430 431
    if (tmp != NULL) {
        info->memory = atol(tmp);
        info->maxMem = atol(tmp);
        free(tmp);
    } else {
        info->memory = 0;
        info->maxMem = 0;
    }
#if 0
    /* doesn't seems to work */
432
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "cpu_time");
433 434 435 436 437 438 439
    if (tmp != NULL) {
        info->cpuTime = atol(tmp);
        free(tmp);
    } else {
        info->cpuTime = 0;
    }
#endif
440
    snprintf(request, 199, "/local/domain/%d/cpu", domain->id);
441 442 443 444 445 446 447 448 449 450
    request[199] = 0;
    tmp2 = virConnectDoStoreList(domain->conn, request, &nb_vcpus);
    if (tmp2 != NULL) {
        info->nrVirtCpu = nb_vcpus;
        free(tmp2);
    }
    return (0);
}

/**
451
 * xenStoreDomainSetMemory:
452 453 454 455 456 457 458 459
 * @domain: pointer to the domain block
 * @memory: the max memory size in kilobytes.
 *
 * Change the maximum amount of memory allowed in the xen store
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
460
xenStoreDomainSetMemory(virDomainPtr domain, unsigned long memory)
461 462 463 464
{
    int ret;
    char value[20];

D
Daniel Veillard 已提交
465 466
    if ((domain == NULL) || (domain->conn == NULL) ||
        (memory < 1024 * MIN_XEN_GUEST_SIZE)) {
467 468 469 470
        virXenStoreError(domain ? domain->conn : NULL, VIR_ERR_INVALID_ARG,
	                 __FUNCTION__);
	return(-1);
    }
471
    if (domain->id == -1)
472
        return(-1);
D
Daniel Veillard 已提交
473 474
    if ((domain->id == 0) && (memory < (2 * MIN_XEN_GUEST_SIZE * 1024)))
	return(-1);
475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
    snprintf(value, 19, "%lu", memory);
    value[19] = 0;
    ret = virDomainDoStoreWrite(domain, "memory/target", &value[0]);
    if (ret < 0)
        return (-1);
    return (0);
}

/**
 * xenStoreDomainGetMaxMemory:
 * @domain: pointer to the domain block
 *
 * Ask the xenstore for the maximum memory allowed for a domain
 *
 * Returns the memory size in kilobytes or 0 in case of error.
 */
unsigned long
xenStoreDomainGetMaxMemory(virDomainPtr domain)
{
    char *tmp;
    unsigned long ret = 0;

497 498
    if (!VIR_IS_CONNECTED_DOMAIN(domain))
        return (ret);
499
    if (domain->id == -1)
500
        return(-1);
501

502
    tmp = virDomainDoStoreQuery(domain->conn, domain->id, "memory/target");
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
    if (tmp != NULL) {
	ret = (unsigned long) atol(tmp);
	free(tmp);
    }
    return(ret);
}

/**
 * xenStoreNumOfDomains:
 * @conn: pointer to the hypervisor connection
 *
 * Provides the number of active domains.
 *
 * Returns the number of domain found or -1 in case of error
 */
int
xenStoreNumOfDomains(virConnectPtr conn)
{
    unsigned int num;
    char **idlist;
    int ret = -1;
524
    xenUnifiedPrivatePtr priv;
525

526
    if (conn == NULL) {
527
        virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
528
        return -1;
529
    }
530 531 532 533 534 535 536

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL) {
        virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
        return(-1);
    }
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
    if (idlist) {
        free(idlist);
	ret = num;
    }
    return(ret);
}

/**
 * xenStoreListDomains:
 * @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
xenStoreListDomains(virConnectPtr conn, int *ids, int maxids)
{
    char **idlist = NULL, *endptr;
    unsigned int num, i;
    int ret;
    long id;
561
    xenUnifiedPrivatePtr priv;
562 563 564 565 566

    if ((conn == NULL) || (ids == NULL)) {
        virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
	return(-1);
    }
567 568 569

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
570 571
        return(-1);

572
    idlist = xs_directory (priv->xshandle, 0, "/local/domain", &num);
573 574 575 576 577 578 579 580 581
    if (idlist == NULL)
	return(-1);

    for (ret = 0, i = 0; (i < num) && (ret < maxids); i++) {
	id = strtol(idlist[i], &endptr, 10);
	if ((endptr == idlist[i]) || (*endptr != 0)) {
	    ret = -1;
	    break;
	}
582
#if 0
583 584
	if (virConnectCheckStoreID(conn, (int) id) < 0)
	    continue;
585
#endif
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
	ids[ret++] = (int) id;
    }
    return(ret);
}

/**
 * xenStoreDomainLookupByName:
 * @conn: A xend instance
 * @name: The name of the domain
 *
 * Try to lookup a domain on the Xen Store based on its name.
 *
 * Returns a new domain object or NULL in case of failure
 */
virDomainPtr
xenStoreDomainLookupByName(virConnectPtr conn, const char *name)
{
    virDomainPtr ret = NULL;
    unsigned int num, i, len;
    long id = -1;
    char **idlist = NULL, *endptr;
    char prop[200], *tmp, *path = NULL;
    int found = 0;
    struct xend_domain *xenddomain = NULL;
610
    xenUnifiedPrivatePtr priv;
611 612 613 614 615

    if ((conn == NULL) || (name == NULL)) {
        virXenStoreError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
	return(NULL);
    }
616 617 618

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
619 620
        return(NULL);

621
    idlist = xs_directory(priv->xshandle, 0, "/local/domain", &num);
622 623 624 625 626 627 628 629
    if (idlist == NULL)
	goto done;

    for (i = 0; i < num; i++) {
	id = strtol(idlist[i], &endptr, 10);
	if ((endptr == idlist[i]) || (*endptr != 0)) {
	    goto done;
	}
630
#if 0
631 632
	if (virConnectCheckStoreID(conn, (int) id) < 0)
	    continue;
633
#endif
634 635
	snprintf(prop, 199, "/local/domain/%s/name", idlist[i]);
	prop[199] = 0;
636
	tmp = xs_read(priv->xshandle, 0, prop, &len);
637 638 639 640 641 642 643
	if (tmp != NULL) {
	    found = !strcmp(name, tmp);
	    free(tmp);
	    if (found)
		break;
	}
    }
644
    path = xs_get_domain_path(priv->xshandle, (unsigned int) id);
645 646 647 648

    if (!found)
        return(NULL);

649 650
    ret = virGetDomain(conn, name, NULL);
    if (ret == NULL) {
651
        virXenStoreError(conn, VIR_ERR_NO_MEMORY, _("allocating domain"));
652 653
	if (path != NULL)
	    free(path);
654
	goto done;
655
    }
656
    ret->id = id;
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684

done:
    if (xenddomain != NULL)
	free(xenddomain);
    if (idlist != NULL)
	free(idlist);

    return(ret);
}

/**
 * xenStoreDomainShutdown:
 * @domain: pointer to the Domain block
 *
 * Shutdown the domain, the OS is requested to properly shutdown
 * and the domain may ignore it.  It will return immediately
 * after queuing the request.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
xenStoreDomainShutdown(virDomainPtr domain)
{
    if ((domain == NULL) || (domain->conn == NULL)) {
        virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
	                 __FUNCTION__);
        return(-1);
    }
685
    if (domain->id == -1 || domain->id == 0)
686
        return(-1);
687 688 689 690 691 692 693
    /*
     * this is very hackish, the domU kernel probes for a special 
     * node in the xenstore and launch the shutdown command if found.
     */
    return(virDomainDoStoreWrite(domain, "control/shutdown", "halt"));
}

694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
/**
 * xenStoreDomainReboot:
 * @domain: pointer to the Domain block
 * @flags: extra flags for the reboot operation, not used yet
 *
 * Reboot the domain, the OS is requested to properly shutdown
 * and reboot but the domain may ignore it.  It will return immediately
 * after queuing the request.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
xenStoreDomainReboot(virDomainPtr domain, unsigned int flags ATTRIBUTE_UNUSED)
{
    if ((domain == NULL) || (domain->conn == NULL)) {
        virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
	                 __FUNCTION__);
        return(-1);
    }
713
    if (domain->id == -1 || domain->id == 0)
714
        return(-1);
715 716 717 718 719 720
    /*
     * this is very hackish, the domU kernel probes for a special 
     * node in the xenstore and launch the shutdown command if found.
     */
    return(virDomainDoStoreWrite(domain, "control/shutdown", "reboot"));
}
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748

/*
 * xenStoreDomainGetOSType:
 * @domain: a domain object
 *
 * Get the type of domain operation system.
 *
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
static char *
xenStoreDomainGetOSType(virDomainPtr domain) {
    char *vm, *str = NULL;

    if ((domain == NULL) || (domain->conn == NULL)) {
        virXenStoreError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG,
	                 __FUNCTION__);
        return(NULL);
    }

    vm = virDomainGetVM(domain);
    if (vm) {
        str = virDomainGetVMInfo(domain, vm, "image/ostype");
        free(vm);
    }

    return (str);
}
749
#endif /* ! PROXY */
750

751 752
/**
 * xenStoreDomainGetVNCPort:
753 754
 * @conn: the hypervisor connection
 * @domid: id of the domain
755 756 757 758 759 760
 *
 * Return the port number on which the domain is listening for VNC
 * connections. 
 *
 * Returns the port number, -1 in case of error
 */
761
int             xenStoreDomainGetVNCPort(virConnectPtr conn, int domid) {
762 763 764
    char *tmp;
    int ret = -1;

765
    tmp = virDomainDoStoreQuery(conn, domid, "console/vnc-port");
766 767 768 769 770 771 772 773 774 775 776 777
    if (tmp != NULL) {
        char *end;
        ret = strtol(tmp, &end, 10);
        if (ret == 0 && end == tmp)
            ret = -1;
        free(tmp);
    }
    return(ret);
}

/**
 * xenStoreDomainGetConsolePath:
778 779
 * @conn: the hypervisor connection
 * @domid: id of the domain
780 781 782 783 784 785 786 787
 *
 * Return the path to the psuedo TTY on which the guest domain's
 * serial console is attached.
 *
 * Returns the path to the serial console. It is the callers
 * responsibilty to free() the return string. Returns NULL
 * on error
 */
788 789
char *          xenStoreDomainGetConsolePath(virConnectPtr conn, int domid) {
  return virDomainDoStoreQuery(conn, domid, "console/tty");
790
}
791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807

#ifdef PROXY
/*
 * xenStoreDomainGetOSTypeID:
 * @conn: pointer to the connection.
 * @id: the domain id
 *
 * Get the type of domain operation system.
 *
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
char *
xenStoreDomainGetOSTypeID(virConnectPtr conn, int id) {
    char *vm, *str = NULL;
    char query[200];
    unsigned int len;
808
    xenUnifiedPrivatePtr priv;
809 810 811 812

    if (id < 0)
        return(NULL);

813 814
    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
815 816 817 818 819
        return (NULL);

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

820
    vm = xs_read(priv->xshandle, 0, &query[0], &len);
821 822 823

    if (vm) {
        snprintf(query, 199, "%s/image/ostype", vm);
824
	str = xs_read(priv->xshandle, 0, &query[0], &len);
825 826
        free(vm);
    }
827 828 829
    if (str == NULL)
        str = strdup("linux");

830 831 832 833

    return (str);
}
#endif /* PROXY */
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851

/*
 * xenStoreDomainGetNetworkID:
 * @conn: pointer to the connection.
 * @id: the domain id
 * @mac: the mac address
 *
 * Get the reference (i.e. the string number) for the device on that domain
 * which uses the given mac address
 *
 * Returns the new string or NULL in case of error, the string must be
 *         freed by the caller.
 */
char *
xenStoreDomainGetNetworkID(virConnectPtr conn, int id, const char *mac) {
    char dir[80], path[128], **list = NULL, *val = NULL;
    unsigned int maclen, len, i, num;
    char *ret = NULL;
852
    xenUnifiedPrivatePtr priv;
853 854 855

    if (id < 0)
        return(NULL);
856 857 858

    priv = (xenUnifiedPrivatePtr) conn->privateData;
    if (priv->xshandle == NULL)
859 860 861 862 863 864 865
        return (NULL);
    if (mac == NULL)
        return (NULL);
    maclen = strlen(mac);
    if (maclen <= 0)
        return (NULL);

866
    snprintf(dir, sizeof(dir), "/local/domain/0/backend/vif/%d", id);
867
    list = xs_directory(priv->xshandle, 0, dir, &num);
868 869 870
    if (list == NULL)
	return(NULL);
    for (i = 0; i < num; i++) {
871
	snprintf(path, sizeof(path), "%s/%s/%s", dir, list[i], "mac");
872
	val = xs_read(priv->xshandle, 0, path, &len);
873 874 875 876 877
	if (val == NULL)
	    break;
	if ((maclen != len) || memcmp(val, mac, len)) {
	    free(val);
	} else {
878
	    ret = strdup(list[i]);
879 880 881 882 883 884 885
	    free(val);
	    break;
	}
    }
    free(list);
    return(ret);
}
886 887 888 889 890 891 892 893 894 895

#endif /* WITH_XEN */
/*
 * Local variables:
 *  indent-tabs-mode: nil
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 * End:
 */