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

11
#include "libvirt/libvirt.h"
12 13 14 15 16

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

28
#ifndef PROXY
29 30 31 32 33 34 35 36 37
/**
 * 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.
 */
38
static void
39
virXMLError(virConnectPtr conn, virErrorNumber error, const char *info, int value)
40
{
41
    const char *errmsg;
42

43 44 45 46
    if (error == VIR_ERR_OK)
        return;

    errmsg = __virErrorMsg(error, info);
47
    __virRaiseError(conn, NULL, NULL, VIR_FROM_XML, error, VIR_ERR_ERROR,
48
                    errmsg, info, NULL, value, 0, errmsg, info, value);
49 50
}

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
/**
 * 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 *
virXPathString(const char *xpath, xmlXPathContextPtr ctxt) {
    xmlXPathObjectPtr obj;
    char *ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR, 
	            "Invalid parameter to virXPathString()", 0);
        return(NULL);
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_STRING) ||
        (obj->stringval == NULL) || (obj->stringval[0] == 0))
        return(NULL);
    ret = strdup((char *) obj->stringval);
    xmlXPathFreeObject(obj);
    if (ret == NULL) {
        virXMLError(NULL, VIR_ERR_NO_MEMORY, "strdup", 0);
    }
    return(ret);
}

/**
 * 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
virXPathNumber(const char *xpath, xmlXPathContextPtr ctxt, double *value) {
    xmlXPathObjectPtr obj;

    if ((ctxt == NULL) || (xpath == NULL) || (value == NULL)) {
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR, 
	            "Invalid parameter to virXPathNumber()", 0);
        return(-1);
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_NUMBER) ||
        (isnan(obj->floatval))) {
	xmlXPathFreeObject(obj);
	return(-1);
    }
    
    *value = obj->floatval;
    xmlXPathFreeObject(obj);
    return(0);
}

/**
 * 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,
124 125
 *         or -1 if the XPath evaluation failed or -2 if the
 *         value doesn't have a long format.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 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
 */
int
virXPathLong(const char *xpath, xmlXPathContextPtr ctxt, long *value) {
    xmlXPathObjectPtr obj;
    int ret = 0;

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

        val = strtol((const char*)obj->stringval, &conv, 10);
        if (conv == (const char*)obj->stringval) {
            ret = -2;
        } else {
	    *value = val;
	}
    } else if ((obj != NULL) && (obj->type == XPATH_NUMBER) &&
               (!(isnan(obj->floatval)))) {
	*value = (long) obj->floatval;
	if (*value != obj->floatval) {
	    ret = -2;
	}
    } else {
	ret = -1;
    }
    
    xmlXPathFreeObject(obj);
    return(ret);
}

/**
 * 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
virXPathBoolean(const char *xpath, xmlXPathContextPtr ctxt) {
    xmlXPathObjectPtr obj;
    int ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR, 
	            "Invalid parameter to virXPathBoolean()", 0);
        return(-1);
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_BOOLEAN) ||
        (obj->boolval < 0) || (obj->boolval > 1)) {
	xmlXPathFreeObject(obj);
	return(-1);
    }
    ret = obj->boolval;
    
    xmlXPathFreeObject(obj);
    return(ret);
}

/**
 * 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
virXPathNode(const char *xpath, xmlXPathContextPtr ctxt) {
    xmlXPathObjectPtr obj;
    xmlNodePtr ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR, 
	            "Invalid parameter to virXPathNode()", 0);
        return(NULL);
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
	(obj->nodesetval->nodeTab == NULL)) {
	xmlXPathFreeObject(obj);
	return(NULL);
    }
    
    ret = obj->nodesetval->nodeTab[0];
    xmlXPathFreeObject(obj);
    return(ret);
}
/**
 * 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
virXPathNodeSet(const char *xpath, xmlXPathContextPtr ctxt, xmlNodePtr **list) {
    xmlXPathObjectPtr obj;
    int ret;

    if ((ctxt == NULL) || (xpath == NULL)) {
        virXMLError(NULL, VIR_ERR_INTERNAL_ERROR, 
	            "Invalid parameter to virXPathNodeSet()", 0);
        return(-1);
    }
    obj = xmlXPathEval(BAD_CAST xpath, ctxt);
    if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
        (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr <= 0) ||
	(obj->nodesetval->nodeTab == NULL)) {
	xmlXPathFreeObject(obj);
	if (list != NULL)
	    *list = NULL;
	return(-1);
    }
    
    ret = obj->nodesetval->nodeNr;
    if (list != NULL) {
	*list = malloc(ret * sizeof(xmlNodePtr));
	if (*list == NULL) {
	    virXMLError(NULL, VIR_ERR_NO_MEMORY, 
	                _("allocate string array"), ret * sizeof(xmlNodePtr));
	} else {
	    memcpy(*list, obj->nodesetval->nodeTab, ret * sizeof(xmlNodePtr));
	}
    }
    xmlXPathFreeObject(obj);
    return(ret);
}

271
/**
272
 * virtDomainParseXMLGraphicsDescImage:
273
 * @conn: pointer to the hypervisor connection
274 275
 * @node: node containing graphics description
 * @buf: a buffer for the result S-Expr
276
 * @xendConfigVersion: xend configuration file format
277
 *
278 279 280
 * 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
281 282 283 284
 * valid over time.
 *
 * Returns 0 in case of success, -1 in case of error
 */
285
static int virDomainParseXMLGraphicsDescImage(virConnectPtr conn ATTRIBUTE_UNUSED, xmlNodePtr node, virBufferPtr buf, int xendConfigVersion)
286 287 288 289 290 291 292
{
    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);
293 294 295 296 297 298
            /* TODO:
             * Need to understand sdl options
             *
             *virBufferAdd(buf, "(display localhost:10.0)", 24);
             *virBufferAdd(buf, "(xauthority /root/.Xauthority)", 30);
             */
299
        }
300
        else if (xmlStrEqual(graphics_type, BAD_CAST "vnc")) {
301
            virBufferAdd(buf, "(vnc 1)", 7);
302
            if (xendConfigVersion >= 2) {
303
                xmlChar *vncport = xmlGetProp(node, BAD_CAST "port");
304 305
                xmlChar *vnclisten = xmlGetProp(node, BAD_CAST "listen");
                xmlChar *vncpasswd = xmlGetProp(node, BAD_CAST "passwd");
306
                xmlChar *keymap = xmlGetProp(node, BAD_CAST "keymap");
307
                if (vncport != NULL) {
308
                    long port = strtol((const char *)vncport, NULL, 10);
309 310
                    if (port == -1)
                        virBufferAdd(buf, "(vncunused 1)", 13);
311
                    else if (port >= 5900)
312
                        virBufferVSprintf(buf, "(vncdisplay %ld)", port - 5900);
313
                    xmlFree(vncport);
314
                }
315 316 317 318 319 320 321 322
                if (vnclisten != NULL) {
                    virBufferVSprintf(buf, "(vnclisten %s)", vnclisten);
                    xmlFree(vnclisten);
                }
                if (vncpasswd != NULL) {
                    virBufferVSprintf(buf, "(vncpasswd %s)", vncpasswd);
                    xmlFree(vncpasswd);
                }
323 324 325 326
                if (keymap != NULL) {
                    virBufferVSprintf(buf, "(keymap %s)", keymap);
                    xmlFree(keymap);
                }
327 328
            }
        }
329 330 331 332 333 334
        xmlFree(graphics_type);
    }
    return 0;
}


335 336
/**
 * virtDomainParseXMLGraphicsDescVFB:
337
 * @conn: pointer to the hypervisor connection
338 339 340
 * @node: node containing graphics description
 * @buf: a buffer for the result S-Expr
 *
341 342 343
 * 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
344 345 346 347
 * valid over time.
 *
 * Returns 0 in case of success, -1 in case of error
 */
348
static int virDomainParseXMLGraphicsDescVFB(virConnectPtr conn ATTRIBUTE_UNUSED, xmlNodePtr node, virBufferPtr buf)
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
{
    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);
             */
        }
        else if (xmlStrEqual(graphics_type, BAD_CAST "vnc")) {
            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");
370
            xmlChar *keymap = xmlGetProp(node, BAD_CAST "keymap");
371 372 373 374
            if (vncport != NULL) {
                long port = strtol((const char *)vncport, NULL, 10);
                if (port == -1)
                    virBufferAdd(buf, "(vncunused 1)", 13);
375
                else if (port >= 5900)
376
                    virBufferVSprintf(buf, "(vncdisplay %ld)", port - 5900);
377 378 379 380 381 382 383 384 385 386
                xmlFree(vncport);
            }
            if (vnclisten != NULL) {
                virBufferVSprintf(buf, "(vnclisten %s)", vnclisten);
                xmlFree(vnclisten);
            }
            if (vncpasswd != NULL) {
                virBufferVSprintf(buf, "(vncpasswd %s)", vncpasswd);
                xmlFree(vncpasswd);
            }
387 388 389 390
            if (keymap != NULL) {
                virBufferVSprintf(buf, "(keymap %s)", keymap);
                xmlFree(keymap);
            }
391 392 393 394 395 396 397 398
        }
        virBufferAdd(buf, "))", 2);
        xmlFree(graphics_type);
    }
    return 0;
}


399
/**
400
 * virDomainParseXMLOSDescHVM:
401
 * @conn: pointer to the hypervisor connection
402
 * @node: node containing HVM OS description
403
 * @buf: a buffer for the result S-Expr
404
 * @ctxt: a path context representing the XML description
405
 * @vcpus: number of virtual CPUs to configure
406
 * @xendConfigVersion: xend configuration file format
407
 *
408 409
 * 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
410 411 412 413 414 415
 * 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
416
virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf, xmlXPathContextPtr ctxt, int vcpus, int xendConfigVersion)
417 418
{
    xmlNodePtr cur, txt;
419
    xmlNodePtr *nodes = NULL;
420 421
    xmlChar *type = NULL;
    xmlChar *loader = NULL;
422 423
    char bootorder[5];
    int nbootorder = 0;
424
    int res, nb_nodes;
425
    char *str;
426 427 428 429 430 431 432 433

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if ((type == NULL)
                && (xmlStrEqual(cur->name, BAD_CAST "type"))) {
                txt = cur->children;
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
434
                    (txt->next == NULL))
435 436 437 438 439
                    type = txt->content;
            } else if ((loader == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "loader"))) {
                txt = cur->children;
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
440
                    (txt->next == NULL))
441
                    loader = txt->content;
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
            } else if ((xmlStrEqual(cur->name, BAD_CAST "boot"))) {
                xmlChar *boot_dev = xmlGetProp(cur, BAD_CAST "dev");
                if (nbootorder == ((sizeof(bootorder)/sizeof(bootorder[0]))-1)) {
                    virXMLError(conn, VIR_ERR_XML_ERROR, "too many boot devices", 0);
                    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);
463 464 465 466
            }
        }
        cur = cur->next;
    }
467
    bootorder[nbootorder] = '\0';
468 469
    if ((type == NULL) || (!xmlStrEqual(type, BAD_CAST "hvm"))) {
        /* VIR_ERR_OS_TYPE */
470
        virXMLError(conn, VIR_ERR_OS_TYPE, (const char *) type, 0);
471 472 473 474
        return (-1);
    }
    virBufferAdd(buf, "(image (hvm ", 12);
    if (loader == NULL) {
475
        virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0);
476
        goto error;
477
    } else {
478
        virBufferVSprintf(buf, "(kernel '%s')", (const char *) loader);
479 480 481
    }

    /* get the device emulation model */
482 483
    str = virXPathString("string(/domain/devices/emulator[1])", ctxt);
    if (str == NULL) {
484
        virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0); /* TODO: error */
485 486
        goto error;
    }
487 488
    virBufferVSprintf(buf, "(device_model '%s')", str);
    xmlFree(str);
489

490 491
    virBufferVSprintf(buf, "(vcpus %d)", vcpus);

492 493
    if (nbootorder)
        virBufferVSprintf(buf, "(boot %s)", bootorder);
494

495 496 497
    /* get the 1st floppy device file */
	cur = virXPathNode("/domain/devices/disk[@device='floppy' and target/@dev='fda']/source",
                       ctxt);
498
	if (cur != NULL) {
499 500
        xmlChar *fdfile;
        fdfile = xmlGetProp(cur, BAD_CAST "file");
501
	    if (fdfile != NULL) {
502 503
            virBufferVSprintf(buf, "(fda '%s')", fdfile);
            free(fdfile);
504
	    }
505
    }
506

507 508 509
    /* get the 2nd floppy device file */
	cur = virXPathNode("/domain/devices/disk[@device='floppy' and target/@dev='fdb']/source",
                       ctxt);
510
	if (cur != NULL) {
511 512
        xmlChar *fdfile;
        fdfile = xmlGetProp(cur, BAD_CAST "file");
513
	    if (fdfile != NULL) {
514 515
            virBufferVSprintf(buf, "(fdb '%s')", fdfile);
            free(fdfile);
516
	    }
517
    }
518 519


520 521 522 523
    /* get the cdrom device file */
    /* Only XenD <= 3.0.2 wants cdrom config here */
    if (xendConfigVersion == 1) {
	    cur = virXPathNode("/domain/devices/disk[@device='cdrom' and target/@dev='hdc']/source",
524 525
	                       ctxt);
	    if (cur != NULL) {
526 527 528 529 530 531 532
            xmlChar *cdfile;

            cdfile = xmlGetProp(cur, BAD_CAST "file");
            if (cdfile != NULL) {
                virBufferVSprintf(buf, "(cdrom '%s')",
                                  (const char *)cdfile);
                xmlFree(cdfile);
533 534
            }
        }
535 536
    }

537 538 539 540 541 542 543
    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);

544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
    virBufferAdd(buf, "(usb 1)", 7);
    nb_nodes = virXPathNodeSet("/domain/devices/input", ctxt, &nodes);
    if (nb_nodes > 0) {
        int i;
        for (i = 0; i < nb_nodes; i++) {
            xmlChar *itype = NULL, *bus = NULL;
            int isMouse = 1;

            itype = xmlGetProp(nodes[i], (xmlChar *)"type");

            if (!itype) {
                goto error;
            }
            if (!strcmp((const char *)itype, "tablet"))
                isMouse = 0;
            else if (strcmp((const char*)itype, "mouse")) {
                xmlFree(itype);
                virXMLError(conn, VIR_ERR_XML_ERROR, "input", 0);
                goto error;
            }
            xmlFree(itype);

            bus = xmlGetProp(nodes[i], (xmlChar *)"bus");
            if (!bus) {
                if (!isMouse) {
                    /* Nothing - implicit ps2 */
                } else {
                    virBufferAdd(buf, "(usbdevice tablet)", 13);
                }
            } else {
                if (!strcmp((const char*)bus, "ps2")) {
                    if (!isMouse) {
                        xmlFree(bus);
                        virXMLError(conn, VIR_ERR_XML_ERROR, "input", 0);
                        goto error;
                    }
                    /* Nothing - implicit ps2 */
                } else if (!strcmp((const char*)bus, "usb")) {
                    if (isMouse)
                        virBufferAdd(buf, "(usbdevice mouse)", 17);
                    else
                        virBufferAdd(buf, "(usbdevice tablet)", 18);
                }
            }
            xmlFree(bus);
        }
        free(nodes);
        nodes = NULL;
    }


595 596
    res = virXPathBoolean("count(domain/devices/console) > 0", ctxt);
    if (res < 0) {
597
        virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0);
598
        goto error;
599
    }
600
    if (res) {
601
        virBufferAdd(buf, "(serial pty)", 12);
602
    }
603

604 605 606 607 608 609 610 611 612 613
    /* 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;
            }
614 615 616
        }
    }

617 618 619 620 621
    str = virXPathString("string(/domain/clock/@offset)", ctxt);
    if (str != NULL && !strcmp(str, "localtime")) {
        virBufferAdd(buf, "(localtime 1)", 13);
    }

622 623 624
    virBufferAdd(buf, "))", 2);

    return (0);
625

626
 error:
627 628
    if (nodes)
        free(nodes);
629 630 631 632 633
    return(-1);
}

/**
 * virDomainParseXMLOSDescPV:
634
 * @conn: pointer to the hypervisor connection
635 636
 * @node: node containing PV OS description
 * @buf: a buffer for the result S-Expr
637
 * @ctxt: a path context representing the XML description
638
 * @xendConfigVersion: xend configuration file format
639 640 641 642 643 644 645 646 647
 *
 * 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
648
virDomainParseXMLOSDescPV(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf, xmlXPathContextPtr ctxt, int xendConfigVersion)
649
{
650 651 652 653 654 655
    xmlNodePtr cur, txt;
    const xmlChar *type = NULL;
    const xmlChar *root = NULL;
    const xmlChar *kernel = NULL;
    const xmlChar *initrd = NULL;
    const xmlChar *cmdline = NULL;
656
    int res;
657 658 659 660

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
661 662 663
            if ((type == NULL)
                && (xmlStrEqual(cur->name, BAD_CAST "type"))) {
                txt = cur->children;
664
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
665
                    (txt->next == NULL))
666 667 668 669
                    type = txt->content;
            } else if ((kernel == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "kernel"))) {
                txt = cur->children;
670
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
671
                    (txt->next == NULL))
672 673 674 675
                    kernel = txt->content;
            } else if ((root == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "root"))) {
                txt = cur->children;
676
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
677
                    (txt->next == NULL))
678 679 680 681
                    root = txt->content;
            } else if ((initrd == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "initrd"))) {
                txt = cur->children;
682
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
683
                    (txt->next == NULL))
684 685 686 687
                    initrd = txt->content;
            } else if ((cmdline == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "cmdline"))) {
                txt = cur->children;
688
                if ((txt != NULL) && (txt->type == XML_TEXT_NODE) &&
689
                    (txt->next == NULL))
690 691 692
                    cmdline = txt->content;
            }
        }
693 694 695 696
        cur = cur->next;
    }
    if ((type != NULL) && (!xmlStrEqual(type, BAD_CAST "linux"))) {
        /* VIR_ERR_OS_TYPE */
697
        virXMLError(conn, VIR_ERR_OS_TYPE, (const char *) type, 0);
698
        return (-1);
699
    }
700
    virBufferAdd(buf, "(image (linux ", 14);
701
    if (kernel == NULL) {
702
        virXMLError(conn, VIR_ERR_NO_KERNEL, NULL, 0);
703
        return (-1);
704
    } else {
705
        virBufferVSprintf(buf, "(kernel '%s')", (const char *) kernel);
706 707
    }
    if (initrd != NULL)
708
        virBufferVSprintf(buf, "(ramdisk '%s')", (const char *) initrd);
709
    if (root != NULL)
710
        virBufferVSprintf(buf, "(root '%s')", (const char *) root);
711
    if (cmdline != NULL)
712
        virBufferVSprintf(buf, "(args '%s')", (const char *) cmdline);
713

714
    /* PV graphics for xen <= 3.0.4 */
715
    if (xendConfigVersion < 3) {
716 717 718
        cur = virXPathNode("/domain/devices/graphics[1]", ctxt);
        if (cur != NULL) {
            res = virDomainParseXMLGraphicsDescImage(conn, cur, buf,
719
                                                     xendConfigVersion);
720 721 722
            if (res != 0) {
                goto error;
            }
723 724 725 726
        }
    }

 error:
727
    virBufferAdd(buf, "))", 2);
728
    return (0);
729 730
}

731 732 733 734 735 736 737 738 739 740
/**
 * 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
741
virCatchXMLParseError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) {
742 743
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;

744
    if ((ctxt != NULL) &&
745
        (ctxt->lastError.level == XML_ERR_FATAL) &&
746
        (ctxt->lastError.message != NULL)) {
747
        virXMLError(NULL, VIR_ERR_XML_DETAIL, ctxt->lastError.message,
748
                    ctxt->lastError.line);
749 750 751
    }
}

752 753
/**
 * virDomainParseXMLDiskDesc:
754
 * @node: node containing disk description
755
 * @conn: pointer to the hypervisor connection
756
 * @buf: a buffer for the result S-Expr
757
 * @xendConfigVersion: xend configuration file format
758 759 760 761 762 763 764 765 766
 *
 * 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
767
virDomainParseXMLDiskDesc(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf, int hvm, int xendConfigVersion)
768
{
769 770
    xmlNodePtr cur;
    xmlChar *type = NULL;
771
    xmlChar *device = NULL;
772 773
    xmlChar *source = NULL;
    xmlChar *target = NULL;
774 775
    xmlChar *drvName = NULL;
    xmlChar *drvType = NULL;
776
    int ro = 0;
777
    int shareable = 0;
778
    int typ = 0;
779
    int cdrom = 0;
780
    int isNoSrcCdrom = 0;
781
    int ret = 0;
782 783 784

    type = xmlGetProp(node, BAD_CAST "type");
    if (type != NULL) {
785 786 787 788 789
        if (xmlStrEqual(type, BAD_CAST "file"))
            typ = 0;
        else if (xmlStrEqual(type, BAD_CAST "block"))
            typ = 1;
        xmlFree(type);
790
    }
791
    device = xmlGetProp(node, BAD_CAST "device");
792

793 794 795
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
796 797 798 799 800 801 802 803 804 805
            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");
806 807 808 809 810
            } else if ((drvName == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "driver"))) {
                drvName = xmlGetProp(cur, BAD_CAST "name");
                if (drvName && !strcmp((const char *)drvName, "tap"))
                    drvType = xmlGetProp(cur, BAD_CAST "type");
811 812
            } else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
                ro = 1;
813
            } else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
814
                shareable = 1;
815 816
            }
        }
817 818 819 820
        cur = cur->next;
    }

    if (source == NULL) {
821 822 823 824 825 826 827 828 829 830
        /* There is a case without the source
         * to the CD-ROM device
         */
        if (hvm &&
            device &&
            !strcmp((const char *)device, "cdrom")) {
            isNoSrcCdrom = 1;
        }
        if (!isNoSrcCdrom) {
            virXMLError(conn, VIR_ERR_NO_SOURCE, (const char *) target, 0);
831 832
            ret = -1;
            goto cleanup;
833
        }
834 835
    }
    if (target == NULL) {
836
        virXMLError(conn, VIR_ERR_NO_TARGET, (const char *) source, 0);
837 838
        ret = -1;
        goto cleanup;
839
    }
840

841 842
    /* Xend (all versions) put the floppy device config
     * under the hvm (image (os)) block
843
     */
844
    if (hvm &&
845
        device &&
846
        !strcmp((const char *)device, "floppy")) {
847
        goto cleanup;
848 849 850
    }

    /* Xend <= 3.0.2 doesn't include cdrom config here */
851
    if (hvm &&
852 853
        device &&
        !strcmp((const char *)device, "cdrom")) {
854
        if (xendConfigVersion == 1)
855
            goto cleanup;
856 857
        else
            cdrom = 1;
858 859 860 861
    }


    virBufferAdd(buf, "(device ", 8);
862 863 864 865 866 867 868 869
    /* Normally disks are in a (device (vbd ...)) block
       but blktap disks ended up in a differently named
       (device (tap ....)) block.... */
    if (drvName && !strcmp((const char *)drvName, "tap")) {
        virBufferAdd(buf, "(tap ", 5);
    } else {
        virBufferAdd(buf, "(vbd ", 5);
    }
870

871 872
    if (hvm) {
        char *tmp = (char *)target;
873
        /* Just in case user mistakenly still puts ioemu: in their XML */
874 875
        if (!strncmp((const char *) tmp, "ioemu:", 6))
            tmp += 6;
876 877 878

        /* Xend <= 3.0.2 wants a ioemu: prefix on devices for HVM */
        if (xendConfigVersion == 1)
879
            virBufferVSprintf(buf, "(dev 'ioemu:%s')", (const char *)tmp);
880
        else /* But newer does not */
881
            virBufferVSprintf(buf, "(dev '%s%s')", (const char *)tmp, cdrom ? ":cdrom" : ":disk");
882
    } else
883 884
        virBufferVSprintf(buf, "(dev '%s')", (const char *)target);

885
    if (drvName && !isNoSrcCdrom) {
886 887 888 889 890 891 892 893 894 895
        if (!strcmp((const char *)drvName, "tap")) {
            virBufferVSprintf(buf, "(uname '%s:%s:%s')",
                              (const char *)drvName,
                              (drvType ? (const char *)drvType : "aio"),
                              (const char *)source);
        } else {
            virBufferVSprintf(buf, "(uname '%s:%s')",
                              (const char *)drvName,
                              (const char *)source);
        }
896
    } else if (!isNoSrcCdrom) {
897 898 899 900 901 902 903 904
        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);
        }
905
    }
906
    if (ro == 1)
907
        virBufferVSprintf(buf, "(mode 'r')");
908 909 910 911
    else if (shareable == 1)
        virBufferVSprintf(buf, "(mode 'w!')");
    else
        virBufferVSprintf(buf, "(mode 'w')");
912

913
    virBufferAdd(buf, ")", 1);
914
    virBufferAdd(buf, ")", 1);
915 916

 cleanup:
917 918 919 920 921 922 923 924 925 926 927
    if(drvType)
        xmlFree(drvType);
    if(drvName)
        xmlFree(drvName);
    if(device)
        xmlFree(device);
    if(target)
        xmlFree(target);
    if(source)
        xmlFree(source);
    return (ret);
928 929 930 931
}

/**
 * virDomainParseXMLIfDesc:
932
 * @conn: pointer to the hypervisor connection
933
 * @node: node containing the interface description
934
 * @buf: a buffer for the result S-Expr
935
 * @xendConfigVersion: xend configuration file format
936 937 938 939 940 941 942 943 944
 *
 * 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
945
virDomainParseXMLIfDesc(virConnectPtr conn ATTRIBUTE_UNUSED, xmlNodePtr node, virBufferPtr buf, int hvm, int xendConfigVersion)
946
{
947 948 949 950 951
    xmlNodePtr cur;
    xmlChar *type = NULL;
    xmlChar *source = NULL;
    xmlChar *mac = NULL;
    xmlChar *script = NULL;
952
    xmlChar *ip = NULL;
953
    int typ = 0;
954
    int ret = -1;
955 956 957

    type = xmlGetProp(node, BAD_CAST "type");
    if (type != NULL) {
958 959 960 961
        if (xmlStrEqual(type, BAD_CAST "bridge"))
            typ = 0;
        else if (xmlStrEqual(type, BAD_CAST "ethernet"))
            typ = 1;
962 963
        else if (xmlStrEqual(type, BAD_CAST "network"))
            typ = 2;
964
        xmlFree(type);
965 966 967 968
    }
    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
969 970 971 972
            if ((source == NULL) &&
                (xmlStrEqual(cur->name, BAD_CAST "source"))) {
                if (typ == 0)
                    source = xmlGetProp(cur, BAD_CAST "bridge");
973
                else if (typ == 1)
974
                    source = xmlGetProp(cur, BAD_CAST "dev");
975 976
                else
                    source = xmlGetProp(cur, BAD_CAST "network");
977 978 979 980 981 982
            } 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");
983 984 985 986 987 988 989
            } else if ((ip == NULL) &&
                       (xmlStrEqual(cur->name, BAD_CAST "ip"))) {
                /* XXX in future expect to need to have > 1 ip
                   address element - eg ipv4 & ipv6. For now
                   xen only supports a single address though
                   so lets ignore that complication */
                ip = xmlGetProp(cur, BAD_CAST "address");
990 991
            }
        }
992 993 994 995
        cur = cur->next;
    }

    virBufferAdd(buf, "(vif ", 5);
996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
    if (mac != NULL) {
        unsigned int addr[12];
        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]);
        if (tmp != 12 || strlen((const char *) mac) != 17) {
            virXMLError(conn, VIR_ERR_INVALID_MAC, (const char *) mac, 0);
            goto error;
        }
1010
        virBufferVSprintf(buf, "(mac '%s')", (const char *) mac);
1011
    }
1012
    if (source != NULL) {
1013 1014
        if (typ == 0)
            virBufferVSprintf(buf, "(bridge '%s')", (const char *) source);
1015
        else if (typ == 1)      /* TODO does that work like that ? */
1016
            virBufferVSprintf(buf, "(dev '%s')", (const char *) source);
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
        else {
            virNetworkPtr network = virNetworkLookupByName(conn, (const char *) source);
            char *bridge;
            if (!network || !(bridge = virNetworkGetBridgeName(network))) {
                virXMLError(conn, VIR_ERR_NO_SOURCE, (const char *) source, 0);
                goto error;
            }
            virBufferVSprintf(buf, "(bridge '%s')", bridge);
            free(bridge);
        }
1027 1028 1029
    }
    if (script != NULL)
        virBufferVSprintf(buf, "(script '%s')", script);
1030 1031
    if (ip != NULL)
        virBufferVSprintf(buf, "(ip '%s')", ip);
1032 1033 1034 1035 1036
    /*
     * apparently (type ioemu) breaks paravirt drivers on HVM so skip this
     * from Xen 3.1.0
     */
    if ((hvm) && (xendConfigVersion < 4))
1037
        virBufferAdd(buf, "(type ioemu)", 12);
1038 1039

    virBufferAdd(buf, ")", 1);
1040 1041
    ret = 0;
 error:
1042
    if (mac != NULL)
1043
        xmlFree(mac);
1044
    if (source != NULL)
1045
        xmlFree(source);
1046
    if (script != NULL)
1047
        xmlFree(script);
1048 1049
    if (ip != NULL)
        xmlFree(ip);
1050
    return (ret);
1051 1052 1053 1054
}

/**
 * virDomainParseXMLDesc:
1055
 * @conn: pointer to the hypervisor connection
1056
 * @xmldesc: string with the XML description
1057
 * @xendConfigVersion: xend configuration file format
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
 *
 * 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 *
1068
virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, int xendConfigVersion)
1069
{
1070 1071
    xmlDocPtr xml = NULL;
    xmlNodePtr node;
1072
    char *nam = NULL;
1073 1074
    virBuffer buf;
    xmlChar *prop;
1075
    xmlParserCtxtPtr pctxt;
1076 1077
    xmlXPathContextPtr ctxt = NULL;
    int i, res;
1078
    int bootloader = 0;
1079
    int hvm = 0;
1080
    unsigned int vcpus = 1;
1081
    unsigned long mem = 0, max_mem = 0;
1082 1083 1084 1085
    char *str;
    double f;
    xmlNodePtr *nodes;
    int nb_nodes;
1086 1087

    if (name != NULL)
1088
        *name = NULL;
1089 1090
    buf.content = malloc(1000);
    if (buf.content == NULL)
1091
        return (NULL);
1092 1093 1094
    buf.size = 1000;
    buf.use = 0;

1095 1096 1097 1098 1099
    pctxt = xmlNewParserCtxt();
    if ((pctxt == NULL) || (pctxt->sax == NULL)) {
        goto error;
    }

1100 1101 1102
    /* TODO pass the connection point to the error handler:
     *   pctxt->userData = virConnectPtr;
     */
1103 1104 1105 1106 1107
    pctxt->sax->error = virCatchXMLParseError;

    xml = xmlCtxtReadDoc(pctxt, (const xmlChar *) xmldesc, "domain.xml", NULL,
                         XML_PARSE_NOENT | XML_PARSE_NONET |
                         XML_PARSE_NOWARNING);
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
    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")) {
1118 1119 1120 1121
            xmlFree(prop);
            goto error;
        }
        xmlFree(prop);
1122 1123 1124 1125 1126 1127 1128
    }
    virBufferAdd(&buf, "(vm ", 4);
    ctxt = xmlXPathNewContext(xml);
    if (ctxt == NULL) {
        goto error;
    }
    /*
1129
     * extract some of the basics, name, memory, cpus ...
1130
     */
1131
    nam = virXPathString("string(/domain/name[1])", ctxt);
1132
    if (nam == NULL) {
1133
        virXMLError(conn, VIR_ERR_NO_NAME, xmldesc, 0);
1134
        goto error;
1135
    }
1136
    virBufferVSprintf(&buf, "(name '%s')", nam);
1137

1138 1139
    if ((virXPathNumber("number(/domain/memory[1])", ctxt, &f) < 0) ||
        (f < MIN_XEN_GUEST_SIZE * 1024)) {
1140
        max_mem = 128;
1141
    } else {
1142
        max_mem = (f / 1024);
1143
    }
1144 1145 1146

    if ((virXPathNumber("number(/domain/currentMemory[1])", ctxt, &f) < 0) ||
        (f < MIN_XEN_GUEST_SIZE * 1024)) {
1147 1148
        mem = max_mem;
    } else {
1149
        mem = (f / 1024);
1150 1151 1152
        if (mem > max_mem) {
            max_mem = mem;
        }
1153
    }
1154
    virBufferVSprintf(&buf, "(memory %lu)(maxmem %lu)", mem, max_mem);
1155

1156 1157 1158
    if ((virXPathNumber("number(/domain/vcpu[1])", ctxt, &f) == 0) &&
        (f > 0)) {
        vcpus = (unsigned int) f;
1159
    }
1160
    virBufferVSprintf(&buf, "(vcpus %u)", vcpus);
1161

1162 1163 1164 1165
    str = virXPathString("string(/domain/uuid[1])", ctxt);
    if (str != NULL) {
        virBufferVSprintf(&buf, "(uuid '%s')", str);
	free(str);
1166 1167
    }

1168 1169 1170
    str = virXPathString("string(/domain/bootloader[1])", ctxt);
    if (str != NULL) {
        virBufferVSprintf(&buf, "(bootloader '%s')", str);
1171
        /*
1172
         * if using a bootloader, the kernel and initrd strings are not
1173 1174
         * significant and should be discarded
         */
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
        bootloader = 1;
	free(str);
    }

    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);
1185
	free(str);
1186 1187
    }

1188 1189 1190 1191
    str = virXPathString("string(/domain/on_poweroff[1])", ctxt);
    if (str != NULL) {
        virBufferVSprintf(&buf, "(on_poweroff '%s')", str);
	free(str);
1192 1193
    }

1194 1195 1196 1197
    str = virXPathString("string(/domain/on_reboot[1])", ctxt);
    if (str != NULL) {
        virBufferVSprintf(&buf, "(on_reboot '%s')", str);
	free(str);
1198 1199
    }

1200 1201 1202 1203
    str = virXPathString("string(/domain/on_crash[1])", ctxt);
    if (str != NULL) {
        virBufferVSprintf(&buf, "(on_crash '%s')", str);
	free(str);
1204 1205
    }

1206
    if (!bootloader) {
1207
        if ((node = virXPathNode("/domain/os[1]", ctxt)) != NULL) {
1208
            /* Analyze of the os description, based on HVM or PV. */
1209
            str = virXPathString("string(/domain/os/type[1])", ctxt);
1210

1211 1212
            if ((str == NULL) || (strcmp(str, "hvm"))) {
                res = virDomainParseXMLOSDescPV(conn, node,
1213 1214 1215
                                                &buf, ctxt, xendConfigVersion);
            } else {
                hvm = 1;
1216 1217
                res = virDomainParseXMLOSDescHVM(conn, node, &buf, ctxt,
		                                 vcpus, xendConfigVersion);
1218 1219
            }

1220
            if (str != NULL) free(str);
1221 1222 1223

            if (res != 0)
                goto error;
1224
        } else {
1225
            virXMLError(conn, VIR_ERR_NO_OS, nam, 0);
1226 1227
            goto error;
        }
1228 1229 1230
    }

    /* analyze of the devices */
1231 1232 1233 1234 1235
    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,
	                                    hvm, xendConfigVersion);
1236
            if (res != 0) {
1237
	        free(nodes);
1238 1239 1240
                goto error;
            }
        }
1241
        free(nodes);
1242
    }
1243

1244 1245 1246
    nb_nodes = virXPathNodeSet("/domain/devices/interface", ctxt, &nodes);
    if (nb_nodes > 0) {
        for (i = 0; i < nb_nodes; i++) {
1247
            virBufferAdd(&buf, "(device ", 8);
1248
            res = virDomainParseXMLIfDesc(conn, nodes[i], &buf, hvm, xendConfigVersion);
1249
            if (res != 0) {
1250
	        free(nodes);
1251 1252 1253 1254
                goto error;
            }
            virBufferAdd(&buf, ")", 1);
        }
1255
        free(nodes);
1256 1257
    }

1258 1259 1260 1261
    /* New style PV graphics config xen >= 3.0.4,
     * or HVM graphics config xen >= 3.0.5 */
    if ((xendConfigVersion >= 3 && !hvm) ||
        (xendConfigVersion >= 4 && hvm)) {
1262
        nb_nodes = virXPathNodeSet("/domain/devices/graphics", ctxt, &nodes);
1263
        if (nb_nodes > 0) {
1264 1265
            for (i = 0; i < nb_nodes; i++) {
                res = virDomainParseXMLGraphicsDescVFB(conn, nodes[i], &buf);
1266
                if (res != 0) {
1267
                    free(nodes);
1268 1269 1270
                    goto error;
                }
            }
1271
            free(nodes);
1272 1273 1274
        }
    }

1275

D
Daniel Veillard 已提交
1276
    virBufferAdd(&buf, ")", 1); /* closes (vm */
1277 1278 1279 1280
    buf.content[buf.use] = 0;

    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(xml);
1281
    xmlFreeParserCtxt(pctxt);
1282 1283

    if (name != NULL)
1284
        *name = nam;
1285 1286
    else
        free(nam);
1287

1288
    return (buf.content);
1289

1290
 error:
1291
    if (nam != NULL)
1292
        free(nam);
1293
    if (name != NULL)
1294
        *name = NULL;
1295 1296 1297 1298
    if (ctxt != NULL)
        xmlXPathFreeContext(ctxt);
    if (xml != NULL)
        xmlFreeDoc(xml);
1299 1300
    if (pctxt != NULL)
        xmlFreeParserCtxt(pctxt);
1301 1302
    if (buf.content != NULL)
        free(buf.content);
1303
    return (NULL);
1304
}
1305 1306

#endif /* !PROXY */
1307 1308 1309 1310



unsigned char *virParseUUID(char **ptr, const char *uuid) {
1311
    int rawuuid[VIR_UUID_BUFLEN];
1312
    const char *cur;
1313 1314 1315 1316 1317 1318
    unsigned char *dst_uuid = NULL;
    int i;

    if (uuid == NULL)
        goto error;

1319 1320 1321 1322 1323
    /*
     * do a liberal scan allowing '-' and ' ' anywhere between character
     * pairs as long as there is 32 of them in the end.
     */
    cur = uuid;
1324
    for (i = 0;i < VIR_UUID_BUFLEN;) {
1325 1326
        rawuuid[i] = 0;
        if (*cur == 0)
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341
            goto error;
        if ((*cur == '-') || (*cur == ' ')) {
            cur++;
            continue;
        }
        if ((*cur >= '0') && (*cur <= '9'))
            rawuuid[i] = *cur - '0';
        else if ((*cur >= 'a') && (*cur <= 'f'))
            rawuuid[i] = *cur - 'a' + 10;
        else if ((*cur >= 'A') && (*cur <= 'F'))
            rawuuid[i] = *cur - 'A' + 10;
        else
            goto error;
        rawuuid[i] *= 16;
        cur++;
1342
        if (*cur == 0)
1343 1344 1345 1346 1347 1348 1349 1350 1351
            goto error;
        if ((*cur >= '0') && (*cur <= '9'))
            rawuuid[i] += *cur - '0';
        else if ((*cur >= 'a') && (*cur <= 'f'))
            rawuuid[i] += *cur - 'a' + 10;
        else if ((*cur >= 'A') && (*cur <= 'F'))
            rawuuid[i] += *cur - 'A' + 10;
        else
            goto error;
1352
        i++;
1353
        cur++;
1354
    }
1355 1356 1357 1358

    dst_uuid = (unsigned char *) *ptr;
    *ptr += 16;

1359
    for (i = 0; i < VIR_UUID_BUFLEN; i++)
1360 1361
        dst_uuid[i] = rawuuid[i] & 0xFF;

1362
 error:
1363
    return(dst_uuid);
1364
}
1365

1366 1367 1368
#ifndef PROXY
/**
 * virParseXMLDevice:
1369
 * @conn: pointer to the hypervisor connection
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
 * @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 *
1383
virParseXMLDevice(virConnectPtr conn, char *xmldesc, int hvm, int xendConfigVersion)
1384 1385 1386 1387 1388 1389 1390 1391 1392 1393
{
    xmlDocPtr xml = NULL;
    xmlNodePtr node;
    virBuffer buf;

    buf.content = malloc(1000);
    if (buf.content == NULL)
        return (NULL);
    buf.size = 1000;
    buf.use = 0;
1394
    buf.content[0] = 0;
1395 1396 1397 1398 1399 1400 1401 1402 1403
    xml = xmlReadDoc((const xmlChar *) xmldesc, "domain.xml", NULL,
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
    if (xml == NULL)
        goto error;
    node = xmlDocGetRootElement(xml);
    if (node == NULL)
        goto error;
    if (xmlStrEqual(node->name, BAD_CAST "disk")) {
1404
        if (virDomainParseXMLDiskDesc(conn, node, &buf, hvm, xendConfigVersion) != 0)
1405
            goto error;
1406 1407 1408
        /* SXP is not created when device is "floppy". */
       else if (buf.use == 0)
           goto error;
1409 1410
    }
    else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
1411
        if (virDomainParseXMLIfDesc(conn, node, &buf, hvm, xendConfigVersion) != 0)
1412
            goto error;
1413 1414 1415
    } else {
        virXMLError(conn, VIR_ERR_XML_ERROR, (const char *) node->name, 0);
	goto error;
1416
    }
1417
 cleanup:
1418 1419 1420
    if (xml != NULL)
        xmlFreeDoc(xml);
    return buf.content;
1421
 error:
1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446
    free(buf.content);
    buf.content = NULL;
    goto cleanup;
}

/**
 * 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
virDomainXMLDevID(virDomainPtr domain, char *xmldesc, char *class, char *ref)
{
    xmlDocPtr xml = NULL;
    xmlNodePtr node, cur;
    xmlChar *attr = NULL;
1447
#ifdef WITH_XEN
1448
    char *xref;
1449
#endif /* WITH_XEN */
1450
    int ret = 0;
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463

    xml = xmlReadDoc((const xmlChar *) xmldesc, "domain.xml", NULL,
                     XML_PARSE_NOENT | XML_PARSE_NONET |
                     XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
    if (xml == NULL)
        goto error;
    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) ||
1464
                (!xmlStrEqual(cur->name, BAD_CAST "target"))) continue;
1465 1466 1467
            attr = xmlGetProp(cur, BAD_CAST "dev");
            if (attr == NULL)
                goto error;
1468
            strcpy(ref, (char *)attr);
1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480
            goto cleanup;
        }
    }
    else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
        strcpy(class, "vif");
        for (cur = node->children; cur != NULL; cur = cur->next) {
            if ((cur->type != XML_ELEMENT_NODE) ||
                (!xmlStrEqual(cur->name, BAD_CAST "mac"))) continue;
            attr = xmlGetProp(cur, BAD_CAST "address");
            if (attr == NULL)
                goto error;

1481
#ifdef WITH_XEN
1482
            xref = xenStoreDomainGetNetworkID(domain->conn, domain->id,
1483 1484 1485 1486 1487 1488
                                              (char *) attr);
            if (xref != NULL) {
                strcpy(ref, xref);
                free(xref);
                goto cleanup;
            }
1489 1490 1491 1492
#else /* without xen */
            /* hack to avoid the warning that domain is unused */
            if (domain->id < 0)
	        ret = -1;
1493
#endif /* WITH_XEN */
1494

1495 1496 1497
            goto error;
        }
    }
1498
 error:
1499
    ret = -1;
1500
 cleanup:
1501 1502 1503 1504 1505 1506 1507 1508
    if (xml != NULL)
        xmlFreeDoc(xml);
    if (attr != NULL)
        xmlFree(attr);
    return ret;
}
#endif /* !PROXY */

1509 1510 1511 1512 1513 1514 1515 1516
/*
 * Local variables:
 *  indent-tabs-mode: nil
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 4
 * End:
 */