xen_sxpr.c 84.6 KB
Newer Older
1 2 3
/*
 * xen_sxpr.c: Xen SEXPR parsing functions
 *
4
 * Copyright (C) 2010-2014 Red Hat, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (C) 2011 Univention GmbH
 * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library.  If not, see
O
Osier Yang 已提交
20
 * <http://www.gnu.org/licenses/>.
21 22 23 24 25 26 27 28 29
 *
 * Author: Anthony Liguori <aliguori@us.ibm.com>
 * Author: Daniel Veillard <veillard@redhat.com>
 * Author: Markus Groß <gross@univention.de>
 */

#include <config.h>

#include "internal.h"
30
#include "virerror.h"
31
#include "virconf.h"
32
#include "viralloc.h"
33
#include "verify.h"
34
#include "viruuid.h"
35
#include "virlog.h"
36 37 38
#include "count-one-bits.h"
#include "xenxs_private.h"
#include "xen_sxpr.h"
39
#include "virstoragefile.h"
40
#include "virstring.h"
41

J
Jim Fehlig 已提交
42
VIR_LOG_INIT("xenconfig.xen_sxpr");
43

P
Philipp Hahn 已提交
44
/* Get a domain id from a S-expression string */
45
int xenGetDomIdFromSxprString(const char *sexpr, int xendConfigVersion, int *id)
46 47
{
    struct sexpr *root = string2sexpr(sexpr);
48 49 50
    int ret;

    *id = -1;
51 52 53 54

    if (!root)
        return -1;

55
    ret = xenGetDomIdFromSxpr(root, xendConfigVersion, id);
56
    sexpr_free(root);
57
    return ret;
58 59
}

P
Philipp Hahn 已提交
60
/* Get a domain id from a S-expression */
61
int xenGetDomIdFromSxpr(const struct sexpr *root, int xendConfigVersion, int *id)
62 63
{
    const char * tmp = sexpr_node(root, "domain/domid");
64
    if (tmp == NULL && xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { /* domid was mandatory */
65 66
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("domain information incomplete, missing id"));
67
        return -1;
68
    } else {
69 70
        *id = tmp ? sexpr_int(root, "domain/domid") : -1;
        return 0;
71 72 73 74 75
    }
}

/*****************************************************************
 ******
P
Philipp Hahn 已提交
76
 ****** Parsing of S-Expression into virDomainDef objects
77 78 79 80
 ******
 *****************************************************************/

/**
P
Philipp Hahn 已提交
81
 * xenParseSxprOS:
82 83
 * @node: the root of the parsed S-Expression
 * @def: the domain config
P
Philipp Hahn 已提交
84
 * @hvm: true or 1 if node contains HVM S-Expression
85 86 87 88 89 90
 *
 * Parse the xend sexp for description of os and append it to buf.
 *
 * Returns 0 in case of success and -1 in case of error
 */
static int
M
Markus Groß 已提交
91 92 93
xenParseSxprOS(const struct sexpr *node,
               virDomainDefPtr def,
               int hvm)
94 95 96
{
    if (hvm) {
        if (sexpr_node_copy(node, "domain/image/hvm/loader", &def->os.loader) < 0)
97
            goto error;
98 99
        if (def->os.loader == NULL) {
            if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.loader) < 0)
100
                goto error;
101 102

            if (def->os.loader == NULL) {
103 104
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("domain information incomplete, missing HVM loader"));
105
                return -1;
106 107 108
            }
        } else {
            if (sexpr_node_copy(node, "domain/image/hvm/kernel", &def->os.kernel) < 0)
109
                goto error;
110
            if (sexpr_node_copy(node, "domain/image/hvm/ramdisk", &def->os.initrd) < 0)
111
                goto error;
112
            if (sexpr_node_copy(node, "domain/image/hvm/args", &def->os.cmdline) < 0)
113
                goto error;
114
            if (sexpr_node_copy(node, "domain/image/hvm/root", &def->os.root) < 0)
115
                goto error;
116 117 118
        }
    } else {
        if (sexpr_node_copy(node, "domain/image/linux/kernel", &def->os.kernel) < 0)
119
            goto error;
120
        if (sexpr_node_copy(node, "domain/image/linux/ramdisk", &def->os.initrd) < 0)
121
            goto error;
122
        if (sexpr_node_copy(node, "domain/image/linux/args", &def->os.cmdline) < 0)
123
            goto error;
124
        if (sexpr_node_copy(node, "domain/image/linux/root", &def->os.root) < 0)
125
            goto error;
126 127 128 129 130 131 132 133
    }

    /* If HVM kenrel == loader, then old xend, so kill off kernel */
    if (hvm &&
        def->os.kernel &&
        STREQ(def->os.kernel, def->os.loader)) {
        VIR_FREE(def->os.kernel);
    }
134 135 136 137 138 139
    /* Drop kernel argument that has no value */
    if (hvm &&
        def->os.kernel && *def->os.kernel == '\0' &&
        def->os.loader) {
        VIR_FREE(def->os.kernel);
    }
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

    if (!def->os.kernel &&
        hvm) {
        const char *boot = sexpr_node(node, "domain/image/hvm/boot");
        if ((boot != NULL) && (boot[0] != 0)) {
            while (*boot &&
                   def->os.nBootDevs < VIR_DOMAIN_BOOT_LAST) {
                if (*boot == 'a')
                    def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_FLOPPY;
                else if (*boot == 'c')
                    def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_DISK;
                else if (*boot == 'd')
                    def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_CDROM;
                else if (*boot == 'n')
                    def->os.bootDevs[def->os.nBootDevs++] = VIR_DOMAIN_BOOT_NET;
                boot++;
            }
        }
    }

    if (!hvm &&
        !def->os.kernel &&
        !def->os.bootloader) {
163 164
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("domain information incomplete, missing kernel & bootloader"));
165 166 167 168 169
        return -1;
    }

    return 0;

170
 error:
171 172 173
    return -1;
}

P
Philipp Hahn 已提交
174 175 176 177 178 179 180 181 182 183

/**
  * xenParseSxprChar:
  * @value: A string describing a character device.
  * @tty: the console pty path
  *
  * Parse the xend S-expression for description of a character device.
  *
  * Returns a character device object or NULL in case of failure.
  */
184
virDomainChrDefPtr
M
Markus Groß 已提交
185 186
xenParseSxprChar(const char *value,
                 const char *tty)
187 188 189 190 191
{
    const char *prefix;
    char *tmp;
    virDomainChrDefPtr def;

M
Michal Novotny 已提交
192
    if (!(def = virDomainChrDefNew()))
193 194 195 196 197 198
        return NULL;

    prefix = value;

    if (value[0] == '/') {
        def->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
199 200
        if (VIR_STRDUP(def->source.data.file.path, value) < 0)
            goto error;
201 202 203 204 205 206 207 208 209 210 211
    } else {
        if ((tmp = strchr(value, ':')) != NULL) {
            *tmp = '\0';
            value = tmp + 1;
        }

        if (STRPREFIX(prefix, "telnet")) {
            def->source.type = VIR_DOMAIN_CHR_TYPE_TCP;
            def->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
        } else {
            if ((def->source.type = virDomainChrTypeFromString(prefix)) < 0) {
212 213
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown chr device type '%s'"), prefix);
214 215 216 217 218 219 220
                goto error;
            }
        }
    }

    switch (def->source.type) {
    case VIR_DOMAIN_CHR_TYPE_PTY:
221 222
        if (VIR_STRDUP(def->source.data.file.path, tty) < 0)
            goto error;
223 224 225 226
        break;

    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
227 228
        if (VIR_STRDUP(def->source.data.file.path, value) < 0)
            goto error;
229 230 231 232 233 234 235 236
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
    {
        const char *offset = strchr(value, ':');
        const char *offset2;

        if (offset == NULL) {
237 238
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("malformed char device string"));
239 240 241 242
            goto error;
        }

        if (offset != value &&
243 244
            VIR_STRNDUP(def->source.data.tcp.host, value, offset - value) < 0)
            goto error;
245 246

        offset2 = strchr(offset, ',');
247 248
        offset++;
        if (VIR_STRNDUP(def->source.data.tcp.service, offset,
249
                        offset2 ? offset2 - offset : -1) < 0)
250
            goto error;
251 252 253 254 255 256 257 258 259 260 261 262

        if (offset2 && strstr(offset2, ",server"))
            def->source.data.tcp.listen = true;
    }
    break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
    {
        const char *offset = strchr(value, ':');
        const char *offset2, *offset3;

        if (offset == NULL) {
263 264
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("malformed char device string"));
265 266 267 268
            goto error;
        }

        if (offset != value &&
269 270
            VIR_STRNDUP(def->source.data.udp.connectHost, value, offset - value) < 0)
            goto error;
271 272 273

        offset2 = strchr(offset, '@');
        if (offset2 != NULL) {
274 275 276
            if (VIR_STRNDUP(def->source.data.udp.connectService,
                            offset + 1, offset2 - offset - 1) < 0)
                goto error;
277 278 279

            offset3 = strchr(offset2, ':');
            if (offset3 == NULL) {
280 281
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("malformed char device string"));
282 283 284 285
                goto error;
            }

            if (offset3 > (offset2 + 1) &&
286 287 288
                VIR_STRNDUP(def->source.data.udp.bindHost,
                            offset2 + 1, offset3 - offset2 - 1) < 0)
                goto error;
289

290 291
            if (VIR_STRDUP(def->source.data.udp.bindService, offset3 + 1) < 0)
                goto error;
292
        } else {
293 294
            if (VIR_STRDUP(def->source.data.udp.connectService, offset + 1) < 0)
                goto error;
295 296 297 298 299 300 301
        }
    }
    break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
    {
        const char *offset = strchr(value, ',');
302
        if (VIR_STRNDUP(def->source.data.nix.path, value,
303
                        offset ? offset - value : -1) < 0)
304
            goto error;
305 306 307 308 309 310 311 312 313 314

        if (offset != NULL &&
            strstr(offset, ",server") != NULL)
            def->source.data.nix.listen = true;
    }
    break;
    }

    return def;

315
 error:
316 317 318 319
    virDomainChrDefFree(def);
    return NULL;
}

P
Philipp Hahn 已提交
320

321
/**
P
Philipp Hahn 已提交
322 323 324 325
 * xenParseSxprDisks:
 * @def: the domain config
 * @root: root S-expression
 * @hvm: true or 1 if node contains HVM S-Expression
326 327
 * @xendConfigVersion: version of xend
 *
P
Philipp Hahn 已提交
328
 * This parses out block devices from the domain S-expression
329 330 331 332
 *
 * Returns 0 if successful or -1 if failed.
 */
static int
M
Markus Groß 已提交
333 334 335 336
xenParseSxprDisks(virDomainDefPtr def,
                  const struct sexpr *root,
                  int hvm,
                  int xendConfigVersion)
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
{
    const struct sexpr *cur, *node;
    virDomainDiskDefPtr disk = NULL;

    for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        node = cur->u.s.car;
        /* Normally disks are in a (device (vbd ...)) block
           but blktap disks ended up in a differently named
           (device (tap ....)) block.... */
        if (sexpr_lookup(node, "device/vbd") ||
            sexpr_lookup(node, "device/tap") ||
            sexpr_lookup(node, "device/tap2")) {
            char *offset;
            const char *src = NULL;
            const char *dst = NULL;
            const char *mode = NULL;
P
Philipp Hahn 已提交
353
            const char *bootable = NULL;
354 355 356 357 358 359

            /* Again dealing with (vbd...) vs (tap ...) differences */
            if (sexpr_lookup(node, "device/vbd")) {
                src = sexpr_node(node, "device/vbd/uname");
                dst = sexpr_node(node, "device/vbd/dev");
                mode = sexpr_node(node, "device/vbd/mode");
P
Philipp Hahn 已提交
360
                bootable = sexpr_node(node, "device/vbd/bootable");
361 362 363 364
            } else if (sexpr_lookup(node, "device/tap2")) {
                src = sexpr_node(node, "device/tap2/uname");
                dst = sexpr_node(node, "device/tap2/dev");
                mode = sexpr_node(node, "device/tap2/mode");
P
Philipp Hahn 已提交
365
                bootable = sexpr_node(node, "device/tap2/bootable");
366 367 368 369
            } else {
                src = sexpr_node(node, "device/tap/uname");
                dst = sexpr_node(node, "device/tap/dev");
                mode = sexpr_node(node, "device/tap/mode");
P
Philipp Hahn 已提交
370
                bootable = sexpr_node(node, "device/tap/bootable");
371 372
            }

373
            if (!(disk = virDomainDiskDefNew()))
374
                goto error;
375 376

            if (dst == NULL) {
377 378
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("domain information incomplete, vbd has no dev"));
379 380 381 382 383 384 385 386 387
                goto error;
            }

            if (src == NULL) {
                /* There is a case without the uname to the CD-ROM device */
                offset = strchr(dst, ':');
                if (!offset ||
                    !hvm ||
                    STRNEQ(offset, ":cdrom")) {
388 389
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("domain information incomplete, vbd has no src"));
390 391 392 393 394 395 396
                    goto error;
                }
            }

            if (src != NULL) {
                offset = strchr(src, ':');
                if (!offset) {
397 398
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("cannot parse vbd filename, missing driver name"));
399 400 401
                    goto error;
                }

P
Philipp Hahn 已提交
402 403
                if (sexpr_lookup(node, "device/tap2") &&
                    STRPREFIX(src, "tap:")) {
404
                    if (virDomainDiskSetDriver(disk, "tap2") < 0)
405
                        goto error;
P
Philipp Hahn 已提交
406
                } else {
407 408
                    char *tmp;
                    if (VIR_STRNDUP(tmp, src, offset - src) < 0)
409
                        goto error;
410 411
                    if (virDomainDiskSetDriver(disk, tmp) < 0) {
                        VIR_FREE(tmp);
P
Philipp Hahn 已提交
412 413
                        goto error;
                    }
414
                    VIR_FREE(tmp);
415 416 417 418
                }

                src = offset + 1;

419 420
                if (STREQ(virDomainDiskGetDriver(disk), "tap") ||
                    STREQ(virDomainDiskGetDriver(disk), "tap2")) {
421 422
                    char *driverType = NULL;

423 424
                    offset = strchr(src, ':');
                    if (!offset) {
425 426
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       "%s", _("cannot parse vbd filename, missing driver type"));
427 428 429
                        goto error;
                    }

430 431
                    if (VIR_STRNDUP(driverType, src, offset - src) < 0)
                        goto error;
432
                    if (STREQ(driverType, "aio"))
433
                        virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
434
                    else
435 436
                        virDomainDiskSetFormat(disk,
                                               virStorageFileFormatTypeFromString(driverType));
437
                    VIR_FREE(driverType);
438
                    if (virDomainDiskGetFormat(disk) <= 0) {
439
                        virReportError(VIR_ERR_INTERNAL_ERROR,
440
                                       _("Unknown driver type %s"), src);
441 442 443 444 445 446 447 448 449
                        goto error;
                    }

                    src = offset + 1;
                    /* Its possible to use blktap driver for block devs
                       too, but kinda pointless because blkback is better,
                       so we assume common case here. If blktap becomes
                       omnipotent, we can revisit this, perhaps stat()'ing
                       the src file in question */
E
Eric Blake 已提交
450
                    virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
451
                } else if (STREQ(virDomainDiskGetDriver(disk), "phy")) {
E
Eric Blake 已提交
452
                    virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK);
453
                } else if (STREQ(virDomainDiskGetDriver(disk), "file")) {
E
Eric Blake 已提交
454
                    virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
455 456 457 458 459
                }
            } else {
                /* No CDROM media so can't really tell. We'll just
                   call if a FILE for now and update when media
                   is inserted later */
E
Eric Blake 已提交
460
                virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
461 462
            }

463
            if (STREQLEN(dst, "ioemu:", 6))
464 465 466 467
                dst += 6;

            disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
            /* New style disk config from Xen >= 3.0.3 */
468
            if (xendConfigVersion >= XEND_CONFIG_VERSION_3_0_3) {
469 470
                offset = strrchr(dst, ':');
                if (offset) {
471
                    if (STREQ(offset, ":cdrom")) {
472
                        disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
473
                    } else if (STREQ(offset, ":disk")) {
474 475 476 477 478 479 480 481
                        /* The default anyway */
                    } else {
                        /* Unknown, lets pretend its a disk too */
                    }
                    offset[0] = '\0';
                }
            }

482 483
            if (VIR_STRDUP(disk->dst, dst) < 0)
                goto error;
484
            if (virDomainDiskSetSource(disk, src) < 0)
485
                goto error;
486 487 488 489 490 491 492 493 494 495 496 497

            if (STRPREFIX(disk->dst, "xvd"))
                disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
            else if (STRPREFIX(disk->dst, "hd"))
                disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
            else if (STRPREFIX(disk->dst, "sd"))
                disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
            else
                disk->bus = VIR_DOMAIN_DISK_BUS_IDE;

            if (mode &&
                strchr(mode, 'r'))
498
                disk->src->readonly = true;
499 500
            if (mode &&
                strchr(mode, '!'))
501
                disk->src->shared = true;
502 503

            if (VIR_REALLOC_N(def->disks, def->ndisks+1) < 0)
504
                goto error;
505

P
Philipp Hahn 已提交
506 507 508 509 510 511 512
            /* re-order disks if there is a bootable device */
            if (STREQ_NULLABLE(bootable, "1")) {
                def->disks[def->ndisks++] = def->disks[0];
                def->disks[0] = disk;
            } else {
                def->disks[def->ndisks++] = disk;
            }
513 514 515 516 517 518
            disk = NULL;
        }
    }

    return 0;

519
 error:
520 521 522 523 524
    virDomainDiskDefFree(disk);
    return -1;
}


P
Philipp Hahn 已提交
525 526 527 528 529 530 531 532 533
/**
 * xenParseSxprNets:
 * @def: the domain config
 * @root: root S-expression
 *
 * This parses out network devices from the domain S-expression
 *
 * Returns 0 if successful or -1 if failed.
 */
534
static int
M
Markus Groß 已提交
535 536
xenParseSxprNets(virDomainDefPtr def,
                 const struct sexpr *root)
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
{
    virDomainNetDefPtr net = NULL;
    const struct sexpr *cur, *node;
    const char *tmp;
    int vif_index = 0;

    for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        node = cur->u.s.car;
        if (sexpr_lookup(node, "device/vif")) {
            const char *tmp2, *model, *type;
            tmp2 = sexpr_node(node, "device/vif/script");
            tmp = sexpr_node(node, "device/vif/bridge");
            model = sexpr_node(node, "device/vif/model");
            type = sexpr_node(node, "device/vif/type");

            if (VIR_ALLOC(net) < 0)
553
                goto cleanup;
554 555 556 557 558 559

            if (tmp != NULL ||
                (tmp2 != NULL && STREQ(tmp2, DEFAULT_VIF_SCRIPT))) {
                net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
                /* XXX virtual network reverse resolve */

560 561 562 563 564
                if (VIR_STRDUP(net->data.bridge.brname, tmp) < 0)
                    goto cleanup;
                if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
                    VIR_STRDUP(net->script, tmp2) < 0)
                    goto cleanup;
565
                tmp = sexpr_node(node, "device/vif/ip");
566 567
                if (VIR_STRDUP(net->data.bridge.ipaddr, tmp) < 0)
                    goto cleanup;
568 569
            } else {
                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
570 571
                if (VIR_STRDUP(net->script, tmp2) < 0)
                    goto cleanup;
572
                tmp = sexpr_node(node, "device/vif/ip");
573 574
                if (VIR_STRDUP(net->data.ethernet.ipaddr, tmp) < 0)
                    goto cleanup;
575 576 577
            }

            tmp = sexpr_node(node, "device/vif/vifname");
578 579 580 581
            /* If vifname is specified in xend config, include it in net
             * definition regardless of domain state.  If vifname is not
             * specified, only generate one if domain is active (id != -1). */
            if (tmp) {
582 583
                if (VIR_STRDUP(net->ifname, tmp) < 0)
                    goto cleanup;
584 585
            } else if (def->id != -1) {
                if (virAsprintf(&net->ifname, "vif%d.%d", def->id, vif_index) < 0)
586
                    goto cleanup;
587 588 589 590
            }

            tmp = sexpr_node(node, "device/vif/mac");
            if (tmp) {
591
                if (virMacAddrParse(tmp, &net->mac) < 0) {
592 593
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("malformed mac address '%s'"), tmp);
594 595 596 597
                    goto cleanup;
                }
            }

598 599
            if (VIR_STRDUP(net->model, model) < 0)
                goto cleanup;
600

601 602 603
            if (!model && type && STREQ(type, "netfront") &&
                VIR_STRDUP(net->model, "netfront") < 0)
                goto cleanup;
604

605
            if (VIR_APPEND_ELEMENT(def->nets, def->nnets, net) < 0)
606
                goto cleanup;
607 608 609 610 611 612 613

            vif_index++;
        }
    }

    return 0;

614
 cleanup:
615 616 617 618 619
    virDomainNetDefFree(net);
    return -1;
}


P
Philipp Hahn 已提交
620 621 622 623 624 625 626 627 628
/**
 * xenParseSxprSound:
 * @def: the domain config
 * @str: comma separated list of sound models
 *
 * This parses out sound devices from the domain S-expression
 *
 * Returns 0 if successful or -1 if failed.
 */
629
int
M
Markus Groß 已提交
630 631
xenParseSxprSound(virDomainDefPtr def,
                  const char *str)
632 633
{
    if (STREQ(str, "all")) {
634
        size_t i;
635 636

        /*
637
         * Special compatibility code for Xen with a bogus
638 639
         * sound=all in config.
         *
E
Eric Blake 已提交
640
         * NB deliberately, don't include all possible
641 642 643 644 645 646 647 648 649 650
         * sound models anymore, just the 2 that were
         * historically present in Xen's QEMU.
         *
         * ie just es1370 + sb16.
         *
         * Hence use of MODEL_ES1370 + 1, instead of MODEL_LAST
         */

        if (VIR_ALLOC_N(def->sounds,
                        VIR_DOMAIN_SOUND_MODEL_ES1370 + 1) < 0)
651
            goto error;
652 653


654
        for (i = 0; i < (VIR_DOMAIN_SOUND_MODEL_ES1370 + 1); i++) {
655 656
            virDomainSoundDefPtr sound;
            if (VIR_ALLOC(sound) < 0)
657
                goto error;
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
            sound->model = i;
            def->sounds[def->nsounds++] = sound;
        }
    } else {
        char model[10];
        const char *offset = str, *offset2;

        do {
            int len;
            virDomainSoundDefPtr sound;
            offset2 = strchr(offset, ',');
            if (offset2)
                len = (offset2 - offset);
            else
                len = strlen(offset);
            if (virStrncpy(model, offset, len, sizeof(model)) == NULL) {
674 675 676
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Sound model %s too big for destination"),
                               offset);
677 678 679 680
                goto error;
            }

            if (VIR_ALLOC(sound) < 0)
681
                goto error;
682 683 684 685 686 687

            if ((sound->model = virDomainSoundModelTypeFromString(model)) < 0) {
                VIR_FREE(sound);
                goto error;
            }

688
            if (VIR_APPEND_ELEMENT(def->sounds, def->nsounds, sound) < 0) {
689
                virDomainSoundDefFree(sound);
690
                goto error;
691 692 693 694 695 696 697 698
            }

            offset = offset2 ? offset2 + 1 : NULL;
        } while (offset);
    }

    return 0;

699
 error:
700 701 702 703
    return -1;
}


P
Philipp Hahn 已提交
704 705 706 707 708 709 710 711 712
/**
 * xenParseSxprUSB:
 * @def: the domain config
 * @root: root S-expression
 *
 * This parses out USB devices from the domain S-expression
 *
 * Returns 0 if successful or -1 if failed.
 */
713
static int
M
Markus Groß 已提交
714 715
xenParseSxprUSB(virDomainDefPtr def,
                const struct sexpr *root)
716 717 718 719 720 721 722 723 724 725
{
    struct sexpr *cur, *node;
    const char *tmp;

    for (cur = sexpr_lookup(root, "domain/image/hvm"); cur && cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        node = cur->u.s.car;
        if (sexpr_lookup(node, "usbdevice")) {
            tmp = sexpr_node(node, "usbdevice");
            if (tmp && *tmp) {
                if (STREQ(tmp, "tablet") ||
726 727
                    STREQ(tmp, "mouse") ||
                    STREQ(tmp, "keyboard")) {
728 729
                    virDomainInputDefPtr input;
                    if (VIR_ALLOC(input) < 0)
730
                        goto error;
731 732 733
                    input->bus = VIR_DOMAIN_INPUT_BUS_USB;
                    if (STREQ(tmp, "tablet"))
                        input->type = VIR_DOMAIN_INPUT_TYPE_TABLET;
734
                    else if (STREQ(tmp, "mouse"))
735
                        input->type = VIR_DOMAIN_INPUT_TYPE_MOUSE;
736 737
                    else
                        input->type = VIR_DOMAIN_INPUT_TYPE_KBD;
738

739
                    if (VIR_APPEND_ELEMENT(def->inputs, def->ninputs, input) < 0) {
740
                        VIR_FREE(input);
741
                        goto error;
742 743 744 745 746 747 748 749 750
                    }
                } else {
                    /* XXX Handle other non-input USB devices later */
                }
            }
        }
    }
    return 0;

751
 error:
752 753 754
    return -1;
}

P
Philipp Hahn 已提交
755 756 757 758 759 760 761 762 763 764 765 766 767

/*
 * xenParseSxprGraphicsOld:
 * @def: the domain config
 * @root: root S-expression
 * @hvm: true or 1 if root contains HVM S-Expression
 * @xendConfigVersion: version of xend
 * @vncport: VNC port number
 *
 * This parses out VNC devices from the domain S-expression
 *
 * Returns 0 if successful or -1 if failed.
 */
768
static int
M
Markus Groß 已提交
769 770 771 772
xenParseSxprGraphicsOld(virDomainDefPtr def,
                        const struct sexpr *root,
                        int hvm,
                        int xendConfigVersion, int vncport)
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
{
    const char *tmp;
    virDomainGraphicsDefPtr graphics = NULL;

    if ((tmp = sexpr_fmt_node(root, "domain/image/%s/vnc", hvm ? "hvm" : "linux")) &&
        tmp[0] == '1') {
        /* Graphics device (HVM, or old (pre-3.0.4) style PV VNC config) */
        int port;
        const char *listenAddr = sexpr_fmt_node(root, "domain/image/%s/vnclisten", hvm ? "hvm" : "linux");
        const char *vncPasswd = sexpr_fmt_node(root, "domain/image/%s/vncpasswd", hvm ? "hvm" : "linux");
        const char *keymap = sexpr_fmt_node(root, "domain/image/%s/keymap", hvm ? "hvm" : "linux");
        const char *unused = sexpr_fmt_node(root, "domain/image/%s/vncunused", hvm ? "hvm" : "linux");

        port = vncport;

        if (VIR_ALLOC(graphics) < 0)
789
            goto error;
790 791 792 793 794

        graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
        /* For Xen >= 3.0.3, don't generate a fixed port mapping
         * because it will almost certainly be wrong ! Just leave
         * it as -1 which lets caller see that the VNC server isn't
J
Ján Tomko 已提交
795
         * present yet. Subsequent dumps of the XML will eventually
796 797
         * find the port in XenStore once VNC server has started
         */
798
        if (port == -1 && xendConfigVersion < XEND_CONFIG_VERSION_3_0_3)
799 800 801
            port = 5900 + def->id;

        if ((unused && STREQ(unused, "1")) || port == -1)
802
            graphics->data.vnc.autoport = true;
803 804 805
        graphics->data.vnc.port = port;

        if (listenAddr &&
806 807
            virDomainGraphicsListenSetAddress(graphics, 0, listenAddr, -1, true))
            goto error;
808

809 810
        if (VIR_STRDUP(graphics->data.vnc.auth.passwd, vncPasswd) < 0)
            goto error;
811

812 813
        if (VIR_STRDUP(graphics->data.vnc.keymap, keymap) < 0)
            goto error;
814 815

        if (VIR_ALLOC_N(def->graphics, 1) < 0)
816
            goto error;
817 818 819 820 821 822 823 824 825 826
        def->graphics[0] = graphics;
        def->ngraphics = 1;
        graphics = NULL;
    } else if ((tmp = sexpr_fmt_node(root, "domain/image/%s/sdl", hvm ? "hvm" : "linux")) &&
               tmp[0] == '1') {
        /* Graphics device (HVM, or old (pre-3.0.4) style PV sdl config) */
        const char *display = sexpr_fmt_node(root, "domain/image/%s/display", hvm ? "hvm" : "linux");
        const char *xauth = sexpr_fmt_node(root, "domain/image/%s/xauthority", hvm ? "hvm" : "linux");

        if (VIR_ALLOC(graphics) < 0)
827
            goto error;
828 829

        graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
830 831 832 833
        if (VIR_STRDUP(graphics->data.sdl.display, display) < 0)
            goto error;
        if (VIR_STRDUP(graphics->data.sdl.xauth, xauth) < 0)
            goto error;
834 835

        if (VIR_ALLOC_N(def->graphics, 1) < 0)
836
            goto error;
837 838 839 840 841 842 843
        def->graphics[0] = graphics;
        def->ngraphics = 1;
        graphics = NULL;
    }

    return 0;

844
 error:
845 846 847 848 849
    virDomainGraphicsDefFree(graphics);
    return -1;
}


P
Philipp Hahn 已提交
850 851 852 853 854 855 856 857 858 859
/*
 * xenParseSxprGraphicsNew:
 * @def: the domain config
 * @root: root S-expression
 * @vncport: VNC port number
 *
 * This parses out VNC devices from the domain S-expression
 *
 * Returns 0 if successful or -1 if failed.
 */
860
static int
M
Markus Groß 已提交
861 862
xenParseSxprGraphicsNew(virDomainDefPtr def,
                        const struct sexpr *root, int vncport)
863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
{
    virDomainGraphicsDefPtr graphics = NULL;
    const struct sexpr *cur, *node;
    const char *tmp;

    /* append network devices and framebuffer */
    for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        node = cur->u.s.car;
        if (sexpr_lookup(node, "device/vfb")) {
            /* New style graphics config for PV guests in >= 3.0.4,
             * or for HVM guests in >= 3.0.5 */
            if (sexpr_node(node, "device/vfb/type")) {
                tmp = sexpr_node(node, "device/vfb/type");
            } else if (sexpr_node(node, "device/vfb/vnc")) {
                tmp = "vnc";
            } else if (sexpr_node(node, "device/vfb/sdl")) {
                tmp = "sdl";
            } else {
                tmp = "unknown";
            }

            if (VIR_ALLOC(graphics) < 0)
885
                goto error;
886 887

            if ((graphics->type = virDomainGraphicsTypeFromString(tmp)) < 0) {
888 889
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown graphics type '%s'"), tmp);
890 891 892 893 894 895
                goto error;
            }

            if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
                const char *display = sexpr_node(node, "device/vfb/display");
                const char *xauth = sexpr_node(node, "device/vfb/xauthority");
896 897 898 899
                if (VIR_STRDUP(graphics->data.sdl.display, display) < 0)
                    goto error;
                if (VIR_STRDUP(graphics->data.sdl.xauth, xauth) < 0)
                    goto error;
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
            } else {
                int port;
                const char *listenAddr = sexpr_node(node, "device/vfb/vnclisten");
                const char *vncPasswd = sexpr_node(node, "device/vfb/vncpasswd");
                const char *keymap = sexpr_node(node, "device/vfb/keymap");
                const char *unused = sexpr_node(node, "device/vfb/vncunused");

                port = vncport;

                /* Didn't find port entry in xenstore */
                if (port == -1) {
                    const char *str = sexpr_node(node, "device/vfb/vncdisplay");
                    int val;
                    if (str != NULL && virStrToLong_i(str, NULL, 0, &val) == 0)
                        port = val;
                }

                if ((unused && STREQ(unused, "1")) || port == -1)
918
                    graphics->data.vnc.autoport = true;
919 920 921 922 923 924

                if (port >= 0 && port < 5900)
                    port += 5900;
                graphics->data.vnc.port = port;

                if (listenAddr &&
925 926
                    virDomainGraphicsListenSetAddress(graphics, 0, listenAddr, -1, true))
                    goto error;
927

928 929
                if (VIR_STRDUP(graphics->data.vnc.auth.passwd, vncPasswd) < 0)
                    goto error;
930

931 932
                if (VIR_STRDUP(graphics->data.vnc.keymap, keymap) < 0)
                    goto error;
933 934 935
            }

            if (VIR_ALLOC_N(def->graphics, 1) < 0)
936
                goto error;
937 938 939 940 941 942 943 944 945
            def->graphics[0] = graphics;
            def->ngraphics = 1;
            graphics = NULL;
            break;
        }
    }

    return 0;

946
 error:
947 948 949 950
    virDomainGraphicsDefFree(graphics);
    return -1;
}

P
Philipp Hahn 已提交
951

952
/**
P
Philipp Hahn 已提交
953 954
 * xenParseSxprPCI:
 * @def: the domain config
955 956
 * @root: root sexpr
 *
P
Philipp Hahn 已提交
957
 * This parses out PCI devices from the domain sexpr
958 959 960 961
 *
 * Returns 0 if successful or -1 if failed.
 */
static int
M
Markus Groß 已提交
962 963
xenParseSxprPCI(virDomainDefPtr def,
                const struct sexpr *root)
964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
{
    const struct sexpr *cur, *tmp = NULL, *node;
    virDomainHostdevDefPtr dev = NULL;

    /*
     * With the (domain ...) block we have the following odd setup
     *
     * (device
     *    (pci
     *       (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0))
     *       (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0))
     *    )
     * )
     *
     * Normally there is one (device ...) block per device, but in
E
Eric Blake 已提交
979
     * weird world of Xen PCI, once (device ...) covers multiple
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
     * devices.
     */

    for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        node = cur->u.s.car;
        if ((tmp = sexpr_lookup(node, "device/pci")) != NULL)
            break;
    }

    if (!tmp)
        return 0;

    for (cur = tmp; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
        const char *domain = NULL;
        const char *bus = NULL;
        const char *slot = NULL;
        const char *func = NULL;
        int domainID;
        int busID;
        int slotID;
        int funcID;

        node = cur->u.s.car;
        if (!sexpr_lookup(node, "dev"))
            continue;

        if (!(domain = sexpr_node(node, "dev/domain"))) {
1007 1008
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing PCI domain"));
1009 1010 1011
            goto error;
        }
        if (!(bus = sexpr_node(node, "dev/bus"))) {
1012 1013
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing PCI bus"));
1014 1015 1016
            goto error;
        }
        if (!(slot = sexpr_node(node, "dev/slot"))) {
1017 1018
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing PCI slot"));
1019 1020 1021
            goto error;
        }
        if (!(func = sexpr_node(node, "dev/func"))) {
1022 1023
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("missing PCI func"));
1024 1025 1026 1027
            goto error;
        }

        if (virStrToLong_i(domain, NULL, 0, &domainID) < 0) {
1028 1029
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse PCI domain '%s'"), domain);
1030 1031 1032
            goto error;
        }
        if (virStrToLong_i(bus, NULL, 0, &busID) < 0) {
1033 1034
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse PCI bus '%s'"), bus);
1035 1036 1037
            goto error;
        }
        if (virStrToLong_i(slot, NULL, 0, &slotID) < 0) {
1038 1039
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse PCI slot '%s'"), slot);
1040 1041 1042
            goto error;
        }
        if (virStrToLong_i(func, NULL, 0, &funcID) < 0) {
1043 1044
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot parse PCI func '%s'"), func);
1045 1046 1047
            goto error;
        }

1048 1049
        if (!(dev = virDomainHostdevDefAlloc()))
           goto error;
1050 1051

        dev->mode = VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
1052
        dev->managed = false;
1053
        dev->source.subsys.type = VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI;
1054 1055 1056 1057
        dev->source.subsys.u.pci.addr.domain = domainID;
        dev->source.subsys.u.pci.addr.bus = busID;
        dev->source.subsys.u.pci.addr.slot = slotID;
        dev->source.subsys.u.pci.addr.function = funcID;
1058

1059
        if (VIR_APPEND_ELEMENT(def->hostdevs, def->nhostdevs, dev) < 0)
1060
            goto error;
1061 1062 1063 1064
    }

    return 0;

1065
 error:
1066 1067 1068 1069 1070 1071
    virDomainHostdevDefFree(dev);
    return -1;
}


/**
M
Markus Groß 已提交
1072
 * xenParseSxpr:
1073 1074 1075
 * @root: the root of the parsed S-Expression
 * @xendConfigVersion: version of xend
 * @cpus: set of cpus the domain may be pinned to
P
Philipp Hahn 已提交
1076 1077
 * @tty: the console pty path
 * @vncport: VNC port number
1078
 *
P
Philipp Hahn 已提交
1079 1080
 * Parse the xend S-expression description and turn it into a virDomainDefPtr
 * representing these settings as closely as is practical.
1081
 *
P
Philipp Hahn 已提交
1082 1083
 * Returns the domain config or NULL in case of error.
 *         The caller must free() the returned value.
1084 1085
 */
virDomainDefPtr
M
Markus Groß 已提交
1086 1087 1088
xenParseSxpr(const struct sexpr *root,
             int xendConfigVersion,
             const char *cpus, char *tty, int vncport)
1089 1090 1091
{
    const char *tmp;
    virDomainDefPtr def;
P
Philipp Hahn 已提交
1092
    int hvm = 0, vmlocaltime;
1093 1094

    if (VIR_ALLOC(def) < 0)
1095
        goto error;
1096 1097

    tmp = sexpr_node(root, "domain/domid");
1098
    if (tmp == NULL && xendConfigVersion < XEND_CONFIG_VERSION_3_0_4) { /* domid was mandatory */
1099 1100
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("domain information incomplete, missing id"));
1101 1102 1103 1104 1105 1106 1107 1108 1109
        goto error;
    }
    def->virtType = VIR_DOMAIN_VIRT_XEN;
    if (tmp)
        def->id = sexpr_int(root, "domain/domid");
    else
        def->id = -1;

    if (sexpr_node_copy(root, "domain/name", &def->name) < 0)
1110
        goto error;
1111
    if (def->name == NULL) {
1112 1113
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("domain information incomplete, missing name"));
1114 1115 1116 1117 1118
        goto error;
    }

    tmp = sexpr_node(root, "domain/uuid");
    if (tmp == NULL) {
1119 1120
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("domain information incomplete, missing name"));
1121 1122
        goto error;
    }
1123 1124
    if (virUUIDParse(tmp, def->uuid) < 0)
        goto error;
1125 1126

    if (sexpr_node_copy(root, "domain/description", &def->description) < 0)
1127
        goto error;
1128 1129 1130 1131 1132

    hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0;
    if (!hvm) {
        if (sexpr_node_copy(root, "domain/bootloader",
                            &def->os.bootloader) < 0)
1133
            goto error;
1134 1135 1136

        if (!def->os.bootloader &&
            sexpr_has(root, "domain/bootloader") &&
1137 1138
            VIR_STRDUP(def->os.bootloader, "") < 0)
            goto error;
1139 1140 1141 1142

        if (def->os.bootloader &&
            sexpr_node_copy(root, "domain/bootloader_args",
                            &def->os.bootloaderArgs) < 0)
1143
            goto error;
1144 1145
    }

1146 1147
    if (VIR_STRDUP(def->os.type, hvm ? "hvm" : "linux") < 0)
        goto error;
1148 1149 1150

    if (def->id != 0) {
        if (sexpr_lookup(root, "domain/image")) {
M
Markus Groß 已提交
1151
            if (xenParseSxprOS(root, def, hvm) < 0)
1152 1153 1154 1155
                goto error;
        }
    }

1156 1157
    def->mem.max_balloon = (sexpr_u64(root, "domain/maxmem") << 10);
    def->mem.cur_balloon = (sexpr_u64(root, "domain/memory") << 10);
1158 1159 1160 1161
    if (def->mem.cur_balloon > def->mem.max_balloon)
        def->mem.cur_balloon = def->mem.max_balloon;

    if (cpus != NULL) {
H
Hu Tao 已提交
1162
        if (virBitmapParse(cpus, 0, &def->cpumask,
1163
                           VIR_DOMAIN_CPUMASK_LEN) < 0)
1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174
            goto error;
    }

    def->maxvcpus = sexpr_int(root, "domain/vcpus");
    def->vcpus = count_one_bits_l(sexpr_u64(root, "domain/vcpu_avail"));
    if (!def->vcpus || def->maxvcpus < def->vcpus)
        def->vcpus = def->maxvcpus;

    tmp = sexpr_node(root, "domain/on_poweroff");
    if (tmp != NULL) {
        if ((def->onPoweroff = virDomainLifecycleTypeFromString(tmp)) < 0) {
1175 1176
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown lifecycle type %s"), tmp);
1177 1178 1179 1180 1181 1182 1183 1184
            goto error;
        }
    } else
        def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;

    tmp = sexpr_node(root, "domain/on_reboot");
    if (tmp != NULL) {
        if ((def->onReboot = virDomainLifecycleTypeFromString(tmp)) < 0) {
1185 1186
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown lifecycle type %s"), tmp);
1187 1188 1189 1190 1191 1192 1193 1194
            goto error;
        }
    } else
        def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;

    tmp = sexpr_node(root, "domain/on_crash");
    if (tmp != NULL) {
        if ((def->onCrash = virDomainLifecycleCrashTypeFromString(tmp)) < 0) {
1195 1196
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown lifecycle type %s"), tmp);
1197 1198 1199 1200 1201 1202 1203
            goto error;
        }
    } else
        def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;

    if (hvm) {
        if (sexpr_int(root, "domain/image/hvm/acpi"))
J
Ján Tomko 已提交
1204
            def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON;
1205
        if (sexpr_int(root, "domain/image/hvm/apic"))
J
Ján Tomko 已提交
1206
            def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_TRISTATE_SWITCH_ON;
1207
        if (sexpr_int(root, "domain/image/hvm/pae"))
J
Ján Tomko 已提交
1208
            def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
1209
        if (sexpr_int(root, "domain/image/hvm/hap"))
J
Ján Tomko 已提交
1210
            def->features[VIR_DOMAIN_FEATURE_HAP] = VIR_TRISTATE_SWITCH_ON;
1211
        if (sexpr_int(root, "domain/image/hvm/viridian"))
J
Ján Tomko 已提交
1212
            def->features[VIR_DOMAIN_FEATURE_VIRIDIAN] = VIR_TRISTATE_SWITCH_ON;
P
Philipp Hahn 已提交
1213
    }
1214

P
Philipp Hahn 已提交
1215 1216 1217 1218 1219 1220
    /* 12aaf4a2486b (3.0.3) added a second low-priority 'localtime' setting */
    vmlocaltime = sexpr_int(root, "domain/localtime");
    if (hvm) {
        const char *value = sexpr_node(root, "domain/image/hvm/localtime");
        if (value) {
            if (virStrToLong_i(value, NULL, 0, &vmlocaltime) < 0) {
1221 1222
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown localtime offset %s"), value);
P
Philipp Hahn 已提交
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241
                goto error;
            }
        }
        /* only managed HVM domains since 3.1.0 have persistent rtc_timeoffset */
        if (xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
            if (vmlocaltime)
                def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
            else
                def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
            def->clock.data.utc_reset = true;
        } else {
            int rtc_offset;
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_VARIABLE;
            rtc_offset =  sexpr_int(root, "domain/image/hvm/rtc_timeoffset");
            def->clock.data.variable.adjustment = rtc_offset;
            def->clock.data.variable.basis = vmlocaltime ?
                VIR_DOMAIN_CLOCK_BASIS_LOCALTIME :
                VIR_DOMAIN_CLOCK_BASIS_UTC;
        }
1242 1243 1244 1245 1246

        if (sexpr_lookup(root, "domain/image/hvm/hpet")) {
            virDomainTimerDefPtr timer;

            if (VIR_ALLOC_N(def->clock.timers, 1) < 0 ||
1247
                VIR_ALLOC(timer) < 0)
1248 1249 1250 1251 1252 1253 1254 1255 1256
                goto error;

            timer->name = VIR_DOMAIN_TIMER_NAME_HPET;
            timer->present = sexpr_int(root, "domain/image/hvm/hpet");
            timer->tickpolicy = -1;

            def->clock.ntimers = 1;
            def->clock.timers[0] = timer;
        }
P
Philipp Hahn 已提交
1257 1258 1259 1260
    } else {
        const char *value = sexpr_node(root, "domain/image/linux/localtime");
        if (value) {
            if (virStrToLong_i(value, NULL, 0, &vmlocaltime) < 0) {
1261 1262
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unknown localtime offset %s"), value);
P
Philipp Hahn 已提交
1263 1264 1265 1266 1267
                goto error;
            }
        }
        /* PV domains do not have an emulated RTC and the offset is fixed. */
        if (vmlocaltime)
1268
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
P
Philipp Hahn 已提交
1269 1270 1271 1272
        else
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_UTC;
        def->clock.data.utc_reset = true;
    } /* !hvm */
1273 1274 1275 1276 1277

    if (sexpr_node_copy(root, hvm ?
                        "domain/image/hvm/device_model" :
                        "domain/image/linux/device_model",
                        &def->emulator) < 0)
1278
        goto error;
1279 1280

    /* append block devices */
M
Markus Groß 已提交
1281
    if (xenParseSxprDisks(def, root, hvm, xendConfigVersion) < 0)
1282 1283
        goto error;

M
Markus Groß 已提交
1284
    if (xenParseSxprNets(def, root) < 0)
1285 1286
        goto error;

M
Markus Groß 已提交
1287
    if (xenParseSxprPCI(def, root) < 0)
1288 1289 1290
        goto error;

    /* New style graphics device config */
M
Markus Groß 已提交
1291
    if (xenParseSxprGraphicsNew(def, root, vncport) < 0)
1292 1293 1294 1295
        goto error;

    /* Graphics device (HVM <= 3.0.4, or PV <= 3.0.3) vnc config */
    if ((def->ngraphics == 0) &&
M
Markus Groß 已提交
1296
        xenParseSxprGraphicsOld(def, root, hvm, xendConfigVersion,
1297 1298 1299 1300 1301 1302
                                      vncport) < 0)
        goto error;


    /* Old style cdrom config from Xen <= 3.0.2 */
    if (hvm &&
1303
        xendConfigVersion == XEND_CONFIG_VERSION_3_0_2) {
1304 1305 1306
        tmp = sexpr_node(root, "domain/image/hvm/cdrom");
        if ((tmp != NULL) && (tmp[0] != 0)) {
            virDomainDiskDefPtr disk;
1307
            if (!(disk = virDomainDiskDefNew()))
1308
                goto error;
1309
            if (virDomainDiskSetSource(disk, tmp) < 0) {
1310
                virDomainDiskDefFree(disk);
1311
                goto error;
1312
            }
E
Eric Blake 已提交
1313
            virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
1314
            disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
1315
            if (VIR_STRDUP(disk->dst, "hdc") < 0) {
1316
                virDomainDiskDefFree(disk);
1317
                goto error;
1318
            }
1319
            if (virDomainDiskSetDriver(disk, "file") < 0) {
1320
                virDomainDiskDefFree(disk);
1321
                goto error;
1322 1323
            }
            disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
1324
            disk->src->readonly = true;
1325

1326
            if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) {
1327
                virDomainDiskDefFree(disk);
1328
                goto error;
1329 1330 1331 1332 1333 1334 1335 1336
            }
        }
    }


    /* Floppy disk config */
    if (hvm) {
        const char *const fds[] = { "fda", "fdb" };
1337
        size_t i;
1338
        for (i = 0; i < ARRAY_CARDINALITY(fds); i++) {
1339 1340 1341
            tmp = sexpr_fmt_node(root, "domain/image/hvm/%s", fds[i]);
            if ((tmp != NULL) && (tmp[0] != 0)) {
                virDomainDiskDefPtr disk;
1342
                if (!(disk = virDomainDiskDefNew()))
1343
                    goto error;
1344
                if (virDomainDiskSetSource(disk, tmp) < 0) {
1345
                    virDomainDiskDefFree(disk);
1346
                    goto error;
1347
                }
E
Eric Blake 已提交
1348
                virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
1349
                disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
1350
                if (VIR_STRDUP(disk->dst, fds[i]) < 0) {
1351
                    virDomainDiskDefFree(disk);
1352
                    goto error;
1353
                }
1354
                if (virDomainDiskSetSource(disk, "file") < 0) {
1355
                    virDomainDiskDefFree(disk);
1356
                    goto error;
1357 1358 1359
                }
                disk->bus = VIR_DOMAIN_DISK_BUS_FDC;

1360
                if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0) {
1361
                    virDomainDiskDefFree(disk);
1362
                    goto error;
1363 1364 1365 1366 1367 1368 1369
                }
            }
        }
    }

    /* in case of HVM we have USB device emulation */
    if (hvm &&
M
Markus Groß 已提交
1370
        xenParseSxprUSB(def, root) < 0)
1371 1372 1373 1374
        goto error;

    /* Character device config */
    if (hvm) {
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392
        const struct sexpr *serial_root;
        bool have_multiple_serials = false;

        serial_root = sexpr_lookup(root, "domain/image/hvm/serial");
        if (serial_root) {
            const struct sexpr *cur, *node, *cur2;
            int ports_skipped = 0;

            for (cur = serial_root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
                node = cur->u.s.car;

                for (cur2 = node; cur2->kind == SEXPR_CONS; cur2 = cur2->u.s.cdr) {
                    tmp = cur2->u.s.car->u.value;

                    if (tmp && STRNEQ(tmp, "none")) {
                        virDomainChrDefPtr chr;
                        if ((chr = xenParseSxprChar(tmp, tty)) == NULL)
                            goto error;
1393 1394 1395
                        chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
                        chr->target.port = def->nserials + ports_skipped;
                        if (VIR_APPEND_ELEMENT(def->serials, def->nserials, chr) < 0) {
1396
                            virDomainChrDefFree(chr);
1397
                            goto error;
1398 1399 1400 1401 1402 1403 1404
                        }
                    }
                    else
                        ports_skipped++;

                    have_multiple_serials = true;
                }
1405 1406
            }
        }
1407 1408 1409 1410 1411 1412 1413

        if (!have_multiple_serials) {
            tmp = sexpr_node(root, "domain/image/hvm/serial");
            if (tmp && STRNEQ(tmp, "none")) {
                virDomainChrDefPtr chr;
                if ((chr = xenParseSxprChar(tmp, tty)) == NULL)
                    goto error;
1414 1415 1416
                chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
                chr->target.port = 0;
                if (VIR_APPEND_ELEMENT(def->serials, def->nserials, chr) < 0) {
1417
                    virDomainChrDefFree(chr);
1418
                    goto error;
1419 1420 1421 1422
                }
            }
        }

1423 1424 1425 1426
        tmp = sexpr_node(root, "domain/image/hvm/parallel");
        if (tmp && STRNEQ(tmp, "none")) {
            virDomainChrDefPtr chr;
            /* XXX does XenD stuff parallel port tty info into xenstore somewhere ? */
M
Markus Groß 已提交
1427
            if ((chr = xenParseSxprChar(tmp, NULL)) == NULL)
1428
                goto error;
1429 1430 1431
            chr->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
            chr->target.port = 0;
            if (VIR_APPEND_ELEMENT(def->parallels, def->nparallels, chr) < 0) {
1432
                virDomainChrDefFree(chr);
1433
                goto error;
1434 1435
            }
        }
1436
    } else if (def->id != 0) {
1437
        if (VIR_ALLOC_N(def->consoles, 1) < 0)
1438
            goto error;
1439
        def->nconsoles = 1;
1440
        /* Fake a paravirt console, since that's not in the sexpr */
1441
        if (!(def->consoles[0] = xenParseSxprChar("pty", tty)))
1442
            goto error;
1443 1444 1445
        def->consoles[0]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
        def->consoles[0]->target.port = 0;
        def->consoles[0]->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
1446 1447 1448 1449 1450 1451 1452 1453
    }
    VIR_FREE(tty);


    /* Sound device config */
    if (hvm &&
        (tmp = sexpr_node(root, "domain/image/hvm/soundhw")) != NULL &&
        *tmp) {
M
Markus Groß 已提交
1454
        if (xenParseSxprSound(def, tmp) < 0)
1455 1456 1457 1458 1459
            goto error;
    }

    return def;

1460
 error:
1461 1462 1463 1464 1465
    VIR_FREE(tty);
    virDomainDefFree(def);
    return NULL;
}

P
Philipp Hahn 已提交
1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479

/**
 * xenParseSxprString:
 * @sexpr: the root of the parsed S-Expression
 * @xendConfigVersion: version of xend
 * @tty: the console pty path
 * @vncport: VNC port number
 *
 * Parse the xend S-expression description and turn it into a virDomainDefPtr
 * representing these settings as closely as is practical.
 *
 * Returns the domain config or NULL in case of error.
 *         The caller must free() the returned value.
 */
1480
virDomainDefPtr
M
Markus Groß 已提交
1481
xenParseSxprString(const char *sexpr,
1482 1483 1484 1485 1486 1487 1488 1489
                         int xendConfigVersion, char *tty, int vncport)
{
    struct sexpr *root = string2sexpr(sexpr);
    virDomainDefPtr def;

    if (!root)
        return NULL;

M
Markus Groß 已提交
1490
    def = xenParseSxpr(root, xendConfigVersion, NULL, tty, vncport);
1491 1492 1493 1494

    sexpr_free(root);

    return def;
1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
}

/************************************************************************
 *                                                                      *
 * Converter functions to go from the XML tree to an S-Expr for Xen     *
 *                                                                      *
 ************************************************************************/


/**
P
Philipp Hahn 已提交
1505 1506 1507
 * xenFormatSxprGraphicsNew:
 * @def: the domain config
 * @buf: a buffer for the result S-expression
1508
 *
P
Philipp Hahn 已提交
1509 1510
 * Convert the graphics part of the domain description into a S-expression
 * in buf. (HVM > 3.0.4 or PV > 3.0.3)
1511 1512 1513 1514
 *
 * Returns 0 in case of success, -1 in case of error
 */
static int
M
Markus Groß 已提交
1515 1516
xenFormatSxprGraphicsNew(virDomainGraphicsDefPtr def,
                         virBufferPtr buf)
1517
{
1518 1519
    const char *listenAddr;

1520 1521
    if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
        def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
1522 1523 1524
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected graphics type %d"),
                       def->type);
1525 1526 1527 1528 1529 1530 1531 1532 1533
        return -1;
    }

    virBufferAddLit(buf, "(device (vkbd))");
    virBufferAddLit(buf, "(device (vfb ");

    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
        virBufferAddLit(buf, "(type sdl)");
        if (def->data.sdl.display)
1534
            virBufferAsprintf(buf, "(display '%s')", def->data.sdl.display);
1535
        if (def->data.sdl.xauth)
1536
            virBufferAsprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
1537 1538 1539 1540 1541 1542
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
        virBufferAddLit(buf, "(type vnc)");
        if (def->data.vnc.autoport) {
            virBufferAddLit(buf, "(vncunused 1)");
        } else {
            virBufferAddLit(buf, "(vncunused 0)");
1543
            virBufferAsprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
1544 1545
        }

1546 1547 1548
        listenAddr = virDomainGraphicsListenGetAddress(def, 0);
        if (listenAddr)
            virBufferAsprintf(buf, "(vnclisten '%s')", listenAddr);
1549
        if (def->data.vnc.auth.passwd)
1550
            virBufferAsprintf(buf, "(vncpasswd '%s')", def->data.vnc.auth.passwd);
1551
        if (def->data.vnc.keymap)
1552
            virBufferAsprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
1553 1554 1555 1556 1557 1558 1559 1560
    }

    virBufferAddLit(buf, "))");

    return 0;
}


P
Philipp Hahn 已提交
1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571
/**
 * xenFormatSxprGraphicsOld:
 * @def: the domain config
 * @buf: a buffer for the result S-expression
 * @xendConfigVersion: version of xend
 *
 * Convert the graphics part of the domain description into a S-expression
 * in buf. (HVM <= 3.0.4 or PV <= 3.0.3)
 *
 * Returns 0 in case of success, -1 in case of error
 */
1572
static int
M
Markus Groß 已提交
1573 1574 1575
xenFormatSxprGraphicsOld(virDomainGraphicsDefPtr def,
                         virBufferPtr buf,
                         int xendConfigVersion)
1576
{
1577 1578
    const char *listenAddr;

1579 1580
    if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_SDL &&
        def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
1581 1582 1583
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected graphics type %d"),
                       def->type);
1584 1585 1586 1587 1588 1589
        return -1;
    }

    if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
        virBufferAddLit(buf, "(sdl 1)");
        if (def->data.sdl.display)
1590
            virBufferAsprintf(buf, "(display '%s')", def->data.sdl.display);
1591
        if (def->data.sdl.xauth)
1592
            virBufferAsprintf(buf, "(xauthority '%s')", def->data.sdl.xauth);
1593 1594
    } else if (def->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
        virBufferAddLit(buf, "(vnc 1)");
1595
        if (xendConfigVersion >= XEND_CONFIG_VERSION_3_0_3) {
1596 1597 1598 1599
            if (def->data.vnc.autoport) {
                virBufferAddLit(buf, "(vncunused 1)");
            } else {
                virBufferAddLit(buf, "(vncunused 0)");
1600
                virBufferAsprintf(buf, "(vncdisplay %d)", def->data.vnc.port-5900);
1601 1602
            }

1603 1604 1605
            listenAddr = virDomainGraphicsListenGetAddress(def, 0);
            if (listenAddr)
                virBufferAsprintf(buf, "(vnclisten '%s')", listenAddr);
1606
            if (def->data.vnc.auth.passwd)
1607
                virBufferAsprintf(buf, "(vncpasswd '%s')", def->data.vnc.auth.passwd);
1608
            if (def->data.vnc.keymap)
1609
                virBufferAsprintf(buf, "(keymap '%s')", def->data.vnc.keymap);
1610 1611 1612 1613 1614 1615 1616

        }
    }

    return 0;
}

P
Philipp Hahn 已提交
1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627

/**
 * xenFormatSxprChr:
 * @def: the domain config
 * @buf: a buffer for the result S-expression
 *
 * Convert the character device part of the domain config into a S-expression
 * in buf.
 *
 * Returns 0 in case of success, -1 in case of error
 */
1628
int
M
Markus Groß 已提交
1629 1630
xenFormatSxprChr(virDomainChrDefPtr def,
                 virBufferPtr buf)
1631 1632 1633 1634
{
    const char *type = virDomainChrTypeToString(def->source.type);

    if (!type) {
1635 1636
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unexpected chr device type"));
1637 1638 1639 1640 1641 1642 1643 1644
        return -1;
    }

    switch (def->source.type) {
    case VIR_DOMAIN_CHR_TYPE_NULL:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_PTY:
1645
        virBufferAdd(buf, type, -1);
1646 1647 1648 1649
        break;

    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
1650
        virBufferAsprintf(buf, "%s:", type);
1651 1652 1653 1654 1655 1656 1657 1658
        virBufferEscapeSexpr(buf, "%s", def->source.data.file.path);
        break;

    case VIR_DOMAIN_CHR_TYPE_DEV:
        virBufferEscapeSexpr(buf, "%s", def->source.data.file.path);
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
1659
        virBufferAsprintf(buf, "%s:%s:%s%s",
1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671
                          (def->source.data.tcp.protocol
                           == VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW ?
                           "tcp" : "telnet"),
                          (def->source.data.tcp.host ?
                           def->source.data.tcp.host : ""),
                          (def->source.data.tcp.service ?
                           def->source.data.tcp.service : ""),
                          (def->source.data.tcp.listen ?
                           ",server,nowait" : ""));
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
1672
        virBufferAsprintf(buf, "%s:%s:%s@%s:%s", type,
1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683
                          (def->source.data.udp.connectHost ?
                           def->source.data.udp.connectHost : ""),
                          (def->source.data.udp.connectService ?
                           def->source.data.udp.connectService : ""),
                          (def->source.data.udp.bindHost ?
                           def->source.data.udp.bindHost : ""),
                          (def->source.data.udp.bindService ?
                           def->source.data.udp.bindService : ""));
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
1684
        virBufferAsprintf(buf, "%s:", type);
1685 1686 1687 1688
        virBufferEscapeSexpr(buf, "%s", def->source.data.nix.path);
        if (def->source.data.nix.listen)
            virBufferAddLit(buf, ",server,nowait");
        break;
1689 1690

    default:
1691 1692
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unsupported chr device type '%s'"), type);
1693
        return -1;
1694 1695
    }

1696
    if (virBufferCheckError(buf) < 0)
1697 1698 1699 1700 1701 1702 1703
        return -1;

    return 0;
}


/**
P
Philipp Hahn 已提交
1704 1705 1706 1707
 * xenFormatSxprDisk:
 * @node: node containing the disk description
 * @buf: a buffer for the result S-expression
 * @hvm: true or 1 if domain is HVM
1708
 * @xendConfigVersion: xend configuration file format
P
Philipp Hahn 已提交
1709
 * @isAttach: create expression for device attach (1).
1710
 *
P
Philipp Hahn 已提交
1711
 * Convert the disk device part of the domain config into a S-expresssion in buf.
1712 1713 1714 1715
 *
 * Returns 0 in case of success, -1 in case of error.
 */
int
1716
xenFormatSxprDisk(virDomainDiskDefPtr def,
M
Markus Groß 已提交
1717 1718 1719 1720
                  virBufferPtr buf,
                  int hvm,
                  int xendConfigVersion,
                  int isAttach)
1721
{
1722 1723 1724
    const char *src = virDomainDiskGetSource(def);
    const char *driver = virDomainDiskGetDriver(def);

1725 1726 1727 1728 1729 1730
    /* Xend (all versions) put the floppy device config
     * under the hvm (image (os)) block
     */
    if (hvm &&
        def->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
        if (isAttach) {
1731
            virReportError(VIR_ERR_INVALID_ARG,
1732
                           _("Cannot directly attach floppy %s"), src);
1733 1734 1735 1736 1737 1738 1739 1740
            return -1;
        }
        return 0;
    }

    /* Xend <= 3.0.2 doesn't include cdrom config here */
    if (hvm &&
        def->device == VIR_DOMAIN_DISK_DEVICE_CDROM &&
1741
        xendConfigVersion == XEND_CONFIG_VERSION_3_0_2) {
1742
        if (isAttach) {
1743
            virReportError(VIR_ERR_INVALID_ARG,
1744
                           _("Cannot directly attach CDROM %s"), src);
1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755
            return -1;
        }
        return 0;
    }

    if (!isAttach)
        virBufferAddLit(buf, "(device ");

    /* Normally disks are in a (device (vbd ...)) block
     * but blktap disks ended up in a differently named
     * (device (tap ....)) block.... */
1756
    if (STREQ_NULLABLE(driver, "tap")) {
1757
        virBufferAddLit(buf, "(tap ");
1758
    } else if (STREQ_NULLABLE(driver, "tap2")) {
1759 1760 1761 1762 1763 1764 1765
        virBufferAddLit(buf, "(tap2 ");
    } else {
        virBufferAddLit(buf, "(vbd ");
    }

    if (hvm) {
        /* Xend <= 3.0.2 wants a ioemu: prefix on devices for HVM */
1766
        if (xendConfigVersion == XEND_CONFIG_VERSION_3_0_2) {
1767 1768 1769 1770
            virBufferEscapeSexpr(buf, "(dev 'ioemu:%s')", def->dst);
        } else {
            /* But newer does not */
            virBufferEscapeSexpr(buf, "(dev '%s:", def->dst);
1771
            virBufferAsprintf(buf, "%s')",
1772 1773 1774 1775 1776 1777 1778 1779 1780
                              def->device == VIR_DOMAIN_DISK_DEVICE_CDROM ?
                              "cdrom" : "disk");
        }
    } else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
        virBufferEscapeSexpr(buf, "(dev '%s:cdrom')", def->dst);
    } else {
        virBufferEscapeSexpr(buf, "(dev '%s')", def->dst);
    }

1781 1782 1783 1784
    if (src) {
        if (driver) {
            if (STREQ(driver, "tap") ||
                STREQ(driver, "tap2")) {
1785
                const char *type;
1786
                int format = virDomainDiskGetFormat(def);
1787

1788
                if (!format || format == VIR_STORAGE_FILE_RAW)
1789
                    type = "aio";
1790
                else
1791 1792
                    type = virStorageFileFormatTypeToString(format);
                virBufferEscapeSexpr(buf, "(uname '%s:", driver);
1793
                virBufferEscapeSexpr(buf, "%s:", type);
1794
                virBufferEscapeSexpr(buf, "%s')", src);
1795
            } else {
1796 1797
                virBufferEscapeSexpr(buf, "(uname '%s:", driver);
                virBufferEscapeSexpr(buf, "%s')", src);
1798 1799
            }
        } else {
1800 1801
            int type = virDomainDiskGetType(def);

E
Eric Blake 已提交
1802
            if (type == VIR_STORAGE_TYPE_FILE) {
1803
                virBufferEscapeSexpr(buf, "(uname 'file:%s')", src);
E
Eric Blake 已提交
1804
            } else if (type == VIR_STORAGE_TYPE_BLOCK) {
1805 1806
                if (src[0] == '/')
                    virBufferEscapeSexpr(buf, "(uname 'phy:%s')", src);
1807 1808
                else
                    virBufferEscapeSexpr(buf, "(uname 'phy:/dev/%s')",
1809
                                         src);
1810
            } else {
1811 1812
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported disk type %s"),
E
Eric Blake 已提交
1813
                               virStorageTypeToString(type));
1814 1815 1816 1817 1818
                return -1;
            }
        }
    }

1819
    if (def->src->readonly)
1820
        virBufferAddLit(buf, "(mode 'r')");
1821
    else if (def->src->shared)
1822 1823 1824
        virBufferAddLit(buf, "(mode 'w!')");
    else
        virBufferAddLit(buf, "(mode 'w')");
1825
    if (def->transient) {
1826
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1827
                       _("transient disks not supported yet"));
1828 1829
        return -1;
    }
1830 1831 1832 1833 1834 1835 1836 1837 1838 1839

    if (!isAttach)
        virBufferAddLit(buf, ")");

    virBufferAddLit(buf, ")");

    return 0;
}

/**
P
Philipp Hahn 已提交
1840 1841 1842 1843 1844
 * xenFormatSxprNet:
 * @conn: connection
 * @def: the domain config
 * @buf: a buffer for the result S-expression
 * @hvm: true or 1 if domain is HVM
1845
 * @xendConfigVersion: xend configuration file format
P
Philipp Hahn 已提交
1846
 * @isAttach: create expression for device attach (1).
1847
 *
P
Philipp Hahn 已提交
1848
 * Convert the interface description of the domain config into a S-expression in buf.
1849 1850 1851 1852 1853 1854 1855
 * 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.
 */
int
M
Markus Groß 已提交
1856 1857 1858 1859 1860 1861
xenFormatSxprNet(virConnectPtr conn,
                 virDomainNetDefPtr def,
                 virBufferPtr buf,
                 int hvm,
                 int xendConfigVersion,
                 int isAttach)
1862 1863
{
    const char *script = DEFAULT_VIF_SCRIPT;
1864
    char macaddr[VIR_MAC_STRING_BUFLEN];
1865 1866 1867 1868

    if (def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
        def->type != VIR_DOMAIN_NET_TYPE_NETWORK &&
        def->type != VIR_DOMAIN_NET_TYPE_ETHERNET) {
1869 1870
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unsupported network type %d"), def->type);
1871 1872
        return -1;
    }
1873 1874 1875
    if (def->script &&
        def->type != VIR_DOMAIN_NET_TYPE_BRIDGE &&
        def->type != VIR_DOMAIN_NET_TYPE_ETHERNET) {
1876 1877 1878
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("scripts are not supported on interfaces of type %s"),
                       virDomainNetTypeToString(def->type));
1879 1880
        return -1;
    }
1881 1882 1883 1884 1885 1886

    if (!isAttach)
        virBufferAddLit(buf, "(device ");

    virBufferAddLit(buf, "(vif ");

1887
    virBufferAsprintf(buf, "(mac '%s')", virMacAddrFormat(&def->mac, macaddr));
1888 1889 1890 1891

    switch (def->type) {
    case VIR_DOMAIN_NET_TYPE_BRIDGE:
        virBufferEscapeSexpr(buf, "(bridge '%s')", def->data.bridge.brname);
1892 1893
        if (def->script)
            script = def->script;
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906

        virBufferEscapeSexpr(buf, "(script '%s')", script);
        if (def->data.bridge.ipaddr != NULL)
            virBufferEscapeSexpr(buf, "(ip '%s')", def->data.bridge.ipaddr);
        break;

    case VIR_DOMAIN_NET_TYPE_NETWORK:
    {
        virNetworkPtr network =
            virNetworkLookupByName(conn, def->data.network.name);
        char *bridge;

        if (!network) {
1907 1908
            virReportError(VIR_ERR_NO_NETWORK, "%s",
                           def->data.network.name);
1909 1910 1911 1912 1913 1914
            return -1;
        }

        bridge = virNetworkGetBridgeName(network);
        virNetworkFree(network);
        if (!bridge) {
1915 1916 1917
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("network %s is not active"),
                           def->data.network.name);
1918 1919 1920 1921 1922 1923 1924 1925 1926
            return -1;
        }
        virBufferEscapeSexpr(buf, "(bridge '%s')", bridge);
        virBufferEscapeSexpr(buf, "(script '%s')", script);
        VIR_FREE(bridge);
    }
    break;

    case VIR_DOMAIN_NET_TYPE_ETHERNET:
1927
        if (def->script)
1928
            virBufferEscapeSexpr(buf, "(script '%s')",
1929
                                 def->script);
1930 1931 1932 1933
        if (def->data.ethernet.ipaddr != NULL)
            virBufferEscapeSexpr(buf, "(ip '%s')", def->data.ethernet.ipaddr);
        break;

M
Michele Paolino 已提交
1934
    case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
1935 1936 1937 1938 1939 1940
    case VIR_DOMAIN_NET_TYPE_USER:
    case VIR_DOMAIN_NET_TYPE_SERVER:
    case VIR_DOMAIN_NET_TYPE_CLIENT:
    case VIR_DOMAIN_NET_TYPE_MCAST:
    case VIR_DOMAIN_NET_TYPE_INTERNAL:
    case VIR_DOMAIN_NET_TYPE_DIRECT:
1941
    case VIR_DOMAIN_NET_TYPE_HOSTDEV:
1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954
    case VIR_DOMAIN_NET_TYPE_LAST:
        break;
    }

    if (def->ifname != NULL &&
        !STRPREFIX(def->ifname, "vif"))
        virBufferEscapeSexpr(buf, "(vifname '%s')", def->ifname);

    if (!hvm) {
        if (def->model != NULL)
            virBufferEscapeSexpr(buf, "(model '%s')", def->model);
    }
    else {
1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969
        if (def->model != NULL && STREQ(def->model, "netfront")) {
            virBufferAddLit(buf, "(type netfront)");
        }
        else {
            if (def->model != NULL) {
                virBufferEscapeSexpr(buf, "(model '%s')", def->model);
            }
            /*
             * apparently (type ioemu) breaks paravirt drivers on HVM so skip
             * this from XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU
             */
            if (xendConfigVersion <= XEND_CONFIG_MAX_VERS_NET_TYPE_IOEMU) {
                virBufferAddLit(buf, "(type ioemu)");
            }
        }
1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980
    }

    if (!isAttach)
        virBufferAddLit(buf, ")");

    virBufferAddLit(buf, ")");

    return 0;
}


P
Philipp Hahn 已提交
1981 1982 1983 1984 1985 1986 1987 1988 1989
/**
 * xenFormatSxprPCI:
 * @def: the device config
 * @buf: a buffer for the result S-expression
 *
 * Convert a single PCI device part of the domain config into a S-expresssion in buf.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
1990
static void
M
Markus Groß 已提交
1991 1992
xenFormatSxprPCI(virDomainHostdevDefPtr def,
                 virBufferPtr buf)
1993
{
1994
    virBufferAsprintf(buf, "(dev (domain 0x%04x)(bus 0x%02x)(slot 0x%02x)(func 0x%x))",
1995 1996 1997 1998
                      def->source.subsys.u.pci.addr.domain,
                      def->source.subsys.u.pci.addr.bus,
                      def->source.subsys.u.pci.addr.slot,
                      def->source.subsys.u.pci.addr.function);
1999 2000
}

P
Philipp Hahn 已提交
2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011

/**
 * xenFormatSxprOnePCI:
 * @def: the device config
 * @buf: a buffer for the result S-expression
 * @detach: create expression for device detach (1).
 *
 * Convert a single PCI device part of the domain config into a S-expresssion in buf.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
2012
int
M
Markus Groß 已提交
2013 2014 2015
xenFormatSxprOnePCI(virDomainHostdevDefPtr def,
                    virBufferPtr buf,
                    int detach)
2016 2017
{
    if (def->managed) {
2018 2019
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("managed PCI devices not supported with XenD"));
2020 2021 2022 2023
        return -1;
    }

    virBufferAddLit(buf, "(pci ");
M
Markus Groß 已提交
2024
    xenFormatSxprPCI(def, buf);
2025 2026 2027 2028 2029 2030 2031 2032 2033
    if (detach)
        virBufferAddLit(buf, "(state 'Closing')");
    else
        virBufferAddLit(buf, "(state 'Initialising')");
    virBufferAddLit(buf, ")");

    return 0;
}

P
Philipp Hahn 已提交
2034 2035 2036 2037 2038 2039 2040 2041 2042 2043

/**
 * xenFormatSxprAllPCI:
 * @def: the domain config
 * @buf: a buffer for the result S-expression
 *
 * Convert all PCI device parts of the domain config into a S-expresssion in buf.
 *
 * Returns 0 in case of success, -1 in case of error.
 */
2044
static int
M
Markus Groß 已提交
2045 2046
xenFormatSxprAllPCI(virDomainDefPtr def,
                    virBufferPtr buf)
2047 2048
{
    int hasPCI = 0;
2049
    size_t i;
2050

2051
    for (i = 0; i < def->nhostdevs; i++)
2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073
        if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
            hasPCI = 1;

    if (!hasPCI)
        return 0;

    /*
     * With the (domain ...) block we have the following odd setup
     *
     * (device
     *    (pci
     *       (dev (domain 0x0000) (bus 0x00) (slot 0x1b) (func 0x0))
     *       (dev (domain 0x0000) (bus 0x00) (slot 0x13) (func 0x0))
     *    )
     * )
     *
     * Normally there is one (device ...) block per device, but in the
     * weird world of Xen PCI, one (device ...) covers multiple devices.
     */

    virBufferAddLit(buf, "(device (pci ");
2074
    for (i = 0; i < def->nhostdevs; i++) {
2075 2076 2077
        if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            def->hostdevs[i]->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) {
            if (def->hostdevs[i]->managed) {
2078 2079
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("managed PCI devices not supported with XenD"));
2080 2081 2082
                return -1;
            }

M
Markus Groß 已提交
2083
            xenFormatSxprPCI(def->hostdevs[i], buf);
2084 2085 2086 2087 2088 2089 2090
        }
    }
    virBufferAddLit(buf, "))");

    return 0;
}

P
Philipp Hahn 已提交
2091 2092 2093 2094 2095 2096 2097 2098 2099 2100

/**
 * xenFormatSxprSound:
 * @def: the domain config
 * @buf: a buffer for the result S-expression
 *
 * Convert all sound device parts of the domain config into S-expression in buf.
 *
 * Returns 0 if successful or -1 if failed.
 */
2101
int
M
Markus Groß 已提交
2102 2103
xenFormatSxprSound(virDomainDefPtr def,
                   virBufferPtr buf)
2104 2105
{
    const char *str;
2106
    size_t i;
2107

2108
    for (i = 0; i < def->nsounds; i++) {
2109
        if (!(str = virDomainSoundModelTypeToString(def->sounds[i]->model))) {
2110 2111 2112
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected sound model %d"),
                           def->sounds[i]->model);
2113 2114 2115 2116 2117 2118 2119
            return -1;
        }
        if (i)
            virBufferAddChar(buf, ',');
        virBufferEscapeSexpr(buf, "%s", str);
    }

2120
    if (virBufferCheckError(buf) < 0)
2121 2122 2123 2124 2125 2126
        return -1;

    return 0;
}


P
Philipp Hahn 已提交
2127 2128 2129 2130 2131 2132 2133 2134 2135
/**
 * xenFormatSxprInput:
 * @input: the input config
 * @buf: a buffer for the result S-expression
 *
 * Convert all input device parts of the domain config into S-expression in buf.
 *
 * Returns 0 if successful or -1 if failed.
 */
2136
static int
M
Markus Groß 已提交
2137 2138
xenFormatSxprInput(virDomainInputDefPtr input,
                   virBufferPtr buf)
2139 2140 2141 2142 2143
{
    if (input->bus != VIR_DOMAIN_INPUT_BUS_USB)
        return 0;

    if (input->type != VIR_DOMAIN_INPUT_TYPE_MOUSE &&
2144 2145
        input->type != VIR_DOMAIN_INPUT_TYPE_TABLET &&
        input->type != VIR_DOMAIN_INPUT_TYPE_KBD) {
2146 2147
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected input type %d"), input->type);
2148 2149 2150
        return -1;
    }

2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161
    switch (input->type) {
        case VIR_DOMAIN_INPUT_TYPE_MOUSE:
            virBufferAsprintf(buf, "(usbdevice %s)", "mouse");
            break;
        case VIR_DOMAIN_INPUT_TYPE_TABLET:
            virBufferAsprintf(buf, "(usbdevice %s)", "tablet");
            break;
        case VIR_DOMAIN_INPUT_TYPE_KBD:
            virBufferAsprintf(buf, "(usbdevice %s)", "keyboard");
            break;
    }
2162 2163 2164 2165 2166 2167 2168 2169 2170 2171

    return 0;
}


/* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is
   either 32, or 64 on a platform where long is big enough.  */
verify(MAX_VIRT_CPUS <= sizeof(1UL) * CHAR_BIT);

/**
M
Markus Groß 已提交
2172
 * xenFormatSxpr:
2173 2174 2175 2176
 * @conn: pointer to the hypervisor connection
 * @def: domain config definition
 * @xendConfigVersion: xend configuration file format
 *
P
Philipp Hahn 已提交
2177
 * Generate an S-expression representing the domain configuration.
2178 2179 2180 2181 2182
 *
 * Returns the 0 terminated S-Expr string or NULL in case of error.
 *         the caller must free() the returned value.
 */
char *
M
Markus Groß 已提交
2183 2184 2185
xenFormatSxpr(virConnectPtr conn,
              virDomainDefPtr def,
              int xendConfigVersion)
2186 2187 2188 2189 2190
{
    virBuffer buf = VIR_BUFFER_INITIALIZER;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    const char *tmp;
    char *bufout;
2191 2192
    int hvm = 0, vmlocaltime = -1;
    size_t i;
P
Philipp Hahn 已提交
2193
    bool in_image = false;
2194

2195
    VIR_DEBUG("Formatting domain sexpr");
2196 2197 2198

    virBufferAddLit(&buf, "(vm ");
    virBufferEscapeSexpr(&buf, "(name '%s')", def->name);
2199
    virBufferAsprintf(&buf, "(memory %llu)(maxmem %llu)",
2200 2201
                      VIR_DIV_UP(def->mem.cur_balloon, 1024),
                      VIR_DIV_UP(def->mem.max_balloon, 1024));
2202
    virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus);
2203 2204 2205
    /* Computing the vcpu_avail bitmask works because MAX_VIRT_CPUS is
       either 32, or 64 on a platform where long is big enough.  */
    if (def->vcpus < def->maxvcpus)
2206
        virBufferAsprintf(&buf, "(vcpu_avail %lu)", (1UL << def->vcpus) - 1);
2207 2208

    if (def->cpumask) {
H
Hu Tao 已提交
2209
        char *ranges = virBitmapFormat(def->cpumask);
2210 2211 2212 2213 2214 2215 2216
        if (ranges == NULL)
            goto error;
        virBufferEscapeSexpr(&buf, "(cpus '%s')", ranges);
        VIR_FREE(ranges);
    }

    virUUIDFormat(def->uuid, uuidstr);
2217
    virBufferAsprintf(&buf, "(uuid '%s')", uuidstr);
2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232

    if (def->description)
        virBufferEscapeSexpr(&buf, "(description '%s')", def->description);

    if (def->os.bootloader) {
        if (def->os.bootloader[0])
            virBufferEscapeSexpr(&buf, "(bootloader '%s')", def->os.bootloader);
        else
            virBufferAddLit(&buf, "(bootloader)");

        if (def->os.bootloaderArgs)
            virBufferEscapeSexpr(&buf, "(bootloader_args '%s')", def->os.bootloaderArgs);
    }

    if (!(tmp = virDomainLifecycleTypeToString(def->onPoweroff))) {
2233 2234
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected lifecycle value %d"), def->onPoweroff);
2235 2236
        goto error;
    }
2237
    virBufferAsprintf(&buf, "(on_poweroff '%s')", tmp);
2238 2239

    if (!(tmp = virDomainLifecycleTypeToString(def->onReboot))) {
2240 2241
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected lifecycle value %d"), def->onReboot);
2242 2243
        goto error;
    }
2244
    virBufferAsprintf(&buf, "(on_reboot '%s')", tmp);
2245 2246

    if (!(tmp = virDomainLifecycleCrashTypeToString(def->onCrash))) {
2247 2248
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unexpected lifecycle value %d"), def->onCrash);
2249 2250
        goto error;
    }
2251
    virBufferAsprintf(&buf, "(on_crash '%s')", tmp);
2252

P
Philipp Hahn 已提交
2253 2254
    if (STREQ(def->os.type, "hvm"))
        hvm = 1;
2255 2256 2257 2258 2259 2260

    if (!def->os.bootloader) {
        if (hvm)
            virBufferAddLit(&buf, "(image (hvm ");
        else
            virBufferAddLit(&buf, "(image (linux ");
P
Philipp Hahn 已提交
2261
        in_image = true;
2262 2263 2264

        if (hvm &&
            def->os.loader == NULL) {
2265
            virReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
2266
                           "%s", _("no HVM domain loader"));
2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285
            goto error;
        }

        if (def->os.kernel)
            virBufferEscapeSexpr(&buf, "(kernel '%s')", def->os.kernel);
        if (def->os.initrd)
            virBufferEscapeSexpr(&buf, "(ramdisk '%s')", def->os.initrd);
        if (def->os.root)
            virBufferEscapeSexpr(&buf, "(root '%s')", def->os.root);
        if (def->os.cmdline)
            virBufferEscapeSexpr(&buf, "(args '%s')", def->os.cmdline);

        if (hvm) {
            char bootorder[VIR_DOMAIN_BOOT_LAST+1];
            if (def->os.kernel)
                virBufferEscapeSexpr(&buf, "(loader '%s')", def->os.loader);
            else
                virBufferEscapeSexpr(&buf, "(kernel '%s')", def->os.loader);

2286
            virBufferAsprintf(&buf, "(vcpus %u)", def->maxvcpus);
2287
            if (def->vcpus < def->maxvcpus)
2288
                virBufferAsprintf(&buf, "(vcpu_avail %lu)",
2289 2290
                                  (1UL << def->vcpus) - 1);

2291
            for (i = 0; i < def->os.nBootDevs; i++) {
2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313
                switch (def->os.bootDevs[i]) {
                case VIR_DOMAIN_BOOT_FLOPPY:
                    bootorder[i] = 'a';
                    break;
                default:
                case VIR_DOMAIN_BOOT_DISK:
                    bootorder[i] = 'c';
                    break;
                case VIR_DOMAIN_BOOT_CDROM:
                    bootorder[i] = 'd';
                    break;
                case VIR_DOMAIN_BOOT_NET:
                    bootorder[i] = 'n';
                    break;
                }
            }
            if (def->os.nBootDevs == 0) {
                bootorder[0] = 'c';
                bootorder[1] = '\0';
            } else {
                bootorder[def->os.nBootDevs] = '\0';
            }
2314
            virBufferAsprintf(&buf, "(boot %s)", bootorder);
2315 2316

            /* some disk devices are defined here */
2317
            for (i = 0; i < def->ndisks; i++) {
2318 2319
                const char *src = virDomainDiskGetSource(def->disks[i]);

2320 2321 2322
                switch (def->disks[i]->device) {
                case VIR_DOMAIN_DISK_DEVICE_CDROM:
                    /* Only xend <= 3.0.2 wants cdrom config here */
2323
                    if (xendConfigVersion != XEND_CONFIG_VERSION_3_0_2)
2324
                        break;
2325
                    if (!STREQ(def->disks[i]->dst, "hdc") || !src)
2326 2327
                        break;

2328
                    virBufferEscapeSexpr(&buf, "(cdrom '%s')", src);
2329 2330 2331 2332 2333
                    break;

                case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
                    /* all xend versions define floppies here */
                    virBufferEscapeSexpr(&buf, "(%s ", def->disks[i]->dst);
2334
                    virBufferEscapeSexpr(&buf, "'%s')", src);
2335 2336 2337 2338 2339 2340 2341
                    break;

                default:
                    break;
                }
            }

J
Ján Tomko 已提交
2342
            if (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_TRISTATE_SWITCH_ON)
2343
                virBufferAddLit(&buf, "(acpi 1)");
J
Ján Tomko 已提交
2344
            if (def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_TRISTATE_SWITCH_ON)
2345
                virBufferAddLit(&buf, "(apic 1)");
J
Ján Tomko 已提交
2346
            if (def->features[VIR_DOMAIN_FEATURE_PAE] == VIR_TRISTATE_SWITCH_ON)
2347
                virBufferAddLit(&buf, "(pae 1)");
J
Ján Tomko 已提交
2348
            if (def->features[VIR_DOMAIN_FEATURE_HAP] == VIR_TRISTATE_SWITCH_ON)
2349
                virBufferAddLit(&buf, "(hap 1)");
J
Ján Tomko 已提交
2350
            if (def->features[VIR_DOMAIN_FEATURE_VIRIDIAN] == VIR_TRISTATE_SWITCH_ON)
2351
                virBufferAddLit(&buf, "(viridian 1)");
2352 2353 2354

            virBufferAddLit(&buf, "(usb 1)");

2355
            for (i = 0; i < def->ninputs; i++)
M
Markus Groß 已提交
2356
                if (xenFormatSxprInput(def->inputs[i], &buf) < 0)
2357 2358 2359 2360
                    goto error;

            if (def->parallels) {
                virBufferAddLit(&buf, "(parallel ");
M
Markus Groß 已提交
2361
                if (xenFormatSxprChr(def->parallels[0], &buf) < 0)
2362 2363 2364 2365 2366 2367
                    goto error;
                virBufferAddLit(&buf, ")");
            } else {
                virBufferAddLit(&buf, "(parallel none)");
            }
            if (def->serials) {
2368
                if ((def->nserials > 1) || (def->serials[0]->target.port != 0)) {
2369 2370
                    int maxport = -1, port;
                    size_t j = 0;
2371 2372 2373 2374 2375 2376

                    virBufferAddLit(&buf, "(serial (");
                    for (i = 0; i < def->nserials; i++)
                        if (def->serials[i]->target.port > maxport)
                            maxport = def->serials[i]->target.port;

2377
                    for (port = 0; port <= maxport; port++) {
2378 2379
                        virDomainChrDefPtr chr = NULL;

2380
                        if (port)
2381 2382
                            virBufferAddLit(&buf, " ");
                        for (j = 0; j < def->nserials; j++) {
2383
                            if (def->serials[j]->target.port == port) {
2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402
                                chr = def->serials[j];
                                break;
                            }
                        }
                        if (chr) {
                            if (xenFormatSxprChr(chr, &buf) < 0)
                                goto error;
                        } else {
                            virBufferAddLit(&buf, "none");
                        }
                    }
                    virBufferAddLit(&buf, "))");
                }
                else {
                    virBufferAddLit(&buf, "(serial ");
                    if (xenFormatSxprChr(def->serials[0], &buf) < 0)
                        goto error;
                    virBufferAddLit(&buf, ")");
                }
2403 2404 2405 2406 2407 2408
            } else {
                virBufferAddLit(&buf, "(serial none)");
            }

            if (def->sounds) {
                virBufferAddLit(&buf, "(soundhw '");
M
Markus Groß 已提交
2409
                if (xenFormatSxprSound(def, &buf) < 0)
2410 2411 2412
                    goto error;
                virBufferAddLit(&buf, "')");
            }
P
Philipp Hahn 已提交
2413
        } /* hvm */
2414 2415

        /* get the device emulation model */
2416
        if (def->emulator && (hvm || xendConfigVersion >= XEND_CONFIG_VERSION_3_0_4))
2417 2418
            virBufferEscapeSexpr(&buf, "(device_model '%s')", def->emulator);

2419 2420 2421 2422 2423 2424 2425 2426 2427
        /* look for HPET in order to override the hypervisor/xend default */
        for (i = 0; i < def->clock.ntimers; i++) {
            if (def->clock.timers[i]->name == VIR_DOMAIN_TIMER_NAME_HPET &&
                def->clock.timers[i]->present != -1) {
                virBufferAsprintf(&buf, "(hpet %d)",
                                  def->clock.timers[i]->present);
                break;
            }
        }
2428

2429 2430
        /* PV graphics for xen <= 3.0.4, or HVM graphics */
        if (hvm || (xendConfigVersion < XEND_CONFIG_MIN_VERS_PVFB_NEWCONF)) {
2431
            if ((def->ngraphics == 1) &&
M
Markus Groß 已提交
2432 2433
                xenFormatSxprGraphicsOld(def->graphics[0],
                                         &buf, xendConfigVersion) < 0)
2434 2435
                goto error;
        }
2436 2437 2438
    } else {
        /* PV domains accept kernel cmdline args */
        if (def->os.cmdline) {
P
Philipp Hahn 已提交
2439 2440
            virBufferEscapeSexpr(&buf, "(image (linux (args '%s')", def->os.cmdline);
            in_image = true;
2441
        }
P
Philipp Hahn 已提交
2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454
    } /* os.bootloader */


    if (xendConfigVersion < XEND_CONFIG_VERSION_3_1_0) {
        /* <3.1: UTC and LOCALTIME */
        switch (def->clock.offset) {
        case VIR_DOMAIN_CLOCK_OFFSET_UTC:
            vmlocaltime = 0;
            break;
        case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
            vmlocaltime = 1;
            break;
        default:
2455 2456 2457
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unsupported clock offset='%s'"),
                           virDomainClockOffsetTypeToString(def->clock.offset));
P
Philipp Hahn 已提交
2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477
            goto error;
        }
    } else {
        if (!in_image) {
            if (hvm)
                virBufferAddLit(&buf, "(image (hvm ");
            else
                virBufferAddLit(&buf, "(image (linux ");
            in_image = true;
        }
        if (hvm) {
            /* >=3.1 HV: VARIABLE */
            int rtc_timeoffset;
            switch (def->clock.offset) {
            case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
                vmlocaltime = (int)def->clock.data.variable.basis;
                rtc_timeoffset = def->clock.data.variable.adjustment;
                break;
            case VIR_DOMAIN_CLOCK_OFFSET_UTC:
                if (def->clock.data.utc_reset) {
2478
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2479
                                   _("unsupported clock adjustment='reset'"));
P
Philipp Hahn 已提交
2480 2481 2482 2483 2484 2485 2486
                    goto error;
                }
                vmlocaltime = 0;
                rtc_timeoffset = 0;
                break;
            case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
                if (def->clock.data.utc_reset) {
2487
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
2488
                                   _("unsupported clock adjustment='reset'"));
P
Philipp Hahn 已提交
2489 2490 2491 2492 2493 2494
                    goto error;
                }
                vmlocaltime = 1;
                rtc_timeoffset = 0;
                break;
            default:
2495 2496 2497
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported clock offset='%s'"),
                               virDomainClockOffsetTypeToString(def->clock.offset));
P
Philipp Hahn 已提交
2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510
                goto error;
            }
            virBufferAsprintf(&buf, "(rtc_timeoffset %d)", rtc_timeoffset);
        } else {
            /* >=3.1 PV: UTC and LOCALTIME */
            switch (def->clock.offset) {
            case VIR_DOMAIN_CLOCK_OFFSET_UTC:
                vmlocaltime = 0;
                break;
            case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
                vmlocaltime = 1;
                break;
            default:
2511 2512 2513
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported clock offset='%s'"),
                               virDomainClockOffsetTypeToString(def->clock.offset));
P
Philipp Hahn 已提交
2514 2515 2516 2517 2518
                goto error;
            }
        } /* !hvm */
        /* default post-XenD-3.1 location: */
        virBufferAsprintf(&buf, "(localtime %d)", vmlocaltime);
2519
    }
P
Philipp Hahn 已提交
2520 2521 2522 2523 2524 2525 2526 2527
    if (in_image) {
        /* closes (image(hvm|linux */
        virBufferAddLit(&buf, "))");
        in_image = false;
    }
    /* pre-XenD-3.1 and compatibility location */
    virBufferAsprintf(&buf, "(localtime %d)", vmlocaltime);

2528

2529
    for (i = 0; i < def->ndisks; i++)
2530
        if (xenFormatSxprDisk(def->disks[i],
M
Markus Groß 已提交
2531
                              &buf, hvm, xendConfigVersion, 0) < 0)
2532 2533
            goto error;

2534
    for (i = 0; i < def->nnets; i++)
M
Markus Groß 已提交
2535 2536
        if (xenFormatSxprNet(conn, def->nets[i],
                             &buf, hvm, xendConfigVersion, 0) < 0)
2537 2538
            goto error;

M
Markus Groß 已提交
2539
    if (xenFormatSxprAllPCI(def, &buf) < 0)
2540 2541
        goto error;

2542 2543
    /* New style PV graphics config xen >= 3.0.4 */
    if (!hvm && (xendConfigVersion >= XEND_CONFIG_MIN_VERS_PVFB_NEWCONF)) {
2544
        if ((def->ngraphics == 1) &&
M
Markus Groß 已提交
2545
            xenFormatSxprGraphicsNew(def->graphics[0], &buf) < 0)
2546 2547 2548 2549 2550
            goto error;
    }

    virBufferAddLit(&buf, ")"); /* closes (vm */

2551
    if (virBufferCheckError(&buf) < 0)
2552 2553 2554 2555 2556 2557
        goto error;

    bufout = virBufferContentAndReset(&buf);
    VIR_DEBUG("Formatted sexpr: \n%s", bufout);
    return bufout;

2558
 error:
2559 2560 2561
    virBufferFreeAndReset(&buf);
    return NULL;
}