vmx.c 118.0 KB
Newer Older
1 2

/*
3
 * vmx.c: VMware VMX parsing/formatting functions
4
 *
5
 * Copyright (C) 2010-2011 Red Hat, Inc.
6
 * Copyright (C) 2009-2010 Matthias Bolte <matthias.bolte@googlemail.com>
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * 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
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 */

#include <config.h>

26
#include <c-ctype.h>
27
#include <libxml/uri.h>
28

29 30
#include "internal.h"
#include "virterror_internal.h"
31
#include "conf.h"
32 33
#include "memory.h"
#include "logging.h"
34 35
#include "uuid.h"
#include "vmx.h"
36 37 38 39 40 41 42 43 44

/*

mapping:

domain-xml                        <=>   vmx


                                        config.version = "8"                    # essential
45 46
                                        virtualHW.version = "4"                 # essential for ESX 3.5
                                        virtualHW.version = "7"                 # essential for ESX 4.0
47 48 49 50 51 52


???                               <=>   guestOS = "<value>"                     # essential, FIXME: not representable
def->id = <value>                 <=>   ???                                     # not representable
def->uuid = <value>               <=>   uuid.bios = "<value>"
def->name = <value>               <=>   displayName = "<value>"
53 54
def->mem.max_balloon = <value kilobyte>    <=>   memsize = "<value megabyte>"            # must be a multiple of 4, defaults to 32
def->mem.cur_balloon = <value kilobyte>    <=>   sched.mem.max = "<value megabyte>"      # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon
55
def->mem.min_guarantee = <value kilobyte>  <=>   sched.mem.minsize = "<value megabyte>"  # defaults to 0
E
Eric Blake 已提交
56
def->maxvcpus = <value>           <=>   numvcpus = "<value>"                    # must be 1 or a multiple of 2, defaults to 1
57 58 59 60 61 62 63 64 65 66
def->cpumask = <uint list>        <=>   sched.cpu.affinity = "<uint list>"



################################################################################
## os ##########################################################################

def->os

->type = "hvm"
M
Matthias Bolte 已提交
67
->arch = <arch>                   <=>   guestOS = "<value>"                     # if <value> ends with -64 than <arch> is x86_64, otherwise <arch> is i686
68 69 70 71 72 73 74 75 76 77 78
->machine
->nBootDevs
->bootDevs
->init
->kernel
->initrd
->cmdline
->root
->loader
->bootloader
->bootloaderArgs
M
Matthias Bolte 已提交
79
->smbios_mode                     <=>   smbios.reflecthost = "<value>"          # <value> == true means SMBIOS_HOST, otherwise it's SMBIOS_EMULATE, defaults to "false"
80 81 82 83 84 85



################################################################################
## disks #######################################################################

86 87 88
                                        scsi[0..3]:[0..6,8..15] -> <controller>:<unit> with 1 bus per controller
                                        ide[0..1]:[0..1]        -> <bus>:<unit> with 1 controller
                                        floppy[0..1]            -> <unit> with 1 controller and 1 bus per controller
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107

def->disks[0]...

## disks: scsi hard drive from .vmdk image #####################################

                                        scsi0.present = "true"                  # defaults to "false"
                                        scsi0:0.present = "true"                # defaults to "false"
                                        scsi0:0.startConnected = "true"         # defaults to "true"

???                               <=>   scsi0:0.mode = "persistent"             # defaults to "persistent"
                                        scsi0:0.mode = "undoable"
                                        scsi0:0.mode = "independent-persistent"
                                        scsi0:0.mode = "independent-nonpersistent"

...
->type = _DISK_TYPE_FILE          <=>   scsi0:0.deviceType = "scsi-hardDisk"    # defaults to ?
->device = _DISK_DEVICE_DISK      <=>   scsi0:0.deviceType = "scsi-hardDisk"    # defaults to ?
->bus = _DISK_BUS_SCSI
->src = <value>.vmdk              <=>   scsi0:0.fileName = "<value>.vmdk"
108
->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
->driverType
->cachemode                       <=>   scsi0:0.writeThrough = "<value>"        # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT
->readonly
->shared
->slotnum


## disks: ide hard drive from .vmdk image ######################################

                                        ide0:0.present = "true"                 # defaults to "false"
                                        ide0:0.startConnected = "true"          # defaults to "true"

???                               <=>   ide0:0.mode = "persistent"              # defaults to "persistent"
                                        ide0:0.mode = "undoable"
                                        ide0:0.mode = "independent-persistent"
                                        ide0:0.mode = "independent-nonpersistent"

...
->type = _DISK_TYPE_FILE          <=>   ide0:0.deviceType = "ata-hardDisk"      # defaults to ?
->device = _DISK_DEVICE_DISK      <=>   ide0:0.deviceType = "ata-hardDisk"      # defaults to ?
->bus = _DISK_BUS_IDE
->src = <value>.vmdk              <=>   ide0:0.fileName = "<value>.vmdk"
132
->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
->driverName
->driverType
->cachemode                       <=>   ide0:0.writeThrough = "<value>"         # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT
->readonly
->shared
->slotnum


## disks: scsi cdrom from .iso image ###########################################

                                        scsi0.present = "true"                  # defaults to "false"
                                        scsi0:0.present = "true"                # defaults to "false"
                                        scsi0:0.startConnected = "true"         # defaults to "true"

...
->type = _DISK_TYPE_FILE          <=>   scsi0:0.deviceType = "cdrom-image"      # defaults to ?
->device = _DISK_DEVICE_CDROM     <=>   scsi0:0.deviceType = "cdrom-image"      # defaults to ?
->bus = _DISK_BUS_SCSI
->src = <value>.iso               <=>   scsi0:0.fileName = "<value>.iso"
152
->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
->driverType
->cachemode
->readonly
->shared
->slotnum


## disks: ide cdrom from .iso image ############################################

                                        ide0:0.present = "true"                 # defaults to "false"
                                        ide0:0.startConnected = "true"          # defaults to "true"

...
->type = _DISK_TYPE_FILE          <=>   ide0:0.deviceType = "cdrom-image"       # defaults to ?
->device = _DISK_DEVICE_CDROM     <=>   ide0:0.deviceType = "cdrom-image"       # defaults to ?
->bus = _DISK_BUS_IDE
->src = <value>.iso               <=>   ide0:0.fileName = "<value>.iso"
171
->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
->driverName
->driverType
->cachemode
->readonly
->shared
->slotnum


## disks: scsi cdrom from host device ##########################################

                                        scsi0.present = "true"                  # defaults to "false"
                                        scsi0:0.present = "true"                # defaults to "false"
                                        scsi0:0.startConnected = "true"         # defaults to "true"

...
->type = _DISK_TYPE_BLOCK         <=>   scsi0:0.deviceType = "atapi-cdrom"      # defaults to ?
->device = _DISK_DEVICE_CDROM     <=>   scsi0:0.deviceType = "atapi-cdrom"      # defaults to ?
->bus = _DISK_BUS_SCSI
->src = <value>                   <=>   scsi0:0.fileName = "<value>"            # e.g. "/dev/scd0" ?
191
->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
->driverType
->cachemode
->readonly
->shared
->slotnum


## disks: ide cdrom from host device ###########################################

                                        ide0:0.present = "true"                 # defaults to "false"
                                        ide0:0.startConnected = "true"          # defaults to "true"
                                        ide0:0.clientDevice = "false"           # defaults to "false"

...
->type = _DISK_TYPE_BLOCK         <=>   ide0:0.deviceType = "atapi-cdrom"       # defaults to ?
->device = _DISK_DEVICE_CDROM     <=>   ide0:0.deviceType = "atapi-cdrom"       # defaults to ?
->bus = _DISK_BUS_IDE
->src = <value>                   <=>   ide0:0.fileName = "<value>"             # e.g. "/dev/scd0"
211
->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
212 213 214 215 216 217 218 219 220 221
->driverName
->driverType
->cachemode
->readonly
->shared
->slotnum


## disks: floppy from .flp image ###############################################

222
                                        floppy0.present = "true"                # defaults to "true"
223 224 225 226 227 228 229 230
                                        floppy0.startConnected = "true"         # defaults to "true"
                                        floppy0.clientDevice = "false"          # defaults to "false"

...
->type = _DISK_TYPE_FILE          <=>   floppy0.fileType = "file"               # defaults to ?
->device = _DISK_DEVICE_FLOPPY
->bus = _DISK_BUS_FDC
->src = <value>.flp               <=>   floppy0.fileName = "<value>.flp"
231
->dst = fd[<unit> mapped to [a-z]+]
232 233 234 235 236 237 238 239 240 241
->driverName
->driverType
->cachemode
->readonly
->shared
->slotnum


## disks: floppy from host device ##############################################

242
                                        floppy0.present = "true"                # defaults to "true"
243 244 245 246 247 248 249 250
                                        floppy0.startConnected = "true"         # defaults to "true"
                                        floppy0.clientDevice = "false"          # defaults to "false"

...
->type = _DISK_TYPE_BLOCK         <=>   floppy0.fileType = "device"             # defaults to ?
->device = _DISK_DEVICE_FLOPPY
->bus = _DISK_BUS_FDC
->src = <value>                   <=>   floppy0.fileName = "<value>"            # e.g. "/dev/fd0"
251
->dst = fd[<unit> mapped to [a-z]+]
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
->driverName
->driverType
->cachemode
->readonly
->shared
->slotnum



################################################################################
## nets ########################################################################

                                        ethernet[0..3] -> <controller>

                                        ethernet0.present = "true"              # defaults to "false"
                                        ethernet0.startConnected = "true"       # defaults to "true"

                                        ethernet0.networkName = "VM Network"    # FIXME

def->nets[0]...
->model = <model>                 <=>   ethernet0.virtualDev = "<model>"        # default depends on guestOS value
273
                                        ethernet0.features = "15"               # if present and virtualDev is "vmxnet" => vmxnet2 (enhanced)
274 275 276 277


                                        ethernet0.addressType = "generated"     # default to "generated"
->mac = <value>                   <=>   ethernet0.generatedAddress = "<value>"
278
                                        ethernet0.generatedAddressOffset = "0"  # ?
279 280 281 282 283


                                        ethernet0.addressType = "static"        # default to "generated"
->mac = <value>                   <=>   ethernet0.address = "<value>"

284 285 286 287

                                        ethernet0.addressType = "vpx"           # default to "generated"
->mac = <value>                   <=>   ethernet0.generatedAddress = "<value>"

288 289 290 291 292

                                        ethernet0.addressType = "static"        # default to "generated"
->mac = <value>                   <=>   ethernet0.address = "<value>"
                                        ethernet0.checkMACAddress = "false"     # mac address outside the VMware prefixes

M
Matthias Bolte 已提交
293
                                                                                # 00:0c:29 prefix for autogenerated mac's -> ethernet0.addressType = "generated"
294
                                                                                # 00:50:56 prefix for manual configured mac's
M
Matthias Bolte 已提交
295
                                                                                #          00:50:56:00:00:00 - 00:50:56:3f:ff:ff -> ethernet0.addressType = "static"
296
                                                                                #          00:50:56:80:00:00 - 00:50:56:bf:ff:ff -> ethernet0.addressType = "vpx"
297 298 299 300 301 302 303
                                                                                # 00:05:69 old prefix from esx 1.5


## nets: bridged ###############################################################

...
->type = _NET_TYPE_BRIDGE         <=>   ethernet0.connectionType = "bridged"    # defaults to "bridged"
M
Matthias Bolte 已提交
304
->data.bridge.brname = <value>    <=>   ethernet0.networkName = "<value>"
305 306 307 308


## nets: hostonly ##############################################################

M
Matthias Bolte 已提交
309
...                                                                             # FIXME: Investigate if ESX supports this
310 311 312 313 314
->type = _NET_TYPE_NETWORK        <=>   ethernet0.connectionType = "hostonly"   # defaults to "bridged"


## nets: nat ###################################################################

M
Matthias Bolte 已提交
315
...                                                                             # FIXME: Investigate if ESX supports this
316 317 318 319 320 321 322
->type = _NET_TYPE_USER           <=>   ethernet0.connectionType = "nat"        # defaults to "bridged"


## nets: custom ################################################################

...
->type = _NET_TYPE_BRIDGE         <=>   ethernet0.connectionType = "custom"     # defaults to "bridged"
M
Matthias Bolte 已提交
323 324
->data.bridge.brname = <value>    <=>   ethernet0.networkName = "<value>"
->ifname = <value>                <=>   ethernet0.vnet = "<value>"
325 326 327



328 329 330 331 332 333 334 335 336 337
################################################################################
## video #######################################################################

def->videos[0]...
->type = _VIDEO_TYPE_VMVGA
->vram = <value kilobyte>         <=>   svga.vramSize = "<value byte>"
->heads = 1



338 339 340 341 342 343 344 345 346
################################################################################
## serials #####################################################################

                                        serial[0..3] -> <port>

                                        serial0.present = "true"                # defaults to "false"
                                        serial0.startConnected = "true"         # defaults to "true"

def->serials[0]...
347
->target.port = <port>
348 349 350 351 352 353 354


## serials: device #############################################################

->type = _CHR_TYPE_DEV            <=>   serial0.fileType = "device"
->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "/dev/ttyS0"
???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
M
Matthias Bolte 已提交
355
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
356 357 358 359 360 361 362


## serials: file ###############################################################

->type = _CHR_TYPE_FILE           <=>   serial0.fileType = "file"
->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.file"
???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
M
Matthias Bolte 已提交
363
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
364 365 366 367 368 369


## serials: pipe, far end -> app ###############################################

->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
M
Matthias Bolte 已提交
370
???                               <=>   serial0.pipe.endPoint = "client"        # defaults to ?, FIXME: not representable
371
???                               <=>   serial0.tryNoRxLoss = "true"            # defaults to "false", FIXME: not representable
M
Matthias Bolte 已提交
372
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
373 374 375

->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
M
Matthias Bolte 已提交
376
???                               <=>   serial0.pipe.endPoint = "server"        # defaults to ?, FIXME: not representable
377
???                               <=>   serial0.tryNoRxLoss = "true"            # defaults to "false", FIXME: not representable
M
Matthias Bolte 已提交
378
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
379 380 381 382 383 384


## serials: pipe, far end -> vm ################################################

->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
M
Matthias Bolte 已提交
385
???                               <=>   serial0.pipe.endPoint = "client"        # defaults to ?, FIXME: not representable
386
???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
M
Matthias Bolte 已提交
387
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
388 389 390

->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
M
Matthias Bolte 已提交
391
???                               <=>   serial0.pipe.endPoint = "server"        # defaults to ?, FIXME: not representable
392
???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
M
Matthias Bolte 已提交
393
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
394 395


396 397 398 399 400 401 402 403
## serials: network, server (since vSphere 4.1) ################################

->type = _CHR_TYPE_TCP            <=>   serial0.fileType = "network"

->data.tcp.host = <host>          <=>   serial0.fileName = "<protocol>://<host>:<service>"
->data.tcp.service = <service>                                                  # e.g. "telnet://0.0.0.0:42001"
->data.tcp.protocol = <protocol>

404
->data.tcp.listen = true          <=>   serial0.network.endPoint = "server"     # defaults to "server"
405 406 407 408 409 410 411 412 413 414 415 416 417 418

???                               <=>   serial0.vspc = "foobar"                 # defaults to <not present>, FIXME: not representable
???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable


## serials: network, client (since vSphere 4.1) ################################

->type = _CHR_TYPE_TCP            <=>   serial0.fileType = "network"

->data.tcp.host = <host>          <=>   serial0.fileName = "<protocol>://<host>:<service>"
->data.tcp.service = <service>                                                  # e.g. "telnet://192.168.0.17:42001"
->data.tcp.protocol = <protocol>

419
->data.tcp.listen = false         <=>   serial0.network.endPoint = "client"     # defaults to "server"
420 421 422 423 424 425

???                               <=>   serial0.vspc = "foobar"                 # defaults to <not present>, FIXME: not representable
???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable


426 427 428 429 430 431 432 433 434 435

################################################################################
## parallels ###################################################################

                                        parallel[0..2] -> <port>

                                        parallel0.present = "true"              # defaults to "false"
                                        parallel0.startConnected = "true"       # defaults to "true"

def->parallels[0]...
436
->target.port = <port>
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451


## parallels: device #############################################################

->type = _CHR_TYPE_DEV            <=>   parallel0.fileType = "device"
->data.file.path = <value>        <=>   parallel0.fileName = "<value>"          # e.g. "/dev/parport0"
???                               <=>   parallel0.bidirectional = "<value>"     # defaults to ?, FIXME: not representable


## parallels: file #############################################################

->type = _CHR_TYPE_FILE           <=>   parallel0.fileType = "file"
->data.file.path = <value>        <=>   parallel0.fileName = "<value>"          # e.g. "parallel0.file"
???                               <=>   parallel0.bidirectional = "<value>"     # must be "false" for fileType = "file", FIXME: not representable

M
Matthias Bolte 已提交
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466


################################################################################
## sound #######################################################################

                                        sound.present = "true"                  # defaults to "false"
                                        sound.startConnected = "true"           # defaults to "true"
                                        sound.autodetect = "true"
                                        sound.fileName = "-1"

                                        FIXME: Investigate if ESX supports this,
                                               at least the VI Client GUI has no
                                               options to add a sound device, but
                                               the VI API contains a VirtualSoundCard

467 468
*/

469
#define VIR_FROM_THIS VIR_FROM_NONE
470

471 472 473 474 475
#define VMX_ERROR(code, ...)                                                  \
    virReportErrorHelper(NULL, VIR_FROM_NONE, code, __FILE__, __FUNCTION__,   \
                         __LINE__, __VA_ARGS__)

#define VMX_BUILD_NAME_EXTRA(_suffix, _extra)                                 \
476 477
    snprintf(_suffix##_name, sizeof(_suffix##_name), "%s."_extra, prefix);

478 479
#define VMX_BUILD_NAME(_suffix)                                               \
    VMX_BUILD_NAME_EXTRA(_suffix, #_suffix)
480

481
/* directly map the virDomainControllerModel to virVMXSCSIControllerModel,
482 483
 * this is good enough for now because all virDomainControllerModel values
 * are actually SCSI controller models in the ESX case */
484 485
VIR_ENUM_DECL(virVMXSCSIControllerModel)
VIR_ENUM_IMPL(virVMXSCSIControllerModel, VIR_DOMAIN_CONTROLLER_MODEL_LAST,
486
              "auto", /* just to match virDomainControllerModel, will never be used */
487 488 489 490
              "buslogic",
              "lsilogic",
              "lsisas1068",
              "pvscsi");
491 492


493 494 495 496 497

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Helpers
 */

498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
char *
virVMXEscapeHex(const char *string, char escape, const char *special)
{
    char *escaped = NULL;
    size_t length = 1; /* 1 byte for termination */
    const char *tmp1 = string;
    char *tmp2;

    /* Calculate length of escaped string */
    while (*tmp1 != '\0') {
        if (*tmp1 == escape || strspn(tmp1, special) > 0) {
            length += 2;
        }

        ++tmp1;
        ++length;
    }

    if (VIR_ALLOC_N(escaped, length) < 0) {
        virReportOOMError();
        return NULL;
    }

    tmp1 = string; /* reading from this one */
    tmp2 = escaped; /* writing to this one */

    /* Escape to 'cXX' where c is the escape char and X is a hex digit */
    while (*tmp1 != '\0') {
        if (*tmp1 == escape || strspn(tmp1, special) > 0) {
            *tmp2++ = escape;

            snprintf(tmp2, 3, "%02x", (unsigned int)*tmp1);

            tmp2 += 2;
        } else {
            *tmp2++ = *tmp1;
        }

        ++tmp1;
    }

    *tmp2 = '\0';

    return escaped;
}



M
Matthias Bolte 已提交
546
int
547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
virVMXUnescapeHex(char *string, char escape)
{
    char *tmp1 = string; /* reading from this one */
    char *tmp2 = string; /* writing to this one */

    /* Unescape from 'cXX' where c is the escape char and X is a hex digit */
    while (*tmp1 != '\0') {
        if (*tmp1 == escape) {
            if (!c_isxdigit(tmp1[1]) || !c_isxdigit(tmp1[2])) {
                return -1;
            }

            *tmp2++ = virHexToBin(tmp1[1]) * 16 + virHexToBin(tmp1[2]);
            tmp1 += 3;
        } else {
            *tmp2++ = *tmp1++;
        }
    }

    *tmp2 = '\0';

    return 0;
}



char *
virVMXConvertToUTF8(const char *encoding, const char *string)
{
    char *result = NULL;
    xmlCharEncodingHandlerPtr handler;
    xmlBufferPtr input;
    xmlBufferPtr utf8;

    handler = xmlFindCharEncodingHandler(encoding);

    if (handler == NULL) {
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("libxml2 doesn't handle %s encoding"), encoding);
        return NULL;
    }

    input = xmlBufferCreateStatic((char *)string, strlen(string));
    utf8 = xmlBufferCreate();

    if (xmlCharEncInFunc(handler, utf8, input) < 0) {
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Could not convert from %s to UTF-8 encoding"), encoding);
        goto cleanup;
    }

    result = (char *)utf8->content;
    utf8->content = NULL;

  cleanup:
    xmlCharEncCloseFunc(handler);
    xmlBufferFree(input);
    xmlBufferFree(utf8);

    return result;
}



static int
virVMXGetConfigString(virConfPtr conf, const char *name, char **string,
                      bool optional)
{
    virConfValuePtr value;

    *string = NULL;
    value = virConfGetValue(conf, name);

    if (value == NULL) {
        if (optional) {
            return 0;
        }

        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Missing essential config entry '%s'"), name);
        return -1;
    }

    if (value->type != VIR_CONF_STRING) {
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Config entry '%s' must be a string"), name);
        return -1;
    }

    if (value->str == NULL) {
        if (optional) {
            return 0;
        }

        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Missing essential config entry '%s'"), name);
        return -1;
    }

    *string = strdup(value->str);

    if (*string == NULL) {
        virReportOOMError();
        return -1;
    }

    return 0;
}



static int
virVMXGetConfigUUID(virConfPtr conf, const char *name, unsigned char *uuid,
                    bool optional)
{
    virConfValuePtr value;

    value = virConfGetValue(conf, name);

    if (value == NULL) {
        if (optional) {
            return 0;
        } else {
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                      _("Missing essential config entry '%s'"), name);
            return -1;
        }
    }

    if (value->type != VIR_CONF_STRING) {
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Config entry '%s' must be a string"), name);
        return -1;
    }

    if (value->str == NULL) {
        if (optional) {
            return 0;
        } else {
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                      _("Missing essential config entry '%s'"), name);
            return -1;
        }
    }

    if (virUUIDParse(value->str, uuid) < 0) {
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Could not parse UUID from string '%s'"), value->str);
        return -1;
    }

    return 0;
}



static int
virVMXGetConfigLong(virConfPtr conf, const char *name, long long *number,
                    long long default_, bool optional)
{
    virConfValuePtr value;

    *number = default_;
    value = virConfGetValue(conf, name);

    if (value == NULL) {
        if (optional) {
            return 0;
        } else {
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                      _("Missing essential config entry '%s'"), name);
            return -1;
        }
    }

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                          _("Missing essential config entry '%s'"), name);
                return -1;
            }
        }

        if (STREQ(value->str, "unlimited")) {
            *number = -1;
        } else if (virStrToLong_ll(value->str, NULL, 10, number) < 0) {
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                      _("Config entry '%s' must represent an integer value"),
                      name);
            return -1;
        }
    } else {
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Config entry '%s' must be a string"), name);
        return -1;
    }

    return 0;
}



static int
virVMXGetConfigBoolean(virConfPtr conf, const char *name, bool *boolean_,
                       bool default_, bool optional)
{
    virConfValuePtr value;

    *boolean_ = default_;
    value = virConfGetValue(conf, name);

    if (value == NULL) {
        if (optional) {
            return 0;
        } else {
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                      _("Missing essential config entry '%s'"), name);
            return -1;
        }
    }

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                          _("Missing essential config entry '%s'"), name);
                return -1;
            }
        }

        if (STRCASEEQ(value->str, "true")) {
            *boolean_ = 1;
        } else if (STRCASEEQ(value->str, "false")) {
            *boolean_ = 0;
        } else {
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                      _("Config entry '%s' must represent a boolean value "
                        "(true|false)"), name);
            return -1;
        }
    } else {
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Config entry '%s' must be a string"), name);
        return -1;
    }

    return 0;
}



static int
virVMXSCSIDiskNameToControllerAndUnit(const char *name, int *controller, int *unit)
M
Matthias Bolte 已提交
805 806 807 808
{
    int idx;

    if (! STRPREFIX(name, "sd")) {
809
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
810 811
                  _("Expecting domain XML attribute 'dev' of entry "
                    "'devices/disk/target' to start with 'sd'"));
M
Matthias Bolte 已提交
812 813 814 815 816 817
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
818
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
819
                  _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
820 821 822
        return -1;
    }

823
    /* Each of the 4 SCSI controllers has 1 bus with 15 units each for devices */
M
Matthias Bolte 已提交
824
    if (idx >= (4 * 15)) {
825
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
826
                  _("SCSI disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
827 828 829 830
        return -1;
    }

    *controller = idx / 15;
831
    *unit = idx % 15;
M
Matthias Bolte 已提交
832

833 834 835
    /* Skip the controller ifself at unit 7 */
    if (*unit >= 7) {
        ++(*unit);
M
Matthias Bolte 已提交
836 837 838 839 840 841 842
    }

    return 0;
}



843 844
static int
virVMXIDEDiskNameToBusAndUnit(const char *name, int *bus, int *unit)
M
Matthias Bolte 已提交
845 846 847 848
{
    int idx;

    if (! STRPREFIX(name, "hd")) {
849
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
850 851
                  _("Expecting domain XML attribute 'dev' of entry "
                    "'devices/disk/target' to start with 'hd'"));
M
Matthias Bolte 已提交
852 853 854 855 856 857
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
858
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
859
                  _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
860 861 862
        return -1;
    }

863
    /* The IDE controller has 2 buses with 2 units each for devices */
M
Matthias Bolte 已提交
864
    if (idx >= (2 * 2)) {
865
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
866
                  _("IDE disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
867 868 869
        return -1;
    }

870 871
    *bus = idx / 2;
    *unit = idx % 2;
M
Matthias Bolte 已提交
872 873 874 875 876 877

    return 0;
}



878 879
static int
virVMXFloppyDiskNameToUnit(const char *name, int *unit)
M
Matthias Bolte 已提交
880 881 882 883
{
    int idx;

    if (! STRPREFIX(name, "fd")) {
884
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
885 886
                  _("Expecting domain XML attribute 'dev' of entry "
                    "'devices/disk/target' to start with 'fd'"));
M
Matthias Bolte 已提交
887 888 889 890 891 892
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
893
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
894
                  _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
895 896 897
        return -1;
    }

898
    /* The FDC controller has 1 bus with 2 units for devices */
M
Matthias Bolte 已提交
899
    if (idx >= 2) {
900
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
901
                  _("Floppy disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
902 903 904
        return -1;
    }

905 906 907 908 909 910 911
    *unit = idx;

    return 0;
}



912 913
static int
virVMXVerifyDiskAddress(virCapsPtr caps, virDomainDiskDefPtr disk)
914 915 916 917 918 919 920
{
    virDomainDiskDef def;
    virDomainDeviceDriveAddressPtr drive;

    memset(&def, 0, sizeof(def));

    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
921
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
922 923 924 925 926 927 928 929 930 931 932
                  _("Unsupported disk address type '%s'"),
                  virDomainDeviceAddressTypeToString(disk->info.type));
        return -1;
    }

    drive = &disk->info.addr.drive;

    def.dst = disk->dst;
    def.bus = disk->bus;

    if (virDomainDiskDefAssignAddress(caps, &def) < 0) {
933
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
934 935 936 937 938 939 940
                  _("Could not verify disk address"));
        return -1;
    }

    if (def.info.addr.drive.controller != drive->controller ||
        def.info.addr.drive.bus != drive->bus ||
        def.info.addr.drive.unit != drive->unit) {
941
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
942 943 944 945 946 947 948 949
                  _("Disk address %d:%d:%d doesn't match target device '%s'"),
                  drive->controller, drive->bus, drive->unit, disk->dst);
        return -1;
    }

    /* drive->{controller|bus|unit} is unsigned, no >= 0 checks are necessary */
    if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
        if (drive->controller > 3) {
950
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
951 952 953 954 955 956
                      _("SCSI controller index %d out of [0..3] range"),
                      drive->controller);
            return -1;
        }

        if (drive->bus != 0) {
957
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
958 959 960 961 962 963
                      _("SCSI bus index %d out of [0] range"),
                      drive->bus);
            return -1;
        }

        if (drive->unit > 15 || drive->unit == 7) {
964
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
965 966 967 968 969 970
                      _("SCSI unit index %d out of [0..6,8..15] range"),
                      drive->unit);
            return -1;
        }
    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
        if (drive->controller != 0) {
971
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
972 973 974 975 976 977
                      _("IDE controller index %d out of [0] range"),
                      drive->controller);
            return -1;
        }

        if (drive->bus > 1) {
978
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
979 980 981 982 983 984
                      _("IDE bus index %d out of [0..1] range"),
                      drive->bus);
            return -1;
        }

        if (drive->unit > 1) {
985
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
986 987 988 989 990 991
                      _("IDE unit index %d out of [0..1] range"),
                      drive->unit);
            return -1;
        }
    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
        if (drive->controller != 0) {
992
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
993 994 995 996 997 998
                      _("FDC controller index %d out of [0] range"),
                      drive->controller);
            return -1;
        }

        if (drive->bus != 0) {
999
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1000 1001 1002 1003 1004 1005
                      _("FDC bus index %d out of [0] range"),
                      drive->bus);
            return -1;
        }

        if (drive->unit > 1) {
1006
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1007 1008 1009 1010 1011
                      _("FDC unit index %d out of [0..1] range"),
                      drive->unit);
            return -1;
        }
    } else {
1012
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
                  _("Unsupported bus type '%s'"),
                  virDomainDiskBusTypeToString(disk->bus));
        return -1;
    }

    return 0;
}



1023 1024 1025
static int
virVMXHandleLegacySCSIDiskDriverName(virDomainDefPtr def,
                                     virDomainDiskDefPtr disk)
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
{
    char *tmp;
    int model, i;
    virDomainControllerDefPtr controller = NULL;

    if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI || disk->driverName == NULL) {
        return 0;
    }

    tmp = disk->driverName;

    for (; *tmp != '\0'; ++tmp) {
        *tmp = c_tolower(*tmp);
    }

    model = virDomainControllerModelTypeFromString(disk->driverName);

    if (model < 0) {
1044
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
                  _("Unknown driver name '%s'"), disk->driverName);
        return -1;
    }

    for (i = 0; i < def->ncontrollers; ++i) {
        if (def->controllers[i]->idx == disk->info.addr.drive.controller) {
            controller = def->controllers[i];
            break;
        }
    }

    if (controller == NULL) {
1057
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1058 1059 1060 1061 1062 1063 1064 1065
                  _("Missing SCSI controller for index %d"),
                  disk->info.addr.drive.controller);
        return -1;
    }

    if (controller->model == -1) {
        controller->model = model;
    } else if (controller->model != model) {
1066
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1067 1068 1069 1070 1071 1072
                  _("Inconsistent SCSI controller model ('%s' is not '%s') "
                    "for SCSI controller index %d"), disk->driverName,
                  virDomainControllerModelTypeToString(controller->model),
                  controller->idx);
        return -1;
    }
M
Matthias Bolte 已提交
1073 1074 1075 1076 1077 1078

    return 0;
}



1079 1080 1081
static int
virVMXGatherSCSIControllers(virVMXContext *ctx, virDomainDefPtr def,
                            int virtualDev[4], bool present[4])
1082 1083 1084
{
    int result = -1;
    int i, k;
M
Matthias Bolte 已提交
1085
    virDomainDiskDefPtr disk;
1086 1087 1088 1089
    virDomainControllerDefPtr controller;
    bool controllerHasDisksAttached;
    int count = 0;
    int *autodetectedModels;
M
Matthias Bolte 已提交
1090

1091 1092 1093 1094 1095 1096 1097
    if (VIR_ALLOC_N(autodetectedModels, def->ndisks) < 0) {
        virReportOOMError();
        return -1;
    }

    for (i = 0; i < def->ncontrollers; ++i) {
        controller = def->controllers[i];
M
Matthias Bolte 已提交
1098

1099
        if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
1100
            /* skip non-SCSI controllers */
M
Matthias Bolte 已提交
1101 1102 1103
            continue;
        }

1104
        controllerHasDisksAttached = false;
1105

1106 1107 1108 1109 1110 1111
        for (k = 0; k < def->ndisks; ++k) {
            disk = def->disks[k];

            if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
                disk->info.addr.drive.controller == controller->idx) {
                controllerHasDisksAttached = true;
1112 1113
                break;
            }
M
Matthias Bolte 已提交
1114 1115
        }

1116
        if (! controllerHasDisksAttached) {
1117
            /* skip SCSI controllers without attached disks */
1118 1119 1120
            continue;
        }

1121 1122
        if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_AUTO &&
            ctx->autodetectSCSIControllerModel != NULL) {
1123 1124
            count = 0;

1125 1126
            /* try to autodetect the SCSI controller model by collecting
             * SCSI controller model of all disks attached to this controller */
1127 1128 1129 1130 1131
            for (k = 0; k < def->ndisks; ++k) {
                disk = def->disks[k];

                if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
                    disk->info.addr.drive.controller == controller->idx) {
1132 1133 1134
                    if (ctx->autodetectSCSIControllerModel
                               (disk, &autodetectedModels[count],
                                ctx->opaque) < 0) {
1135 1136 1137 1138 1139 1140 1141
                        goto cleanup;
                    }

                    ++count;
                }
            }

1142 1143
            /* autodetection fails when the disks attached to one controller
             * have inconsistent SCSI controller models */
1144 1145
            for (k = 0; k < count; ++k) {
                if (autodetectedModels[k] != autodetectedModels[0]) {
1146
                    VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1147 1148 1149 1150 1151 1152 1153 1154
                              _("Disks on SCSI controller %d have inconsistent "
                                "controller models, cannot autodetect model"),
                              controller->idx);
                    goto cleanup;
                }
            }

            controller->model = autodetectedModels[0];
M
Matthias Bolte 已提交
1155 1156
        }

1157 1158 1159
        if (controller->model != -1 &&
            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC &&
            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC &&
1160 1161
            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068 &&
            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI) {
1162
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1163 1164
                      _("Expecting domain XML attribute 'model' of entry "
                        "'controller' to be 'buslogic' or 'lsilogic' or "
1165
                        "'lsisas1068' or 'vmpvscsi' but found '%s'"),
1166
                      virDomainControllerModelTypeToString(controller->model));
1167
            goto cleanup;
M
Matthias Bolte 已提交
1168
        }
1169 1170 1171

        present[controller->idx] = true;
        virtualDev[controller->idx] = controller->model;
M
Matthias Bolte 已提交
1172 1173
    }

1174 1175 1176 1177 1178 1179
    result = 0;

  cleanup:
    VIR_FREE(autodetectedModels);

    return result;
M
Matthias Bolte 已提交
1180 1181 1182 1183 1184 1185 1186 1187
}



/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * VMX -> Domain XML
 */

1188
virDomainDefPtr
1189
virVMXParseConfig(virVMXContext *ctx, virCapsPtr caps, const char *vmx)
1190
{
M
Matthias Bolte 已提交
1191
    bool success = false;
1192
    virConfPtr conf = NULL;
1193 1194
    char *encoding = NULL;
    char *utf8;
1195 1196 1197 1198
    virDomainDefPtr def = NULL;
    long long config_version = 0;
    long long virtualHW_version = 0;
    long long memsize = 0;
1199 1200
    long long sched_mem_max = 0;
    long long sched_mem_minsize = 0;
1201 1202
    long long numvcpus = 0;
    char *sched_cpu_affinity = NULL;
M
Matthias Bolte 已提交
1203
    char *guestOS = NULL;
M
Matthias Bolte 已提交
1204
    bool smbios_reflecthost = false;
1205
    int controller;
1206
    int bus;
1207
    int port;
1208
    bool present;
1209 1210
    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
    int unit;
1211

1212
    if (ctx->parseFileName == NULL) {
1213 1214
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("virVMXContext has no parseFileName function set"));
1215 1216 1217
        return NULL;
    }

1218 1219 1220 1221 1222 1223
    conf = virConfReadMem(vmx, strlen(vmx), VIR_CONF_FLAG_VMX_FORMAT);

    if (conf == NULL) {
        return NULL;
    }

1224
    /* vmx:.encoding */
1225
    if (virVMXGetConfigString(conf, ".encoding", &encoding, true) < 0) {
1226 1227 1228 1229 1230 1231 1232 1233 1234
        goto cleanup;
    }

    if (encoding == NULL || STRCASEEQ(encoding, "UTF-8")) {
        /* nothing */
    } else {
        virConfFree(conf);
        conf = NULL;

1235
        utf8 = virVMXConvertToUTF8(encoding, vmx);
1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250

        if (utf8 == NULL) {
            goto cleanup;
        }

        conf = virConfReadMem(utf8, strlen(utf8), VIR_CONF_FLAG_VMX_FORMAT);

        VIR_FREE(utf8);

        if (conf == NULL) {
            goto cleanup;
        }
    }

    /* Allocate domain def */
1251
    if (VIR_ALLOC(def) < 0) {
1252
        virReportOOMError();
M
Matthias Bolte 已提交
1253
        return NULL;
1254 1255
    }

1256
    def->virtType = VIR_DOMAIN_VIRT_VMWARE;
1257 1258
    def->id = -1;

M
Matthias Bolte 已提交
1259
    /* vmx:config.version */
1260 1261
    if (virVMXGetConfigLong(conf, "config.version", &config_version, 0,
                            false) < 0) {
M
Matthias Bolte 已提交
1262
        goto cleanup;
1263 1264 1265
    }

    if (config_version != 8) {
1266
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1267 1268
                  _("Expecting VMX entry 'config.version' to be 8 but found "
                    "%lld"), config_version);
M
Matthias Bolte 已提交
1269
        goto cleanup;
1270 1271
    }

M
Matthias Bolte 已提交
1272
    /* vmx:virtualHW.version */
1273 1274
    if (virVMXGetConfigLong(conf, "virtualHW.version", &virtualHW_version, 0,
                            false) < 0) {
M
Matthias Bolte 已提交
1275
        goto cleanup;
1276 1277
    }

1278 1279 1280 1281 1282
    if (virtualHW_version != 4 && virtualHW_version != 7) {
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
                  _("Expecting VMX entry 'virtualHW.version' to be 4 or 7 "
                    "but found %lld"),
                  virtualHW_version);
M
Matthias Bolte 已提交
1283
        goto cleanup;
1284 1285
    }

M
Matthias Bolte 已提交
1286
    /* vmx:uuid.bios -> def:uuid */
1287
    /* FIXME: Need to handle 'uuid.action = "create"' */
1288
    if (virVMXGetConfigUUID(conf, "uuid.bios", def->uuid, true) < 0) {
M
Matthias Bolte 已提交
1289
        goto cleanup;
1290 1291
    }

M
Matthias Bolte 已提交
1292
    /* vmx:displayName -> def:name */
1293
    if (virVMXGetConfigString(conf, "displayName", &def->name, true) < 0) {
M
Matthias Bolte 已提交
1294
        goto cleanup;
1295 1296
    }

1297
    if (def->name != NULL) {
1298 1299 1300
        if (virVMXUnescapeHexPercent(def->name) < 0 ||
            virVMXUnescapeHexPipe(def->name) < 0) {
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
1301 1302 1303 1304 1305
                      _("VMX entry 'name' contains invalid escape sequence"));
            goto cleanup;
        }
    }

1306
    /* vmx:annotation -> def:description */
1307 1308
    if (virVMXGetConfigString(conf, "annotation", &def->description,
                              true) < 0) {
1309 1310 1311 1312
        goto cleanup;
    }

    if (def->description != NULL) {
1313 1314
        if (virVMXUnescapeHexPipe(def->description) < 0) {
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
1315 1316 1317
                      _("VMX entry 'annotation' contains invalid escape "
                        "sequence"));
            goto cleanup;
1318 1319 1320
        }
    }

1321
    /* vmx:memsize -> def:mem.max_balloon */
1322
    if (virVMXGetConfigLong(conf, "memsize", &memsize, 32, true) < 0) {
M
Matthias Bolte 已提交
1323
        goto cleanup;
1324 1325 1326
    }

    if (memsize <= 0 || memsize % 4 != 0) {
1327
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1328 1329
                  _("Expecting VMX entry 'memsize' to be an unsigned "
                    "integer (multiple of 4) but found %lld"), memsize);
M
Matthias Bolte 已提交
1330
        goto cleanup;
1331 1332
    }

1333
    def->mem.max_balloon = memsize * 1024; /* Scale from megabytes to kilobytes */
1334

1335
    /* vmx:sched.mem.max -> def:mem.cur_balloon */
1336 1337
    if (virVMXGetConfigLong(conf, "sched.mem.max", &sched_mem_max, memsize,
                            true) < 0) {
M
Matthias Bolte 已提交
1338
        goto cleanup;
1339 1340
    }

1341 1342
    if (sched_mem_max < 0) {
        sched_mem_max = memsize;
1343 1344
    }

1345
    def->mem.cur_balloon = sched_mem_max * 1024; /* Scale from megabytes to kilobytes */
1346

1347 1348
    if (def->mem.cur_balloon > def->mem.max_balloon) {
        def->mem.cur_balloon = def->mem.max_balloon;
1349 1350
    }

1351
    /* vmx:sched.mem.minsize -> def:mem.min_guarantee */
1352 1353
    if (virVMXGetConfigLong(conf, "sched.mem.minsize", &sched_mem_minsize, 0,
                            true) < 0) {
1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
        goto cleanup;
    }

    if (sched_mem_minsize < 0) {
        sched_mem_minsize = 0;
    }

    def->mem.min_guarantee = sched_mem_minsize * 1024; /* Scale from megabytes to kilobytes */

    if (def->mem.min_guarantee > def->mem.max_balloon) {
        def->mem.min_guarantee = def->mem.max_balloon;
    }

M
Matthias Bolte 已提交
1367
    /* vmx:numvcpus -> def:vcpus */
1368
    if (virVMXGetConfigLong(conf, "numvcpus", &numvcpus, 1, true) < 0) {
M
Matthias Bolte 已提交
1369
        goto cleanup;
1370 1371 1372
    }

    if (numvcpus <= 0 || (numvcpus % 2 != 0 && numvcpus != 1)) {
1373
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1374 1375
                  _("Expecting VMX entry 'numvcpus' to be an unsigned "
                    "integer (1 or a multiple of 2) but found %lld"), numvcpus);
M
Matthias Bolte 已提交
1376
        goto cleanup;
1377 1378
    }

E
Eric Blake 已提交
1379
    def->maxvcpus = def->vcpus = numvcpus;
1380

M
Matthias Bolte 已提交
1381
    /* vmx:sched.cpu.affinity -> def:cpumask */
1382
    /* NOTE: maps to VirtualMachine:config.cpuAffinity.affinitySet */
1383 1384
    if (virVMXGetConfigString(conf, "sched.cpu.affinity", &sched_cpu_affinity,
                              true) < 0) {
M
Matthias Bolte 已提交
1385
        goto cleanup;
1386 1387 1388 1389 1390 1391 1392 1393 1394
    }

    if (sched_cpu_affinity != NULL && STRNEQ(sched_cpu_affinity, "all")) {
        const char *current = sched_cpu_affinity;
        int number, count = 0;

        def->cpumasklen = 0;

        if (VIR_ALLOC_N(def->cpumask, VIR_DOMAIN_CPUMASK_LEN) < 0) {
1395
            virReportOOMError();
M
Matthias Bolte 已提交
1396
            goto cleanup;
1397 1398 1399 1400 1401 1402 1403 1404
        }

        while (*current != '\0') {
            virSkipSpaces(&current);

            number = virParseNumber(&current);

            if (number < 0) {
1405
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1406 1407 1408
                          _("Expecting VMX entry 'sched.cpu.affinity' to be "
                            "a comma separated list of unsigned integers but "
                            "found '%s'"), sched_cpu_affinity);
M
Matthias Bolte 已提交
1409
                goto cleanup;
1410 1411 1412
            }

            if (number >= VIR_DOMAIN_CPUMASK_LEN) {
1413
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1414 1415
                          _("VMX entry 'sched.cpu.affinity' contains a %d, "
                            "this value is too large"), number);
M
Matthias Bolte 已提交
1416
                goto cleanup;
1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432
            }

            if (number + 1 > def->cpumasklen) {
                def->cpumasklen = number + 1;
            }

            def->cpumask[number] = 1;
            ++count;

            virSkipSpaces(&current);

            if (*current == ',') {
                ++current;
            } else if (*current == '\0') {
                break;
            } else {
1433
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1434 1435 1436
                          _("Expecting VMX entry 'sched.cpu.affinity' to be "
                            "a comma separated list of unsigned integers but "
                            "found '%s'"), sched_cpu_affinity);
M
Matthias Bolte 已提交
1437
                goto cleanup;
1438 1439 1440 1441 1442 1443
            }

            virSkipSpaces(&current);
        }

        if (count < numvcpus) {
1444
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1445 1446 1447
                      _("Expecting VMX entry 'sched.cpu.affinity' to contain "
                        "at least as many values as 'numvcpus' (%lld) but "
                        "found only %d value(s)"), numvcpus, count);
M
Matthias Bolte 已提交
1448
            goto cleanup;
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460
        }
    }

    /* def:lifecycle */
    def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
    def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
    def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;

    /* def:os */
    def->os.type = strdup("hvm");

    if (def->os.type == NULL) {
1461
        virReportOOMError();
M
Matthias Bolte 已提交
1462
        goto cleanup;
1463 1464
    }

M
Matthias Bolte 已提交
1465
    /* vmx:guestOS -> def:os.arch */
1466
    if (virVMXGetConfigString(conf, "guestOS", &guestOS, true) < 0) {
M
Matthias Bolte 已提交
1467
        goto cleanup;
M
Matthias Bolte 已提交
1468 1469
    }

1470
    if (guestOS != NULL && virFileHasSuffix(guestOS, "-64")) {
M
Matthias Bolte 已提交
1471 1472 1473 1474 1475 1476
        def->os.arch = strdup("x86_64");
    } else {
        def->os.arch = strdup("i686");
    }

    if (def->os.arch == NULL) {
1477
        virReportOOMError();
M
Matthias Bolte 已提交
1478
        goto cleanup;
M
Matthias Bolte 已提交
1479 1480
    }

M
Matthias Bolte 已提交
1481
    /* vmx:smbios.reflecthost -> def:os.smbios_mode */
1482 1483
    if (virVMXGetConfigBoolean(conf, "smbios.reflecthost",
                               &smbios_reflecthost, false, true) < 0) {
M
Matthias Bolte 已提交
1484 1485 1486 1487 1488 1489 1490
        goto cleanup;
    }

    if (smbios_reflecthost) {
        def->os.smbios_mode = VIR_DOMAIN_SMBIOS_HOST;
    }

1491 1492
    /* def:features */
    /* FIXME */
1493

1494 1495
    /* def:clock */
    /* FIXME */
1496 1497

    /* def:graphics */
M
Matthias Bolte 已提交
1498
    if (VIR_ALLOC_N(def->graphics, 1) < 0) {
1499
        virReportOOMError();
M
Matthias Bolte 已提交
1500
        goto cleanup;
M
Matthias Bolte 已提交
1501 1502 1503 1504
    }

    def->ngraphics = 0;

1505
    if (virVMXParseVNC(conf, &def->graphics[def->ngraphics]) < 0) {
M
Matthias Bolte 已提交
1506
        goto cleanup;
M
Matthias Bolte 已提交
1507 1508 1509 1510 1511
    }

    if (def->graphics[def->ngraphics] != NULL) {
        ++def->ngraphics;
    }
1512

M
Matthias Bolte 已提交
1513 1514
    /* def:disks: 4 * 15 scsi + 2 * 2 ide + 2 floppy = 66 */
    if (VIR_ALLOC_N(def->disks, 66) < 0) {
1515
        virReportOOMError();
M
Matthias Bolte 已提交
1516
        goto cleanup;
1517 1518 1519 1520 1521 1522
    }

    def->ndisks = 0;

    /* def:disks (scsi) */
    for (controller = 0; controller < 4; ++controller) {
1523 1524
        if (virVMXParseSCSIController(conf, controller, &present,
                                      &scsi_virtualDev[controller]) < 0) {
M
Matthias Bolte 已提交
1525
            goto cleanup;
1526 1527 1528 1529 1530 1531
        }

        if (! present) {
            continue;
        }

1532 1533
        for (unit = 0; unit < 16; ++unit) {
            if (unit == 7) {
1534
                /*
1535
                 * SCSI unit 7 is assigned to the SCSI controller and cannot be
1536 1537 1538 1539 1540
                 * used for disk devices.
                 */
                continue;
            }

1541 1542 1543
            if (virVMXParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
                                VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
                                &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1544
                goto cleanup;
1545 1546 1547 1548 1549 1550 1551
            }

            if (def->disks[def->ndisks] != NULL) {
                ++def->ndisks;
                continue;
            }

1552
            if (virVMXParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1553
                                 VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
1554
                                 &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1555
                goto cleanup;
1556 1557 1558 1559 1560 1561 1562 1563 1564
            }

            if (def->disks[def->ndisks] != NULL) {
                ++def->ndisks;
            }
        }
    }

    /* def:disks (ide) */
1565 1566
    for (bus = 0; bus < 2; ++bus) {
        for (unit = 0; unit < 2; ++unit) {
1567 1568 1569
            if (virVMXParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
                                &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1570
                goto cleanup;
1571 1572 1573 1574 1575 1576 1577
            }

            if (def->disks[def->ndisks] != NULL) {
                ++def->ndisks;
                continue;
            }

1578 1579 1580
            if (virVMXParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
                                &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1581
                goto cleanup;
1582 1583 1584 1585 1586 1587 1588 1589 1590
            }

            if (def->disks[def->ndisks] != NULL) {
                ++def->ndisks;
            }
        }
    }

    /* def:disks (floppy) */
1591
    for (unit = 0; unit < 2; ++unit) {
1592 1593 1594
        if (virVMXParseDisk(ctx, caps, conf, VIR_DOMAIN_DISK_DEVICE_FLOPPY,
                            VIR_DOMAIN_DISK_BUS_FDC, 0, unit,
                            &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1595
            goto cleanup;
1596 1597 1598 1599 1600 1601 1602
        }

        if (def->disks[def->ndisks] != NULL) {
            ++def->ndisks;
        }
    }

1603 1604
    /* def:controllers */
    if (virDomainDefAddImplicitControllers(def) < 0) {
1605
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not add controllers"));
1606 1607 1608 1609 1610 1611 1612
        goto cleanup;
    }

    for (controller = 0; controller < def->ncontrollers; ++controller) {
        if (def->controllers[controller]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
            if (def->controllers[controller]->idx < 0 ||
                def->controllers[controller]->idx > 3) {
1613
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623
                          _("SCSI controller index %d out of [0..3] range"),
                          def->controllers[controller]->idx);
                goto cleanup;
            }

            def->controllers[controller]->model =
              scsi_virtualDev[def->controllers[controller]->idx];
        }
    }

1624 1625 1626 1627 1628
    /* def:fss */
    /* FIXME */

    /* def:nets */
    if (VIR_ALLOC_N(def->nets, 4) < 0) {
1629
        virReportOOMError();
M
Matthias Bolte 已提交
1630
        goto cleanup;
1631 1632 1633 1634 1635
    }

    def->nnets = 0;

    for (controller = 0; controller < 4; ++controller) {
1636 1637
        if (virVMXParseEthernet(conf, controller,
                                &def->nets[def->nnets]) < 0) {
M
Matthias Bolte 已提交
1638
            goto cleanup;
1639 1640 1641 1642 1643 1644 1645 1646 1647 1648
        }

        if (def->nets[def->nnets] != NULL) {
            ++def->nnets;
        }
    }

    /* def:inputs */
    /* FIXME */

1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662
    /* def:videos */
    if (VIR_ALLOC_N(def->videos, 1) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    def->nvideos = 0;

    if (virVMXParseSVGA(conf, &def->videos[def->nvideos]) < 0) {
        goto cleanup;
    }

    def->nvideos = 1;

1663 1664 1665 1666 1667 1668 1669 1670
    /* def:sounds */
    /* FIXME */

    /* def:hostdevs */
    /* FIXME */

    /* def:serials */
    if (VIR_ALLOC_N(def->serials, 4) < 0) {
1671
        virReportOOMError();
M
Matthias Bolte 已提交
1672
        goto cleanup;
1673 1674 1675 1676 1677
    }

    def->nserials = 0;

    for (port = 0; port < 4; ++port) {
1678 1679
        if (virVMXParseSerial(ctx, conf, port,
                              &def->serials[def->nserials]) < 0) {
M
Matthias Bolte 已提交
1680
            goto cleanup;
1681 1682 1683 1684 1685 1686 1687 1688 1689
        }

        if (def->serials[def->nserials] != NULL) {
            ++def->nserials;
        }
    }

    /* def:parallels */
    if (VIR_ALLOC_N(def->parallels, 3) < 0) {
1690
        virReportOOMError();
M
Matthias Bolte 已提交
1691
        goto cleanup;
1692 1693 1694 1695 1696
    }

    def->nparallels = 0;

    for (port = 0; port < 3; ++port) {
1697 1698
        if (virVMXParseParallel(ctx, conf, port,
                                &def->parallels[def->nparallels]) < 0) {
M
Matthias Bolte 已提交
1699
            goto cleanup;
1700 1701 1702 1703 1704 1705 1706
        }

        if (def->parallels[def->nparallels] != NULL) {
            ++def->nparallels;
        }
    }

M
Matthias Bolte 已提交
1707 1708
    success = true;

M
Matthias Bolte 已提交
1709
  cleanup:
M
Matthias Bolte 已提交
1710 1711 1712 1713 1714
    if (! success) {
        virDomainDefFree(def);
        def = NULL;
    }

1715
    virConfFree(conf);
1716
    VIR_FREE(encoding);
1717
    VIR_FREE(sched_cpu_affinity);
M
Matthias Bolte 已提交
1718
    VIR_FREE(guestOS);
1719 1720 1721 1722 1723 1724

    return def;
}



M
Matthias Bolte 已提交
1725
int
1726
virVMXParseVNC(virConfPtr conf, virDomainGraphicsDefPtr *def)
M
Matthias Bolte 已提交
1727
{
1728
    bool enabled = false;
M
Matthias Bolte 已提交
1729 1730 1731
    long long port = 0;

    if (def == NULL || *def != NULL) {
1732
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
1733 1734 1735
        return -1;
    }

1736 1737
    if (virVMXGetConfigBoolean(conf, "RemoteDisplay.vnc.enabled", &enabled,
                               false, true) < 0) {
M
Matthias Bolte 已提交
1738 1739 1740 1741 1742 1743 1744 1745
        return -1;
    }

    if (! enabled) {
        return 0;
    }

    if (VIR_ALLOC(*def) < 0) {
1746
        virReportOOMError();
M
Matthias Bolte 已提交
1747 1748 1749 1750 1751
        goto failure;
    }

    (*def)->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;

1752 1753 1754 1755 1756 1757 1758 1759
    if (virVMXGetConfigLong(conf, "RemoteDisplay.vnc.port", &port, -1,
                            true) < 0 ||
        virVMXGetConfigString(conf, "RemoteDisplay.vnc.ip",
                              &(*def)->data.vnc.listenAddr, true) < 0 ||
        virVMXGetConfigString(conf, "RemoteDisplay.vnc.keymap",
                              &(*def)->data.vnc.keymap, true) < 0 ||
        virVMXGetConfigString(conf, "RemoteDisplay.vnc.password",
                              &(*def)->data.vnc.auth.passwd, true) < 0) {
M
Matthias Bolte 已提交
1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788
        goto failure;
    }

    if (port < 0) {
        VIR_WARN0("VNC is enabled but VMX entry 'RemoteDisplay.vnc.port' "
                  "is missing, the VNC port is unknown");

        (*def)->data.vnc.port = 0;
        (*def)->data.vnc.autoport = 1;
    } else {
        if (port < 5900 || port > 5964) {
            VIR_WARN("VNC port %lld it out of [5900..5964] range", port);
        }

        (*def)->data.vnc.port = port;
        (*def)->data.vnc.autoport = 0;
    }

    return 0;

  failure:
    virDomainGraphicsDefFree(*def);
    *def = NULL;

    return -1;
}



1789
int
1790 1791
virVMXParseSCSIController(virConfPtr conf, int controller, bool *present,
                          int *virtualDev)
1792 1793 1794
{
    char present_name[32];
    char virtualDev_name[32];
1795 1796
    char *virtualDev_string = NULL;
    char *tmp;
1797

1798
    if (virtualDev == NULL || *virtualDev != -1) {
1799
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1800
        return -1;
1801 1802 1803
    }

    if (controller < 0 || controller > 3) {
1804
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1805
                  _("SCSI controller index %d out of [0..3] range"),
1806
                  controller);
1807
        return -1;
1808 1809
    }

1810 1811 1812
    snprintf(present_name, sizeof(present_name), "scsi%d.present", controller);
    snprintf(virtualDev_name, sizeof(virtualDev_name), "scsi%d.virtualDev",
             controller);
1813

1814
    if (virVMXGetConfigBoolean(conf, present_name, present, false, true) < 0) {
1815 1816 1817 1818 1819 1820 1821
        goto failure;
    }

    if (! *present) {
        return 0;
    }

1822 1823
    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev_string,
                              true) < 0) {
1824 1825 1826
        goto failure;
    }

1827 1828 1829 1830 1831 1832 1833
    if (virtualDev_string != NULL) {
        tmp = virtualDev_string;

        for (; *tmp != '\0'; ++tmp) {
            *tmp = c_tolower(*tmp);
        }

1834
        *virtualDev = virVMXSCSIControllerModelTypeFromString(virtualDev_string);
1835 1836 1837 1838

        if (*virtualDev == -1 ||
            (*virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_BUSLOGIC &&
             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_LSILOGIC &&
1839 1840
             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_LSISAS1068 &&
             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_VMPVSCSI)) {
1841
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1842
                      _("Expecting VMX entry '%s' to be 'buslogic' or 'lsilogic' "
1843 1844
                        "or 'lsisas1068' or 'pvscsi' but found '%s'"),
                       virtualDev_name, virtualDev_string);
1845 1846
            goto failure;
        }
1847 1848 1849 1850
    }

    return 0;

M
Matthias Bolte 已提交
1851
  failure:
1852
    VIR_FREE(virtualDev_string);
1853 1854 1855 1856 1857 1858 1859

    return -1;
}



int
1860 1861 1862
virVMXParseDisk(virVMXContext *ctx, virCapsPtr caps, virConfPtr conf,
                int device, int busType, int controllerOrBus, int unit,
                virDomainDiskDefPtr *def)
1863 1864
{
    /*
1865 1866 1867 1868
     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM}
     *         busType = VIR_DOMAIN_DISK_BUS_SCSI
     * controllerOrBus = [0..3] -> controller
     *            unit = [0..6,8..15]
1869
     *
1870 1871 1872 1873
     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM}
     *         busType = VIR_DOMAIN_DISK_BUS_IDE
     * controllerOrBus = [0..1] -> bus
     *            unit = [0..1]
1874
     *
1875 1876 1877 1878
     *          device = VIR_DOMAIN_DISK_DEVICE_FLOPPY
     *         busType = VIR_DOMAIN_DISK_BUS_FDC
     * controllerOrBus = [0]
     *            unit = [0..1]
1879 1880
     */

M
Matthias Bolte 已提交
1881
    int result = -1;
1882 1883 1884
    char *prefix = NULL;

    char present_name[32] = "";
1885
    bool present = false;
1886 1887

    char startConnected_name[32] = "";
1888
    bool startConnected = false;
1889 1890 1891 1892 1893

    char deviceType_name[32] = "";
    char *deviceType = NULL;

    char clientDevice_name[32] = "";
1894
    bool clientDevice = false;
1895 1896 1897 1898 1899 1900 1901 1902

    char fileType_name[32] = "";
    char *fileType = NULL;

    char fileName_name[32] = "";
    char *fileName = NULL;

    char writeThrough_name[32] = "";
1903
    bool writeThrough = false;
1904 1905

    if (def == NULL || *def != NULL) {
1906
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1907 1908 1909 1910
        return -1;
    }

    if (VIR_ALLOC(*def) < 0) {
1911
        virReportOOMError();
M
Matthias Bolte 已提交
1912
        return -1;
1913 1914 1915
    }

    (*def)->device = device;
1916
    (*def)->bus = busType;
1917 1918 1919 1920

    /* def:dst, def:driverName */
    if (device == VIR_DOMAIN_DISK_DEVICE_DISK ||
        device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
1921 1922
        if (busType == VIR_DOMAIN_DISK_BUS_SCSI) {
            if (controllerOrBus < 0 || controllerOrBus > 3) {
1923
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1924
                          _("SCSI controller index %d out of [0..3] range"),
1925
                          controllerOrBus);
M
Matthias Bolte 已提交
1926
                goto cleanup;
1927 1928
            }

1929
            if (unit < 0 || unit > 15 || unit == 7) {
1930
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1931 1932
                          _("SCSI unit index %d out of [0..6,8..15] range"),
                          unit);
M
Matthias Bolte 已提交
1933
                goto cleanup;
1934 1935
            }

1936
            if (virAsprintf(&prefix, "scsi%d:%d", controllerOrBus, unit) < 0) {
1937
                virReportOOMError();
M
Matthias Bolte 已提交
1938
                goto cleanup;
1939 1940
            }

M
Matthias Bolte 已提交
1941
            (*def)->dst =
1942
               virIndexToDiskName
1943
                 (controllerOrBus * 15 + (unit < 7 ? unit : unit - 1), "sd");
1944 1945

            if ((*def)->dst == NULL) {
M
Matthias Bolte 已提交
1946
                goto cleanup;
1947
            }
1948 1949
        } else if (busType == VIR_DOMAIN_DISK_BUS_IDE) {
            if (controllerOrBus < 0 || controllerOrBus > 1) {
1950
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1951 1952
                          _("IDE bus index %d out of [0..1] range"),
                          controllerOrBus);
M
Matthias Bolte 已提交
1953
                goto cleanup;
1954 1955
            }

1956
            if (unit < 0 || unit > 1) {
1957
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1958
                          _("IDE unit index %d out of [0..1] range"), unit);
M
Matthias Bolte 已提交
1959
                goto cleanup;
1960 1961
            }

1962
            if (virAsprintf(&prefix, "ide%d:%d", controllerOrBus, unit) < 0) {
1963
                virReportOOMError();
M
Matthias Bolte 已提交
1964
                goto cleanup;
1965 1966
            }

1967
            (*def)->dst = virIndexToDiskName(controllerOrBus * 2 + unit, "hd");
1968 1969

            if ((*def)->dst == NULL) {
M
Matthias Bolte 已提交
1970
                goto cleanup;
1971 1972
            }
        } else {
1973
            VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
1974
                      _("Unsupported bus type '%s' for device type '%s'"),
1975
                      virDomainDiskBusTypeToString(busType),
M
Matthias Bolte 已提交
1976
                      virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
1977
            goto cleanup;
1978 1979
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
1980 1981
        if (busType == VIR_DOMAIN_DISK_BUS_FDC) {
            if (controllerOrBus != 0) {
1982
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1983 1984 1985 1986 1987 1988
                          _("FDC controller index %d out of [0] range"),
                          controllerOrBus);
                goto cleanup;
            }

            if (unit < 0 || unit > 1) {
1989
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
1990 1991
                          _("FDC unit index %d out of [0..1] range"),
                          unit);
M
Matthias Bolte 已提交
1992
                goto cleanup;
1993 1994
            }

1995
            if (virAsprintf(&prefix, "floppy%d", unit) < 0) {
1996
                virReportOOMError();
M
Matthias Bolte 已提交
1997
                goto cleanup;
1998 1999
            }

2000
            (*def)->dst = virIndexToDiskName(unit, "fd");
2001 2002

            if ((*def)->dst == NULL) {
M
Matthias Bolte 已提交
2003
                goto cleanup;
2004 2005
            }
        } else {
2006
            VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
2007
                      _("Unsupported bus type '%s' for device type '%s'"),
2008
                      virDomainDiskBusTypeToString(busType),
M
Matthias Bolte 已提交
2009
                      virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2010
            goto cleanup;
2011 2012
        }
    } else {
2013
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
2014
                  _("Unsupported device type '%s'"),
M
Matthias Bolte 已提交
2015
                  virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2016
        goto cleanup;
2017 2018
    }

2019 2020 2021 2022 2023 2024 2025
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(deviceType);
    VMX_BUILD_NAME(clientDevice);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
    VMX_BUILD_NAME(writeThrough);
2026 2027

    /* vmx:present */
2028
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2029
        goto cleanup;
2030 2031 2032
    }

    /* vmx:startConnected */
2033 2034
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2035
        goto cleanup;
2036 2037 2038 2039 2040 2041 2042 2043
    }

    /* FIXME: Need to distiguish between active and inactive domains here */
    if (! present/* && ! startConnected*/) {
        goto ignore;
    }

    /* vmx:deviceType -> def:type */
2044
    if (virVMXGetConfigString(conf, deviceType_name, &deviceType, true) < 0) {
M
Matthias Bolte 已提交
2045
        goto cleanup;
2046 2047 2048
    }

    /* vmx:clientDevice */
2049 2050
    if (virVMXGetConfigBoolean(conf, clientDevice_name, &clientDevice, false,
                               true) < 0) {
M
Matthias Bolte 已提交
2051
        goto cleanup;
2052 2053 2054 2055 2056
    }

    if (clientDevice) {
        /*
         * Just ignore devices in client mode, because I have no clue how to
M
Matthias Bolte 已提交
2057
         * handle them (e.g. assign an image) without the VI Client GUI.
2058 2059 2060 2061 2062
         */
        goto ignore;
    }

    /* vmx:fileType -> def:type */
2063
    if (virVMXGetConfigString(conf, fileType_name, &fileType, true) < 0) {
M
Matthias Bolte 已提交
2064
        goto cleanup;
2065 2066 2067
    }

    /* vmx:fileName -> def:src, def:type */
2068
    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0) {
M
Matthias Bolte 已提交
2069
        goto cleanup;
2070 2071 2072
    }

    /* vmx:writeThrough -> def:cachemode */
2073 2074
    if (virVMXGetConfigBoolean(conf, writeThrough_name, &writeThrough, false,
                               true) < 0) {
M
Matthias Bolte 已提交
2075
        goto cleanup;
2076 2077 2078 2079
    }

    /* Setup virDomainDiskDef */
    if (device == VIR_DOMAIN_DISK_DEVICE_DISK) {
2080
        if (virFileHasSuffix(fileName, ".vmdk")) {
2081
            if (deviceType != NULL) {
2082
                if (busType == VIR_DOMAIN_DISK_BUS_SCSI &&
2083 2084
                    STRCASENEQ(deviceType, "scsi-hardDisk") &&
                    STRCASENEQ(deviceType, "disk")) {
2085
                    VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2086
                              _("Expecting VMX entry '%s' to be 'scsi-hardDisk' "
2087 2088
                                "or 'disk' but found '%s'"), deviceType_name,
                              deviceType);
M
Matthias Bolte 已提交
2089
                    goto cleanup;
2090
                } else if (busType == VIR_DOMAIN_DISK_BUS_IDE &&
2091 2092
                           STRCASENEQ(deviceType, "ata-hardDisk") &&
                           STRCASENEQ(deviceType, "disk")) {
2093
                    VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2094
                              _("Expecting VMX entry '%s' to be 'ata-hardDisk' "
2095 2096
                                "or 'disk' but found '%s'"), deviceType_name,
                              deviceType);
M
Matthias Bolte 已提交
2097
                    goto cleanup;
2098 2099 2100 2101
                }
            }

            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
2102
            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
2103 2104 2105
            (*def)->cachemode = writeThrough ? VIR_DOMAIN_DISK_CACHE_WRITETHRU
                                             : VIR_DOMAIN_DISK_CACHE_DEFAULT;

M
Matthias Bolte 已提交
2106
            if ((*def)->src == NULL) {
M
Matthias Bolte 已提交
2107
                goto cleanup;
M
Matthias Bolte 已提交
2108
            }
2109
        } else if (virFileHasSuffix(fileName, ".iso") ||
2110 2111 2112 2113 2114 2115 2116 2117 2118
                   STREQ(deviceType, "atapi-cdrom")) {
            /*
             * This function was called in order to parse a harddisk device,
             * but .iso files and 'atapi-cdrom' devices are for CDROM devices
             * only. Just ignore it, another call to this function to parse a
             * CDROM device may handle it.
             */
            goto ignore;
        } else {
2119
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2120 2121
                      _("Invalid or not yet handled value '%s' for VMX entry "
                        "'%s'"), fileName, fileName_name);
M
Matthias Bolte 已提交
2122
            goto cleanup;
2123 2124
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
2125
        if (virFileHasSuffix(fileName, ".iso")) {
2126 2127
            if (deviceType != NULL) {
                if (STRCASENEQ(deviceType, "cdrom-image")) {
2128
                    VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2129 2130
                              _("Expecting VMX entry '%s' to be 'cdrom-image' "
                                "but found '%s'"), deviceType_name, deviceType);
M
Matthias Bolte 已提交
2131
                    goto cleanup;
2132 2133 2134 2135
                }
            }

            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
2136
            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
2137

M
Matthias Bolte 已提交
2138
            if ((*def)->src == NULL) {
M
Matthias Bolte 已提交
2139
                goto cleanup;
M
Matthias Bolte 已提交
2140
            }
2141
        } else if (virFileHasSuffix(fileName, ".vmdk")) {
2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154
            /*
             * This function was called in order to parse a CDROM device, but
             * .vmdk files are for harddisk devices only. Just ignore it,
             * another call to this function to parse a harddisk device may
             * handle it.
             */
            goto ignore;
        } else if (STREQ(deviceType, "atapi-cdrom")) {
            (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
            (*def)->src = fileName;

            fileName = NULL;
        } else {
2155
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2156 2157
                      _("Invalid or not yet handled value '%s' for VMX entry "
                        "'%s'"), fileName, fileName_name);
M
Matthias Bolte 已提交
2158
            goto cleanup;
2159 2160
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2161
        if (virFileHasSuffix(fileName, ".flp")) {
2162 2163
            if (fileType != NULL) {
                if (STRCASENEQ(fileType, "file")) {
2164
                    VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2165 2166
                              _("Expecting VMX entry '%s' to be 'file' but "
                                "found '%s'"), fileType_name, fileType);
M
Matthias Bolte 已提交
2167
                    goto cleanup;
2168 2169 2170 2171
                }
            }

            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
2172
            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
2173

M
Matthias Bolte 已提交
2174
            if ((*def)->src == NULL) {
M
Matthias Bolte 已提交
2175
                goto cleanup;
M
Matthias Bolte 已提交
2176
            }
2177 2178 2179 2180 2181 2182
        } else if (fileType != NULL && STREQ(fileType, "device")) {
            (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
            (*def)->src = fileName;

            fileName = NULL;
        } else {
2183
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2184 2185
                      _("Invalid or not yet handled value '%s' for VMX entry "
                        "'%s'"), fileName, fileName_name);
M
Matthias Bolte 已提交
2186
            goto cleanup;
2187 2188
        }
    } else {
2189
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported device type '%s'"),
M
Matthias Bolte 已提交
2190
                  virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2191
        goto cleanup;
2192 2193
    }

2194
    if (virDomainDiskDefAssignAddress(caps, *def) < 0) {
2195
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2196 2197 2198 2199
                  _("Could not assign address to disk '%s'"), (*def)->src);
        goto cleanup;
    }

M
Matthias Bolte 已提交
2200 2201
    result = 0;

M
Matthias Bolte 已提交
2202
  cleanup:
M
Matthias Bolte 已提交
2203 2204 2205 2206 2207
    if (result < 0) {
        virDomainDiskDefFree(*def);
        *def = NULL;
    }

2208 2209 2210 2211 2212 2213 2214
    VIR_FREE(prefix);
    VIR_FREE(deviceType);
    VIR_FREE(fileType);
    VIR_FREE(fileName);

    return result;

M
Matthias Bolte 已提交
2215
  ignore:
2216 2217 2218
    virDomainDiskDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2219 2220
    result = 0;

2221 2222 2223 2224 2225 2226
    goto cleanup;
}



int
2227
virVMXParseEthernet(virConfPtr conf, int controller, virDomainNetDefPtr *def)
2228
{
M
Matthias Bolte 已提交
2229
    int result = -1;
2230 2231 2232
    char prefix[48] = "";

    char present_name[48] = "";
2233
    bool present = false;
2234 2235

    char startConnected_name[48] = "";
2236
    bool startConnected = false;
2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252

    char connectionType_name[48] = "";
    char *connectionType = NULL;

    char addressType_name[48] = "";
    char *addressType = NULL;

    char generatedAddress_name[48] = "";
    char *generatedAddress = NULL;

    char address_name[48] = "";
    char *address = NULL;

    char virtualDev_name[48] = "";
    char *virtualDev = NULL;

2253 2254 2255
    char features_name[48] = "";
    long long features = 0;

2256 2257 2258
    char vnet_name[48] = "";
    char *vnet = NULL;

M
Matthias Bolte 已提交
2259 2260 2261
    char networkName_name[48] = "";
    char *networkName = NULL;

2262
    if (def == NULL || *def != NULL) {
2263
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2264 2265 2266 2267
        return -1;
    }

    if (controller < 0 || controller > 3) {
2268
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2269
                  _("Ethernet controller index %d out of [0..3] range"),
2270
                  controller);
2271
        return -1;
2272 2273 2274
    }

    if (VIR_ALLOC(*def) < 0) {
2275
        virReportOOMError();
M
Matthias Bolte 已提交
2276
        return -1;
2277 2278
    }

2279
    snprintf(prefix, sizeof(prefix), "ethernet%d", controller);
2280

2281 2282 2283 2284 2285 2286 2287 2288 2289 2290
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(connectionType);
    VMX_BUILD_NAME(addressType);
    VMX_BUILD_NAME(generatedAddress);
    VMX_BUILD_NAME(address);
    VMX_BUILD_NAME(virtualDev);
    VMX_BUILD_NAME(features);
    VMX_BUILD_NAME(networkName);
    VMX_BUILD_NAME(vnet);
2291 2292

    /* vmx:present */
2293
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2294
        goto cleanup;
2295 2296 2297
    }

    /* vmx:startConnected */
2298 2299
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2300
        goto cleanup;
2301 2302 2303 2304 2305 2306 2307 2308
    }

    /* FIXME: Need to distiguish between active and inactive domains here */
    if (! present/* && ! startConnected*/) {
        goto ignore;
    }

    /* vmx:connectionType -> def:type */
2309 2310
    if (virVMXGetConfigString(conf, connectionType_name, &connectionType,
                              true) < 0) {
M
Matthias Bolte 已提交
2311
        goto cleanup;
2312 2313 2314
    }

    /* vmx:addressType, vmx:generatedAddress, vmx:address -> def:mac */
2315 2316 2317 2318 2319
    if (virVMXGetConfigString(conf, addressType_name, &addressType,
                              true) < 0 ||
        virVMXGetConfigString(conf, generatedAddress_name, &generatedAddress,
                              true) < 0 ||
        virVMXGetConfigString(conf, address_name, &address, true) < 0) {
M
Matthias Bolte 已提交
2320
        goto cleanup;
2321 2322
    }

2323 2324
    if (addressType == NULL || STRCASEEQ(addressType, "generated") ||
        STRCASEEQ(addressType, "vpx")) {
2325 2326
        if (generatedAddress != NULL) {
            if (virParseMacAddr(generatedAddress, (*def)->mac) < 0) {
2327
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2328 2329
                          _("Expecting VMX entry '%s' to be MAC address but "
                            "found '%s'"), generatedAddress_name,
2330
                          generatedAddress);
M
Matthias Bolte 已提交
2331
                goto cleanup;
2332 2333 2334 2335 2336
            }
        }
    } else if (STRCASEEQ(addressType, "static")) {
        if (address != NULL) {
            if (virParseMacAddr(address, (*def)->mac) < 0) {
2337
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2338 2339
                          _("Expecting VMX entry '%s' to be MAC address but "
                            "found '%s'"), address_name, address);
M
Matthias Bolte 已提交
2340
                goto cleanup;
2341 2342 2343
            }
        }
    } else {
2344
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2345 2346
                  _("Expecting VMX entry '%s' to be 'generated' or 'static' or "
                    "'vpx' but found '%s'"), addressType_name, addressType);
M
Matthias Bolte 已提交
2347
        goto cleanup;
2348 2349
    }

2350
    /* vmx:virtualDev, vmx:features -> def:model */
2351 2352
    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev, true) < 0 ||
        virVMXGetConfigLong(conf, features_name, &features, 0, true) < 0) {
M
Matthias Bolte 已提交
2353
        goto cleanup;
2354 2355
    }

2356 2357 2358 2359 2360
    if (virtualDev != NULL) {
        if (STRCASENEQ(virtualDev, "vlance") &&
            STRCASENEQ(virtualDev, "vmxnet") &&
            STRCASENEQ(virtualDev, "vmxnet3") &&
            STRCASENEQ(virtualDev, "e1000")) {
2361
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2362 2363 2364
                      _("Expecting VMX entry '%s' to be 'vlance' or 'vmxnet' or "
                        "'vmxnet3' or 'e1000' but found '%s'"), virtualDev_name,
                      virtualDev);
M
Matthias Bolte 已提交
2365
            goto cleanup;
2366 2367 2368 2369 2370 2371 2372 2373 2374
        }

        if (STRCASEEQ(virtualDev, "vmxnet") && features == 15) {
            VIR_FREE(virtualDev);

            virtualDev = strdup("vmxnet2");

            if (virtualDev == NULL) {
                virReportOOMError();
M
Matthias Bolte 已提交
2375
                goto cleanup;
2376 2377
            }
        }
2378 2379
    }

M
Matthias Bolte 已提交
2380 2381 2382 2383
    /* vmx:networkName -> def:data.bridge.brname */
    if ((connectionType == NULL ||
         STRCASEEQ(connectionType, "bridged") ||
         STRCASEEQ(connectionType, "custom")) &&
2384 2385
        virVMXGetConfigString(conf, networkName_name, &networkName,
                              false) < 0) {
M
Matthias Bolte 已提交
2386
        goto cleanup;
M
Matthias Bolte 已提交
2387 2388 2389
    }

    /* vmx:vnet -> def:data.ifname */
2390
    if (connectionType != NULL && STRCASEEQ(connectionType, "custom") &&
2391
        virVMXGetConfigString(conf, vnet_name, &vnet, false) < 0) {
M
Matthias Bolte 已提交
2392
        goto cleanup;
2393 2394 2395 2396 2397 2398
    }

    /* Setup virDomainNetDef */
    if (connectionType == NULL || STRCASEEQ(connectionType, "bridged")) {
        (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
        (*def)->model = virtualDev;
M
Matthias Bolte 已提交
2399
        (*def)->data.bridge.brname = networkName;
2400 2401

        virtualDev = NULL;
M
Matthias Bolte 已提交
2402
        networkName = NULL;
2403 2404
    } else if (STRCASEEQ(connectionType, "hostonly")) {
        /* FIXME */
2405
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2406
                  _("No yet handled value '%s' for VMX entry '%s'"),
2407
                  connectionType, connectionType_name);
M
Matthias Bolte 已提交
2408
        goto cleanup;
2409 2410
    } else if (STRCASEEQ(connectionType, "nat")) {
        /* FIXME */
2411
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2412
                  _("No yet handled value '%s' for VMX entry '%s'"),
2413
                  connectionType, connectionType_name);
M
Matthias Bolte 已提交
2414
        goto cleanup;
2415 2416 2417
    } else if (STRCASEEQ(connectionType, "custom")) {
        (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
        (*def)->model = virtualDev;
M
Matthias Bolte 已提交
2418 2419
        (*def)->data.bridge.brname = networkName;
        (*def)->ifname = vnet;
2420 2421

        virtualDev = NULL;
M
Matthias Bolte 已提交
2422
        networkName = NULL;
2423 2424
        vnet = NULL;
    } else {
2425
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2426
                  _("Invalid value '%s' for VMX entry '%s'"), connectionType,
2427
                  connectionType_name);
M
Matthias Bolte 已提交
2428
        goto cleanup;
2429 2430
    }

M
Matthias Bolte 已提交
2431 2432
    result = 0;

M
Matthias Bolte 已提交
2433
  cleanup:
M
Matthias Bolte 已提交
2434 2435 2436 2437 2438
    if (result < 0) {
        virDomainNetDefFree(*def);
        *def = NULL;
    }

2439 2440 2441 2442 2443 2444 2445 2446 2447
    VIR_FREE(connectionType);
    VIR_FREE(addressType);
    VIR_FREE(generatedAddress);
    VIR_FREE(address);
    VIR_FREE(virtualDev);
    VIR_FREE(vnet);

    return result;

M
Matthias Bolte 已提交
2448
  ignore:
2449 2450 2451
    virDomainNetDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2452 2453
    result = 0;

2454 2455 2456 2457 2458 2459
    goto cleanup;
}



int
2460 2461
virVMXParseSerial(virVMXContext *ctx, virConfPtr conf, int port,
                  virDomainChrDefPtr *def)
2462
{
M
Matthias Bolte 已提交
2463
    int result = -1;
2464 2465 2466
    char prefix[48] = "";

    char present_name[48] = "";
2467
    bool present = false;
2468 2469

    char startConnected_name[48] = "";
2470
    bool startConnected = false;
2471 2472 2473 2474 2475 2476 2477

    char fileType_name[48] = "";
    char *fileType = NULL;

    char fileName_name[48] = "";
    char *fileName = NULL;

2478 2479 2480 2481 2482
    char network_endPoint_name[48] = "";
    char *network_endPoint = NULL;

    xmlURIPtr parsedUri = NULL;

2483
    if (def == NULL || *def != NULL) {
2484
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2485 2486 2487 2488
        return -1;
    }

    if (port < 0 || port > 3) {
2489
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2490
                  _("Serial port index %d out of [0..3] range"), port);
2491
        return -1;
2492 2493 2494
    }

    if (VIR_ALLOC(*def) < 0) {
2495
        virReportOOMError();
M
Matthias Bolte 已提交
2496
        return -1;
2497 2498
    }

2499
    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
2500

2501
    snprintf(prefix, sizeof(prefix), "serial%d", port);
2502

2503 2504 2505 2506 2507
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
    VMX_BUILD_NAME_EXTRA(network_endPoint, "network.endPoint");
2508 2509

    /* vmx:present */
2510
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2511
        goto cleanup;
2512 2513 2514
    }

    /* vmx:startConnected */
2515 2516
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2517
        goto cleanup;
2518 2519 2520 2521 2522 2523 2524 2525
    }

    /* FIXME: Need to distiguish between active and inactive domains here */
    if (! present/* && ! startConnected*/) {
        goto ignore;
    }

    /* vmx:fileType -> def:type */
2526
    if (virVMXGetConfigString(conf, fileType_name, &fileType, false) < 0) {
M
Matthias Bolte 已提交
2527
        goto cleanup;
2528 2529 2530
    }

    /* vmx:fileName -> def:data.file.path */
2531
    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0) {
M
Matthias Bolte 已提交
2532
        goto cleanup;
2533 2534
    }

2535
    /* vmx:network.endPoint -> def:data.tcp.listen */
2536 2537
    if (virVMXGetConfigString(conf, network_endPoint_name, &network_endPoint,
                              true) < 0) {
2538 2539 2540
        goto cleanup;
    }

2541 2542
    /* Setup virDomainChrDef */
    if (STRCASEEQ(fileType, "device")) {
2543
        (*def)->target.port = port;
2544 2545
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
        (*def)->source.data.file.path = fileName;
2546 2547 2548

        fileName = NULL;
    } else if (STRCASEEQ(fileType, "file")) {
2549
        (*def)->target.port = port;
2550 2551 2552
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
        (*def)->source.data.file.path = ctx->parseFileName(fileName,
                                                           ctx->opaque);
2553

2554
        if ((*def)->source.data.file.path == NULL) {
M
Matthias Bolte 已提交
2555
            goto cleanup;
M
Matthias Bolte 已提交
2556
        }
2557
    } else if (STRCASEEQ(fileType, "pipe")) {
M
Matthias Bolte 已提交
2558 2559 2560 2561
        /*
         * FIXME: Differences between client/server and VM/application pipes
         *        not representable in domain XML form
         */
2562
        (*def)->target.port = port;
2563 2564
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
        (*def)->source.data.file.path = fileName;
M
Matthias Bolte 已提交
2565 2566

        fileName = NULL;
2567 2568
    } else if (STRCASEEQ(fileType, "network")) {
        (*def)->target.port = port;
2569
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_TCP;
2570 2571 2572 2573 2574 2575 2576 2577 2578

        parsedUri = xmlParseURI(fileName);

        if (parsedUri == NULL) {
            virReportOOMError();
            goto cleanup;
        }

        if (parsedUri->port == 0) {
2579
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2580 2581 2582 2583 2584
                      _("VMX entry '%s' doesn't contain a port part"),
                      fileName_name);
            goto cleanup;
        }

2585
        (*def)->source.data.tcp.host = strdup(parsedUri->server);
2586

2587
        if ((*def)->source.data.tcp.host == NULL) {
2588 2589 2590 2591
            virReportOOMError();
            goto cleanup;
        }

2592 2593
        if (virAsprintf(&(*def)->source.data.tcp.service, "%d",
                        parsedUri->port) < 0) {
2594 2595 2596 2597 2598 2599 2600 2601 2602
            virReportOOMError();
            goto cleanup;
        }

        /* See vSphere API documentation about VirtualSerialPortURIBackingInfo */
        if (parsedUri->scheme == NULL ||
            STRCASEEQ(parsedUri->scheme, "tcp") ||
            STRCASEEQ(parsedUri->scheme, "tcp4") ||
            STRCASEEQ(parsedUri->scheme, "tcp6")) {
2603
            (*def)->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
2604
        } else if (STRCASEEQ(parsedUri->scheme, "telnet")) {
2605 2606
            (*def)->source.data.tcp.protocol
                = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
2607
        } else if (STRCASEEQ(parsedUri->scheme, "telnets")) {
2608 2609
            (*def)->source.data.tcp.protocol
                = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS;
2610 2611 2612 2613
        } else if (STRCASEEQ(parsedUri->scheme, "ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp+ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp4+ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp6+ssl")) {
2614
            (*def)->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS;
2615
        } else {
2616
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2617 2618 2619 2620 2621 2622
                      _("VMX entry '%s' contains unsupported scheme '%s'"),
                      fileName_name, parsedUri->scheme);
            goto cleanup;
        }

        if (network_endPoint == NULL || STRCASEEQ(network_endPoint, "server")) {
2623
            (*def)->source.data.tcp.listen = true;
2624
        } else if (STRCASEEQ(network_endPoint, "client")) {
2625
            (*def)->source.data.tcp.listen = false;
2626
        } else {
2627
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2628 2629 2630 2631
                      _("Expecting VMX entry '%s' to be 'server' or 'client' "
                        "but found '%s'"), network_endPoint_name, network_endPoint);
            goto cleanup;
        }
2632
    } else {
2633
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2634
                  _("Expecting VMX entry '%s' to be 'device', 'file' or 'pipe' "
2635
                    "or 'network' but found '%s'"), fileType_name, fileType);
M
Matthias Bolte 已提交
2636
        goto cleanup;
2637 2638
    }

M
Matthias Bolte 已提交
2639 2640
    result = 0;

M
Matthias Bolte 已提交
2641
  cleanup:
M
Matthias Bolte 已提交
2642 2643 2644 2645 2646
    if (result < 0) {
        virDomainChrDefFree(*def);
        *def = NULL;
    }

2647 2648
    VIR_FREE(fileType);
    VIR_FREE(fileName);
2649 2650
    VIR_FREE(network_endPoint);
    xmlFreeURI(parsedUri);
2651 2652 2653

    return result;

M
Matthias Bolte 已提交
2654
  ignore:
2655 2656 2657
    virDomainChrDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2658 2659
    result = 0;

2660 2661 2662 2663 2664 2665
    goto cleanup;
}



int
2666 2667
virVMXParseParallel(virVMXContext *ctx, virConfPtr conf, int port,
                    virDomainChrDefPtr *def)
2668
{
M
Matthias Bolte 已提交
2669
    int result = -1;
2670 2671 2672
    char prefix[48] = "";

    char present_name[48] = "";
2673
    bool present = false;
2674 2675

    char startConnected_name[48] = "";
2676
    bool startConnected = false;
2677 2678 2679 2680 2681 2682 2683 2684

    char fileType_name[48] = "";
    char *fileType = NULL;

    char fileName_name[48] = "";
    char *fileName = NULL;

    if (def == NULL || *def != NULL) {
2685
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2686 2687 2688 2689
        return -1;
    }

    if (port < 0 || port > 2) {
2690
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2691
                  _("Parallel port index %d out of [0..2] range"), port);
2692
        return -1;
2693 2694 2695
    }

    if (VIR_ALLOC(*def) < 0) {
2696
        virReportOOMError();
M
Matthias Bolte 已提交
2697
        return -1;
2698 2699
    }

2700
    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
2701

2702
    snprintf(prefix, sizeof(prefix), "parallel%d", port);
2703

2704 2705 2706 2707
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
2708 2709

    /* vmx:present */
2710
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2711
        goto cleanup;
2712 2713 2714
    }

    /* vmx:startConnected */
2715 2716
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2717
        goto cleanup;
2718 2719 2720 2721 2722 2723 2724 2725
    }

    /* FIXME: Need to distiguish between active and inactive domains here */
    if (! present/* && ! startConnected*/) {
        goto ignore;
    }

    /* vmx:fileType -> def:type */
2726
    if (virVMXGetConfigString(conf, fileType_name, &fileType, false) < 0) {
M
Matthias Bolte 已提交
2727
        goto cleanup;
2728 2729 2730
    }

    /* vmx:fileName -> def:data.file.path */
2731
    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0) {
M
Matthias Bolte 已提交
2732
        goto cleanup;
2733 2734 2735 2736
    }

    /* Setup virDomainChrDef */
    if (STRCASEEQ(fileType, "device")) {
2737
        (*def)->target.port = port;
2738 2739
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
        (*def)->source.data.file.path = fileName;
2740 2741 2742

        fileName = NULL;
    } else if (STRCASEEQ(fileType, "file")) {
2743
        (*def)->target.port = port;
2744 2745 2746
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
        (*def)->source.data.file.path = ctx->parseFileName(fileName,
                                                           ctx->opaque);
2747

2748
        if ((*def)->source.data.file.path == NULL) {
M
Matthias Bolte 已提交
2749
            goto cleanup;
M
Matthias Bolte 已提交
2750
        }
2751
    } else {
2752
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2753 2754
                  _("Expecting VMX entry '%s' to be 'device' or 'file' but "
                    "found '%s'"), fileType_name, fileType);
M
Matthias Bolte 已提交
2755
        goto cleanup;
2756 2757
    }

M
Matthias Bolte 已提交
2758 2759
    result = 0;

M
Matthias Bolte 已提交
2760
  cleanup:
M
Matthias Bolte 已提交
2761 2762 2763 2764 2765
    if (result < 0) {
        virDomainChrDefFree(*def);
        *def = NULL;
    }

2766 2767 2768 2769 2770
    VIR_FREE(fileType);
    VIR_FREE(fileName);

    return result;

M
Matthias Bolte 已提交
2771
  ignore:
2772 2773 2774
    virDomainChrDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2775 2776
    result = 0;

2777 2778
    goto cleanup;
}
M
Matthias Bolte 已提交
2779 2780 2781



2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805
int
virVMXParseSVGA(virConfPtr conf, virDomainVideoDefPtr *def)
{
    int result = -1;
    long long svga_vramSize = 0;

    if (def == NULL || *def != NULL) {
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
        return -1;
    }

    if (VIR_ALLOC(*def) < 0) {
        virReportOOMError();
        return -1;
    }

    (*def)->type = VIR_DOMAIN_VIDEO_TYPE_VMVGA;

    /* vmx:vramSize */
    if (virVMXGetConfigLong(conf, "svga.vramSize", &svga_vramSize,
                            4 * 1024 * 1024, true) < 0) {
        goto cleanup;
    }

2806
    (*def)->vram = VIR_DIV_UP(svga_vramSize, 1024); /* Scale from bytes to kilobytes */
2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820

    result = 0;

  cleanup:
    if (result < 0) {
        virDomainVideoDefFree(*def);
        *def = NULL;
    }

    return result;
}



M
Matthias Bolte 已提交
2821 2822 2823 2824 2825
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Domain XML -> VMX
 */

char *
2826 2827
virVMXFormatConfig(virVMXContext *ctx, virCapsPtr caps, virDomainDefPtr def,
                   int virtualHW_version)
M
Matthias Bolte 已提交
2828
{
2829
    char *vmx = NULL;
M
Matthias Bolte 已提交
2830 2831 2832 2833
    int i;
    int sched_cpu_affinity_length;
    unsigned char zero[VIR_UUID_BUFLEN];
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
2834 2835
    char *preliminaryDisplayName = NULL;
    char *displayName = NULL;
2836
    char *annotation = NULL;
2837
    unsigned long max_balloon;
2838 2839
    bool scsi_present[4] = { false, false, false, false };
    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
2840
    bool floppy_present[2] = { false, false };
M
Matthias Bolte 已提交
2841

2842
    if (ctx->formatFileName == NULL) {
2843 2844
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                  _("virVMXContext has no formatFileName function set"));
2845 2846 2847
        return NULL;
    }

M
Matthias Bolte 已提交
2848 2849
    memset(zero, 0, VIR_UUID_BUFLEN);

2850 2851
    if (def->virtType != VIR_DOMAIN_VIRT_VMWARE) {
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2852
                  _("Expecting virt type to be '%s' but found '%s'"),
M
Matthias Bolte 已提交
2853 2854 2855 2856 2857
                  virDomainVirtTypeToString(VIR_DOMAIN_VIRT_VMWARE),
                  virDomainVirtTypeToString(def->virtType));
        return NULL;
    }

2858 2859 2860
    /* vmx:.encoding */
    virBufferAddLit(&buffer, ".encoding = \"UTF-8\"\n");

M
Matthias Bolte 已提交
2861 2862 2863 2864
    /* vmx:config.version */
    virBufferAddLit(&buffer, "config.version = \"8\"\n");

    /* vmx:virtualHW.version */
2865 2866
    virBufferVSprintf(&buffer, "virtualHW.version = \"%d\"\n",
                      virtualHW_version);
M
Matthias Bolte 已提交
2867

M
Matthias Bolte 已提交
2868
    /* def:os.arch -> vmx:guestOS */
M
Matthias Bolte 已提交
2869 2870 2871 2872 2873
    if (def->os.arch == NULL || STRCASEEQ(def->os.arch, "i686")) {
        virBufferAddLit(&buffer, "guestOS = \"other\"\n");
    } else if (STRCASEEQ(def->os.arch, "x86_64")) {
        virBufferAddLit(&buffer, "guestOS = \"other-64\"\n");
    } else {
2874
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2875 2876
                  _("Expecting domain XML attribute 'arch' of entry 'os/type' "
                    "to be 'i686' or 'x86_64' but found '%s'"), def->os.arch);
2877
        goto cleanup;
M
Matthias Bolte 已提交
2878 2879
    }

M
Matthias Bolte 已提交
2880 2881 2882 2883 2884 2885 2886
    /* def:os.smbios_mode -> vmx:smbios.reflecthost */
    if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_NONE ||
        def->os.smbios_mode == VIR_DOMAIN_SMBIOS_EMULATE) {
        /* nothing */
    } else if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_HOST) {
        virBufferAddLit(&buffer, "smbios.reflecthost = \"true\"\n");
    } else {
2887
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
M
Matthias Bolte 已提交
2888 2889 2890 2891 2892
                  _("Unsupported SMBIOS mode '%s'"),
                  virDomainSmbiosModeTypeToString(def->os.smbios_mode));
        goto cleanup;
    }

M
Matthias Bolte 已提交
2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906
    /* def:uuid -> vmx:uuid.action, vmx:uuid.bios */
    if (memcmp(def->uuid, zero, VIR_UUID_BUFLEN) == 0) {
        virBufferAddLit(&buffer, "uuid.action = \"create\"\n");
    } else {
        virBufferVSprintf(&buffer, "uuid.bios = \"%02x %02x %02x %02x %02x %02x "
                          "%02x %02x-%02x %02x %02x %02x %02x %02x %02x %02x\"\n",
                          def->uuid[0], def->uuid[1], def->uuid[2], def->uuid[3],
                          def->uuid[4], def->uuid[5], def->uuid[6], def->uuid[7],
                          def->uuid[8], def->uuid[9], def->uuid[10], def->uuid[11],
                          def->uuid[12], def->uuid[13], def->uuid[14],
                          def->uuid[15]);
    }

    /* def:name -> vmx:displayName */
2907
    preliminaryDisplayName = virVMXEscapeHexPipe(def->name);
2908

2909 2910 2911
    if (preliminaryDisplayName == NULL) {
        goto cleanup;
    }
2912

2913
    displayName = virVMXEscapeHexPercent(preliminaryDisplayName);
2914

2915 2916 2917
    if (displayName == NULL) {
        goto cleanup;
    }
2918

2919
    virBufferVSprintf(&buffer, "displayName = \"%s\"\n", displayName);
2920

2921 2922
    /* def:description -> vmx:annotation */
    if (def->description != NULL) {
2923
        annotation = virVMXEscapeHexPipe(def->description);
2924 2925 2926 2927

        virBufferVSprintf(&buffer, "annotation = \"%s\"\n", annotation);
    }

2928
    /* def:mem.max_balloon -> vmx:memsize */
2929 2930
    /* max-memory must be a multiple of 4096 kilobyte */
    max_balloon = VIR_DIV_UP(def->mem.max_balloon, 4096) * 4096;
M
Matthias Bolte 已提交
2931

2932 2933
    virBufferVSprintf(&buffer, "memsize = \"%lu\"\n",
                      max_balloon / 1024); /* Scale from kilobytes to megabytes */
M
Matthias Bolte 已提交
2934

2935
    /* def:mem.cur_balloon -> vmx:sched.mem.max */
2936 2937 2938 2939
    if (def->mem.cur_balloon < max_balloon) {
        virBufferVSprintf(&buffer, "sched.mem.max = \"%lu\"\n",
                          VIR_DIV_UP(def->mem.cur_balloon,
                                     1024)); /* Scale from kilobytes to megabytes */
M
Matthias Bolte 已提交
2940 2941
    }

2942 2943
    /* def:mem.min_guarantee -> vmx:sched.mem.minsize */
    if (def->mem.min_guarantee > 0) {
2944 2945 2946
        virBufferVSprintf(&buffer, "sched.mem.minsize = \"%lu\"\n",
                          VIR_DIV_UP(def->mem.min_guarantee,
                                     1024)); /* Scale from kilobytes to megabytes */
2947 2948
    }

E
Eric Blake 已提交
2949 2950
    /* def:maxvcpus -> vmx:numvcpus */
    if (def->vcpus != def->maxvcpus) {
2951
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
E
Eric Blake 已提交
2952 2953 2954 2955 2956
                  _("No support for domain XML entry 'vcpu' attribute "
                    "'current'"));
        goto cleanup;
    }
    if (def->maxvcpus <= 0 || (def->maxvcpus % 2 != 0 && def->maxvcpus != 1)) {
2957
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2958 2959
                  _("Expecting domain XML entry 'vcpu' to be an unsigned "
                    "integer (1 or a multiple of 2) but found %d"),
E
Eric Blake 已提交
2960
                  def->maxvcpus);
2961
        goto cleanup;
M
Matthias Bolte 已提交
2962 2963
    }

E
Eric Blake 已提交
2964
    virBufferVSprintf(&buffer, "numvcpus = \"%d\"\n", def->maxvcpus);
M
Matthias Bolte 已提交
2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977

    /* def:cpumask -> vmx:sched.cpu.affinity */
    if (def->cpumasklen > 0) {
        virBufferAddLit(&buffer, "sched.cpu.affinity = \"");

        sched_cpu_affinity_length = 0;

        for (i = 0; i < def->cpumasklen; ++i) {
            if (def->cpumask[i]) {
                ++sched_cpu_affinity_length;
            }
        }

E
Eric Blake 已提交
2978
        if (sched_cpu_affinity_length < def->maxvcpus) {
2979
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
2980
                      _("Expecting domain XML attribute 'cpuset' of entry "
E
Eric Blake 已提交
2981 2982
                        "'vcpu' to contain at least %d CPU(s)"),
                      def->maxvcpus);
2983
            goto cleanup;
M
Matthias Bolte 已提交
2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000
        }

        for (i = 0; i < def->cpumasklen; ++i) {
            if (def->cpumask[i]) {
                virBufferVSprintf(&buffer, "%d", i);

                if (sched_cpu_affinity_length > 1) {
                    virBufferAddChar(&buffer, ',');
                }

                --sched_cpu_affinity_length;
            }
        }

        virBufferAddLit(&buffer, "\"\n");
    }

M
Matthias Bolte 已提交
3001 3002 3003 3004
    /* def:graphics */
    for (i = 0; i < def->ngraphics; ++i) {
        switch (def->graphics[i]->type) {
          case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
3005
            if (virVMXFormatVNC(def->graphics[i], &buffer) < 0) {
3006
                goto cleanup;
M
Matthias Bolte 已提交
3007 3008 3009 3010 3011
            }

            break;

          default:
3012
            VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3013
                      _("Unsupported graphics type '%s'"),
M
Matthias Bolte 已提交
3014
                      virDomainGraphicsTypeToString(def->graphics[i]->type));
3015
            goto cleanup;
M
Matthias Bolte 已提交
3016 3017 3018
        }
    }

M
Matthias Bolte 已提交
3019
    /* def:disks */
3020
    for (i = 0; i < def->ndisks; ++i) {
3021 3022
        if (virVMXVerifyDiskAddress(caps, def->disks[i]) < 0 ||
            virVMXHandleLegacySCSIDiskDriverName(def, def->disks[i]) < 0) {
3023
            goto cleanup;
3024 3025
        }
    }
M
Matthias Bolte 已提交
3026

3027 3028
    if (virVMXGatherSCSIControllers(ctx, def, scsi_virtualDev,
                                    scsi_present) < 0) {
3029
        goto cleanup;
M
Matthias Bolte 已提交
3030 3031 3032 3033 3034 3035
    }

    for (i = 0; i < 4; ++i) {
        if (scsi_present[i]) {
            virBufferVSprintf(&buffer, "scsi%d.present = \"true\"\n", i);

3036
            if (scsi_virtualDev[i] != -1) {
M
Matthias Bolte 已提交
3037
                virBufferVSprintf(&buffer, "scsi%d.virtualDev = \"%s\"\n", i,
3038
                                  virVMXSCSIControllerModelTypeToString
3039
                                    (scsi_virtualDev[i]));
M
Matthias Bolte 已提交
3040 3041 3042 3043 3044 3045 3046
            }
        }
    }

    for (i = 0; i < def->ndisks; ++i) {
        switch (def->disks[i]->device) {
          case VIR_DOMAIN_DISK_DEVICE_DISK:
3047
            if (virVMXFormatHardDisk(ctx, def->disks[i], &buffer) < 0) {
3048
                goto cleanup;
M
Matthias Bolte 已提交
3049 3050 3051 3052 3053
            }

            break;

          case VIR_DOMAIN_DISK_DEVICE_CDROM:
3054
            if (virVMXFormatCDROM(ctx, def->disks[i], &buffer) < 0) {
3055
                goto cleanup;
M
Matthias Bolte 已提交
3056 3057 3058 3059 3060
            }

            break;

          case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
3061 3062
            if (virVMXFormatFloppy(ctx, def->disks[i], &buffer,
                                   floppy_present) < 0) {
3063
                goto cleanup;
M
Matthias Bolte 已提交
3064 3065 3066 3067 3068
            }

            break;

          default:
3069
            VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3070
                      _("Unsupported disk device type '%s'"),
M
Matthias Bolte 已提交
3071
                      virDomainDiskDeviceTypeToString(def->disks[i]->device));
3072
            goto cleanup;
M
Matthias Bolte 已提交
3073 3074 3075
        }
    }

3076 3077 3078 3079 3080 3081 3082
    for (i = 0; i < 2; ++i) {
        /* floppy[0..1].present defaults to true, disable it explicitly */
        if (! floppy_present[i]) {
            virBufferVSprintf(&buffer, "floppy%d.present = \"false\"\n", i);
        }
    }

M
Matthias Bolte 已提交
3083 3084 3085 3086 3087
    /* def:fss */
    /* FIXME */

    /* def:nets */
    for (i = 0; i < def->nnets; ++i) {
3088
        if (virVMXFormatEthernet(def->nets[i], i, &buffer) < 0) {
3089
            goto cleanup;
M
Matthias Bolte 已提交
3090 3091 3092 3093 3094 3095 3096 3097 3098
        }
    }

    /* def:inputs */
    /* FIXME */

    /* def:sounds */
    /* FIXME */

3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111
    /* def:videos */
    if (def->nvideos > 0) {
        if (def->nvideos > 1) {
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s",
                      _("No support for multiple video devices"));
            goto cleanup;
        }

        if (virVMXFormatSVGA(def->videos[0], &buffer) < 0) {
            goto cleanup;
        }
    }

M
Matthias Bolte 已提交
3112 3113 3114 3115 3116
    /* def:hostdevs */
    /* FIXME */

    /* def:serials */
    for (i = 0; i < def->nserials; ++i) {
3117
        if (virVMXFormatSerial(ctx, def->serials[i], &buffer) < 0) {
3118
            goto cleanup;
M
Matthias Bolte 已提交
3119 3120 3121 3122 3123
        }
    }

    /* def:parallels */
    for (i = 0; i < def->nparallels; ++i) {
3124
        if (virVMXFormatParallel(ctx, def->parallels[i], &buffer) < 0) {
3125
            goto cleanup;
M
Matthias Bolte 已提交
3126 3127 3128 3129 3130
        }
    }

    /* Get final VMX output */
    if (virBufferError(&buffer)) {
3131
        virReportOOMError();
3132
        goto cleanup;
M
Matthias Bolte 已提交
3133 3134
    }

3135
    vmx = virBufferContentAndReset(&buffer);
M
Matthias Bolte 已提交
3136

3137 3138 3139 3140 3141
  cleanup:
    if (vmx == NULL) {
        virBufferFreeAndReset(&buffer);
    }

3142 3143
    VIR_FREE(preliminaryDisplayName);
    VIR_FREE(displayName);
3144
    VIR_FREE(annotation);
M
Matthias Bolte 已提交
3145

3146
    return vmx;
M
Matthias Bolte 已提交
3147 3148 3149 3150
}



M
Matthias Bolte 已提交
3151
int
3152
virVMXFormatVNC(virDomainGraphicsDefPtr def, virBufferPtr buffer)
M
Matthias Bolte 已提交
3153 3154
{
    if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
3155
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183
        return -1;
    }

    virBufferVSprintf(buffer, "RemoteDisplay.vnc.enabled = \"true\"\n");

    if (def->data.vnc.autoport) {
        VIR_WARN0("VNC autoport is enabled, but the automatically assigned "
                  "VNC port cannot be read back");
    } else {
        if (def->data.vnc.port < 5900 || def->data.vnc.port > 5964) {
            VIR_WARN("VNC port %d it out of [5900..5964] range",
                     def->data.vnc.port);
        }

        virBufferVSprintf(buffer, "RemoteDisplay.vnc.port = \"%d\"\n",
                          def->data.vnc.port);
    }

    if (def->data.vnc.listenAddr != NULL) {
        virBufferVSprintf(buffer, "RemoteDisplay.vnc.ip = \"%s\"\n",
                          def->data.vnc.listenAddr);
    }

    if (def->data.vnc.keymap != NULL) {
        virBufferVSprintf(buffer, "RemoteDisplay.vnc.keymap = \"%s\"\n",
                          def->data.vnc.keymap);
    }

3184
    if (def->data.vnc.auth.passwd != NULL) {
M
Matthias Bolte 已提交
3185
        virBufferVSprintf(buffer, "RemoteDisplay.vnc.password = \"%s\"\n",
3186
                          def->data.vnc.auth.passwd);
M
Matthias Bolte 已提交
3187 3188 3189 3190 3191 3192 3193
    }

    return 0;
}



M
Matthias Bolte 已提交
3194
int
3195 3196
virVMXFormatHardDisk(virVMXContext *ctx, virDomainDiskDefPtr def,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3197
{
3198
    int controllerOrBus, unit;
M
Matthias Bolte 已提交
3199 3200 3201
    const char *busName = NULL;
    const char *entryPrefix = NULL;
    const char *deviceTypePrefix = NULL;
M
Matthias Bolte 已提交
3202
    char *fileName = NULL;
M
Matthias Bolte 已提交
3203 3204

    if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
3205
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3206 3207 3208 3209 3210 3211 3212 3213
        return -1;
    }

    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
        busName = "SCSI";
        entryPrefix = "scsi";
        deviceTypePrefix = "scsi";

3214 3215
        if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
                                                  &unit) < 0) {
M
Matthias Bolte 已提交
3216 3217 3218 3219 3220 3221 3222
            return -1;
        }
    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
        busName = "IDE";
        entryPrefix = "ide";
        deviceTypePrefix = "ata";

3223
        if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
3224
                                           &unit) < 0) {
M
Matthias Bolte 已提交
3225 3226 3227
            return -1;
        }
    } else {
3228
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3229
                  _("Unsupported bus type '%s' for harddisk"),
M
Matthias Bolte 已提交
3230 3231 3232 3233 3234
                  virDomainDiskBusTypeToString(def->bus));
        return -1;
    }

    if (def->type != VIR_DOMAIN_DISK_TYPE_FILE) {
3235
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3236
                  _("%s harddisk '%s' has unsupported type '%s', expecting '%s'"),
M
Matthias Bolte 已提交
3237 3238 3239 3240 3241 3242
                  busName, def->dst, virDomainDiskTypeToString(def->type),
                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE));
        return -1;
    }

    virBufferVSprintf(buffer, "%s%d:%d.present = \"true\"\n",
3243
                      entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3244
    virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"%s-hardDisk\"\n",
3245
                      entryPrefix, controllerOrBus, unit, deviceTypePrefix);
M
Matthias Bolte 已提交
3246 3247

    if (def->src != NULL) {
3248
        if (! virFileHasSuffix(def->src, ".vmdk")) {
3249
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
3250 3251
                      _("Image file for %s harddisk '%s' has unsupported suffix, "
                        "expecting '.vmdk'"), busName, def->dst);
M
Matthias Bolte 已提交
3252 3253 3254
            return -1;
        }

3255
        fileName = ctx->formatFileName(def->src, ctx->opaque);
M
Matthias Bolte 已提交
3256 3257 3258 3259 3260

        if (fileName == NULL) {
            return -1;
        }

M
Matthias Bolte 已提交
3261
        virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3262
                          entryPrefix, controllerOrBus, unit, fileName);
M
Matthias Bolte 已提交
3263 3264

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3265 3266 3267 3268 3269
    }

    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
        if (def->cachemode == VIR_DOMAIN_DISK_CACHE_WRITETHRU) {
            virBufferVSprintf(buffer, "%s%d:%d.writeThrough = \"true\"\n",
3270
                              entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3271
        } else if (def->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) {
3272
            VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3273
                      _("%s harddisk '%s' has unsupported cache mode '%s'"),
M
Matthias Bolte 已提交
3274 3275
                      busName, def->dst,
                      virDomainDiskCacheTypeToString(def->cachemode));
M
Matthias Bolte 已提交
3276
            return -1;
M
Matthias Bolte 已提交
3277 3278 3279 3280 3281 3282 3283 3284 3285
        }
    }

    return 0;
}



int
3286 3287
virVMXFormatCDROM(virVMXContext *ctx, virDomainDiskDefPtr def,
                  virBufferPtr buffer)
M
Matthias Bolte 已提交
3288
{
3289
    int controllerOrBus, unit;
M
Matthias Bolte 已提交
3290 3291
    const char *busName = NULL;
    const char *entryPrefix = NULL;
M
Matthias Bolte 已提交
3292
    char *fileName = NULL;
M
Matthias Bolte 已提交
3293 3294

    if (def->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
3295
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3296 3297 3298 3299 3300 3301 3302
        return -1;
    }

    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
        busName = "SCSI";
        entryPrefix = "scsi";

3303 3304
        if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
                                                  &unit) < 0) {
M
Matthias Bolte 已提交
3305 3306 3307 3308 3309 3310
            return -1;
        }
    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
        busName = "IDE";
        entryPrefix = "ide";

3311 3312
        if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
                                          &unit) < 0) {
M
Matthias Bolte 已提交
3313 3314 3315
            return -1;
        }
    } else {
3316
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3317
                  _("Unsupported bus type '%s' for cdrom"),
M
Matthias Bolte 已提交
3318 3319 3320 3321 3322
                  virDomainDiskBusTypeToString(def->bus));
        return -1;
    }

    virBufferVSprintf(buffer, "%s%d:%d.present = \"true\"\n",
3323
                      entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3324 3325 3326

    if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
        virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"cdrom-image\"\n",
3327
                          entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3328 3329

        if (def->src != NULL) {
3330
            if (! virFileHasSuffix(def->src, ".iso")) {
3331
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
3332 3333
                          _("Image file for %s cdrom '%s' has unsupported "
                            "suffix, expecting '.iso'"), busName, def->dst);
M
Matthias Bolte 已提交
3334 3335 3336
                return -1;
            }

3337
            fileName = ctx->formatFileName(def->src, ctx->opaque);
M
Matthias Bolte 已提交
3338 3339 3340 3341 3342 3343

            if (fileName == NULL) {
                return -1;
            }

            virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3344
                              entryPrefix, controllerOrBus, unit, fileName);
M
Matthias Bolte 已提交
3345 3346 3347

            VIR_FREE(fileName);
        }
M
Matthias Bolte 已提交
3348 3349
    } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
        virBufferVSprintf(buffer, "%s%d:%d.deviceType = \"atapi-cdrom\"\n",
3350
                          entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3351 3352 3353

        if (def->src != NULL) {
            virBufferVSprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3354
                              entryPrefix, controllerOrBus, unit, def->src);
M
Matthias Bolte 已提交
3355
        }
M
Matthias Bolte 已提交
3356
    } else {
3357
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3358 3359
                  _("%s cdrom '%s' has unsupported type '%s', expecting '%s' "
                    "or '%s'"), busName, def->dst,
M
Matthias Bolte 已提交
3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371
                  virDomainDiskTypeToString(def->type),
                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE),
                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_BLOCK));
        return -1;
    }

    return 0;
}



int
3372 3373
virVMXFormatFloppy(virVMXContext *ctx, virDomainDiskDefPtr def,
                   virBufferPtr buffer, bool floppy_present[2])
M
Matthias Bolte 已提交
3374
{
3375
    int unit;
M
Matthias Bolte 已提交
3376
    char *fileName = NULL;
M
Matthias Bolte 已提交
3377 3378

    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
3379
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3380 3381 3382
        return -1;
    }

3383
    if (virVMXFloppyDiskNameToUnit(def->dst, &unit) < 0) {
M
Matthias Bolte 已提交
3384 3385 3386
        return -1;
    }

3387 3388
    floppy_present[unit] = true;

3389
    virBufferVSprintf(buffer, "floppy%d.present = \"true\"\n", unit);
M
Matthias Bolte 已提交
3390 3391

    if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
3392
        virBufferVSprintf(buffer, "floppy%d.fileType = \"file\"\n", unit);
M
Matthias Bolte 已提交
3393 3394

        if (def->src != NULL) {
3395
            if (! virFileHasSuffix(def->src, ".flp")) {
3396
                VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
3397 3398
                          _("Image file for floppy '%s' has unsupported "
                            "suffix, expecting '.flp'"), def->dst);
M
Matthias Bolte 已提交
3399 3400 3401
                return -1;
            }

3402
            fileName = ctx->formatFileName(def->src, ctx->opaque);
M
Matthias Bolte 已提交
3403 3404 3405 3406 3407 3408

            if (fileName == NULL) {
                return -1;
            }

            virBufferVSprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3409
                              unit, fileName);
M
Matthias Bolte 已提交
3410 3411 3412

            VIR_FREE(fileName);
        }
M
Matthias Bolte 已提交
3413
    } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
3414
        virBufferVSprintf(buffer, "floppy%d.fileType = \"device\"\n", unit);
M
Matthias Bolte 已提交
3415 3416 3417

        if (def->src != NULL) {
            virBufferVSprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3418
                              unit, def->src);
M
Matthias Bolte 已提交
3419
        }
M
Matthias Bolte 已提交
3420
    } else {
3421
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3422 3423
                  _("Floppy '%s' has unsupported type '%s', expecting '%s' "
                    "or '%s'"), def->dst,
M
Matthias Bolte 已提交
3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435
                  virDomainDiskTypeToString(def->type),
                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE),
                  virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_BLOCK));
        return -1;
    }

    return 0;
}



int
3436 3437
virVMXFormatEthernet(virDomainNetDefPtr def, int controller,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3438 3439
{
    char mac_string[VIR_MAC_STRING_BUFLEN];
3440
    unsigned int prefix, suffix;
M
Matthias Bolte 已提交
3441 3442

    if (controller < 0 || controller > 3) {
3443
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
3444
                  _("Ethernet controller index %d out of [0..3] range"),
M
Matthias Bolte 已提交
3445 3446 3447 3448 3449 3450
                  controller);
        return -1;
    }

    virBufferVSprintf(buffer, "ethernet%d.present = \"true\"\n", controller);

3451
    /* def:model -> vmx:virtualDev, vmx:features */
M
Matthias Bolte 已提交
3452 3453 3454
    if (def->model != NULL) {
        if (STRCASENEQ(def->model, "vlance") &&
            STRCASENEQ(def->model, "vmxnet") &&
3455
            STRCASENEQ(def->model, "vmxnet2") &&
3456
            STRCASENEQ(def->model, "vmxnet3") &&
M
Matthias Bolte 已提交
3457
            STRCASENEQ(def->model, "e1000")) {
3458
            VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
3459
                      _("Expecting domain XML entry 'devices/interfase/model' "
3460 3461
                        "to be 'vlance' or 'vmxnet' or 'vmxnet2' or 'vmxnet3' "
                        "or 'e1000' but found '%s'"), def->model);
M
Matthias Bolte 已提交
3462 3463 3464
            return -1;
        }

3465 3466 3467 3468 3469 3470 3471 3472 3473
        if (STRCASEEQ(def->model, "vmxnet2")) {
            virBufferVSprintf(buffer, "ethernet%d.virtualDev = \"vmxnet\"\n",
                              controller);
            virBufferVSprintf(buffer, "ethernet%d.features = \"15\"\n",
                              controller);
        } else {
            virBufferVSprintf(buffer, "ethernet%d.virtualDev = \"%s\"\n",
                              controller, def->model);
        }
M
Matthias Bolte 已提交
3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494
    }

    /* def:type, def:ifname -> vmx:connectionType */
    switch (def->type) {
      case VIR_DOMAIN_NET_TYPE_BRIDGE:
        virBufferVSprintf(buffer, "ethernet%d.networkName = \"%s\"\n",
                          controller, def->data.bridge.brname);

        if (def->ifname != NULL) {
            virBufferVSprintf(buffer, "ethernet%d.connectionType = \"custom\"\n",
                              controller);
            virBufferVSprintf(buffer, "ethernet%d.vnet = \"%s\"\n",
                              controller, def->ifname);
        } else {
            virBufferVSprintf(buffer, "ethernet%d.connectionType = \"bridged\"\n",
                              controller);
        }

        break;

      default:
3495
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type '%s'"),
M
Matthias Bolte 已提交
3496 3497 3498 3499
                  virDomainNetTypeToString(def->type));
        return -1;
    }

3500
    /* def:mac -> vmx:addressType, vmx:(generated)Address, vmx:checkMACAddress */
M
Matthias Bolte 已提交
3501 3502
    virFormatMacAddr(def->mac, mac_string);

3503 3504 3505 3506
    prefix = (def->mac[0] << 16) | (def->mac[1] << 8) | def->mac[2];
    suffix = (def->mac[3] << 16) | (def->mac[4] << 8) | def->mac[5];

    if (prefix == 0x000c29) {
M
Matthias Bolte 已提交
3507 3508 3509 3510
        virBufferVSprintf(buffer, "ethernet%d.addressType = \"generated\"\n",
                          controller);
        virBufferVSprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
                          controller, mac_string);
M
Matthias Bolte 已提交
3511 3512
        virBufferVSprintf(buffer, "ethernet%d.generatedAddressOffset = \"0\"\n",
                          controller);
3513 3514 3515 3516 3517 3518 3519 3520 3521 3522
    } else if (prefix == 0x005056 && suffix <= 0x3fffff) {
        virBufferVSprintf(buffer, "ethernet%d.addressType = \"static\"\n",
                          controller);
        virBufferVSprintf(buffer, "ethernet%d.address = \"%s\"\n",
                          controller, mac_string);
    } else if (prefix == 0x005056 && suffix >= 0x800000 && suffix <= 0xbfffff) {
        virBufferVSprintf(buffer, "ethernet%d.addressType = \"vpx\"\n",
                          controller);
        virBufferVSprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
                          controller, mac_string);
M
Matthias Bolte 已提交
3523
    } else {
3524 3525 3526 3527 3528 3529
        virBufferVSprintf(buffer, "ethernet%d.addressType = \"static\"\n",
                          controller);
        virBufferVSprintf(buffer, "ethernet%d.address = \"%s\"\n",
                          controller, mac_string);
        virBufferVSprintf(buffer, "ethernet%d.checkMACAddress = \"false\"\n",
                          controller);
M
Matthias Bolte 已提交
3530 3531 3532 3533 3534 3535 3536 3537
    }

    return 0;
}



int
3538 3539
virVMXFormatSerial(virVMXContext *ctx, virDomainChrDefPtr def,
                   virBufferPtr buffer)
M
Matthias Bolte 已提交
3540
{
M
Matthias Bolte 已提交
3541
    char *fileName = NULL;
3542
    const char *protocol;
M
Matthias Bolte 已提交
3543

3544
    if (def->target.port < 0 || def->target.port > 3) {
3545
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
3546 3547
                  _("Serial port index %d out of [0..3] range"),
                  def->target.port);
M
Matthias Bolte 已提交
3548 3549 3550
        return -1;
    }

3551
    virBufferVSprintf(buffer, "serial%d.present = \"true\"\n", def->target.port);
M
Matthias Bolte 已提交
3552

M
Matthias Bolte 已提交
3553
    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
3554
    switch (def->source.type) {
M
Matthias Bolte 已提交
3555 3556
      case VIR_DOMAIN_CHR_TYPE_DEV:
        virBufferVSprintf(buffer, "serial%d.fileType = \"device\"\n",
3557
                          def->target.port);
M
Matthias Bolte 已提交
3558
        virBufferVSprintf(buffer, "serial%d.fileName = \"%s\"\n",
3559
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3560 3561 3562 3563
        break;

      case VIR_DOMAIN_CHR_TYPE_FILE:
        virBufferVSprintf(buffer, "serial%d.fileType = \"file\"\n",
3564
                          def->target.port);
M
Matthias Bolte 已提交
3565

3566
        fileName = ctx->formatFileName(def->source.data.file.path, ctx->opaque);
M
Matthias Bolte 已提交
3567 3568 3569 3570 3571 3572

        if (fileName == NULL) {
            return -1;
        }

        virBufferVSprintf(buffer, "serial%d.fileName = \"%s\"\n",
3573
                          def->target.port, fileName);
M
Matthias Bolte 已提交
3574 3575

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3576 3577 3578 3579
        break;

      case VIR_DOMAIN_CHR_TYPE_PIPE:
        virBufferVSprintf(buffer, "serial%d.fileType = \"pipe\"\n",
3580
                          def->target.port);
M
Matthias Bolte 已提交
3581 3582
        /* FIXME: Based on VI Client GUI default */
        virBufferVSprintf(buffer, "serial%d.pipe.endPoint = \"client\"\n",
3583
                          def->target.port);
M
Matthias Bolte 已提交
3584 3585
        /* FIXME: Based on VI Client GUI default */
        virBufferVSprintf(buffer, "serial%d.tryNoRxLoss = \"false\"\n",
3586
                          def->target.port);
M
Matthias Bolte 已提交
3587
        virBufferVSprintf(buffer, "serial%d.fileName = \"%s\"\n",
3588
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3589 3590
        break;

3591
      case VIR_DOMAIN_CHR_TYPE_TCP:
3592
        switch (def->source.data.tcp.protocol) {
3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609
          case VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW:
            protocol = "tcp";
            break;

          case VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET:
            protocol = "telnet";
            break;

          case VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS:
            protocol = "telnets";
            break;

          case VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS:
            protocol = "ssl";
            break;

          default:
3610
            VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3611
                      _("Unsupported character device TCP protocol '%s'"),
3612 3613
                      virDomainChrTcpProtocolTypeToString(
                          def->source.data.tcp.protocol));
3614 3615 3616 3617 3618 3619
            return -1;
        }

        virBufferVSprintf(buffer, "serial%d.fileType = \"network\"\n",
                          def->target.port);
        virBufferVSprintf(buffer, "serial%d.fileName = \"%s://%s:%s\"\n",
3620 3621
                          def->target.port, protocol, def->source.data.tcp.host,
                          def->source.data.tcp.service);
3622 3623
        virBufferVSprintf(buffer, "serial%d.network.endPoint = \"%s\"\n",
                          def->target.port,
3624
                          def->source.data.tcp.listen ? "server" : "client");
3625 3626
        break;

M
Matthias Bolte 已提交
3627
      default:
3628
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3629
                  _("Unsupported character device type '%s'"),
3630
                  virDomainChrTypeToString(def->source.type));
M
Matthias Bolte 已提交
3631 3632 3633 3634 3635 3636
        return -1;
    }

    /* vmx:yieldOnMsrRead */
    /* FIXME: Based on VI Client GUI default */
    virBufferVSprintf(buffer, "serial%d.yieldOnMsrRead = \"true\"\n",
3637
                      def->target.port);
M
Matthias Bolte 已提交
3638 3639 3640 3641 3642 3643 3644

    return 0;
}



int
3645 3646
virVMXFormatParallel(virVMXContext *ctx, virDomainChrDefPtr def,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3647
{
M
Matthias Bolte 已提交
3648 3649
    char *fileName = NULL;

3650
    if (def->target.port < 0 || def->target.port > 2) {
3651
        VMX_ERROR(VIR_ERR_INTERNAL_ERROR,
3652
                  _("Parallel port index %d out of [0..2] range"),
3653
                  def->target.port);
M
Matthias Bolte 已提交
3654 3655 3656
        return -1;
    }

3657 3658
    virBufferVSprintf(buffer, "parallel%d.present = \"true\"\n",
                      def->target.port);
M
Matthias Bolte 已提交
3659

M
Matthias Bolte 已提交
3660
    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
3661
    switch (def->source.type) {
M
Matthias Bolte 已提交
3662 3663
      case VIR_DOMAIN_CHR_TYPE_DEV:
        virBufferVSprintf(buffer, "parallel%d.fileType = \"device\"\n",
3664
                          def->target.port);
M
Matthias Bolte 已提交
3665
        virBufferVSprintf(buffer, "parallel%d.fileName = \"%s\"\n",
3666
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3667 3668 3669 3670
        break;

      case VIR_DOMAIN_CHR_TYPE_FILE:
        virBufferVSprintf(buffer, "parallel%d.fileType = \"file\"\n",
3671
                          def->target.port);
M
Matthias Bolte 已提交
3672

3673
        fileName = ctx->formatFileName(def->source.data.file.path, ctx->opaque);
M
Matthias Bolte 已提交
3674 3675 3676 3677 3678 3679

        if (fileName == NULL) {
            return -1;
        }

        virBufferVSprintf(buffer, "parallel%d.fileName = \"%s\"\n",
3680
                          def->target.port, fileName);
M
Matthias Bolte 已提交
3681 3682

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3683 3684 3685
        break;

      default:
3686
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3687
                  _("Unsupported character device type '%s'"),
3688
                  virDomainChrTypeToString(def->source.type));
M
Matthias Bolte 已提交
3689 3690 3691 3692 3693
        return -1;
    }

    return 0;
}
3694 3695 3696 3697 3698 3699



int
virVMXFormatSVGA(virDomainVideoDefPtr def, virBufferPtr buffer)
{
3700 3701
    unsigned long long vram;

3702
    if (def->type != VIR_DOMAIN_VIDEO_TYPE_VMVGA) {
3703
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED,
3704 3705 3706 3707 3708 3709 3710 3711 3712
                  _("Unsupported video device type '%s'"),
                  virDomainVideoTypeToString(def->type));
        return -1;
    }

    /*
     * For Windows guests the VRAM size should be a multiple of 64 kilobyte.
     * See http://kb.vmware.com/kb/1003 and http://kb.vmware.com/kb/1001558
     */
3713
    vram = VIR_DIV_UP(def->vram, 64) * 64;
3714 3715

    if (def->heads > 1) {
3716
        VMX_ERROR(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3717 3718 3719 3720 3721
                  _("Multi-head video devices are unsupported"));
        return -1;
    }

    virBufferVSprintf(buffer, "svga.vramSize = \"%lld\"\n",
3722
                      vram * 1024); /* kilobyte to byte */
3723 3724 3725

    return 0;
}