xml.c 59.9 KB
Newer Older
1 2 3
/*
 * xml.c: XML based interfaces for the libvir library
 *
4
 * Copyright (C) 2005, 2007 Red Hat, Inc.
5 6 7 8 9 10
 *
 * See COPYING.LIB for the License of this software
 *
 * Daniel Veillard <veillard@redhat.com>
 */

11 12
#include "config.h"

13
#include "libvirt/libvirt.h"
14 15 16 17 18

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
19
#include <limits.h>
20
#ifdef WITH_XEN
21
#include <xs.h>
22
#endif
23
#include <math.h>               /* for isnan() */
24 25
#include "internal.h"
#include "hash.h"
D
Daniel Veillard 已提交
26
#include "sexpr.h"
27
#include "xml.h"
28
#include "buf.h"
29
#include "xs_internal.h"        /* for xenStoreDomainGetNetworkID */
30
#include "xen_unified.h"
31

32 33 34 35 36 37 38 39 40
/**
 * virXMLError:
 * @conn: a connection if any
 * @error: the error number
 * @info: information/format string
 * @value: extra integer parameter for the error string
 *
 * Report an error coming from the XML module.
 */
41
static void
42 43
virXMLError(virConnectPtr conn, virErrorNumber error, const char *info,
            int value)
44
{
45
    const char *errmsg;
46

47 48 49 50
    if (error == VIR_ERR_OK)
        return;

    errmsg = __virErrorMsg(error, info);
51
    __virRaiseError(conn, NULL, NULL, VIR_FROM_XML, error, VIR_ERR_ERROR,
52
                    errmsg, info, NULL, value, 0, errmsg, info, value);
53 54
}

55 56 57 58 59
/************************************************************************
 *									*
 * Parser and converter for the CPUset strings used in libvirt		*
 *									*
 ************************************************************************/
60
#if WITH_XEN
61 62 63 64 65 66 67 68 69
/**
 * skipSpaces:
 * @str: pointer to the char pointer used
 *
 * Skip potential blanks, this includes space tabs, line feed,
 * carriage returns and also '\\' which can be erronously emitted
 * by xend
 */
static void
70 71
skipSpaces(const char **str)
{
72 73 74
    const char *cur = *str;

    while ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') ||
75 76
           (*cur == '\r') || (*cur == '\\'))
        cur++;
77 78 79 80 81 82 83
    *str = cur;
}

/**
 * parseNumber:
 * @str: pointer to the char pointer used
 *
84
 * Parse an unsigned number
85
 *
86
 * Returns the unsigned number or -1 in case of error. @str will be
87 88 89
 *         updated to skip the number.
 */
static int
90 91
parseNumber(const char **str)
{
92 93 94 95
    int ret = 0;
    const char *cur = *str;

    if ((*cur < '0') || (*cur > '9'))
96
        return (-1);
97 98

    while ((*cur >= '0') && (*cur <= '9')) {
99 100 101 102 103 104 105
        unsigned int c = *cur - '0';

        if ((ret > INT_MAX / 10) ||
            ((ret == INT_MAX / 10) && (c > INT_MAX % 10)))
            return (-1);
        ret = ret * 10 + c;
        cur++;
106 107
    }
    *str = cur;
108
    return (ret);
109 110 111 112 113 114 115 116 117 118 119 120 121
}

/**
 * parseCpuNumber:
 * @str: pointer to the char pointer used
 * @maxcpu: maximum CPU number allowed
 *
 * Parse a CPU number
 *
 * Returns the CPU number or -1 in case of error. @str will be
 *         updated to skip the number.
 */
static int
122 123
parseCpuNumber(const char **str, int maxcpu)
{
124 125 126 127
    int ret = 0;
    const char *cur = *str;

    if ((*cur < '0') || (*cur > '9'))
128
        return (-1);
129 130 131

    while ((*cur >= '0') && (*cur <= '9')) {
        ret = ret * 10 + (*cur - '0');
132
        if (ret >= maxcpu)
133 134
            return (-1);
        cur++;
135 136
    }
    *str = cur;
137
    return (ret);
138 139 140
}

/**
141
 * virSaveCpuSet:
142 143 144 145 146 147 148 149 150
 * @conn: connection
 * @cpuset: pointer to a char array for the CPU set
 * @maxcpu: number of elements available in @cpuset
 *
 * Serialize the cpuset to a string
 *
 * Returns the new string NULL in case of error. The string need to be
 *         freed by the caller.
 */
151 152
char *
virSaveCpuSet(virConnectPtr conn, char *cpuset, int maxcpu)
153 154 155 156 157 158
{
    virBufferPtr buf;
    char *ret;
    int start, cur;
    int first = 1;

159 160
    if ((cpuset == NULL) || (maxcpu <= 0) || (maxcpu > 100000))
        return (NULL);
161 162 163

    buf = virBufferNew(1000);
    if (buf == NULL) {
164 165
        virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 1000);
        return (NULL);
166 167 168 169 170
    }
    cur = 0;
    start = -1;
    while (cur < maxcpu) {
        if (cpuset[cur]) {
171 172 173 174 175
            if (start == -1)
                start = cur;
        } else if (start != -1) {
            if (!first)
                virBufferAdd(buf, ",", -1);
176
            else
177 178 179 180 181 182 183 184
                first = 0;
            if (cur == start + 1)
                virBufferVSprintf(buf, "%d", start);
            else
                virBufferVSprintf(buf, "%d-%d", start, cur - 1);
            start = -1;
        }
        cur++;
185 186
    }
    if (start != -1) {
187 188 189 190 191 192
        if (!first)
            virBufferAdd(buf, ",", -1);
        if (maxcpu == start + 1)
            virBufferVSprintf(buf, "%d", start);
        else
            virBufferVSprintf(buf, "%d-%d", start, maxcpu - 1);
193 194
    }
    ret = virBufferContentAndFree(buf);
195
    return (ret);
196 197 198 199
}

/**
 * virParseCpuSet:
200
 * @conn: connection
201 202 203 204 205 206 207 208 209 210 211 212 213 214
 * @str: pointer to a CPU set string pointer
 * @sep: potential character used to mark the end of string if not 0
 * @cpuset: pointer to a char array for the CPU set
 * @maxcpu: number of elements available in @cpuset
 *
 * Parse the cpu set, it will set the value for enabled CPUs in the @cpuset
 * to 1, and 0 otherwise. The syntax allows coma separated entries each
 * can be either a CPU number, ^N to unset that CPU or N-M for ranges.
 *
 * Returns the number of CPU found in that set, or -1 in case of error.
 *         @cpuset is modified accordingly to the value parsed.
 *         @str is updated to the end of the part parsed
 */
int
215 216
virParseCpuSet(virConnectPtr conn, const char **str, char sep,
               char *cpuset, int maxcpu)
217 218 219 220 221 222
{
    const char *cur;
    int ret = 0;
    int i, start, last;
    int neg = 0;

223 224 225
    if ((str == NULL) || (cpuset == NULL) || (maxcpu <= 0) ||
        (maxcpu > 100000))
        return (-1);
226 227 228 229 230 231 232

    cur = *str;
    skipSpaces(&cur);
    if (*cur == 0)
        goto parse_error;

    /* initialize cpumap to all 0s */
233 234
    for (i = 0; i < maxcpu; i++)
        cpuset[i] = 0;
235 236 237
    ret = 0;

    while ((*cur != 0) && (*cur != sep)) {
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
        /*
         * 3 constructs are allowed:
         *     - N   : a single CPU number
         *     - N-M : a range of CPU numbers with N < M
         *     - ^N  : remove a single CPU number from the current set
         */
        if (*cur == '^') {
            cur++;
            neg = 1;
        }

        if ((*cur < '0') || (*cur > '9'))
            goto parse_error;
        start = parseCpuNumber(&cur, maxcpu);
        if (start < 0)
            goto parse_error;
        skipSpaces(&cur);
        if ((*cur == ',') || (*cur == 0) || (*cur == sep)) {
            if (neg) {
                if (cpuset[start] == 1) {
                    cpuset[start] = 0;
                    ret--;
                }
            } else {
                if (cpuset[start] == 0) {
                    cpuset[start] = 1;
                    ret++;
                }
            }
        } else if (*cur == '-') {
            if (neg)
                goto parse_error;
            cur++;
            skipSpaces(&cur);
            last = parseCpuNumber(&cur, maxcpu);
            if (last < start)
                goto parse_error;
            for (i = start; i <= last; i++) {
                if (cpuset[i] == 0) {
                    cpuset[i] = 1;
                    ret++;
                }
            }
            skipSpaces(&cur);
        }
        if (*cur == ',') {
            cur++;
            skipSpaces(&cur);
            neg = 0;
        } else if ((*cur == 0) || (*cur == sep)) {
            break;
        } else
            goto parse_error;
291 292
    }
    *str = cur;
293
    return (ret);
294

295
  parse_error:
296
    virXMLError(conn, VIR_ERR_XEN_CALL,
297 298
                _("topology cpuset syntax error"), 0);
    return (-1);
299 300 301 302
}

/**
 * virParseXenCpuTopology:
303
 * @conn: connection
304 305 306 307 308 309 310 311 312 313
 * @xml: XML output buffer
 * @str: the topology string 
 * @maxcpu: number of elements available in @cpuset
 *
 * Parse a Xend CPU topology string and build the associated XML
 * format.
 *
 * Returns 0 in case of success, -1 in case of error
 */
int
314 315
virParseXenCpuTopology(virConnectPtr conn, virBufferPtr xml,
                       const char *str, int maxcpu)
316 317 318 319 320 321
{
    const char *cur;
    char *cpuset = NULL;
    int cell, cpu, nb_cpus;
    int ret;

322 323
    if ((str == NULL) || (xml == NULL) || (maxcpu <= 0) || (maxcpu > 100000))
        return (-1);
324

325
    cpuset = malloc(maxcpu * sizeof(*cpuset));
326 327 328 329 330 331
    if (cpuset == NULL)
        goto memory_error;

    cur = str;
    while (*cur != 0) {
        /*
332 333
         * Find the next NUMA cell described in the xend output
         */
334
        cur = strstr(cur, "node");
335 336 337
        if (cur == NULL)
            break;
        cur += 4;
338
        cell = parseNumber(&cur);
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
        if (cell < 0)
            goto parse_error;
        skipSpaces(&cur);
        if (*cur != ':')
            goto parse_error;
        cur++;
        skipSpaces(&cur);
        if (!strncmp(cur, "no cpus", 7)) {
            nb_cpus = 0;
            for (cpu = 0; cpu < maxcpu; cpu++)
                cpuset[cpu] = 0;
        } else {
            nb_cpus = virParseCpuSet(conn, &cur, 'n', cpuset, maxcpu);
            if (nb_cpus < 0)
                goto error;
        }

        /*
         * add xml for all cpus associated with that cell
         */
        ret = virBufferVSprintf(xml, "\
360 361 362 363
      <cell id='%d'>\n\
        <cpus num='%d'>\n", cell, nb_cpus);
#ifdef STANDALONE
        {
364 365
            char *dump;

366
            dump = virSaveCpuSet(conn, cpuset, maxcpu);
367 368 369 370 371 372 373 374
            if (dump != NULL) {
                virBufferVSprintf(xml, "           <dump>%s</dump>\n",
                                  dump);
                free(dump);
            } else {
                virBufferVSprintf(xml, "           <error>%s</error>\n",
                                  "Failed to dump CPU set");
            }
375 376
        }
#endif
377 378 379 380 381
        if (ret < 0)
            goto memory_error;
        for (cpu = 0; cpu < maxcpu; cpu++) {
            if (cpuset[cpu] == 1) {
                ret = virBufferVSprintf(xml, "\
382
           <cpu id='%d'/>\n", cpu);
383 384 385 386 387
                if (ret < 0)
                    goto memory_error;
            }
        }
        ret = virBufferAdd(xml, "\
388 389 390
        </cpus>\n\
      </cell>\n", -1);
        if (ret < 0)
391 392
            goto memory_error;

393 394
    }
    free(cpuset);
395
    return (0);
396

397 398 399
  parse_error:
    virXMLError(conn, VIR_ERR_XEN_CALL, _("topology syntax error"), 0);
  error:
400 401 402
    if (cpuset != NULL)
        free(cpuset);

403
    return (-1);
404

405
  memory_error:
406 407 408
    if (cpuset != NULL)
        free(cpuset);
    virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 0);
409
    return (-1);
410 411
}

412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
/**
 * virConvertCpuSet:
 * @conn: connection
 * @str: pointer to a Xen or user provided CPU set string pointer
 * @maxcpu: number of CPUs on the node, if 0 4096 will be used
 *
 * Parse the given CPU set string and convert it to a range based
 * string.
 *
 * Returns a new string which must be freed by the caller or NULL in
 *         case of error.
 */
char *
virConvertCpuSet(virConnectPtr conn, const char *str, int maxcpu) {
    int ret;
    char *res, *cpuset;
    const char *cur = str;

    if (str == NULL)
        return(NULL);

    if (maxcpu <= 0)
        maxcpu = 4096;

436
    cpuset = calloc(maxcpu, sizeof(*cpuset));
437 438 439 440 441 442 443 444 445 446 447 448 449 450
    if (cpuset == NULL) {
	virXMLError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"), 0);
	return(NULL);
    }
    
    ret = virParseCpuSet(conn, &cur, 0, cpuset, maxcpu);
    if (ret < 0) {
        free(cpuset);
	return(NULL);
    }
    res = virSaveCpuSet(conn, cpuset, maxcpu);
    free(cpuset);
    return (res);
}
451
#endif /* WITH_XEN */
452
#ifndef PROXY
453 454 455 456 457 458 459

/************************************************************************
 *									*
 * Wrappers around libxml2 XPath specific functions			*
 *									*
 ************************************************************************/

460 461 462 463 464 465 466 467 468 469 470
/**
 * virXPathString:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 *
 * Convenience function to evaluate an XPath string
 *
 * Returns a new string which must be deallocated by the caller or NULL
 *         if the evaluation failed.
 */
char *
471 472
virXPathString(const char *xpath, xmlXPathContextPtr ctxt)
{
473 474 475 476
    xmlXPathObjectPtr obj;
    char *ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
477 478 479
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
                    "Invalid parameter to virXPathString()", 0);
        return (NULL);
480 481 482
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
D
Daniel P. Berrange 已提交
483 484 485
        (obj->stringval == NULL) || (obj->stringval[0] == 0)) {
        if (obj)
            xmlXPathFreeObject(obj);
486
        return (NULL);
D
Daniel P. Berrange 已提交
487
    }
488 489 490 491 492
    ret = strdup((char *) obj->stringval);
    xmlXPathFreeObject(obj);
    if (ret == NULL) {
        virXMLError(NULL, VIR_ERR_NO_MEMORY, "strdup", 0);
    }
493
    return (ret);
494 495 496 497 498 499 500 501 502 503 504 505 506 507
}

/**
 * virXPathNumber:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned double value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
 *         or -1 if the evaluation failed.
 */
int
508 509
virXPathNumber(const char *xpath, xmlXPathContextPtr ctxt, double *value)
{
510 511 512
    xmlXPathObjectPtr obj;

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
513 514 515
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
                    "Invalid parameter to virXPathNumber()", 0);
        return (-1);
516 517 518 519
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
        (isnan(obj->floatval))) {
520 521
        xmlXPathFreeObject(obj);
        return (-1);
522
    }
523

524 525
    *value = obj->floatval;
    xmlXPathFreeObject(obj);
526
    return (0);
527 528 529 530 531 532 533 534 535 536 537
}

/**
 * virXPathLong:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @value: the returned long value
 *
 * Convenience function to evaluate an XPath number
 *
 * Returns 0 in case of success in which case @value is set,
538 539
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
540 541
 */
int
542 543
virXPathLong(const char *xpath, xmlXPathContextPtr ctxt, long *value)
{
544 545 546 547
    xmlXPathObjectPtr obj;
    int ret = 0;

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
548 549 550
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
                    "Invalid parameter to virXPathNumber()", 0);
        return (-1);
551 552 553 554 555
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj != NULL) && (obj->type == XPATH_STRING) &&
        (obj->stringval != NULL) && (obj->stringval[0] != 0)) {
        char *conv = NULL;
556
        long val;
557

558 559
        val = strtol((const char *) obj->stringval, &conv, 10);
        if (conv == (const char *) obj->stringval) {
560 561
            ret = -2;
        } else {
562 563
            *value = val;
        }
564 565
    } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
               (!(isnan(obj->floatval)))) {
566 567 568 569
        *value = (long) obj->floatval;
        if (*value != obj->floatval) {
            ret = -2;
        }
570
    } else {
571
        ret = -1;
572
    }
573

574
    xmlXPathFreeObject(obj);
575
    return (ret);
576 577 578 579 580 581 582 583 584 585 586 587
}

/**
 * virXPathBoolean:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 *
 * Convenience function to evaluate an XPath boolean
 *
 * Returns 0 if false, 1 if true, or -1 if the evaluation failed.
 */
int
588 589
virXPathBoolean(const char *xpath, xmlXPathContextPtr ctxt)
{
590 591 592 593
    xmlXPathObjectPtr obj;
    int ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
594 595 596
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
                    "Invalid parameter to virXPathBoolean()", 0);
        return (-1);
597 598 599 600
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) ||
        (obj->boolval < 0) || (obj->boolval > 1)) {
601 602
        xmlXPathFreeObject(obj);
        return (-1);
603 604
    }
    ret = obj->boolval;
605

606
    xmlXPathFreeObject(obj);
607
    return (ret);
608 609 610 611 612 613 614 615 616 617 618 619 620
}

/**
 * virXPathNode:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 *
 * Convenience function to evaluate an XPath node set and returning
 * only one node, the first one in the set if any
 *
 * Returns a pointer to the node or NULL if the evaluation failed.
 */
xmlNodePtr
621 622
virXPathNode(const char *xpath, xmlXPathContextPtr ctxt)
{
623 624 625 626
    xmlXPathObjectPtr obj;
    xmlNodePtr ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
627 628 629
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
                    "Invalid parameter to virXPathNode()", 0);
        return (NULL);
630 631 632 633
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
634 635 636
        (obj->nodesetval->nodeTab == NULL)) {
        xmlXPathFreeObject(obj);
        return (NULL);
637
    }
638

639 640
    ret = obj->nodesetval->nodeTab[0];
    xmlXPathFreeObject(obj);
641
    return (ret);
642
}
643

644 645 646 647 648 649 650 651 652 653 654 655
/**
 * virXPathNodeSet:
 * @xpath: the XPath string to evaluate
 * @ctxt: an XPath context
 * @list: the returned list of nodes (or NULL if only count matters)
 *
 * Convenience function to evaluate an XPath node set
 *
 * Returns the number of nodes found in which case @list is set (and
 *         must be freed) or -1 if the evaluation failed.
 */
int
656 657 658
virXPathNodeSet(const char *xpath, xmlXPathContextPtr ctxt,
                xmlNodePtr ** list)
{
659 660 661 662
    xmlXPathObjectPtr obj;
    int ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
663 664 665
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR,
                    "Invalid parameter to virXPathNodeSet()", 0);
        return (-1);
666 667 668 669
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
670 671 672 673 674
        (obj->nodesetval->nodeTab == NULL)) {
        xmlXPathFreeObject(obj);
        if (list != NULL)
            *list = NULL;
        return (-1);
675
    }
676

677 678
    ret = obj->nodesetval->nodeNr;
    if (list != NULL) {
679
        *list = malloc(ret * sizeof(**list));
680 681 682
        if (*list == NULL) {
            virXMLError(NULL, VIR_ERR_NO_MEMORY,
                        _("allocate string array"),
683
                        ret * sizeof(**list));
684 685 686 687
        } else {
            memcpy(*list, obj->nodesetval->nodeTab,
                   ret * sizeof(xmlNodePtr));
        }
688 689
    }
    xmlXPathFreeObject(obj);
690
    return (ret);
691 692
}

693 694 695 696 697
/************************************************************************
 *									*
 * Converter functions to go from the XML tree to an S-Expr for Xen	*
 *									*
 ************************************************************************/
698
#if WITH_XEN
699
/**
700
 * virtDomainParseXMLGraphicsDescImage:
701
 * @conn: pointer to the hypervisor connection
702 703
 * @node: node containing graphics description
 * @buf: a buffer for the result S-Expr
704
 * @xendConfigVersion: xend configuration file format
705
 *
706 707 708
 * Parse the graphics part of the XML description and add it to the S-Expr
 * in buf.  This is a temporary interface as the S-Expr interface will be
 * replaced by XML-RPC in the future. However the XML format should stay
709 710 711 712
 * valid over time.
 *
 * Returns 0 in case of success, -1 in case of error
 */
713 714 715 716
static int
virDomainParseXMLGraphicsDescImage(virConnectPtr conn ATTRIBUTE_UNUSED,
                                   xmlNodePtr node, virBufferPtr buf,
                                   int xendConfigVersion)
717 718 719 720 721 722 723
{
    xmlChar *graphics_type = NULL;

    graphics_type = xmlGetProp(node, BAD_CAST "type");
    if (graphics_type != NULL) {
        if (xmlStrEqual(graphics_type, BAD_CAST "sdl")) {
            virBufferAdd(buf, "(sdl 1)", 7);
724 725 726 727 728 729
            /* TODO:
             * Need to understand sdl options
             *
             *virBufferAdd(buf, "(display localhost:10.0)", 24);
             *virBufferAdd(buf, "(xauthority /root/.Xauthority)", 30);
             */
730
        } else if (xmlStrEqual(graphics_type, BAD_CAST "vnc")) {
731
            virBufferAdd(buf, "(vnc 1)", 7);
732
            if (xendConfigVersion >= 2) {
733
                xmlChar *vncport = xmlGetProp(node, BAD_CAST "port");
734 735
                xmlChar *vnclisten = xmlGetProp(node, BAD_CAST "listen");
                xmlChar *vncpasswd = xmlGetProp(node, BAD_CAST "passwd");
736
                xmlChar *keymap = xmlGetProp(node, BAD_CAST "keymap");
737

738
                if (vncport != NULL) {
739 740
                    long port = strtol((const char *) vncport, NULL, 10);

741 742
                    if (port == -1)
                        virBufferAdd(buf, "(vncunused 1)", 13);
743
                    else if (port >= 5900)
744 745
                        virBufferVSprintf(buf, "(vncdisplay %ld)",
                                          port - 5900);
746
                    xmlFree(vncport);
747
                }
748 749 750 751 752 753 754 755
                if (vnclisten != NULL) {
                    virBufferVSprintf(buf, "(vnclisten %s)", vnclisten);
                    xmlFree(vnclisten);
                }
                if (vncpasswd != NULL) {
                    virBufferVSprintf(buf, "(vncpasswd %s)", vncpasswd);
                    xmlFree(vncpasswd);
                }
756 757 758 759
                if (keymap != NULL) {
                    virBufferVSprintf(buf, "(keymap %s)", keymap);
                    xmlFree(keymap);
                }
760 761
            }
        }
762 763 764 765 766 767
        xmlFree(graphics_type);
    }
    return 0;
}


768 769
/**
 * virtDomainParseXMLGraphicsDescVFB:
770
 * @conn: pointer to the hypervisor connection
771 772 773
 * @node: node containing graphics description
 * @buf: a buffer for the result S-Expr
 *
774 775 776
 * Parse the graphics part of the XML description and add it to the S-Expr
 * in buf.  This is a temporary interface as the S-Expr interface will be
 * replaced by XML-RPC in the future. However the XML format should stay
777 778 779 780
 * valid over time.
 *
 * Returns 0 in case of success, -1 in case of error
 */
781 782 783
static int
virDomainParseXMLGraphicsDescVFB(virConnectPtr conn ATTRIBUTE_UNUSED,
                                 xmlNodePtr node, virBufferPtr buf)
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
{
    xmlChar *graphics_type = NULL;

    graphics_type = xmlGetProp(node, BAD_CAST "type");
    if (graphics_type != NULL) {
        virBufferAdd(buf, "(device (vkbd))", 15);
        virBufferAdd(buf, "(device (vfb ", 13);
        if (xmlStrEqual(graphics_type, BAD_CAST "sdl")) {
            virBufferAdd(buf, "(type sdl)", 10);
            /* TODO:
             * Need to understand sdl options
             *
             *virBufferAdd(buf, "(display localhost:10.0)", 24);
             *virBufferAdd(buf, "(xauthority /root/.Xauthority)", 30);
             */
799
        } else if (xmlStrEqual(graphics_type, BAD_CAST "vnc")) {
800 801 802 803
            virBufferAdd(buf, "(type vnc)", 10);
            xmlChar *vncport = xmlGetProp(node, BAD_CAST "port");
            xmlChar *vnclisten = xmlGetProp(node, BAD_CAST "listen");
            xmlChar *vncpasswd = xmlGetProp(node, BAD_CAST "passwd");
804
            xmlChar *keymap = xmlGetProp(node, BAD_CAST "keymap");
805

806
            if (vncport != NULL) {
807 808
                long port = strtol((const char *) vncport, NULL, 10);

809 810
                if (port == -1)
                    virBufferAdd(buf, "(vncunused 1)", 13);
811
                else if (port >= 5900)
812 813
                    virBufferVSprintf(buf, "(vncdisplay %ld)",
                                      port - 5900);
814 815 816 817 818 819 820 821 822 823
                xmlFree(vncport);
            }
            if (vnclisten != NULL) {
                virBufferVSprintf(buf, "(vnclisten %s)", vnclisten);
                xmlFree(vnclisten);
            }
            if (vncpasswd != NULL) {
                virBufferVSprintf(buf, "(vncpasswd %s)", vncpasswd);
                xmlFree(vncpasswd);
            }
824 825 826 827
            if (keymap != NULL) {
                virBufferVSprintf(buf, "(keymap %s)", keymap);
                xmlFree(keymap);
            }
828 829 830 831 832 833 834 835
        }
        virBufferAdd(buf, "))", 2);
        xmlFree(graphics_type);
    }
    return 0;
}


836
/**
837
 * virDomainParseXMLOSDescHVM:
838
 * @conn: pointer to the hypervisor connection
839
 * @node: node containing HVM OS description
840
 * @buf: a buffer for the result S-Expr
841
 * @ctxt: a path context representing the XML description
842
 * @vcpus: number of virtual CPUs to configure
843
 * @xendConfigVersion: xend configuration file format
844
 *
845 846
 * Parse the OS part of the XML description for an HVM domain and add it to
 * the S-Expr in buf. This is a temporary interface as the S-Expr interface
847 848 849 850 851 852
 * will be replaced by XML-RPC in the future. However the XML format should
 * stay valid over time.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
static int
853 854 855
virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node,
                           virBufferPtr buf, xmlXPathContextPtr ctxt,
                           int vcpus, int xendConfigVersion)
856 857
{
    xmlNodePtr cur, txt;
858
    xmlNodePtr *nodes = NULL;
859 860
    xmlChar *type = NULL;
    xmlChar *loader = NULL;
861 862
    char bootorder[5];
    int nbootorder = 0;
863
    int res, nb_nodes;
864
    char *str;
865 866 867 868

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
869 870
            if ((type == NULL) &&
	        (xmlStrEqual(cur->name, BAD_CAST "type"))) {
871 872
                txt = cur->children;
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
873
                    (txt->next == NULL))
874 875 876 877 878
                    type = txt->content;
            } else if ((loader == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "loader"))) {
                txt = cur->children;
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
879
                    (txt->next == NULL))
880
                    loader = txt->content;
881 882
            } else if ((xmlStrEqual(cur->name, BAD_CAST "boot"))) {
                xmlChar *boot_dev = xmlGetProp(cur, BAD_CAST "dev");
883 884 885 886 887

                if (nbootorder ==
                    ((sizeof(bootorder) / sizeof(bootorder[0])) - 1)) {
                    virXMLError(conn, VIR_ERR_XML_ERROR,
                                "too many boot devices", 0);
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
                    return (-1);
                }
                if (xmlStrEqual(boot_dev, BAD_CAST "fd")) {
                    bootorder[nbootorder++] = 'a';
                } else if (xmlStrEqual(boot_dev, BAD_CAST "cdrom")) {
                    bootorder[nbootorder++] = 'd';
                } else if (xmlStrEqual(boot_dev, BAD_CAST "network")) {
                    bootorder[nbootorder++] = 'n';
                } else if (xmlStrEqual(boot_dev, BAD_CAST "hd")) {
                    bootorder[nbootorder++] = 'c';
                } else {
                    xmlFree(boot_dev);
                    /* Any other type of boot dev is unsupported right now */
                    virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0);
                    return (-1);
                }
                xmlFree(boot_dev);
905 906 907 908
            }
        }
        cur = cur->next;
    }
909
    bootorder[nbootorder] = '\0';
910 911
    if ((type == NULL) || (!xmlStrEqual(type, BAD_CAST "hvm"))) {
        /* VIR_ERR_OS_TYPE */
912
        virXMLError(conn, VIR_ERR_OS_TYPE, (const char *) type, 0);
913 914 915 916
        return (-1);
    }
    virBufferAdd(buf, "(image (hvm ", 12);
    if (loader == NULL) {
917
        virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0);
918
        goto error;
919
    } else {
920
        virBufferVSprintf(buf, "(kernel '%s')", (const char *) loader);
921 922 923
    }

    /* get the device emulation model */
924 925
    str = virXPathString("string(/domain/devices/emulator[1])", ctxt);
    if (str == NULL) {
926
        virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0);  /* TODO: error */
927 928
        goto error;
    }
929 930
    virBufferVSprintf(buf, "(device_model '%s')", str);
    xmlFree(str);
931

932 933
    virBufferVSprintf(buf, "(vcpus %d)", vcpus);

934 935
    if (nbootorder)
        virBufferVSprintf(buf, "(boot %s)", bootorder);
936

937
    /* get the 1st floppy device file */
938 939 940 941
    cur = virXPathNode(
         "/domain/devices/disk[@device='floppy' and target/@dev='fda']/source",
         ctxt);
    if (cur != NULL) {
942
        xmlChar *fdfile;
943

944
        fdfile = xmlGetProp(cur, BAD_CAST "file");
945
        if (fdfile != NULL) {
946 947
            virBufferVSprintf(buf, "(fda '%s')", fdfile);
            free(fdfile);
948
        }
949
    }
950

951
    /* get the 2nd floppy device file */
952 953 954 955
    cur = virXPathNode(
         "/domain/devices/disk[@device='floppy' and target/@dev='fdb']/source",
         ctxt);
    if (cur != NULL) {
956
        xmlChar *fdfile;
957

958
        fdfile = xmlGetProp(cur, BAD_CAST "file");
959
        if (fdfile != NULL) {
960 961
            virBufferVSprintf(buf, "(fdb '%s')", fdfile);
            free(fdfile);
962
        }
963
    }
964 965


966 967 968
    /* get the cdrom device file */
    /* Only XenD <= 3.0.2 wants cdrom config here */
    if (xendConfigVersion == 1) {
969 970 971 972
        cur = virXPathNode(
	  "/domain/devices/disk[@device='cdrom' and target/@dev='hdc']/source",
             ctxt);
        if (cur != NULL) {
973 974 975 976 977
            xmlChar *cdfile;

            cdfile = xmlGetProp(cur, BAD_CAST "file");
            if (cdfile != NULL) {
                virBufferVSprintf(buf, "(cdrom '%s')",
978
                                  (const char *) cdfile);
979
                xmlFree(cdfile);
980 981
            }
        }
982 983
    }

984 985 986 987 988 989 990
    if (virXPathNode("/domain/features/acpi", ctxt) != NULL)
        virBufferAdd(buf, "(acpi 1)", 8);
    if (virXPathNode("/domain/features/apic", ctxt) != NULL)
        virBufferAdd(buf, "(apic 1)", 8);
    if (virXPathNode("/domain/features/pae", ctxt) != NULL)
        virBufferAdd(buf, "(pae 1)", 7);

991 992 993 994
    virBufferAdd(buf, "(usb 1)", 7);
    nb_nodes = virXPathNodeSet("/domain/devices/input", ctxt, &nodes);
    if (nb_nodes > 0) {
        int i;
995

996 997 998 999
        for (i = 0; i < nb_nodes; i++) {
            xmlChar *itype = NULL, *bus = NULL;
            int isMouse = 1;

1000
            itype = xmlGetProp(nodes[i], (xmlChar *) "type");
1001 1002 1003 1004

            if (!itype) {
                goto error;
            }
1005
            if (!strcmp((const char *) itype, "tablet"))
1006
                isMouse = 0;
1007
            else if (strcmp((const char *) itype, "mouse")) {
1008 1009 1010 1011 1012 1013
                xmlFree(itype);
                virXMLError(conn, VIR_ERR_XML_ERROR, "input", 0);
                goto error;
            }
            xmlFree(itype);

1014
            bus = xmlGetProp(nodes[i], (xmlChar *) "bus");
1015 1016 1017 1018 1019 1020 1021
            if (!bus) {
                if (!isMouse) {
                    /* Nothing - implicit ps2 */
                } else {
                    virBufferAdd(buf, "(usbdevice tablet)", 13);
                }
            } else {
1022
                if (!strcmp((const char *) bus, "ps2")) {
1023 1024 1025 1026 1027 1028
                    if (!isMouse) {
                        xmlFree(bus);
                        virXMLError(conn, VIR_ERR_XML_ERROR, "input", 0);
                        goto error;
                    }
                    /* Nothing - implicit ps2 */
1029
                } else if (!strcmp((const char *) bus, "usb")) {
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
                    if (isMouse)
                        virBufferAdd(buf, "(usbdevice mouse)", 17);
                    else
                        virBufferAdd(buf, "(usbdevice tablet)", 18);
                }
            }
            xmlFree(bus);
        }
        free(nodes);
        nodes = NULL;
    }


1043 1044
    res = virXPathBoolean("count(domain/devices/console) > 0", ctxt);
    if (res < 0) {
1045
        virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0);
1046
        goto error;
1047
    }
1048
    if (res) {
1049
        virBufferAdd(buf, "(serial pty)", 12);
1050
    }
1051

1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
    /* HVM graphics for xen <= 3.0.5 */
    if (xendConfigVersion < 4) {
        /* Is a graphics device specified? */
        cur = virXPathNode("/domain/devices/graphics[1]", ctxt);
        if (cur != NULL) {
            res = virDomainParseXMLGraphicsDescImage(conn, cur, buf,
                                                     xendConfigVersion);
            if (res != 0) {
                goto error;
            }
1062 1063 1064
        }
    }

1065 1066 1067 1068
    str = virXPathString("string(/domain/clock/@offset)", ctxt);
    if (str != NULL && !strcmp(str, "localtime")) {
        virBufferAdd(buf, "(localtime 1)", 13);
    }
D
Daniel P. Berrange 已提交
1069 1070
    if (str)
        free(str);
1071

1072 1073 1074
    virBufferAdd(buf, "))", 2);

    return (0);
1075

1076
  error:
1077 1078
    if (nodes)
        free(nodes);
1079
    return (-1);
1080 1081 1082 1083
}

/**
 * virDomainParseXMLOSDescPV:
1084
 * @conn: pointer to the hypervisor connection
1085 1086
 * @node: node containing PV OS description
 * @buf: a buffer for the result S-Expr
1087
 * @ctxt: a path context representing the XML description
1088
 * @xendConfigVersion: xend configuration file format
1089 1090 1091 1092 1093 1094 1095 1096 1097
 *
 * Parse the OS part of the XML description for a paravirtualized domain
 * and add it to the S-Expr in buf.  This is a temporary interface as the
 * S-Expr interface will be replaced by XML-RPC in the future. However
 * the XML format should stay valid over time.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
static int
1098 1099 1100
virDomainParseXMLOSDescPV(virConnectPtr conn, xmlNodePtr node,
                          virBufferPtr buf, xmlXPathContextPtr ctxt,
                          int xendConfigVersion)
1101
{
1102 1103 1104 1105 1106 1107
    xmlNodePtr cur, txt;
    const xmlChar *type = NULL;
    const xmlChar *root = NULL;
    const xmlChar *kernel = NULL;
    const xmlChar *initrd = NULL;
    const xmlChar *cmdline = NULL;
1108
    int res;
1109 1110 1111 1112

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
1113 1114 1115
            if ((type == NULL)
                && (xmlStrEqual(cur->name, BAD_CAST "type"))) {
                txt = cur->children;
1116
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
1117
                    (txt->next == NULL))
1118 1119 1120 1121
                    type = txt->content;
            } else if ((kernel == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "kernel"))) {
                txt = cur->children;
1122
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
1123
                    (txt->next == NULL))
1124 1125 1126 1127
                    kernel = txt->content;
            } else if ((root == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "root"))) {
                txt = cur->children;
1128
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
1129
                    (txt->next == NULL))
1130 1131 1132 1133
                    root = txt->content;
            } else if ((initrd == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "initrd"))) {
                txt = cur->children;
1134
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
1135
                    (txt->next == NULL))
1136 1137 1138 1139
                    initrd = txt->content;
            } else if ((cmdline == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "cmdline"))) {
                txt = cur->children;
1140
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
1141
                    (txt->next == NULL))
1142 1143 1144
                    cmdline = txt->content;
            }
        }
1145 1146 1147 1148
        cur = cur->next;
    }
    if ((type != NULL) && (!xmlStrEqual(type, BAD_CAST "linux"))) {
        /* VIR_ERR_OS_TYPE */
1149
        virXMLError(conn, VIR_ERR_OS_TYPE, (const char *) type, 0);
1150
        return (-1);
1151
    }
1152
    virBufferAdd(buf, "(image (linux ", 14);
1153
    if (kernel == NULL) {
1154
        virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0);
1155
        return (-1);
1156
    } else {
1157
        virBufferVSprintf(buf, "(kernel '%s')", (const char *) kernel);
1158 1159
    }
    if (initrd != NULL)
1160
        virBufferVSprintf(buf, "(ramdisk '%s')", (const char *) initrd);
1161
    if (root != NULL)
1162
        virBufferVSprintf(buf, "(root '%s')", (const char *) root);
1163
    if (cmdline != NULL)
1164
        virBufferVSprintf(buf, "(args '%s')", (const char *) cmdline);
1165

1166
    /* PV graphics for xen <= 3.0.4 */
1167
    if (xendConfigVersion < 3) {
1168 1169 1170
        cur = virXPathNode("/domain/devices/graphics[1]", ctxt);
        if (cur != NULL) {
            res = virDomainParseXMLGraphicsDescImage(conn, cur, buf,
1171
                                                     xendConfigVersion);
1172 1173 1174
            if (res != 0) {
                goto error;
            }
1175 1176 1177
        }
    }

1178
  error:
1179
    virBufferAdd(buf, "))", 2);
1180
    return (0);
1181 1182
}

1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
/**
 * virCatchXMLParseError:
 * @ctx: the context
 * @msg: the error message
 * @...: extra arguments
 *
 * SAX callback on parsing errors, act as a gate for libvirt own
 * error reporting.
 */
static void
1193 1194
virCatchXMLParseError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
{
1195 1196
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;

1197
    if ((ctxt != NULL) &&
1198
        (ctxt->lastError.level == XML_ERR_FATAL) &&
1199
        (ctxt->lastError.message != NULL)) {
1200
        virXMLError(NULL, VIR_ERR_XML_DETAIL, ctxt->lastError.message,
1201
                    ctxt->lastError.line);
1202 1203 1204
    }
}

1205 1206
/**
 * virDomainParseXMLDiskDesc:
1207
 * @node: node containing disk description
1208
 * @conn: pointer to the hypervisor connection
1209
 * @buf: a buffer for the result S-Expr
1210
 * @xendConfigVersion: xend configuration file format
1211 1212 1213 1214 1215 1216 1217 1218 1219
 *
 * Parse the one disk in the XML description and add it to the S-Expr in buf
 * This is a temporary interface as the S-Expr interface
 * will be replaced by XML-RPC in the future. However the XML format should
 * stay valid over time.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
static int
1220 1221
virDomainParseXMLDiskDesc(virConnectPtr conn, xmlNodePtr node,
                          virBufferPtr buf, int hvm, int xendConfigVersion)
1222
{
1223 1224
    xmlNodePtr cur;
    xmlChar *type = NULL;
1225
    xmlChar *device = NULL;
1226 1227
    xmlChar *source = NULL;
    xmlChar *target = NULL;
1228 1229
    xmlChar *drvName = NULL;
    xmlChar *drvType = NULL;
1230
    int ro = 0;
1231
    int shareable = 0;
1232
    int typ = 0;
1233
    int cdrom = 0;
1234
    int isNoSrcCdrom = 0;
1235
    int ret = 0;
1236 1237 1238

    type = xmlGetProp(node, BAD_CAST "type");
    if (type != NULL) {
1239 1240 1241 1242 1243
        if (xmlStrEqual(type, BAD_CAST "file"))
            typ = 0;
        else if (xmlStrEqual(type, BAD_CAST "block"))
            typ = 1;
        xmlFree(type);
1244
    }
1245
    device = xmlGetProp(node, BAD_CAST "device");
1246

1247 1248 1249
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259
            if ((source == NULL) &&
                (xmlStrEqual(cur->name, BAD_CAST "source"))) {

                if (typ == 0)
                    source = xmlGetProp(cur, BAD_CAST "file");
                else
                    source = xmlGetProp(cur, BAD_CAST "dev");
            } else if ((target == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "target"))) {
                target = xmlGetProp(cur, BAD_CAST "dev");
1260 1261 1262
            } else if ((drvName == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "driver"))) {
                drvName = xmlGetProp(cur, BAD_CAST "name");
1263
                if (drvName && !strcmp((const char *) drvName, "tap"))
1264
                    drvType = xmlGetProp(cur, BAD_CAST "type");
1265 1266
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
                ro = 1;
1267
            } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
1268
                shareable = 1;
1269 1270
            }
        }
1271 1272 1273 1274
        cur = cur->next;
    }

    if (source == NULL) {
1275 1276 1277
        /* There is a case without the source
         * to the CD-ROM device
         */
1278
        if (hvm && device && !strcmp((const char *) device, "cdrom")) {
1279 1280 1281 1282
            isNoSrcCdrom = 1;
        }
        if (!isNoSrcCdrom) {
            virXMLError(conn, VIR_ERR_NO_SOURCE, (const char *) target, 0);
1283 1284
            ret = -1;
            goto cleanup;
1285
        }
1286 1287
    }
    if (target == NULL) {
1288
        virXMLError(conn, VIR_ERR_NO_TARGET, (const char *) source, 0);
1289 1290
        ret = -1;
        goto cleanup;
1291
    }
1292

1293 1294
    /* Xend (all versions) put the floppy device config
     * under the hvm (image (os)) block
1295
     */
1296
    if (hvm && device && !strcmp((const char *) device, "floppy")) {
1297
        goto cleanup;
1298 1299 1300
    }

    /* Xend <= 3.0.2 doesn't include cdrom config here */
1301
    if (hvm && device && !strcmp((const char *) device, "cdrom")) {
1302
        if (xendConfigVersion == 1)
1303
            goto cleanup;
1304 1305
        else
            cdrom = 1;
1306 1307 1308 1309
    }


    virBufferAdd(buf, "(device ", 8);
1310
    /* Normally disks are in a (device (vbd ...)) block
1311 1312 1313
     * but blktap disks ended up in a differently named
     * (device (tap ....)) block.... */
    if (drvName && !strcmp((const char *) drvName, "tap")) {
1314 1315 1316 1317
        virBufferAdd(buf, "(tap ", 5);
    } else {
        virBufferAdd(buf, "(vbd ", 5);
    }
1318

1319
    if (hvm) {
1320 1321
        char *tmp = (char *) target;

1322
        /* Just in case user mistakenly still puts ioemu: in their XML */
1323 1324
        if (!strncmp((const char *) tmp, "ioemu:", 6))
            tmp += 6;
1325 1326 1327

        /* Xend <= 3.0.2 wants a ioemu: prefix on devices for HVM */
        if (xendConfigVersion == 1)
1328 1329 1330 1331
            virBufferVSprintf(buf, "(dev 'ioemu:%s')", (const char *) tmp);
        else                    /* But newer does not */
            virBufferVSprintf(buf, "(dev '%s%s')", (const char *) tmp,
                              cdrom ? ":cdrom" : ":disk");
1332
    } else
1333
        virBufferVSprintf(buf, "(dev '%s')", (const char *) target);
1334

1335
    if (drvName && !isNoSrcCdrom) {
1336
        if (!strcmp((const char *) drvName, "tap")) {
1337
            virBufferVSprintf(buf, "(uname '%s:%s:%s')",
1338 1339 1340
                              (const char *) drvName,
                              (drvType ? (const char *) drvType : "aio"),
                              (const char *) source);
1341 1342
        } else {
            virBufferVSprintf(buf, "(uname '%s:%s')",
1343 1344
                              (const char *) drvName,
                              (const char *) source);
1345
        }
1346
    } else if (!isNoSrcCdrom) {
1347 1348 1349 1350 1351 1352 1353 1354
        if (typ == 0)
            virBufferVSprintf(buf, "(uname 'file:%s')", source);
        else if (typ == 1) {
            if (source[0] == '/')
                virBufferVSprintf(buf, "(uname 'phy:%s')", source);
            else
                virBufferVSprintf(buf, "(uname 'phy:/dev/%s')", source);
        }
1355
    }
1356
    if (ro == 1)
1357
        virBufferVSprintf(buf, "(mode 'r')");
1358 1359 1360 1361
    else if (shareable == 1)
        virBufferVSprintf(buf, "(mode 'w!')");
    else
        virBufferVSprintf(buf, "(mode 'w')");
1362

1363
    virBufferAdd(buf, ")", 1);
1364
    virBufferAdd(buf, ")", 1);
1365

1366 1367
  cleanup:
    if (drvType)
1368
        xmlFree(drvType);
1369
    if (drvName)
1370
        xmlFree(drvName);
1371
    if (device)
1372
        xmlFree(device);
1373
    if (target)
1374
        xmlFree(target);
1375
    if (source)
1376 1377
        xmlFree(source);
    return (ret);
1378 1379 1380 1381
}

/**
 * virDomainParseXMLIfDesc:
1382
 * @conn: pointer to the hypervisor connection
1383
 * @node: node containing the interface description
1384
 * @buf: a buffer for the result S-Expr
1385
 * @xendConfigVersion: xend configuration file format
1386 1387 1388 1389 1390 1391 1392 1393 1394
 *
 * Parse the one interface the XML description and add it to the S-Expr in buf
 * This is a temporary interface as the S-Expr interface
 * will be replaced by XML-RPC in the future. However the XML format should
 * stay valid over time.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
static int
1395 1396 1397
virDomainParseXMLIfDesc(virConnectPtr conn ATTRIBUTE_UNUSED,
                        xmlNodePtr node, virBufferPtr buf, int hvm,
                        int xendConfigVersion)
1398
{
1399 1400 1401 1402 1403
    xmlNodePtr cur;
    xmlChar *type = NULL;
    xmlChar *source = NULL;
    xmlChar *mac = NULL;
    xmlChar *script = NULL;
1404
    xmlChar *ip = NULL;
1405
    int typ = 0;
1406
    int ret = -1;
1407 1408 1409

    type = xmlGetProp(node, BAD_CAST "type");
    if (type != NULL) {
1410 1411 1412 1413
        if (xmlStrEqual(type, BAD_CAST "bridge"))
            typ = 0;
        else if (xmlStrEqual(type, BAD_CAST "ethernet"))
            typ = 1;
1414 1415
        else if (xmlStrEqual(type, BAD_CAST "network"))
            typ = 2;
1416
        xmlFree(type);
1417 1418 1419 1420
    }
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
1421 1422 1423 1424
            if ((source == NULL) &&
                (xmlStrEqual(cur->name, BAD_CAST "source"))) {
                if (typ == 0)
                    source = xmlGetProp(cur, BAD_CAST "bridge");
1425
                else if (typ == 1)
1426
                    source = xmlGetProp(cur, BAD_CAST "dev");
1427 1428
                else
                    source = xmlGetProp(cur, BAD_CAST "network");
1429 1430 1431 1432 1433 1434
            } else if ((mac == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "mac"))) {
                mac = xmlGetProp(cur, BAD_CAST "address");
            } else if ((script == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "script"))) {
                script = xmlGetProp(cur, BAD_CAST "path");
1435 1436 1437
            } else if ((ip == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "ip"))) {
                /* XXX in future expect to need to have > 1 ip
1438 1439 1440
                 * address element - eg ipv4 & ipv6. For now
                 * xen only supports a single address though
                 * so lets ignore that complication */
1441
                ip = xmlGetProp(cur, BAD_CAST "address");
1442 1443
            }
        }
1444 1445 1446 1447
        cur = cur->next;
    }

    virBufferAdd(buf, "(vif ", 5);
1448 1449
    if (mac != NULL) {
        unsigned int addr[12];
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463
        int tmp = sscanf((const char *) mac,
		     "%01x%01x:%01x%01x:%01x%01x:%01x%01x:%01x%01x:%01x%01x",
                         (unsigned int *) &addr[0],
                         (unsigned int *) &addr[1],
                         (unsigned int *) &addr[2],
                         (unsigned int *) &addr[3],
                         (unsigned int *) &addr[4],
                         (unsigned int *) &addr[5],
                         (unsigned int *) &addr[6],
                         (unsigned int *) &addr[7],
                         (unsigned int *) &addr[8],
                         (unsigned int *) &addr[9],
                         (unsigned int *) &addr[10],
                         (unsigned int *) &addr[11]);
1464 1465 1466 1467
        if (tmp != 12 || strlen((const char *) mac) != 17) {
            virXMLError(conn, VIR_ERR_INVALID_MAC, (const char *) mac, 0);
            goto error;
        }
1468
        virBufferVSprintf(buf, "(mac '%s')", (const char *) mac);
1469
    }
1470
    if (source != NULL) {
1471 1472
        if (typ == 0)
            virBufferVSprintf(buf, "(bridge '%s')", (const char *) source);
1473
        else if (typ == 1)      /* TODO does that work like that ? */
1474
            virBufferVSprintf(buf, "(dev '%s')", (const char *) source);
1475
        else {
1476 1477
            virNetworkPtr network =
                virNetworkLookupByName(conn, (const char *) source);
1478
            char *bridge;
1479

1480
            if (!network || !(bridge = virNetworkGetBridgeName(network))) {
1481 1482
                if (network)
                    virNetworkFree(network);
1483 1484
                virXMLError(conn, VIR_ERR_NO_SOURCE, (const char *) source,
                            0);
1485 1486
                goto error;
            }
1487
            virNetworkFree(network);
1488 1489 1490
            virBufferVSprintf(buf, "(bridge '%s')", bridge);
            free(bridge);
        }
1491 1492 1493
    }
    if (script != NULL)
        virBufferVSprintf(buf, "(script '%s')", script);
1494 1495
    if (ip != NULL)
        virBufferVSprintf(buf, "(ip '%s')", ip);
1496 1497 1498 1499 1500
    /*
     * apparently (type ioemu) breaks paravirt drivers on HVM so skip this
     * from Xen 3.1.0
     */
    if ((hvm) && (xendConfigVersion < 4))
1501
        virBufferAdd(buf, "(type ioemu)", 12);
1502 1503

    virBufferAdd(buf, ")", 1);
1504
    ret = 0;
1505
  error:
1506
    if (mac != NULL)
1507
        xmlFree(mac);
1508
    if (source != NULL)
1509
        xmlFree(source);
1510
    if (script != NULL)
1511
        xmlFree(script);
1512 1513
    if (ip != NULL)
        xmlFree(ip);
1514
    return (ret);
1515 1516 1517 1518
}

/**
 * virDomainParseXMLDesc:
1519
 * @conn: pointer to the hypervisor connection
1520
 * @xmldesc: string with the XML description
1521
 * @xendConfigVersion: xend configuration file format
1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
 *
 * Parse the XML description and turn it into the xend sexp needed to
 * create the comain. This is a temporary interface as the S-Expr interface
 * will be replaced by XML-RPC in the future. However the XML format should
 * stay valid over time.
 *
 * Returns the 0 terminatedi S-Expr string or NULL in case of error.
 *         the caller must free() the returned value.
 */
char *
1532 1533
virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name,
                      int xendConfigVersion)
1534
{
1535 1536
    xmlDocPtr xml = NULL;
    xmlNodePtr node;
1537
    char *nam = NULL;
1538 1539
    virBuffer buf;
    xmlChar *prop;
1540
    xmlParserCtxtPtr pctxt;
1541 1542
    xmlXPathContextPtr ctxt = NULL;
    int i, res;
1543
    int bootloader = 0;
1544
    int hvm = 0;
1545
    unsigned int vcpus = 1;
1546
    unsigned long mem = 0, max_mem = 0;
1547 1548 1549 1550
    char *str;
    double f;
    xmlNodePtr *nodes;
    int nb_nodes;
1551 1552

    if (name != NULL)
1553
        *name = NULL;
1554 1555
    buf.content = malloc(1000);
    if (buf.content == NULL)
1556
        return (NULL);
1557 1558 1559
    buf.size = 1000;
    buf.use = 0;

1560 1561 1562 1563 1564
    pctxt = xmlNewParserCtxt();
    if ((pctxt == NULL) || (pctxt->sax == NULL)) {
        goto error;
    }

1565 1566 1567
    /* TODO pass the connection point to the error handler:
     *   pctxt->userData = virConnectPtr;
     */
1568 1569
    pctxt->sax->error = virCatchXMLParseError;

1570 1571
    xml = xmlCtxtReadDoc(pctxt, (const xmlChar *) xmldesc, "domain.xml",
                         NULL, XML_PARSE_NOENT | XML_PARSE_NONET |
1572
                         XML_PARSE_NOWARNING);
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582
    if (xml == NULL) {
        goto error;
    }
    node = xmlDocGetRootElement(xml);
    if ((node == NULL) || (!xmlStrEqual(node->name, BAD_CAST "domain")))
        goto error;

    prop = xmlGetProp(node, BAD_CAST "type");
    if (prop != NULL) {
        if (!xmlStrEqual(prop, BAD_CAST "xen")) {
1583 1584 1585 1586
            xmlFree(prop);
            goto error;
        }
        xmlFree(prop);
1587 1588 1589 1590 1591 1592 1593
    }
    virBufferAdd(&buf, "(vm ", 4);
    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
        goto error;
    }
    /*
1594
     * extract some of the basics, name, memory, cpus ...
1595
     */
1596
    nam = virXPathString("string(/domain/name[1])", ctxt);
1597
    if (nam == NULL) {
1598
        virXMLError(conn, VIR_ERR_NO_NAME, xmldesc, 0);
1599
        goto error;
1600
    }
1601
    virBufferVSprintf(&buf, "(name '%s')", nam);
1602

1603 1604
    if ((virXPathNumber("number(/domain/memory[1])", ctxt, &f) < 0) ||
        (f < MIN_XEN_GUEST_SIZE * 1024)) {
1605
        max_mem = 128;
1606
    } else {
1607
        max_mem = (f / 1024);
1608
    }
1609

1610 1611
    if ((virXPathNumber("number(/domain/currentMemory[1])", ctxt, &f) < 0)
        || (f < MIN_XEN_GUEST_SIZE * 1024)) {
1612 1613
        mem = max_mem;
    } else {
1614
        mem = (f / 1024);
1615 1616 1617
        if (mem > max_mem) {
            max_mem = mem;
        }
1618
    }
1619
    virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)", mem, max_mem);
1620

1621 1622 1623
    if ((virXPathNumber("number(/domain/vcpu[1])", ctxt, &f) == 0) &&
        (f > 0)) {
        vcpus = (unsigned int) f;
1624
    }
1625
    virBufferVSprintf(&buf, "(vcpus %u)", vcpus);
1626

1627 1628 1629
    str = virXPathString("string(/domain/vcpu/@cpuset)", ctxt);
    if (str != NULL) {
        int maxcpu = xenNbCpus(conn);
1630 1631 1632 1633 1634 1635 1636 1637 1638
        char *cpuset = NULL;
        char *ranges = NULL;
        const char *cur = str;

        /*
         * Parse the CPUset attribute given in libvirt format and reserialize
         * it in a range format guaranteed to be understood by Xen.
         */
        if (maxcpu > 0) {
1639
            cpuset = malloc(maxcpu * sizeof(*cpuset));
1640 1641 1642
            if (cpuset != NULL) {
                res = virParseCpuSet(conn, &cur, 0, cpuset, maxcpu);
                if (res > 0) {
1643
                    ranges = virSaveCpuSet(conn, cpuset, maxcpu);
1644 1645 1646 1647 1648 1649
                    if (ranges != NULL) {
                        virBufferVSprintf(&buf, "(cpus '%s')", ranges);
                        free(ranges);
                    }
                }
                free(cpuset);
1650 1651
                if (res < 0) 
                    goto error;
1652 1653 1654 1655
            } else {
                virXMLError(conn, VIR_ERR_NO_MEMORY, xmldesc, 0);
            }
        }
1656 1657 1658
        free(str);
    }

1659 1660 1661
    str = virXPathString("string(/domain/uuid[1])", ctxt);
    if (str != NULL) {
        virBufferVSprintf(&buf, "(uuid '%s')", str);
1662
        free(str);
1663 1664
    }

1665 1666 1667
    str = virXPathString("string(/domain/bootloader[1])", ctxt);
    if (str != NULL) {
        virBufferVSprintf(&buf, "(bootloader '%s')", str);
1668
        /*
1669
         * if using a bootloader, the kernel and initrd strings are not
1670 1671
         * significant and should be discarded
         */
1672
        bootloader = 1;
1673 1674 1675
        free(str);
    } else if (virXPathNumber("count(/domain/bootloader)", ctxt, &f) == 0
               && (f > 0)) {
D
Daniel P. Berrange 已提交
1676 1677 1678 1679 1680
        virBufferVSprintf(&buf, "(bootloader)");
        /*
         * if using a bootloader, the kernel and initrd strings are not
         * significant and should be discarded
         */
1681
        bootloader = 1;
1682 1683 1684 1685 1686 1687 1688 1689
    }

    str = virXPathString("string(/domain/bootloader_args[1])", ctxt);
    if (str != NULL && bootloader) {
        /*
         * ignore the bootloader_args value unless a bootloader was specified
         */
        virBufferVSprintf(&buf, "(bootloader_args '%s')", str);
1690
        free(str);
1691 1692
    }

1693 1694 1695
    str = virXPathString("string(/domain/on_poweroff[1])", ctxt);
    if (str != NULL) {
        virBufferVSprintf(&buf, "(on_poweroff '%s')", str);
1696
        free(str);
1697 1698
    }

1699 1700 1701
    str = virXPathString("string(/domain/on_reboot[1])", ctxt);
    if (str != NULL) {
        virBufferVSprintf(&buf, "(on_reboot '%s')", str);
1702
        free(str);
1703 1704
    }

1705 1706 1707
    str = virXPathString("string(/domain/on_crash[1])", ctxt);
    if (str != NULL) {
        virBufferVSprintf(&buf, "(on_crash '%s')", str);
1708
        free(str);
1709 1710
    }

1711
    if (!bootloader) {
1712
        if ((node = virXPathNode("/domain/os[1]", ctxt)) != NULL) {
1713
            /* Analyze of the os description, based on HVM or PV. */
1714
            str = virXPathString("string(/domain/os/type[1])", ctxt);
1715

1716 1717
            if ((str == NULL) || (strcmp(str, "hvm"))) {
                res = virDomainParseXMLOSDescPV(conn, node,
1718 1719
                                                &buf, ctxt,
                                                xendConfigVersion);
1720 1721
            } else {
                hvm = 1;
1722
                res = virDomainParseXMLOSDescHVM(conn, node, &buf, ctxt,
1723
                                                 vcpus, xendConfigVersion);
1724 1725
            }

1726 1727
            if (str != NULL)
                free(str);
1728 1729 1730

            if (res != 0)
                goto error;
1731
        } else {
1732
            virXMLError(conn, VIR_ERR_NO_OS, nam, 0);
1733 1734
            goto error;
        }
1735 1736 1737
    }

    /* analyze of the devices */
1738 1739 1740 1741
    nb_nodes = virXPathNodeSet("/domain/devices/disk", ctxt, &nodes);
    if (nb_nodes > 0) {
        for (i = 0; i < nb_nodes; i++) {
            res = virDomainParseXMLDiskDesc(conn, nodes[i], &buf,
1742
                                            hvm, xendConfigVersion);
1743
            if (res != 0) {
1744
                free(nodes);
1745 1746 1747
                goto error;
            }
        }
1748
        free(nodes);
1749
    }
1750

1751 1752 1753
    nb_nodes = virXPathNodeSet("/domain/devices/interface", ctxt, &nodes);
    if (nb_nodes > 0) {
        for (i = 0; i < nb_nodes; i++) {
1754
            virBufferAdd(&buf, "(device ", 8);
1755 1756 1757
            res =
                virDomainParseXMLIfDesc(conn, nodes[i], &buf, hvm,
                                        xendConfigVersion);
1758
            if (res != 0) {
1759
                free(nodes);
1760 1761 1762 1763
                goto error;
            }
            virBufferAdd(&buf, ")", 1);
        }
1764
        free(nodes);
1765 1766
    }

1767 1768 1769 1770
    /* New style PV graphics config xen >= 3.0.4,
     * or HVM graphics config xen >= 3.0.5 */
    if ((xendConfigVersion >= 3 && !hvm) ||
        (xendConfigVersion >= 4 && hvm)) {
1771
        nb_nodes = virXPathNodeSet("/domain/devices/graphics", ctxt, &nodes);
1772
        if (nb_nodes > 0) {
1773 1774
            for (i = 0; i < nb_nodes; i++) {
                res = virDomainParseXMLGraphicsDescVFB(conn, nodes[i], &buf);
1775
                if (res != 0) {
1776
                    free(nodes);
1777 1778 1779
                    goto error;
                }
            }
1780
            free(nodes);
1781 1782 1783
        }
    }

1784

D
Daniel Veillard 已提交
1785
    virBufferAdd(&buf, ")", 1); /* closes (vm */
1786 1787 1788 1789
    buf.content[buf.use] = 0;

    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(xml);
1790
    xmlFreeParserCtxt(pctxt);
1791 1792

    if (name != NULL)
1793
        *name = nam;
1794 1795
    else
        free(nam);
1796

1797
    return (buf.content);
1798

1799
  error:
1800
    if (nam != NULL)
1801
        free(nam);
1802
    if (name != NULL)
1803
        *name = NULL;
1804 1805 1806 1807
    if (ctxt != NULL)
        xmlXPathFreeContext(ctxt);
    if (xml != NULL)
        xmlFreeDoc(xml);
1808 1809
    if (pctxt != NULL)
        xmlFreeParserCtxt(pctxt);
1810 1811
    if (buf.content != NULL)
        free(buf.content);
1812
    return (NULL);
1813
}
1814

1815 1816
/**
 * virParseXMLDevice:
1817
 * @conn: pointer to the hypervisor connection
1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830
 * @xmldesc: string with the XML description
 * @hvm: 1 for fully virtualized guest, 0 for paravirtualized
 * @xendConfigVersion: xend configuration file format
 *
 * Parse the XML description and turn it into the xend sexp needed to
 * create the device. This is a temporary interface as the S-Expr interface
 * will be replaced by XML-RPC in the future. However the XML format should
 * stay valid over time.
 *
 * Returns the 0-terminated S-Expr string, or NULL in case of error.
 *         the caller must free() the returned value.
 */
char *
1831 1832
virParseXMLDevice(virConnectPtr conn, const char *xmldesc, int hvm,
                  int xendConfigVersion)
1833 1834 1835 1836 1837 1838 1839 1840 1841 1842
{
    xmlDocPtr xml = NULL;
    xmlNodePtr node;
    virBuffer buf;

    buf.content = malloc(1000);
    if (buf.content == NULL)
        return (NULL);
    buf.size = 1000;
    buf.use = 0;
1843
    buf.content[0] = 0;
1844
    xml = xmlReadDoc((const xmlChar *) xmldesc, "device.xml", NULL,
1845 1846
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
1847 1848
    if (xml == NULL) {
        virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0);
1849
        goto error;
1850
    }
1851 1852 1853 1854
    node = xmlDocGetRootElement(xml);
    if (node == NULL)
        goto error;
    if (xmlStrEqual(node->name, BAD_CAST "disk")) {
1855 1856
        if (virDomainParseXMLDiskDesc(conn, node, &buf, hvm,
	                              xendConfigVersion) != 0)
1857
            goto error;
1858
        /* SXP is not created when device is "floppy". */
1859 1860 1861 1862 1863
        else if (buf.use == 0)
            goto error;
    } else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
        if (virDomainParseXMLIfDesc(conn, node, &buf, hvm,
	                            xendConfigVersion) != 0)
1864
            goto error;
1865 1866
    } else {
        virXMLError(conn, VIR_ERR_XML_ERROR, (const char *) node->name, 0);
1867
        goto error;
1868
    }
1869
  cleanup:
1870 1871 1872
    if (xml != NULL)
        xmlFreeDoc(xml);
    return buf.content;
1873
  error:
1874 1875 1876 1877 1878
    free(buf.content);
    buf.content = NULL;
    goto cleanup;
}

1879

1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894
/**
 * virDomainXMLDevID:
 * @domain: pointer to domain object
 * @xmldesc: string with the XML description
 * @class: Xen device class "vbd" or "vif" (OUT)
 * @ref: Xen device reference (OUT)
 *
 * Set class according to XML root, and:
 *  - if disk, copy in ref the target name from description
 *  - if network, get MAC address from description, scan XenStore and
 *    copy in ref the corresponding vif number.
 *
 * Returns 0 in case of success, -1 in case of failure.
 */
int
1895 1896
virDomainXMLDevID(virDomainPtr domain, const char *xmldesc, char *class,
                  char *ref, int ref_len)
1897 1898 1899 1900
{
    xmlDocPtr xml = NULL;
    xmlNodePtr node, cur;
    xmlChar *attr = NULL;
1901

1902
    char *xref;
1903
    int ret = 0;
1904

1905
    xml = xmlReadDoc((const xmlChar *) xmldesc, "device.xml", NULL,
1906 1907
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
1908 1909
    if (xml == NULL) {
        virXMLError(NULL, VIR_ERR_XML_ERROR, NULL, 0);
1910
        goto error;
1911
    }
1912 1913 1914 1915 1916 1917 1918
    node = xmlDocGetRootElement(xml);
    if (node == NULL)
        goto error;
    if (xmlStrEqual(node->name, BAD_CAST "disk")) {
        strcpy(class, "vbd");
        for (cur = node->children; cur != NULL; cur = cur->next) {
            if ((cur->type != XML_ELEMENT_NODE) ||
1919 1920
                (!xmlStrEqual(cur->name, BAD_CAST "target")))
                continue;
1921 1922 1923
            attr = xmlGetProp(cur, BAD_CAST "dev");
            if (attr == NULL)
                goto error;
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936
            xref = xenStoreDomainGetDiskID(domain->conn, domain->id,
                                              (char *) attr);
            if (xref != NULL) {
                strncpy(ref, xref, ref_len);
                free(xref);
                ref[ref_len - 1] = '\0';
                goto cleanup;
            }
            /* hack to avoid the warning that domain is unused */
            if (domain->id < 0)
                ret = -1;

            goto error;
1937
        }
1938
    } else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
1939 1940 1941
        strcpy(class, "vif");
        for (cur = node->children; cur != NULL; cur = cur->next) {
            if ((cur->type != XML_ELEMENT_NODE) ||
1942 1943
                (!xmlStrEqual(cur->name, BAD_CAST "mac")))
                continue;
1944 1945 1946 1947
            attr = xmlGetProp(cur, BAD_CAST "address");
            if (attr == NULL)
                goto error;

1948
            xref = xenStoreDomainGetNetworkID(domain->conn, domain->id,
1949 1950
                                              (char *) attr);
            if (xref != NULL) {
1951
                strncpy(ref, xref, ref_len);
1952
                free(xref);
1953
                ref[ref_len - 1] = '\0';
1954 1955
                goto cleanup;
            }
1956 1957
            /* hack to avoid the warning that domain is unused */
            if (domain->id < 0)
1958
                ret = -1;
1959

1960 1961
            goto error;
        }
1962 1963
    } else {
        virXMLError(NULL, VIR_ERR_XML_ERROR, (const char *) node->name, 0);
1964
    }
1965
  error:
1966
    ret = -1;
1967
  cleanup:
1968 1969 1970 1971 1972 1973
    if (xml != NULL)
        xmlFreeDoc(xml);
    if (attr != NULL)
        xmlFree(attr);
    return ret;
}
1974
#endif /* WITH_XEN */
1975 1976
#endif /* !PROXY */

1977 1978 1979 1980 1981 1982 1983 1984
/*
 * Local variables:
 *  indent-tabs-mode: nil
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 * End:
 */