You need to sign in or sign up before continuing.
vmx.c 128.6 KB
Newer Older
1
/*
2
 * vmx.c: VMware VMX parsing/formatting functions
3
 *
4
 * Copyright (C) 2010-2013 Red Hat, Inc.
5
 * Copyright (C) 2009-2010 Matthias Bolte <matthias.bolte@googlemail.com>
6 7 8 9 10 11 12 13 14 15 16 17
 *
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
20 21 22 23 24
 *
 */

#include <config.h>

25 26
#include <c-ctype.h>

27
#include "internal.h"
28
#include "virerror.h"
29
#include "virconf.h"
30
#include "viralloc.h"
31
#include "virlog.h"
32
#include "viruuid.h"
33
#include "vmx.h"
M
Martin Kletzander 已提交
34
#include "viruri.h"
35
#include "virstring.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
P
Patrice LACHANCE 已提交
47
                                        virtualHW.version = "8"                 # essential for ESX 5.0
48
                                        virtualHW.version = "9"                 # essential for ESX 5.1
49 50 51 52 53 54


???                               <=>   guestOS = "<value>"                     # essential, FIXME: not representable
def->id = <value>                 <=>   ???                                     # not representable
def->uuid = <value>               <=>   uuid.bios = "<value>"
def->name = <value>               <=>   displayName = "<value>"
55 56
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
57
def->mem.min_guarantee = <value kilobyte>  <=>   sched.mem.minsize = "<value megabyte>"  # defaults to 0
E
Eric Blake 已提交
58
def->maxvcpus = <value>           <=>   numvcpus = "<value>"                    # must be 1 or a multiple of 2, defaults to 1
59
def->cpumask = <uint list>        <=>   sched.cpu.affinity = "<uint list>"
60 61
def->cputune.shares = <value>     <=>   sched.cpu.shares = "<value>"            # with handling for special values
                                                                                # "high", "normal", "low"
62 63 64 65 66 67 68 69 70



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

def->os

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



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

90 91 92
                                        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
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

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"
112
->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
->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"
136
->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
->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"
156
->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
->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"
175
->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
->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" ?
195
->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
->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"
215
->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
216 217 218 219 220 221 222 223 224 225
->driverName
->driverType
->cachemode
->readonly
->shared
->slotnum


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

226
                                        floppy0.present = "true"                # defaults to "true"
227 228 229 230 231 232 233 234
                                        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"
235
->dst = fd[<unit> mapped to [a-z]+]
236 237 238 239 240 241 242 243 244 245
->driverName
->driverType
->cachemode
->readonly
->shared
->slotnum


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

246
                                        floppy0.present = "true"                # defaults to "true"
247 248 249 250 251 252 253 254
                                        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"
255
->dst = fd[<unit> mapped to [a-z]+]
256 257 258 259 260 261 262 263 264
->driverName
->driverType
->cachemode
->readonly
->shared
->slotnum



265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
################################################################################
## filesystems #################################################################

                                        isolation.tools.hgfs.disable = "false"  # defaults to "true"

def->nfss = 1                     <=>   sharedFolder.maxNum = "1"               # must match the number of shared folders

                                        sharedFolder[0..n] -> <filesystem>

def->fss[0]...                    <=>   sharedFolder0.present = "true"          # defaults to "false"
                                        sharedFolder0.enabled = "true"          # defaults to "false"
                                        sharedFolder0.expiration = "never"      # defaults to "never"
                                        sharedFolder0.readAccess = "true"       # defaults to "false"
->type = _FS_TYPE_MOUNT
->fsdriver
->accessmode
->wrpolicy
->src = <value>                   <=>   sharedFolder0.hostPath = "<value>"      # defaults to ?
->dst = <value>                   <=>   sharedFolder0.guestName = "<value>"
->readonly = <readonly>           <=>   sharedFolder0.writeAccess = "<value>"   # "true" -> <readonly> = 0, "false" -> <readonly> = 1



288 289 290 291 292 293 294 295 296 297 298 299
################################################################################
## 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
300
                                        ethernet0.features = "15"               # if present and virtualDev is "vmxnet" => vmxnet2 (enhanced)
301 302 303 304


                                        ethernet0.addressType = "generated"     # default to "generated"
->mac = <value>                   <=>   ethernet0.generatedAddress = "<value>"
305
                                        ethernet0.generatedAddressOffset = "0"  # ?
306 307 308 309 310


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

311 312 313 314

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

315 316 317 318 319

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

M
Matthias Bolte 已提交
320
                                                                                # 00:0c:29 prefix for autogenerated mac's -> ethernet0.addressType = "generated"
321
                                                                                # 00:50:56 prefix for manual configured mac's
M
Matthias Bolte 已提交
322
                                                                                #          00:50:56:00:00:00 - 00:50:56:3f:ff:ff -> ethernet0.addressType = "static"
323
                                                                                #          00:50:56:80:00:00 - 00:50:56:bf:ff:ff -> ethernet0.addressType = "vpx"
324 325 326 327 328 329 330
                                                                                # 00:05:69 old prefix from esx 1.5


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

...
->type = _NET_TYPE_BRIDGE         <=>   ethernet0.connectionType = "bridged"    # defaults to "bridged"
M
Matthias Bolte 已提交
331
->data.bridge.brname = <value>    <=>   ethernet0.networkName = "<value>"
332 333 334 335


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

M
Matthias Bolte 已提交
336
...                                                                             # FIXME: Investigate if ESX supports this
337 338 339 340 341
->type = _NET_TYPE_NETWORK        <=>   ethernet0.connectionType = "hostonly"   # defaults to "bridged"


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

M
Matthias Bolte 已提交
342
...                                                                             # FIXME: Investigate if ESX supports this
343 344 345 346 347 348 349
->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 已提交
350 351
->data.bridge.brname = <value>    <=>   ethernet0.networkName = "<value>"
->ifname = <value>                <=>   ethernet0.vnet = "<value>"
352 353 354



355 356 357 358 359 360 361 362 363 364
################################################################################
## video #######################################################################

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



365 366 367 368 369 370 371 372 373
################################################################################
## serials #####################################################################

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

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

def->serials[0]...
374
->target.port = <port>
375 376 377 378 379 380 381


## 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 已提交
382
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
383 384 385 386 387 388 389


## 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 已提交
390
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
391 392 393 394 395 396


## 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 已提交
397
???                               <=>   serial0.pipe.endPoint = "client"        # defaults to ?, FIXME: not representable
398
???                               <=>   serial0.tryNoRxLoss = "true"            # defaults to "false", FIXME: not representable
M
Matthias Bolte 已提交
399
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
400 401 402

->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
M
Matthias Bolte 已提交
403
???                               <=>   serial0.pipe.endPoint = "server"        # defaults to ?, FIXME: not representable
404
???                               <=>   serial0.tryNoRxLoss = "true"            # defaults to "false", FIXME: not representable
M
Matthias Bolte 已提交
405
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
406 407 408 409 410 411


## 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 已提交
412
???                               <=>   serial0.pipe.endPoint = "client"        # defaults to ?, FIXME: not representable
413
???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
M
Matthias Bolte 已提交
414
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
415 416 417

->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
M
Matthias Bolte 已提交
418
???                               <=>   serial0.pipe.endPoint = "server"        # defaults to ?, FIXME: not representable
419
???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
M
Matthias Bolte 已提交
420
???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
421 422


423 424 425 426 427 428 429 430
## 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>

431
->data.tcp.listen = true          <=>   serial0.network.endPoint = "server"     # defaults to "server"
432 433 434 435 436 437 438 439 440 441 442 443 444 445

???                               <=>   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>

446
->data.tcp.listen = false         <=>   serial0.network.endPoint = "client"     # defaults to "server"
447 448 449 450 451 452

???                               <=>   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


453 454 455 456 457 458 459 460 461 462

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

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

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

def->parallels[0]...
463
->target.port = <port>
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478


## 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 已提交
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493


################################################################################
## 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

494 495
*/

496
#define VIR_FROM_THIS VIR_FROM_NONE
497

498
#define VMX_BUILD_NAME_EXTRA(_suffix, _extra)                                 \
499 500
    snprintf(_suffix##_name, sizeof(_suffix##_name), "%s."_extra, prefix);

501 502
#define VMX_BUILD_NAME(_suffix)                                               \
    VMX_BUILD_NAME_EXTRA(_suffix, #_suffix)
503

504 505 506
/* directly map the virDomainControllerModel to virVMXSCSIControllerModel,
 * this is good enough for now because all virDomainControllerModel values
 * are actually SCSI controller models in the ESX case */
507 508
VIR_ENUM_DECL(virVMXControllerModelSCSI)
VIR_ENUM_IMPL(virVMXControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
509
              "auto", /* just to match virDomainControllerModel, will never be used */
510 511 512
              "buslogic",
              "lsilogic",
              "lsisas1068",
513
              "pvscsi",
514
              "UNUSED ibmvscsi",
515 516
              "UNUSED virtio-scsi",
              "UNUSED lsisas1078");
517 518


519 520 521 522 523

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

524 525
virDomainDefParserConfig virVMXDomainDefParserConfig = {
    .hasWideScsiBus = true,
526
    .macPrefix = {0x00, 0x0c, 0x29},
527 528 529 530 531 532 533 534 535 536
};


virDomainXMLOptionPtr
virVMXDomainXMLConfInit(void)
{
    return virDomainXMLOptionNew(&virVMXDomainDefParserConfig,
                               NULL, NULL);
}

537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
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 已提交
585
int
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
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) {
623 624
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxml2 doesn't handle %s encoding"), encoding);
625 626 627 628 629 630 631
        return NULL;
    }

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

    if (xmlCharEncInFunc(handler, utf8, input) < 0) {
632 633
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not convert from %s to UTF-8 encoding"), encoding);
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
        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;
        }

664 665
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing essential config entry '%s'"), name);
666 667 668 669
        return -1;
    }

    if (value->type != VIR_CONF_STRING) {
670 671
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Config entry '%s' must be a string"), name);
672 673 674 675 676 677 678 679
        return -1;
    }

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

680 681
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing essential config entry '%s'"), name);
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
        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 {
709 710
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing essential config entry '%s'"), name);
711 712 713 714 715
            return -1;
        }
    }

    if (value->type != VIR_CONF_STRING) {
716 717
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Config entry '%s' must be a string"), name);
718 719 720 721 722 723 724
        return -1;
    }

    if (value->str == NULL) {
        if (optional) {
            return 0;
        } else {
725 726
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing essential config entry '%s'"), name);
727 728 729 730 731
            return -1;
        }
    }

    if (virUUIDParse(value->str, uuid) < 0) {
732 733
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse UUID from string '%s'"), value->str);
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
        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 {
755 756
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing essential config entry '%s'"), name);
757 758 759 760 761 762 763 764 765
            return -1;
        }
    }

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
766 767
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing essential config entry '%s'"), name);
768 769 770 771
                return -1;
            }
        }

772
        if (STRCASEEQ(value->str, "unlimited")) {
773 774
            *number = -1;
        } else if (virStrToLong_ll(value->str, NULL, 10, number) < 0) {
775 776 777
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Config entry '%s' must represent an integer value"),
                           name);
778 779 780
            return -1;
        }
    } else {
781 782
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Config entry '%s' must be a string"), name);
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
        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 {
804 805
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing essential config entry '%s'"), name);
806 807 808 809 810 811 812 813 814
            return -1;
        }
    }

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
815 816
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing essential config entry '%s'"), name);
817 818 819 820 821 822 823 824 825
                return -1;
            }
        }

        if (STRCASEEQ(value->str, "true")) {
            *boolean_ = 1;
        } else if (STRCASEEQ(value->str, "false")) {
            *boolean_ = 0;
        } else {
826 827 828
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Config entry '%s' must represent a boolean value "
                             "(true|false)"), name);
829 830 831
            return -1;
        }
    } else {
832 833
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Config entry '%s' must be a string"), name);
834 835 836 837 838 839 840 841 842 843
        return -1;
    }

    return 0;
}



static int
virVMXSCSIDiskNameToControllerAndUnit(const char *name, int *controller, int *unit)
M
Matthias Bolte 已提交
844 845 846 847
{
    int idx;

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

    idx = virDiskNameToIndex(name);

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

862
    /* Each of the 4 SCSI controllers has 1 bus with 15 units each for devices */
M
Matthias Bolte 已提交
863
    if (idx >= (4 * 15)) {
864 865
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("SCSI disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
866 867 868 869
        return -1;
    }

    *controller = idx / 15;
870
    *unit = idx % 15;
M
Matthias Bolte 已提交
871

872 873 874
    /* Skip the controller ifself at unit 7 */
    if (*unit >= 7) {
        ++(*unit);
M
Matthias Bolte 已提交
875 876 877 878 879 880 881
    }

    return 0;
}



882 883
static int
virVMXIDEDiskNameToBusAndUnit(const char *name, int *bus, int *unit)
M
Matthias Bolte 已提交
884 885 886 887
{
    int idx;

    if (! STRPREFIX(name, "hd")) {
888 889 890
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expecting domain XML attribute 'dev' of entry "
                         "'devices/disk/target' to start with 'hd'"));
M
Matthias Bolte 已提交
891 892 893 894 895 896
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
897 898
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
899 900 901
        return -1;
    }

902
    /* The IDE controller has 2 buses with 2 units each for devices */
M
Matthias Bolte 已提交
903
    if (idx >= (2 * 2)) {
904 905
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("IDE disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
906 907 908
        return -1;
    }

909 910
    *bus = idx / 2;
    *unit = idx % 2;
M
Matthias Bolte 已提交
911 912 913 914 915 916

    return 0;
}



917 918
static int
virVMXFloppyDiskNameToUnit(const char *name, int *unit)
M
Matthias Bolte 已提交
919 920 921 922
{
    int idx;

    if (! STRPREFIX(name, "fd")) {
923 924 925
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expecting domain XML attribute 'dev' of entry "
                         "'devices/disk/target' to start with 'fd'"));
M
Matthias Bolte 已提交
926 927 928 929 930 931
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
932 933
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
934 935 936
        return -1;
    }

937
    /* The FDC controller has 1 bus with 2 units for devices */
M
Matthias Bolte 已提交
938
    if (idx >= 2) {
939 940
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Floppy disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
941 942 943
        return -1;
    }

944 945 946 947 948 949 950
    *unit = idx;

    return 0;
}



951
static int
952
virVMXVerifyDiskAddress(virDomainXMLOptionPtr xmlopt, virDomainDiskDefPtr disk)
953 954 955 956 957 958 959
{
    virDomainDiskDef def;
    virDomainDeviceDriveAddressPtr drive;

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

    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
960 961 962
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported disk address type '%s'"),
                       virDomainDeviceAddressTypeToString(disk->info.type));
963 964 965 966 967 968 969 970
        return -1;
    }

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

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

971
    if (virDomainDiskDefAssignAddress(xmlopt, &def) < 0) {
972 973
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not verify disk address"));
974 975 976 977 978 979
        return -1;
    }

    if (def.info.addr.drive.controller != drive->controller ||
        def.info.addr.drive.bus != drive->bus ||
        def.info.addr.drive.unit != drive->unit) {
980 981 982
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Disk address %d:%d:%d doesn't match target device '%s'"),
                       drive->controller, drive->bus, drive->unit, disk->dst);
983 984 985 986 987 988
        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) {
989 990 991
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("SCSI controller index %d out of [0..3] range"),
                           drive->controller);
992 993 994 995
            return -1;
        }

        if (drive->bus != 0) {
996 997 998
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("SCSI bus index %d out of [0] range"),
                           drive->bus);
999 1000 1001 1002
            return -1;
        }

        if (drive->unit > 15 || drive->unit == 7) {
1003 1004 1005
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("SCSI unit index %d out of [0..6,8..15] range"),
                           drive->unit);
1006 1007 1008 1009
            return -1;
        }
    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
        if (drive->controller != 0) {
1010 1011 1012
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE controller index %d out of [0] range"),
                           drive->controller);
1013 1014 1015 1016
            return -1;
        }

        if (drive->bus > 1) {
1017 1018 1019
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE bus index %d out of [0..1] range"),
                           drive->bus);
1020 1021 1022 1023
            return -1;
        }

        if (drive->unit > 1) {
1024 1025 1026
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE unit index %d out of [0..1] range"),
                           drive->unit);
1027 1028 1029 1030
            return -1;
        }
    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
        if (drive->controller != 0) {
1031 1032 1033
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC controller index %d out of [0] range"),
                           drive->controller);
1034 1035 1036 1037
            return -1;
        }

        if (drive->bus != 0) {
1038 1039 1040
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC bus index %d out of [0] range"),
                           drive->bus);
1041 1042 1043 1044
            return -1;
        }

        if (drive->unit > 1) {
1045 1046 1047
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC unit index %d out of [0..1] range"),
                           drive->unit);
1048 1049 1050
            return -1;
        }
    } else {
1051 1052 1053
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported bus type '%s'"),
                       virDomainDiskBusTypeToString(disk->bus));
1054 1055 1056 1057 1058 1059 1060 1061
        return -1;
    }

    return 0;
}



1062 1063 1064
static int
virVMXHandleLegacySCSIDiskDriverName(virDomainDefPtr def,
                                     virDomainDiskDefPtr disk)
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
{
    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);
    }

1080
    model = virDomainControllerModelSCSITypeFromString(disk->driverName);
1081 1082

    if (model < 0) {
1083 1084
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unknown driver name '%s'"), disk->driverName);
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
        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) {
1096 1097 1098
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing SCSI controller for index %d"),
                       disk->info.addr.drive.controller);
1099 1100 1101 1102 1103 1104
        return -1;
    }

    if (controller->model == -1) {
        controller->model = model;
    } else if (controller->model != model) {
1105 1106 1107 1108 1109
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Inconsistent SCSI controller model ('%s' is not '%s') "
                         "for SCSI controller index %d"), disk->driverName,
                       virDomainControllerModelSCSITypeToString(controller->model),
                       controller->idx);
1110 1111
        return -1;
    }
M
Matthias Bolte 已提交
1112 1113 1114 1115 1116 1117

    return 0;
}



1118 1119 1120
static int
virVMXGatherSCSIControllers(virVMXContext *ctx, virDomainDefPtr def,
                            int virtualDev[4], bool present[4])
1121 1122 1123
{
    int result = -1;
    int i, k;
M
Matthias Bolte 已提交
1124
    virDomainDiskDefPtr disk;
1125 1126 1127 1128
    virDomainControllerDefPtr controller;
    bool controllerHasDisksAttached;
    int count = 0;
    int *autodetectedModels;
M
Matthias Bolte 已提交
1129

1130 1131 1132 1133 1134 1135 1136
    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 已提交
1137

1138
        if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
1139
            /* skip non-SCSI controllers */
M
Matthias Bolte 已提交
1140 1141 1142
            continue;
        }

1143
        controllerHasDisksAttached = false;
1144

1145 1146 1147 1148 1149 1150
        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;
1151 1152
                break;
            }
M
Matthias Bolte 已提交
1153 1154
        }

1155
        if (! controllerHasDisksAttached) {
1156
            /* skip SCSI controllers without attached disks */
1157 1158 1159
            continue;
        }

1160
        if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO &&
1161
            ctx->autodetectSCSIControllerModel != NULL) {
1162 1163
            count = 0;

1164 1165
            /* try to autodetect the SCSI controller model by collecting
             * SCSI controller model of all disks attached to this controller */
1166 1167 1168 1169 1170
            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) {
1171 1172 1173
                    if (ctx->autodetectSCSIControllerModel
                               (disk, &autodetectedModels[count],
                                ctx->opaque) < 0) {
1174 1175 1176 1177 1178 1179 1180
                        goto cleanup;
                    }

                    ++count;
                }
            }

1181 1182
            /* autodetection fails when the disks attached to one controller
             * have inconsistent SCSI controller models */
1183 1184
            for (k = 0; k < count; ++k) {
                if (autodetectedModels[k] != autodetectedModels[0]) {
1185 1186 1187 1188
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Disks on SCSI controller %d have inconsistent "
                                     "controller models, cannot autodetect model"),
                                   controller->idx);
1189 1190 1191 1192 1193
                    goto cleanup;
                }
            }

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

1196
        if (controller->model != -1 &&
1197 1198 1199 1200
            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC &&
            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC &&
            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068 &&
            controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI) {
1201 1202 1203 1204 1205
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting domain XML attribute 'model' of entry "
                             "'controller' to be 'buslogic' or 'lsilogic' or "
                             "'lsisas1068' or 'vmpvscsi' but found '%s'"),
                           virDomainControllerModelSCSITypeToString(controller->model));
1206
            goto cleanup;
M
Matthias Bolte 已提交
1207
        }
1208 1209 1210

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

1213 1214 1215 1216 1217 1218
    result = 0;

  cleanup:
    VIR_FREE(autodetectedModels);

    return result;
M
Matthias Bolte 已提交
1219 1220 1221 1222 1223 1224 1225 1226
}



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

1227
virDomainDefPtr
1228 1229 1230
virVMXParseConfig(virVMXContext *ctx,
                  virDomainXMLOptionPtr xmlopt,
                  const char *vmx)
1231
{
M
Matthias Bolte 已提交
1232
    bool success = false;
1233
    virConfPtr conf = NULL;
1234 1235
    char *encoding = NULL;
    char *utf8;
1236 1237 1238 1239
    virDomainDefPtr def = NULL;
    long long config_version = 0;
    long long virtualHW_version = 0;
    long long memsize = 0;
1240 1241
    long long sched_mem_max = 0;
    long long sched_mem_minsize = 0;
1242 1243
    long long numvcpus = 0;
    char *sched_cpu_affinity = NULL;
1244
    char *sched_cpu_shares = NULL;
M
Matthias Bolte 已提交
1245
    char *guestOS = NULL;
M
Matthias Bolte 已提交
1246
    bool smbios_reflecthost = false;
1247
    int controller;
1248
    int bus;
1249
    int port;
1250
    bool present;
1251 1252
    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
    int unit;
1253 1254
    bool hgfs_disabled = true;
    long long sharedFolder_maxNum = 0;
H
Hu Tao 已提交
1255
    int cpumasklen;
1256

1257
    if (ctx->parseFileName == NULL) {
1258 1259
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("virVMXContext has no parseFileName function set"));
1260 1261 1262
        return NULL;
    }

1263 1264 1265 1266 1267 1268
    conf = virConfReadMem(vmx, strlen(vmx), VIR_CONF_FLAG_VMX_FORMAT);

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

1269
    /* vmx:.encoding */
1270
    if (virVMXGetConfigString(conf, ".encoding", &encoding, true) < 0) {
1271 1272 1273 1274 1275 1276 1277 1278 1279
        goto cleanup;
    }

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

1280
        utf8 = virVMXConvertToUTF8(encoding, vmx);
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295

        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 */
1296
    if (VIR_ALLOC(def) < 0) {
1297
        virReportOOMError();
A
ajia@redhat.com 已提交
1298
        goto cleanup;
1299 1300
    }

1301
    def->virtType = VIR_DOMAIN_VIRT_VMWARE;
1302 1303
    def->id = -1;

M
Matthias Bolte 已提交
1304
    /* vmx:config.version */
1305 1306
    if (virVMXGetConfigLong(conf, "config.version", &config_version, 0,
                            false) < 0) {
M
Matthias Bolte 已提交
1307
        goto cleanup;
1308 1309 1310
    }

    if (config_version != 8) {
1311 1312 1313
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry 'config.version' to be 8 but found "
                         "%lld"), config_version);
M
Matthias Bolte 已提交
1314
        goto cleanup;
1315 1316
    }

M
Matthias Bolte 已提交
1317
    /* vmx:virtualHW.version */
1318 1319
    if (virVMXGetConfigLong(conf, "virtualHW.version", &virtualHW_version, 0,
                            false) < 0) {
M
Matthias Bolte 已提交
1320
        goto cleanup;
1321 1322
    }

P
Patrice LACHANCE 已提交
1323
    if (virtualHW_version != 4 && virtualHW_version != 7 &&
1324
        virtualHW_version != 8 && virtualHW_version != 9) {
1325
        virReportError(VIR_ERR_INTERNAL_ERROR,
1326 1327
                       _("Expecting VMX entry 'virtualHW.version' to be "
                         "4, 7, 8 or 9 but found %lld"),
1328
                       virtualHW_version);
M
Matthias Bolte 已提交
1329
        goto cleanup;
1330 1331
    }

M
Matthias Bolte 已提交
1332
    /* vmx:uuid.bios -> def:uuid */
1333
    /* FIXME: Need to handle 'uuid.action = "create"' */
1334
    if (virVMXGetConfigUUID(conf, "uuid.bios", def->uuid, true) < 0) {
M
Matthias Bolte 已提交
1335
        goto cleanup;
1336 1337
    }

M
Matthias Bolte 已提交
1338
    /* vmx:displayName -> def:name */
1339
    if (virVMXGetConfigString(conf, "displayName", &def->name, true) < 0) {
M
Matthias Bolte 已提交
1340
        goto cleanup;
1341 1342
    }

1343
    if (def->name != NULL) {
1344 1345
        if (virVMXUnescapeHexPercent(def->name) < 0 ||
            virVMXUnescapeHexPipe(def->name) < 0) {
1346 1347
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("VMX entry 'name' contains invalid escape sequence"));
1348 1349 1350 1351
            goto cleanup;
        }
    }

1352
    /* vmx:annotation -> def:description */
1353 1354
    if (virVMXGetConfigString(conf, "annotation", &def->description,
                              true) < 0) {
1355 1356 1357 1358
        goto cleanup;
    }

    if (def->description != NULL) {
1359
        if (virVMXUnescapeHexPipe(def->description) < 0) {
1360 1361 1362
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("VMX entry 'annotation' contains invalid escape "
                             "sequence"));
1363
            goto cleanup;
1364 1365 1366
        }
    }

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

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

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

1381
    /* vmx:sched.mem.max -> def:mem.cur_balloon */
1382 1383
    if (virVMXGetConfigLong(conf, "sched.mem.max", &sched_mem_max, memsize,
                            true) < 0) {
M
Matthias Bolte 已提交
1384
        goto cleanup;
1385 1386
    }

1387 1388
    if (sched_mem_max < 0) {
        sched_mem_max = memsize;
1389 1390
    }

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

1393 1394
    if (def->mem.cur_balloon > def->mem.max_balloon) {
        def->mem.cur_balloon = def->mem.max_balloon;
1395 1396
    }

1397
    /* vmx:sched.mem.minsize -> def:mem.min_guarantee */
1398 1399
    if (virVMXGetConfigLong(conf, "sched.mem.minsize", &sched_mem_minsize, 0,
                            true) < 0) {
1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412
        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 已提交
1413
    /* vmx:numvcpus -> def:vcpus */
1414
    if (virVMXGetConfigLong(conf, "numvcpus", &numvcpus, 1, true) < 0) {
M
Matthias Bolte 已提交
1415
        goto cleanup;
1416 1417 1418
    }

    if (numvcpus <= 0 || (numvcpus % 2 != 0 && numvcpus != 1)) {
1419 1420 1421
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry 'numvcpus' to be an unsigned "
                         "integer (1 or a multiple of 2) but found %lld"), numvcpus);
M
Matthias Bolte 已提交
1422
        goto cleanup;
1423 1424
    }

E
Eric Blake 已提交
1425
    def->maxvcpus = def->vcpus = numvcpus;
1426

M
Matthias Bolte 已提交
1427
    /* vmx:sched.cpu.affinity -> def:cpumask */
1428
    /* NOTE: maps to VirtualMachine:config.cpuAffinity.affinitySet */
1429 1430
    if (virVMXGetConfigString(conf, "sched.cpu.affinity", &sched_cpu_affinity,
                              true) < 0) {
M
Matthias Bolte 已提交
1431
        goto cleanup;
1432 1433
    }

1434
    if (sched_cpu_affinity != NULL && STRCASENEQ(sched_cpu_affinity, "all")) {
1435 1436 1437
        const char *current = sched_cpu_affinity;
        int number, count = 0;

H
Hu Tao 已提交
1438
        cpumasklen = 0;
1439

H
Hu Tao 已提交
1440 1441
        def->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN);
        if (!def->cpumask) {
1442
            virReportOOMError();
M
Matthias Bolte 已提交
1443
            goto cleanup;
1444 1445 1446 1447 1448 1449 1450 1451
        }

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

            number = virParseNumber(&current);

            if (number < 0) {
1452 1453 1454 1455
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry 'sched.cpu.affinity' to be "
                                 "a comma separated list of unsigned integers but "
                                 "found '%s'"), sched_cpu_affinity);
M
Matthias Bolte 已提交
1456
                goto cleanup;
1457 1458 1459
            }

            if (number >= VIR_DOMAIN_CPUMASK_LEN) {
1460 1461 1462
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("VMX entry 'sched.cpu.affinity' contains a %d, "
                                 "this value is too large"), number);
M
Matthias Bolte 已提交
1463
                goto cleanup;
1464 1465
            }

H
Hu Tao 已提交
1466 1467
            if (number + 1 > cpumasklen) {
                cpumasklen = number + 1;
1468 1469
            }

H
Hu Tao 已提交
1470
            ignore_value(virBitmapSetBit(def->cpumask, number));
1471 1472 1473 1474 1475 1476 1477 1478 1479
            ++count;

            virSkipSpaces(&current);

            if (*current == ',') {
                ++current;
            } else if (*current == '\0') {
                break;
            } else {
1480 1481 1482 1483
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry 'sched.cpu.affinity' to be "
                                 "a comma separated list of unsigned integers but "
                                 "found '%s'"), sched_cpu_affinity);
M
Matthias Bolte 已提交
1484
                goto cleanup;
1485 1486 1487 1488 1489 1490
            }

            virSkipSpaces(&current);
        }

        if (count < numvcpus) {
1491 1492 1493 1494
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("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 已提交
1495
            goto cleanup;
1496 1497 1498
        }
    }

1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514
    /* vmx:sched.cpu.shares -> def:cputune.shares */
    if (virVMXGetConfigString(conf, "sched.cpu.shares", &sched_cpu_shares,
                              true) < 0) {
        goto cleanup;
    }

    if (sched_cpu_shares != NULL) {
        /* See http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.SharesInfo.Level.html */
        if (STRCASEEQ(sched_cpu_shares, "low")) {
            def->cputune.shares = def->vcpus * 500;
        } else if (STRCASEEQ(sched_cpu_shares, "normal")) {
            def->cputune.shares = def->vcpus * 1000;
        } else if (STRCASEEQ(sched_cpu_shares, "high")) {
            def->cputune.shares = def->vcpus * 2000;
        } else if (virStrToLong_ul(sched_cpu_shares, NULL, 10,
                                   &def->cputune.shares) < 0) {
1515 1516 1517 1518
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting VMX entry 'sched.cpu.shares' to be an "
                             "unsigned integer or 'low', 'normal' or 'high' but "
                             "found '%s'"), sched_cpu_shares);
1519 1520 1521 1522
            goto cleanup;
        }
    }

1523 1524 1525 1526 1527 1528 1529 1530 1531
    /* 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) {
1532
        virReportOOMError();
M
Matthias Bolte 已提交
1533
        goto cleanup;
1534 1535
    }

M
Matthias Bolte 已提交
1536
    /* vmx:guestOS -> def:os.arch */
1537
    if (virVMXGetConfigString(conf, "guestOS", &guestOS, true) < 0) {
M
Matthias Bolte 已提交
1538
        goto cleanup;
M
Matthias Bolte 已提交
1539 1540
    }

1541
    if (guestOS != NULL && virFileHasSuffix(guestOS, "-64")) {
1542
        def->os.arch = VIR_ARCH_X86_64;
M
Matthias Bolte 已提交
1543
    } else {
1544
        def->os.arch = VIR_ARCH_I686;
M
Matthias Bolte 已提交
1545 1546
    }

M
Matthias Bolte 已提交
1547
    /* vmx:smbios.reflecthost -> def:os.smbios_mode */
1548 1549
    if (virVMXGetConfigBoolean(conf, "smbios.reflecthost",
                               &smbios_reflecthost, false, true) < 0) {
M
Matthias Bolte 已提交
1550 1551 1552 1553 1554 1555 1556
        goto cleanup;
    }

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

1557 1558
    /* def:features */
    /* FIXME */
1559

1560 1561
    /* def:clock */
    /* FIXME */
1562 1563

    /* def:graphics */
M
Matthias Bolte 已提交
1564
    if (VIR_ALLOC_N(def->graphics, 1) < 0) {
1565
        virReportOOMError();
M
Matthias Bolte 已提交
1566
        goto cleanup;
M
Matthias Bolte 已提交
1567 1568 1569 1570
    }

    def->ngraphics = 0;

1571
    if (virVMXParseVNC(conf, &def->graphics[def->ngraphics]) < 0) {
M
Matthias Bolte 已提交
1572
        goto cleanup;
M
Matthias Bolte 已提交
1573 1574 1575 1576 1577
    }

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

M
Matthias Bolte 已提交
1579 1580
    /* def:disks: 4 * 15 scsi + 2 * 2 ide + 2 floppy = 66 */
    if (VIR_ALLOC_N(def->disks, 66) < 0) {
1581
        virReportOOMError();
M
Matthias Bolte 已提交
1582
        goto cleanup;
1583 1584 1585 1586 1587 1588
    }

    def->ndisks = 0;

    /* def:disks (scsi) */
    for (controller = 0; controller < 4; ++controller) {
1589 1590
        if (virVMXParseSCSIController(conf, controller, &present,
                                      &scsi_virtualDev[controller]) < 0) {
M
Matthias Bolte 已提交
1591
            goto cleanup;
1592 1593 1594 1595 1596 1597
        }

        if (! present) {
            continue;
        }

1598 1599
        for (unit = 0; unit < 16; ++unit) {
            if (unit == 7) {
1600
                /*
1601
                 * SCSI unit 7 is assigned to the SCSI controller and cannot be
1602 1603 1604 1605 1606
                 * used for disk devices.
                 */
                continue;
            }

1607
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
1608 1609
                                VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
                                &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1610
                goto cleanup;
1611 1612 1613 1614 1615 1616 1617
            }

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

1618
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1619
                                 VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
1620
                                 &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1621
                goto cleanup;
1622 1623 1624 1625 1626 1627 1628 1629 1630
            }

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

    /* def:disks (ide) */
1631 1632
    for (bus = 0; bus < 2; ++bus) {
        for (unit = 0; unit < 2; ++unit) {
1633
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
1634 1635
                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
                                &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1636
                goto cleanup;
1637 1638 1639 1640 1641 1642 1643
            }

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

1644
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1645 1646
                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
                                &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1647
                goto cleanup;
1648 1649 1650 1651 1652 1653 1654 1655 1656
            }

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

    /* def:disks (floppy) */
1657
    for (unit = 0; unit < 2; ++unit) {
1658
        if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_FLOPPY,
1659 1660
                            VIR_DOMAIN_DISK_BUS_FDC, 0, unit,
                            &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1661
            goto cleanup;
1662 1663 1664 1665 1666 1667 1668
        }

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

1669 1670
    /* def:controllers */
    if (virDomainDefAddImplicitControllers(def) < 0) {
1671
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not add controllers"));
1672 1673 1674 1675 1676 1677 1678
        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) {
1679 1680 1681
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("SCSI controller index %d out of [0..3] range"),
                               def->controllers[controller]->idx);
1682 1683 1684 1685 1686 1687 1688 1689
                goto cleanup;
            }

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

1690
    /* def:fss */
1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723
    if (virVMXGetConfigBoolean(conf, "isolation.tools.hgfs.disable",
                               &hgfs_disabled, true, true) < 0) {
        goto cleanup;
    }

    if (!hgfs_disabled) {
        if (virVMXGetConfigLong(conf, "sharedFolder.maxNum", &sharedFolder_maxNum,
                                0, true) < 0) {
            goto cleanup;
        }

        if (sharedFolder_maxNum > 0) {
            int number;

            if (VIR_ALLOC_N(def->fss, sharedFolder_maxNum) < 0) {
                virReportOOMError();
                goto cleanup;
            }

            def->nfss = 0;

            for (number = 0; number < sharedFolder_maxNum; ++number) {
                if (virVMXParseFileSystem(conf, number,
                                          &def->fss[def->nfss]) < 0) {
                    goto cleanup;
                }

                if (def->fss[def->nfss] != NULL) {
                    ++def->nfss;
                }
            }
        }
    }
1724 1725 1726

    /* def:nets */
    if (VIR_ALLOC_N(def->nets, 4) < 0) {
1727
        virReportOOMError();
M
Matthias Bolte 已提交
1728
        goto cleanup;
1729 1730 1731 1732 1733
    }

    def->nnets = 0;

    for (controller = 0; controller < 4; ++controller) {
1734 1735
        if (virVMXParseEthernet(conf, controller,
                                &def->nets[def->nnets]) < 0) {
M
Matthias Bolte 已提交
1736
            goto cleanup;
1737 1738 1739 1740 1741 1742 1743 1744 1745 1746
        }

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

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

1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760
    /* 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;

1761 1762 1763 1764 1765 1766 1767 1768
    /* def:sounds */
    /* FIXME */

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

    /* def:serials */
    if (VIR_ALLOC_N(def->serials, 4) < 0) {
1769
        virReportOOMError();
M
Matthias Bolte 已提交
1770
        goto cleanup;
1771 1772 1773 1774 1775
    }

    def->nserials = 0;

    for (port = 0; port < 4; ++port) {
1776 1777
        if (virVMXParseSerial(ctx, conf, port,
                              &def->serials[def->nserials]) < 0) {
M
Matthias Bolte 已提交
1778
            goto cleanup;
1779 1780 1781 1782 1783 1784 1785 1786 1787
        }

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

    /* def:parallels */
    if (VIR_ALLOC_N(def->parallels, 3) < 0) {
1788
        virReportOOMError();
M
Matthias Bolte 已提交
1789
        goto cleanup;
1790 1791 1792 1793 1794
    }

    def->nparallels = 0;

    for (port = 0; port < 3; ++port) {
1795 1796
        if (virVMXParseParallel(ctx, conf, port,
                                &def->parallels[def->nparallels]) < 0) {
M
Matthias Bolte 已提交
1797
            goto cleanup;
1798 1799 1800 1801 1802 1803 1804
        }

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

M
Matthias Bolte 已提交
1805 1806
    success = true;

M
Matthias Bolte 已提交
1807
  cleanup:
M
Matthias Bolte 已提交
1808 1809 1810 1811 1812
    if (! success) {
        virDomainDefFree(def);
        def = NULL;
    }

1813
    virConfFree(conf);
1814
    VIR_FREE(encoding);
1815
    VIR_FREE(sched_cpu_affinity);
1816
    VIR_FREE(sched_cpu_shares);
M
Matthias Bolte 已提交
1817
    VIR_FREE(guestOS);
1818 1819 1820 1821 1822 1823

    return def;
}



M
Matthias Bolte 已提交
1824
int
1825
virVMXParseVNC(virConfPtr conf, virDomainGraphicsDefPtr *def)
M
Matthias Bolte 已提交
1826
{
1827
    bool enabled = false;
M
Matthias Bolte 已提交
1828
    long long port = 0;
1829
    char *listenAddr = NULL;
M
Matthias Bolte 已提交
1830 1831

    if (def == NULL || *def != NULL) {
1832
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
1833 1834 1835
        return -1;
    }

1836 1837
    if (virVMXGetConfigBoolean(conf, "RemoteDisplay.vnc.enabled", &enabled,
                               false, true) < 0) {
M
Matthias Bolte 已提交
1838 1839 1840 1841 1842 1843 1844 1845
        return -1;
    }

    if (! enabled) {
        return 0;
    }

    if (VIR_ALLOC(*def) < 0) {
1846
        virReportOOMError();
M
Matthias Bolte 已提交
1847 1848 1849 1850 1851
        goto failure;
    }

    (*def)->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;

1852 1853 1854
    if (virVMXGetConfigLong(conf, "RemoteDisplay.vnc.port", &port, -1,
                            true) < 0 ||
        virVMXGetConfigString(conf, "RemoteDisplay.vnc.ip",
1855
                              &listenAddr, true) < 0 ||
1856 1857 1858 1859
        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 已提交
1860 1861 1862
        goto failure;
    }

1863 1864 1865 1866 1867 1868
    if (listenAddr) {
        if (virDomainGraphicsListenSetAddress(*def, 0, listenAddr, -1, true) < 0)
            goto failure;
        VIR_FREE(listenAddr);
    }

M
Matthias Bolte 已提交
1869
    if (port < 0) {
1870
        VIR_WARN("VNC is enabled but VMX entry 'RemoteDisplay.vnc.port' "
M
Matthias Bolte 已提交
1871 1872 1873
                  "is missing, the VNC port is unknown");

        (*def)->data.vnc.port = 0;
1874
        (*def)->data.vnc.autoport = true;
M
Matthias Bolte 已提交
1875 1876 1877 1878 1879 1880
    } else {
        if (port < 5900 || port > 5964) {
            VIR_WARN("VNC port %lld it out of [5900..5964] range", port);
        }

        (*def)->data.vnc.port = port;
1881
        (*def)->data.vnc.autoport = false;
M
Matthias Bolte 已提交
1882 1883 1884 1885 1886
    }

    return 0;

  failure:
1887
    VIR_FREE(listenAddr);
M
Matthias Bolte 已提交
1888 1889 1890 1891 1892 1893 1894 1895
    virDomainGraphicsDefFree(*def);
    *def = NULL;

    return -1;
}



1896
int
1897 1898
virVMXParseSCSIController(virConfPtr conf, int controller, bool *present,
                          int *virtualDev)
1899
{
1900
    int result = -1;
1901 1902
    char present_name[32];
    char virtualDev_name[32];
1903 1904
    char *virtualDev_string = NULL;
    char *tmp;
1905

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

    if (controller < 0 || controller > 3) {
1912 1913 1914
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("SCSI controller index %d out of [0..3] range"),
                       controller);
1915
        return -1;
1916 1917
    }

1918 1919 1920
    snprintf(present_name, sizeof(present_name), "scsi%d.present", controller);
    snprintf(virtualDev_name, sizeof(virtualDev_name), "scsi%d.virtualDev",
             controller);
1921

1922
    if (virVMXGetConfigBoolean(conf, present_name, present, false, true) < 0) {
1923
        goto cleanup;
1924 1925 1926
    }

    if (! *present) {
1927 1928
        result = 0;
        goto cleanup;
1929 1930
    }

1931 1932
    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev_string,
                              true) < 0) {
1933
        goto cleanup;
1934 1935
    }

1936 1937 1938 1939 1940 1941 1942
    if (virtualDev_string != NULL) {
        tmp = virtualDev_string;

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

1943
        *virtualDev = virVMXControllerModelSCSITypeFromString(virtualDev_string);
1944 1945

        if (*virtualDev == -1 ||
1946 1947 1948 1949
            (*virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC &&
             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC &&
             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068 &&
             *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI)) {
1950 1951 1952 1953
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting VMX entry '%s' to be 'buslogic' or 'lsilogic' "
                             "or 'lsisas1068' or 'pvscsi' but found '%s'"),
                           virtualDev_name, virtualDev_string);
1954
            goto cleanup;
1955
        }
1956 1957
    }

1958
    result = 0;
1959

1960
  cleanup:
1961
    VIR_FREE(virtualDev_string);
1962

1963
    return result;
1964 1965 1966 1967 1968
}



int
1969
virVMXParseDisk(virVMXContext *ctx, virDomainXMLOptionPtr xmlopt, virConfPtr conf,
1970 1971
                int device, int busType, int controllerOrBus, int unit,
                virDomainDiskDefPtr *def)
1972 1973
{
    /*
1974 1975 1976 1977
     *          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]
1978
     *
1979 1980 1981 1982
     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM}
     *         busType = VIR_DOMAIN_DISK_BUS_IDE
     * controllerOrBus = [0..1] -> bus
     *            unit = [0..1]
1983
     *
1984 1985 1986 1987
     *          device = VIR_DOMAIN_DISK_DEVICE_FLOPPY
     *         busType = VIR_DOMAIN_DISK_BUS_FDC
     * controllerOrBus = [0]
     *            unit = [0..1]
1988 1989
     */

M
Matthias Bolte 已提交
1990
    int result = -1;
1991 1992 1993
    char *prefix = NULL;

    char present_name[32] = "";
1994
    bool present = false;
1995 1996

    char startConnected_name[32] = "";
1997
    bool startConnected = false;
1998 1999 2000 2001 2002

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

    char clientDevice_name[32] = "";
2003
    bool clientDevice = false;
2004 2005 2006 2007 2008 2009 2010 2011

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

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

    char writeThrough_name[32] = "";
2012
    bool writeThrough = false;
2013 2014

    if (def == NULL || *def != NULL) {
2015
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2016 2017 2018 2019
        return -1;
    }

    if (VIR_ALLOC(*def) < 0) {
2020
        virReportOOMError();
M
Matthias Bolte 已提交
2021
        return -1;
2022 2023 2024
    }

    (*def)->device = device;
2025
    (*def)->bus = busType;
2026 2027 2028 2029

    /* def:dst, def:driverName */
    if (device == VIR_DOMAIN_DISK_DEVICE_DISK ||
        device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
2030 2031
        if (busType == VIR_DOMAIN_DISK_BUS_SCSI) {
            if (controllerOrBus < 0 || controllerOrBus > 3) {
2032 2033 2034
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("SCSI controller index %d out of [0..3] range"),
                               controllerOrBus);
M
Matthias Bolte 已提交
2035
                goto cleanup;
2036 2037
            }

2038
            if (unit < 0 || unit > 15 || unit == 7) {
2039 2040 2041
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("SCSI unit index %d out of [0..6,8..15] range"),
                               unit);
M
Matthias Bolte 已提交
2042
                goto cleanup;
2043 2044
            }

2045
            if (virAsprintf(&prefix, "scsi%d:%d", controllerOrBus, unit) < 0) {
2046
                virReportOOMError();
M
Matthias Bolte 已提交
2047
                goto cleanup;
2048 2049
            }

M
Matthias Bolte 已提交
2050
            (*def)->dst =
2051
               virIndexToDiskName
2052
                 (controllerOrBus * 15 + (unit < 7 ? unit : unit - 1), "sd");
2053 2054

            if ((*def)->dst == NULL) {
M
Matthias Bolte 已提交
2055
                goto cleanup;
2056
            }
2057 2058
        } else if (busType == VIR_DOMAIN_DISK_BUS_IDE) {
            if (controllerOrBus < 0 || controllerOrBus > 1) {
2059 2060 2061
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("IDE bus index %d out of [0..1] range"),
                               controllerOrBus);
M
Matthias Bolte 已提交
2062
                goto cleanup;
2063 2064
            }

2065
            if (unit < 0 || unit > 1) {
2066 2067
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("IDE unit index %d out of [0..1] range"), unit);
M
Matthias Bolte 已提交
2068
                goto cleanup;
2069 2070
            }

2071
            if (virAsprintf(&prefix, "ide%d:%d", controllerOrBus, unit) < 0) {
2072
                virReportOOMError();
M
Matthias Bolte 已提交
2073
                goto cleanup;
2074 2075
            }

2076
            (*def)->dst = virIndexToDiskName(controllerOrBus * 2 + unit, "hd");
2077 2078

            if ((*def)->dst == NULL) {
M
Matthias Bolte 已提交
2079
                goto cleanup;
2080 2081
            }
        } else {
2082 2083 2084 2085
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported bus type '%s' for device type '%s'"),
                           virDomainDiskBusTypeToString(busType),
                           virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2086
            goto cleanup;
2087 2088
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2089 2090
        if (busType == VIR_DOMAIN_DISK_BUS_FDC) {
            if (controllerOrBus != 0) {
2091 2092 2093
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("FDC controller index %d out of [0] range"),
                               controllerOrBus);
2094 2095 2096 2097
                goto cleanup;
            }

            if (unit < 0 || unit > 1) {
2098 2099 2100
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("FDC unit index %d out of [0..1] range"),
                               unit);
M
Matthias Bolte 已提交
2101
                goto cleanup;
2102 2103
            }

2104
            if (virAsprintf(&prefix, "floppy%d", unit) < 0) {
2105
                virReportOOMError();
M
Matthias Bolte 已提交
2106
                goto cleanup;
2107 2108
            }

2109
            (*def)->dst = virIndexToDiskName(unit, "fd");
2110 2111

            if ((*def)->dst == NULL) {
M
Matthias Bolte 已提交
2112
                goto cleanup;
2113 2114
            }
        } else {
2115 2116 2117 2118
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported bus type '%s' for device type '%s'"),
                           virDomainDiskBusTypeToString(busType),
                           virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2119
            goto cleanup;
2120 2121
        }
    } else {
2122 2123 2124
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported device type '%s'"),
                       virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2125
        goto cleanup;
2126 2127
    }

2128 2129 2130 2131 2132 2133 2134
    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);
2135 2136

    /* vmx:present */
2137
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2138
        goto cleanup;
2139 2140 2141
    }

    /* vmx:startConnected */
2142 2143
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2144
        goto cleanup;
2145 2146 2147 2148 2149 2150 2151 2152
    }

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

    /* vmx:deviceType -> def:type */
2153
    if (virVMXGetConfigString(conf, deviceType_name, &deviceType, true) < 0) {
M
Matthias Bolte 已提交
2154
        goto cleanup;
2155 2156 2157
    }

    /* vmx:clientDevice */
2158 2159
    if (virVMXGetConfigBoolean(conf, clientDevice_name, &clientDevice, false,
                               true) < 0) {
M
Matthias Bolte 已提交
2160
        goto cleanup;
2161 2162 2163 2164 2165
    }

    if (clientDevice) {
        /*
         * Just ignore devices in client mode, because I have no clue how to
M
Matthias Bolte 已提交
2166
         * handle them (e.g. assign an image) without the VI Client GUI.
2167 2168 2169 2170 2171
         */
        goto ignore;
    }

    /* vmx:fileType -> def:type */
2172
    if (virVMXGetConfigString(conf, fileType_name, &fileType, true) < 0) {
M
Matthias Bolte 已提交
2173
        goto cleanup;
2174 2175 2176
    }

    /* vmx:fileName -> def:src, def:type */
2177
    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0) {
M
Matthias Bolte 已提交
2178
        goto cleanup;
2179 2180 2181
    }

    /* vmx:writeThrough -> def:cachemode */
2182 2183
    if (virVMXGetConfigBoolean(conf, writeThrough_name, &writeThrough, false,
                               true) < 0) {
M
Matthias Bolte 已提交
2184
        goto cleanup;
2185 2186 2187 2188
    }

    /* Setup virDomainDiskDef */
    if (device == VIR_DOMAIN_DISK_DEVICE_DISK) {
2189
        if (virFileHasSuffix(fileName, ".vmdk")) {
2190
            if (deviceType != NULL) {
2191
                if (busType == VIR_DOMAIN_DISK_BUS_SCSI &&
2192 2193
                    STRCASENEQ(deviceType, "scsi-hardDisk") &&
                    STRCASENEQ(deviceType, "disk")) {
2194 2195 2196 2197
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'scsi-hardDisk' "
                                     "or 'disk' but found '%s'"), deviceType_name,
                                   deviceType);
M
Matthias Bolte 已提交
2198
                    goto cleanup;
2199
                } else if (busType == VIR_DOMAIN_DISK_BUS_IDE &&
2200 2201
                           STRCASENEQ(deviceType, "ata-hardDisk") &&
                           STRCASENEQ(deviceType, "disk")) {
2202 2203 2204 2205
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'ata-hardDisk' "
                                     "or 'disk' but found '%s'"), deviceType_name,
                                   deviceType);
M
Matthias Bolte 已提交
2206
                    goto cleanup;
2207 2208 2209 2210
                }
            }

            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
2211
            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
2212 2213 2214
            (*def)->cachemode = writeThrough ? VIR_DOMAIN_DISK_CACHE_WRITETHRU
                                             : VIR_DOMAIN_DISK_CACHE_DEFAULT;

M
Matthias Bolte 已提交
2215
            if ((*def)->src == NULL) {
M
Matthias Bolte 已提交
2216
                goto cleanup;
M
Matthias Bolte 已提交
2217
            }
2218
        } else if (virFileHasSuffix(fileName, ".iso") ||
2219
                   STRCASEEQ(deviceType, "atapi-cdrom")) {
2220 2221 2222 2223 2224 2225 2226 2227
            /*
             * 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 {
2228 2229 2230
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid or not yet handled value '%s' for VMX entry "
                             "'%s'"), fileName, fileName_name);
M
Matthias Bolte 已提交
2231
            goto cleanup;
2232 2233
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
2234
        if (virFileHasSuffix(fileName, ".iso")) {
2235 2236
            if (deviceType != NULL) {
                if (STRCASENEQ(deviceType, "cdrom-image")) {
2237 2238 2239
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'cdrom-image' "
                                     "but found '%s'"), deviceType_name, deviceType);
M
Matthias Bolte 已提交
2240
                    goto cleanup;
2241 2242 2243 2244
                }
            }

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

M
Matthias Bolte 已提交
2247
            if ((*def)->src == NULL) {
M
Matthias Bolte 已提交
2248
                goto cleanup;
M
Matthias Bolte 已提交
2249
            }
2250
        } else if (virFileHasSuffix(fileName, ".vmdk")) {
2251 2252 2253 2254 2255 2256 2257
            /*
             * 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;
2258
        } else if (STRCASEEQ(deviceType, "atapi-cdrom")) {
2259 2260 2261 2262 2263
            (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
            (*def)->src = fileName;

            fileName = NULL;
        } else {
2264 2265 2266
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid or not yet handled value '%s' for VMX entry "
                             "'%s'"), fileName, fileName_name);
M
Matthias Bolte 已提交
2267
            goto cleanup;
2268 2269
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2270
        if (virFileHasSuffix(fileName, ".flp")) {
2271 2272
            if (fileType != NULL) {
                if (STRCASENEQ(fileType, "file")) {
2273 2274 2275
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'file' but "
                                     "found '%s'"), fileType_name, fileType);
M
Matthias Bolte 已提交
2276
                    goto cleanup;
2277 2278 2279 2280
                }
            }

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

M
Matthias Bolte 已提交
2283
            if ((*def)->src == NULL) {
M
Matthias Bolte 已提交
2284
                goto cleanup;
M
Matthias Bolte 已提交
2285
            }
2286
        } else if (fileType != NULL && STRCASEEQ(fileType, "device")) {
2287 2288 2289 2290 2291
            (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
            (*def)->src = fileName;

            fileName = NULL;
        } else {
2292 2293 2294
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid or not yet handled value '%s' for VMX entry "
                             "'%s'"), fileName, fileName_name);
M
Matthias Bolte 已提交
2295
            goto cleanup;
2296 2297
        }
    } else {
2298 2299
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported device type '%s'"),
                       virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2300
        goto cleanup;
2301 2302
    }

2303
    if (virDomainDiskDefAssignAddress(xmlopt, *def) < 0) {
2304 2305
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not assign address to disk '%s'"), (*def)->src);
2306 2307 2308
        goto cleanup;
    }

M
Matthias Bolte 已提交
2309 2310
    result = 0;

M
Matthias Bolte 已提交
2311
  cleanup:
M
Matthias Bolte 已提交
2312 2313 2314 2315 2316
    if (result < 0) {
        virDomainDiskDefFree(*def);
        *def = NULL;
    }

2317 2318 2319 2320 2321 2322 2323
    VIR_FREE(prefix);
    VIR_FREE(deviceType);
    VIR_FREE(fileType);
    VIR_FREE(fileName);

    return result;

M
Matthias Bolte 已提交
2324
  ignore:
2325 2326 2327
    virDomainDiskDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2328 2329
    result = 0;

2330 2331 2332 2333 2334
    goto cleanup;
}



2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436
int virVMXParseFileSystem(virConfPtr conf, int number, virDomainFSDefPtr *def)
{
    int result = -1;
    char prefix[48] = "";

    char present_name[48] = "";
    bool present = false;

    char enabled_name[48] = "";
    bool enabled = false;

    char hostPath_name[48] = "";
    char *hostPath = NULL;

    char guestName_name[48] = "";
    char *guestName = NULL;

    char writeAccess_name[48] = "";
    bool writeAccess = false;

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

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

    (*def)->type = VIR_DOMAIN_FS_TYPE_MOUNT;

    snprintf(prefix, sizeof(prefix), "sharedFolder%d", number);

    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(enabled);
    VMX_BUILD_NAME(hostPath);
    VMX_BUILD_NAME(guestName);
    VMX_BUILD_NAME(writeAccess);

    /* vmx:present */
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
        goto cleanup;
    }

    /* vmx:enabled */
    if (virVMXGetConfigBoolean(conf, enabled_name, &enabled, false, true) < 0) {
        goto cleanup;
    }

    if (!(present && enabled)) {
        goto ignore;
    }

    /* vmx:hostPath */
    if (virVMXGetConfigString(conf, hostPath_name, &hostPath, false) < 0) {
        goto cleanup;
    }

    (*def)->src = hostPath;
    hostPath = NULL;

    /* vmx:guestName */
    if (virVMXGetConfigString(conf, guestName_name, &guestName, false) < 0) {
        goto cleanup;
    }

    (*def)->dst = guestName;
    guestName = NULL;

    /* vmx:writeAccess */
    if (virVMXGetConfigBoolean(conf, writeAccess_name, &writeAccess, false,
                               true) < 0) {
        goto cleanup;
    }

    (*def)->readonly = !writeAccess;

    result = 0;

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

    VIR_FREE(hostPath);
    VIR_FREE(guestName);

    return result;

  ignore:
    virDomainFSDefFree(*def);
    *def = NULL;

    result = 0;

    goto cleanup;
}



2437
int
2438
virVMXParseEthernet(virConfPtr conf, int controller, virDomainNetDefPtr *def)
2439
{
M
Matthias Bolte 已提交
2440
    int result = -1;
2441 2442 2443
    char prefix[48] = "";

    char present_name[48] = "";
2444
    bool present = false;
2445 2446

    char startConnected_name[48] = "";
2447
    bool startConnected = false;
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463

    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;

2464 2465 2466
    char features_name[48] = "";
    long long features = 0;

2467 2468 2469
    char vnet_name[48] = "";
    char *vnet = NULL;

M
Matthias Bolte 已提交
2470 2471 2472
    char networkName_name[48] = "";
    char *networkName = NULL;

2473
    if (def == NULL || *def != NULL) {
2474
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2475 2476 2477 2478
        return -1;
    }

    if (controller < 0 || controller > 3) {
2479 2480 2481
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Ethernet controller index %d out of [0..3] range"),
                       controller);
2482
        return -1;
2483 2484 2485
    }

    if (VIR_ALLOC(*def) < 0) {
2486
        virReportOOMError();
M
Matthias Bolte 已提交
2487
        return -1;
2488 2489
    }

2490
    snprintf(prefix, sizeof(prefix), "ethernet%d", controller);
2491

2492 2493 2494 2495 2496 2497 2498 2499 2500 2501
    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);
2502 2503

    /* vmx:present */
2504
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2505
        goto cleanup;
2506 2507 2508
    }

    /* vmx:startConnected */
2509 2510
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2511
        goto cleanup;
2512 2513 2514 2515 2516 2517 2518 2519
    }

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

    /* vmx:connectionType -> def:type */
2520 2521
    if (virVMXGetConfigString(conf, connectionType_name, &connectionType,
                              true) < 0) {
M
Matthias Bolte 已提交
2522
        goto cleanup;
2523 2524 2525
    }

    /* vmx:addressType, vmx:generatedAddress, vmx:address -> def:mac */
2526 2527 2528 2529 2530
    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 已提交
2531
        goto cleanup;
2532 2533
    }

2534 2535
    if (addressType == NULL || STRCASEEQ(addressType, "generated") ||
        STRCASEEQ(addressType, "vpx")) {
2536
        if (generatedAddress != NULL) {
2537
            if (virMacAddrParse(generatedAddress, &(*def)->mac) < 0) {
2538 2539 2540 2541
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry '%s' to be MAC address but "
                                 "found '%s'"), generatedAddress_name,
                               generatedAddress);
M
Matthias Bolte 已提交
2542
                goto cleanup;
2543 2544 2545 2546
            }
        }
    } else if (STRCASEEQ(addressType, "static")) {
        if (address != NULL) {
2547
            if (virMacAddrParse(address, &(*def)->mac) < 0) {
2548 2549 2550
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry '%s' to be MAC address but "
                                 "found '%s'"), address_name, address);
M
Matthias Bolte 已提交
2551
                goto cleanup;
2552 2553 2554
            }
        }
    } else {
2555 2556 2557
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry '%s' to be 'generated' or 'static' or "
                         "'vpx' but found '%s'"), addressType_name, addressType);
M
Matthias Bolte 已提交
2558
        goto cleanup;
2559 2560
    }

2561
    /* vmx:virtualDev, vmx:features -> def:model */
2562 2563
    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev, true) < 0 ||
        virVMXGetConfigLong(conf, features_name, &features, 0, true) < 0) {
M
Matthias Bolte 已提交
2564
        goto cleanup;
2565 2566
    }

2567 2568 2569 2570 2571
    if (virtualDev != NULL) {
        if (STRCASENEQ(virtualDev, "vlance") &&
            STRCASENEQ(virtualDev, "vmxnet") &&
            STRCASENEQ(virtualDev, "vmxnet3") &&
            STRCASENEQ(virtualDev, "e1000")) {
2572 2573 2574 2575
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting VMX entry '%s' to be 'vlance' or 'vmxnet' or "
                             "'vmxnet3' or 'e1000' but found '%s'"), virtualDev_name,
                           virtualDev);
M
Matthias Bolte 已提交
2576
            goto cleanup;
2577 2578 2579 2580 2581 2582 2583 2584 2585
        }

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

            virtualDev = strdup("vmxnet2");

            if (virtualDev == NULL) {
                virReportOOMError();
M
Matthias Bolte 已提交
2586
                goto cleanup;
2587 2588
            }
        }
2589 2590
    }

M
Matthias Bolte 已提交
2591
    /* vmx:networkName -> def:data.bridge.brname */
2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605
    if (connectionType == NULL ||
        STRCASEEQ(connectionType, "bridged") ||
        STRCASEEQ(connectionType, "custom")) {
        if (virVMXGetConfigString(conf, networkName_name, &networkName,
                                  true) < 0)
            goto cleanup;

        if (networkName == NULL) {
            networkName = strdup("");
            if (networkName == NULL) {
                virReportOOMError();
                goto cleanup;
            }
        }
M
Matthias Bolte 已提交
2606 2607 2608
    }

    /* vmx:vnet -> def:data.ifname */
2609
    if (connectionType != NULL && STRCASEEQ(connectionType, "custom") &&
2610
        virVMXGetConfigString(conf, vnet_name, &vnet, false) < 0) {
M
Matthias Bolte 已提交
2611
        goto cleanup;
2612 2613 2614 2615 2616 2617
    }

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

        virtualDev = NULL;
M
Matthias Bolte 已提交
2621
        networkName = NULL;
2622 2623
    } else if (STRCASEEQ(connectionType, "hostonly")) {
        /* FIXME */
2624 2625 2626
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No yet handled value '%s' for VMX entry '%s'"),
                       connectionType, connectionType_name);
M
Matthias Bolte 已提交
2627
        goto cleanup;
2628
    } else if (STRCASEEQ(connectionType, "nat")) {
2629 2630 2631 2632
        (*def)->type = VIR_DOMAIN_NET_TYPE_USER;
        (*def)->model = virtualDev;

        virtualDev = NULL;
2633 2634 2635
    } else if (STRCASEEQ(connectionType, "custom")) {
        (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
        (*def)->model = virtualDev;
M
Matthias Bolte 已提交
2636 2637
        (*def)->data.bridge.brname = networkName;
        (*def)->ifname = vnet;
2638 2639

        virtualDev = NULL;
M
Matthias Bolte 已提交
2640
        networkName = NULL;
2641 2642
        vnet = NULL;
    } else {
2643 2644 2645
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid value '%s' for VMX entry '%s'"), connectionType,
                       connectionType_name);
M
Matthias Bolte 已提交
2646
        goto cleanup;
2647 2648
    }

M
Matthias Bolte 已提交
2649 2650
    result = 0;

M
Matthias Bolte 已提交
2651
  cleanup:
M
Matthias Bolte 已提交
2652 2653 2654 2655 2656
    if (result < 0) {
        virDomainNetDefFree(*def);
        *def = NULL;
    }

S
Stefan Berger 已提交
2657
    VIR_FREE(networkName);
2658 2659 2660 2661 2662 2663 2664 2665 2666
    VIR_FREE(connectionType);
    VIR_FREE(addressType);
    VIR_FREE(generatedAddress);
    VIR_FREE(address);
    VIR_FREE(virtualDev);
    VIR_FREE(vnet);

    return result;

M
Matthias Bolte 已提交
2667
  ignore:
2668 2669 2670
    virDomainNetDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2671 2672
    result = 0;

2673 2674 2675 2676 2677 2678
    goto cleanup;
}



int
2679 2680
virVMXParseSerial(virVMXContext *ctx, virConfPtr conf, int port,
                  virDomainChrDefPtr *def)
2681
{
M
Matthias Bolte 已提交
2682
    int result = -1;
2683 2684 2685
    char prefix[48] = "";

    char present_name[48] = "";
2686
    bool present = false;
2687 2688

    char startConnected_name[48] = "";
2689
    bool startConnected = false;
2690 2691 2692 2693 2694 2695 2696

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

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

2697 2698 2699
    char network_endPoint_name[48] = "";
    char *network_endPoint = NULL;

M
Martin Kletzander 已提交
2700
    virURIPtr parsedUri = NULL;
2701

2702
    if (def == NULL || *def != NULL) {
2703
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2704 2705 2706 2707
        return -1;
    }

    if (port < 0 || port > 3) {
2708 2709
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Serial port index %d out of [0..3] range"), port);
2710
        return -1;
2711 2712 2713
    }

    if (VIR_ALLOC(*def) < 0) {
2714
        virReportOOMError();
M
Matthias Bolte 已提交
2715
        return -1;
2716 2717
    }

2718
    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
2719

2720
    snprintf(prefix, sizeof(prefix), "serial%d", port);
2721

2722 2723 2724 2725 2726
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
    VMX_BUILD_NAME_EXTRA(network_endPoint, "network.endPoint");
2727 2728

    /* vmx:present */
2729
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2730
        goto cleanup;
2731 2732 2733
    }

    /* vmx:startConnected */
2734 2735
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2736
        goto cleanup;
2737 2738 2739 2740 2741 2742 2743 2744
    }

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

    /* vmx:fileType -> def:type */
2745
    if (virVMXGetConfigString(conf, fileType_name, &fileType, false) < 0) {
M
Matthias Bolte 已提交
2746
        goto cleanup;
2747 2748 2749
    }

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

2754
    /* vmx:network.endPoint -> def:data.tcp.listen */
2755 2756
    if (virVMXGetConfigString(conf, network_endPoint_name, &network_endPoint,
                              true) < 0) {
2757 2758 2759
        goto cleanup;
    }

2760 2761
    /* Setup virDomainChrDef */
    if (STRCASEEQ(fileType, "device")) {
2762
        (*def)->target.port = port;
2763 2764
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
        (*def)->source.data.file.path = fileName;
2765 2766 2767

        fileName = NULL;
    } else if (STRCASEEQ(fileType, "file")) {
2768
        (*def)->target.port = port;
2769 2770 2771
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
        (*def)->source.data.file.path = ctx->parseFileName(fileName,
                                                           ctx->opaque);
2772

2773
        if ((*def)->source.data.file.path == NULL) {
M
Matthias Bolte 已提交
2774
            goto cleanup;
M
Matthias Bolte 已提交
2775
        }
2776
    } else if (STRCASEEQ(fileType, "pipe")) {
M
Matthias Bolte 已提交
2777 2778 2779 2780
        /*
         * FIXME: Differences between client/server and VM/application pipes
         *        not representable in domain XML form
         */
2781
        (*def)->target.port = port;
2782 2783
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
        (*def)->source.data.file.path = fileName;
M
Matthias Bolte 已提交
2784 2785

        fileName = NULL;
2786 2787
    } else if (STRCASEEQ(fileType, "network")) {
        (*def)->target.port = port;
2788
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_TCP;
2789

2790
        if (!(parsedUri = virURIParse(fileName)))
2791 2792 2793
            goto cleanup;

        if (parsedUri->port == 0) {
2794 2795 2796
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("VMX entry '%s' doesn't contain a port part"),
                           fileName_name);
2797 2798 2799
            goto cleanup;
        }

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

2802
        if ((*def)->source.data.tcp.host == NULL) {
2803 2804 2805 2806
            virReportOOMError();
            goto cleanup;
        }

2807 2808
        if (virAsprintf(&(*def)->source.data.tcp.service, "%d",
                        parsedUri->port) < 0) {
2809 2810 2811 2812 2813 2814 2815 2816 2817
            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")) {
2818
            (*def)->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
2819
        } else if (STRCASEEQ(parsedUri->scheme, "telnet")) {
2820 2821
            (*def)->source.data.tcp.protocol
                = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
2822
        } else if (STRCASEEQ(parsedUri->scheme, "telnets")) {
2823 2824
            (*def)->source.data.tcp.protocol
                = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS;
2825 2826 2827 2828
        } else if (STRCASEEQ(parsedUri->scheme, "ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp+ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp4+ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp6+ssl")) {
2829
            (*def)->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS;
2830
        } else {
2831 2832 2833
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("VMX entry '%s' contains unsupported scheme '%s'"),
                           fileName_name, parsedUri->scheme);
2834 2835 2836 2837
            goto cleanup;
        }

        if (network_endPoint == NULL || STRCASEEQ(network_endPoint, "server")) {
2838
            (*def)->source.data.tcp.listen = true;
2839
        } else if (STRCASEEQ(network_endPoint, "client")) {
2840
            (*def)->source.data.tcp.listen = false;
2841
        } else {
2842 2843 2844
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting VMX entry '%s' to be 'server' or 'client' "
                             "but found '%s'"), network_endPoint_name, network_endPoint);
2845 2846
            goto cleanup;
        }
2847
    } else {
2848 2849 2850
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry '%s' to be 'device', 'file' or 'pipe' "
                         "or 'network' but found '%s'"), fileType_name, fileType);
M
Matthias Bolte 已提交
2851
        goto cleanup;
2852 2853
    }

M
Matthias Bolte 已提交
2854 2855
    result = 0;

M
Matthias Bolte 已提交
2856
  cleanup:
M
Matthias Bolte 已提交
2857 2858 2859 2860 2861
    if (result < 0) {
        virDomainChrDefFree(*def);
        *def = NULL;
    }

2862 2863
    VIR_FREE(fileType);
    VIR_FREE(fileName);
2864
    VIR_FREE(network_endPoint);
2865
    virURIFree(parsedUri);
2866 2867 2868

    return result;

M
Matthias Bolte 已提交
2869
  ignore:
2870 2871 2872
    virDomainChrDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2873 2874
    result = 0;

2875 2876 2877 2878 2879 2880
    goto cleanup;
}



int
2881 2882
virVMXParseParallel(virVMXContext *ctx, virConfPtr conf, int port,
                    virDomainChrDefPtr *def)
2883
{
M
Matthias Bolte 已提交
2884
    int result = -1;
2885 2886 2887
    char prefix[48] = "";

    char present_name[48] = "";
2888
    bool present = false;
2889 2890

    char startConnected_name[48] = "";
2891
    bool startConnected = false;
2892 2893 2894 2895 2896 2897 2898 2899

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

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

    if (def == NULL || *def != NULL) {
2900
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2901 2902 2903 2904
        return -1;
    }

    if (port < 0 || port > 2) {
2905 2906
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parallel port index %d out of [0..2] range"), port);
2907
        return -1;
2908 2909 2910
    }

    if (VIR_ALLOC(*def) < 0) {
2911
        virReportOOMError();
M
Matthias Bolte 已提交
2912
        return -1;
2913 2914
    }

2915
    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
2916

2917
    snprintf(prefix, sizeof(prefix), "parallel%d", port);
2918

2919 2920 2921 2922
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
2923 2924

    /* vmx:present */
2925
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2926
        goto cleanup;
2927 2928 2929
    }

    /* vmx:startConnected */
2930 2931
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2932
        goto cleanup;
2933 2934 2935 2936 2937 2938 2939 2940
    }

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

    /* vmx:fileType -> def:type */
2941
    if (virVMXGetConfigString(conf, fileType_name, &fileType, false) < 0) {
M
Matthias Bolte 已提交
2942
        goto cleanup;
2943 2944 2945
    }

    /* vmx:fileName -> def:data.file.path */
2946
    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0) {
M
Matthias Bolte 已提交
2947
        goto cleanup;
2948 2949 2950 2951
    }

    /* Setup virDomainChrDef */
    if (STRCASEEQ(fileType, "device")) {
2952
        (*def)->target.port = port;
2953 2954
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
        (*def)->source.data.file.path = fileName;
2955 2956 2957

        fileName = NULL;
    } else if (STRCASEEQ(fileType, "file")) {
2958
        (*def)->target.port = port;
2959 2960 2961
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
        (*def)->source.data.file.path = ctx->parseFileName(fileName,
                                                           ctx->opaque);
2962

2963
        if ((*def)->source.data.file.path == NULL) {
M
Matthias Bolte 已提交
2964
            goto cleanup;
M
Matthias Bolte 已提交
2965
        }
2966
    } else {
2967 2968 2969
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry '%s' to be 'device' or 'file' but "
                         "found '%s'"), fileType_name, fileType);
M
Matthias Bolte 已提交
2970
        goto cleanup;
2971 2972
    }

M
Matthias Bolte 已提交
2973 2974
    result = 0;

M
Matthias Bolte 已提交
2975
  cleanup:
M
Matthias Bolte 已提交
2976 2977 2978 2979 2980
    if (result < 0) {
        virDomainChrDefFree(*def);
        *def = NULL;
    }

2981 2982 2983 2984 2985
    VIR_FREE(fileType);
    VIR_FREE(fileName);

    return result;

M
Matthias Bolte 已提交
2986
  ignore:
2987 2988 2989
    virDomainChrDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2990 2991
    result = 0;

2992 2993
    goto cleanup;
}
M
Matthias Bolte 已提交
2994 2995 2996



2997 2998 2999 3000 3001 3002 3003
int
virVMXParseSVGA(virConfPtr conf, virDomainVideoDefPtr *def)
{
    int result = -1;
    long long svga_vramSize = 0;

    if (def == NULL || *def != NULL) {
3004
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020
        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;
    }

3021
    (*def)->vram = VIR_DIV_UP(svga_vramSize, 1024); /* Scale from bytes to kilobytes */
3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035

    result = 0;

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

    return result;
}



M
Matthias Bolte 已提交
3036 3037 3038 3039 3040
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Domain XML -> VMX
 */

char *
3041
virVMXFormatConfig(virVMXContext *ctx, virDomainXMLOptionPtr xmlopt, virDomainDefPtr def,
3042
                   int virtualHW_version)
M
Matthias Bolte 已提交
3043
{
3044
    char *vmx = NULL;
M
Matthias Bolte 已提交
3045 3046 3047 3048
    int i;
    int sched_cpu_affinity_length;
    unsigned char zero[VIR_UUID_BUFLEN];
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
3049 3050
    char *preliminaryDisplayName = NULL;
    char *displayName = NULL;
3051
    char *annotation = NULL;
3052
    unsigned long long max_balloon;
3053 3054
    bool scsi_present[4] = { false, false, false, false };
    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
3055
    bool floppy_present[2] = { false, false };
M
Matthias Bolte 已提交
3056

3057
    if (ctx->formatFileName == NULL) {
3058 3059
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("virVMXContext has no formatFileName function set"));
3060 3061 3062
        return NULL;
    }

M
Matthias Bolte 已提交
3063 3064
    memset(zero, 0, VIR_UUID_BUFLEN);

3065
    if (def->virtType != VIR_DOMAIN_VIRT_VMWARE) {
3066 3067 3068 3069
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting virt type to be '%s' but found '%s'"),
                       virDomainVirtTypeToString(VIR_DOMAIN_VIRT_VMWARE),
                       virDomainVirtTypeToString(def->virtType));
M
Matthias Bolte 已提交
3070 3071 3072
        return NULL;
    }

3073 3074 3075
    /* vmx:.encoding */
    virBufferAddLit(&buffer, ".encoding = \"UTF-8\"\n");

M
Matthias Bolte 已提交
3076 3077 3078 3079
    /* vmx:config.version */
    virBufferAddLit(&buffer, "config.version = \"8\"\n");

    /* vmx:virtualHW.version */
3080
    virBufferAsprintf(&buffer, "virtualHW.version = \"%d\"\n",
3081
                      virtualHW_version);
M
Matthias Bolte 已提交
3082

M
Matthias Bolte 已提交
3083
    /* def:os.arch -> vmx:guestOS */
3084
    if (def->os.arch == VIR_ARCH_I686) {
M
Matthias Bolte 已提交
3085
        virBufferAddLit(&buffer, "guestOS = \"other\"\n");
3086
    } else if (def->os.arch == VIR_ARCH_X86_64) {
M
Matthias Bolte 已提交
3087 3088
        virBufferAddLit(&buffer, "guestOS = \"other-64\"\n");
    } else {
3089 3090
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting domain XML attribute 'arch' of entry 'os/type' "
3091 3092
                         "to be 'i686' or 'x86_64' but found '%s'"),
                       virArchToString(def->os.arch));
3093
        goto cleanup;
M
Matthias Bolte 已提交
3094 3095
    }

M
Matthias Bolte 已提交
3096 3097 3098 3099 3100 3101 3102
    /* 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 {
3103 3104 3105
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported SMBIOS mode '%s'"),
                       virDomainSmbiosModeTypeToString(def->os.smbios_mode));
M
Matthias Bolte 已提交
3106 3107 3108
        goto cleanup;
    }

M
Matthias Bolte 已提交
3109 3110 3111 3112
    /* def:uuid -> vmx:uuid.action, vmx:uuid.bios */
    if (memcmp(def->uuid, zero, VIR_UUID_BUFLEN) == 0) {
        virBufferAddLit(&buffer, "uuid.action = \"create\"\n");
    } else {
3113
        virBufferAsprintf(&buffer, "uuid.bios = \"%02x %02x %02x %02x %02x %02x "
M
Matthias Bolte 已提交
3114 3115 3116 3117 3118 3119 3120 3121 3122
                          "%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 */
3123
    preliminaryDisplayName = virVMXEscapeHexPipe(def->name);
3124

3125 3126 3127
    if (preliminaryDisplayName == NULL) {
        goto cleanup;
    }
3128

3129
    displayName = virVMXEscapeHexPercent(preliminaryDisplayName);
3130

3131 3132 3133
    if (displayName == NULL) {
        goto cleanup;
    }
3134

3135
    virBufferAsprintf(&buffer, "displayName = \"%s\"\n", displayName);
3136

3137 3138
    /* def:description -> vmx:annotation */
    if (def->description != NULL) {
3139
        annotation = virVMXEscapeHexPipe(def->description);
3140

3141
        virBufferAsprintf(&buffer, "annotation = \"%s\"\n", annotation);
3142 3143
    }

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

3148
    virBufferAsprintf(&buffer, "memsize = \"%llu\"\n",
3149
                      max_balloon / 1024); /* Scale from kilobytes to megabytes */
M
Matthias Bolte 已提交
3150

3151
    /* def:mem.cur_balloon -> vmx:sched.mem.max */
3152
    if (def->mem.cur_balloon < max_balloon) {
3153
        virBufferAsprintf(&buffer, "sched.mem.max = \"%llu\"\n",
3154 3155
                          VIR_DIV_UP(def->mem.cur_balloon,
                                     1024)); /* Scale from kilobytes to megabytes */
M
Matthias Bolte 已提交
3156 3157
    }

3158 3159
    /* def:mem.min_guarantee -> vmx:sched.mem.minsize */
    if (def->mem.min_guarantee > 0) {
3160
        virBufferAsprintf(&buffer, "sched.mem.minsize = \"%llu\"\n",
3161 3162
                          VIR_DIV_UP(def->mem.min_guarantee,
                                     1024)); /* Scale from kilobytes to megabytes */
3163 3164
    }

E
Eric Blake 已提交
3165 3166
    /* def:maxvcpus -> vmx:numvcpus */
    if (def->vcpus != def->maxvcpus) {
3167 3168 3169
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("No support for domain XML entry 'vcpu' attribute "
                         "'current'"));
E
Eric Blake 已提交
3170 3171 3172
        goto cleanup;
    }
    if (def->maxvcpus <= 0 || (def->maxvcpus % 2 != 0 && def->maxvcpus != 1)) {
3173 3174 3175 3176
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting domain XML entry 'vcpu' to be an unsigned "
                         "integer (1 or a multiple of 2) but found %d"),
                       def->maxvcpus);
3177
        goto cleanup;
M
Matthias Bolte 已提交
3178 3179
    }

3180
    virBufferAsprintf(&buffer, "numvcpus = \"%d\"\n", def->maxvcpus);
M
Matthias Bolte 已提交
3181 3182

    /* def:cpumask -> vmx:sched.cpu.affinity */
H
Hu Tao 已提交
3183
    if (def->cpumask && virBitmapSize(def->cpumask) > 0) {
M
Matthias Bolte 已提交
3184 3185 3186 3187
        virBufferAddLit(&buffer, "sched.cpu.affinity = \"");

        sched_cpu_affinity_length = 0;

H
Hu Tao 已提交
3188 3189 3190
        i = -1;
        while ((i = virBitmapNextSetBit(def->cpumask, i)) >= 0) {
            ++sched_cpu_affinity_length;
M
Matthias Bolte 已提交
3191 3192
        }

E
Eric Blake 已提交
3193
        if (sched_cpu_affinity_length < def->maxvcpus) {
3194 3195 3196 3197
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting domain XML attribute 'cpuset' of entry "
                             "'vcpu' to contain at least %d CPU(s)"),
                           def->maxvcpus);
3198
            goto cleanup;
M
Matthias Bolte 已提交
3199 3200
        }

H
Hu Tao 已提交
3201 3202 3203
        i = -1;
        while ((i = virBitmapNextSetBit(def->cpumask, i)) >= 0) {
            virBufferAsprintf(&buffer, "%d", i);
M
Matthias Bolte 已提交
3204

H
Hu Tao 已提交
3205 3206
            if (sched_cpu_affinity_length > 1) {
                virBufferAddChar(&buffer, ',');
M
Matthias Bolte 已提交
3207
            }
H
Hu Tao 已提交
3208 3209

            --sched_cpu_affinity_length;
M
Matthias Bolte 已提交
3210 3211 3212 3213 3214
        }

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

3215 3216 3217 3218 3219 3220 3221 3222 3223 3224
    /* def:cputune.shares -> vmx:sched.cpu.shares */
    if (def->cputune.shares > 0) {
        /* See http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.SharesInfo.Level.html */
        if (def->cputune.shares == def->vcpus * 500) {
            virBufferAddLit(&buffer, "sched.cpu.shares = \"low\"\n");
        } else if (def->cputune.shares == def->vcpus * 1000) {
            virBufferAddLit(&buffer, "sched.cpu.shares = \"normal\"\n");
        } else if (def->cputune.shares == def->vcpus * 2000) {
            virBufferAddLit(&buffer, "sched.cpu.shares = \"high\"\n");
        } else {
3225
            virBufferAsprintf(&buffer, "sched.cpu.shares = \"%lu\"\n",
3226 3227 3228 3229
                              def->cputune.shares);
        }
    }

M
Matthias Bolte 已提交
3230 3231 3232 3233
    /* def:graphics */
    for (i = 0; i < def->ngraphics; ++i) {
        switch (def->graphics[i]->type) {
          case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
3234
            if (virVMXFormatVNC(def->graphics[i], &buffer) < 0) {
3235
                goto cleanup;
M
Matthias Bolte 已提交
3236 3237 3238 3239 3240
            }

            break;

          default:
3241 3242 3243
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported graphics type '%s'"),
                           virDomainGraphicsTypeToString(def->graphics[i]->type));
3244
            goto cleanup;
M
Matthias Bolte 已提交
3245 3246 3247
        }
    }

M
Matthias Bolte 已提交
3248
    /* def:disks */
3249
    for (i = 0; i < def->ndisks; ++i) {
3250
        if (virVMXVerifyDiskAddress(xmlopt, def->disks[i]) < 0 ||
3251
            virVMXHandleLegacySCSIDiskDriverName(def, def->disks[i]) < 0) {
3252
            goto cleanup;
3253 3254
        }
    }
M
Matthias Bolte 已提交
3255

3256 3257
    if (virVMXGatherSCSIControllers(ctx, def, scsi_virtualDev,
                                    scsi_present) < 0) {
3258
        goto cleanup;
M
Matthias Bolte 已提交
3259 3260 3261 3262
    }

    for (i = 0; i < 4; ++i) {
        if (scsi_present[i]) {
3263
            virBufferAsprintf(&buffer, "scsi%d.present = \"true\"\n", i);
M
Matthias Bolte 已提交
3264

3265
            if (scsi_virtualDev[i] != -1) {
3266
                virBufferAsprintf(&buffer, "scsi%d.virtualDev = \"%s\"\n", i,
3267
                                  virVMXControllerModelSCSITypeToString
3268
                                    (scsi_virtualDev[i]));
M
Matthias Bolte 已提交
3269 3270 3271 3272 3273 3274 3275
            }
        }
    }

    for (i = 0; i < def->ndisks; ++i) {
        switch (def->disks[i]->device) {
          case VIR_DOMAIN_DISK_DEVICE_DISK:
3276
            if (virVMXFormatHardDisk(ctx, def->disks[i], &buffer) < 0) {
3277
                goto cleanup;
M
Matthias Bolte 已提交
3278 3279 3280 3281 3282
            }

            break;

          case VIR_DOMAIN_DISK_DEVICE_CDROM:
3283
            if (virVMXFormatCDROM(ctx, def->disks[i], &buffer) < 0) {
3284
                goto cleanup;
M
Matthias Bolte 已提交
3285 3286 3287 3288 3289
            }

            break;

          case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
3290 3291
            if (virVMXFormatFloppy(ctx, def->disks[i], &buffer,
                                   floppy_present) < 0) {
3292
                goto cleanup;
M
Matthias Bolte 已提交
3293 3294 3295 3296 3297
            }

            break;

          default:
3298 3299 3300
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported disk device type '%s'"),
                           virDomainDiskDeviceTypeToString(def->disks[i]->device));
3301
            goto cleanup;
M
Matthias Bolte 已提交
3302 3303 3304
        }
    }

3305 3306 3307
    for (i = 0; i < 2; ++i) {
        /* floppy[0..1].present defaults to true, disable it explicitly */
        if (! floppy_present[i]) {
3308
            virBufferAsprintf(&buffer, "floppy%d.present = \"false\"\n", i);
3309 3310 3311
        }
    }

M
Matthias Bolte 已提交
3312
    /* def:fss */
3313 3314
    if (def->nfss > 0) {
        virBufferAddLit(&buffer, "isolation.tools.hgfs.disable = \"false\"\n");
3315
        virBufferAsprintf(&buffer, "sharedFolder.maxNum = \"%zu\"\n", def->nfss);
3316 3317 3318 3319 3320 3321 3322
    }

    for (i = 0; i < def->nfss; ++i) {
        if (virVMXFormatFileSystem(def->fss[i], i, &buffer) < 0) {
            goto cleanup;
        }
    }
M
Matthias Bolte 已提交
3323 3324 3325

    /* def:nets */
    for (i = 0; i < def->nnets; ++i) {
3326
        if (virVMXFormatEthernet(def->nets[i], i, &buffer) < 0) {
3327
            goto cleanup;
M
Matthias Bolte 已提交
3328 3329 3330 3331 3332 3333 3334 3335 3336
        }
    }

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

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

3337 3338 3339
    /* def:videos */
    if (def->nvideos > 0) {
        if (def->nvideos > 1) {
3340 3341
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No support for multiple video devices"));
3342 3343 3344 3345 3346 3347 3348 3349
            goto cleanup;
        }

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

M
Matthias Bolte 已提交
3350 3351 3352 3353 3354
    /* def:hostdevs */
    /* FIXME */

    /* def:serials */
    for (i = 0; i < def->nserials; ++i) {
3355
        if (virVMXFormatSerial(ctx, def->serials[i], &buffer) < 0) {
3356
            goto cleanup;
M
Matthias Bolte 已提交
3357 3358 3359 3360 3361
        }
    }

    /* def:parallels */
    for (i = 0; i < def->nparallels; ++i) {
3362
        if (virVMXFormatParallel(ctx, def->parallels[i], &buffer) < 0) {
3363
            goto cleanup;
M
Matthias Bolte 已提交
3364 3365 3366 3367 3368
        }
    }

    /* Get final VMX output */
    if (virBufferError(&buffer)) {
3369
        virReportOOMError();
3370
        goto cleanup;
M
Matthias Bolte 已提交
3371 3372
    }

3373
    vmx = virBufferContentAndReset(&buffer);
M
Matthias Bolte 已提交
3374

3375 3376 3377 3378 3379
  cleanup:
    if (vmx == NULL) {
        virBufferFreeAndReset(&buffer);
    }

3380 3381
    VIR_FREE(preliminaryDisplayName);
    VIR_FREE(displayName);
3382
    VIR_FREE(annotation);
M
Matthias Bolte 已提交
3383

3384
    return vmx;
M
Matthias Bolte 已提交
3385 3386 3387 3388
}



M
Matthias Bolte 已提交
3389
int
3390
virVMXFormatVNC(virDomainGraphicsDefPtr def, virBufferPtr buffer)
M
Matthias Bolte 已提交
3391
{
3392 3393
    const char *listenAddr;

M
Matthias Bolte 已提交
3394
    if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
3395
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3396 3397 3398
        return -1;
    }

3399
    virBufferAsprintf(buffer, "RemoteDisplay.vnc.enabled = \"true\"\n");
M
Matthias Bolte 已提交
3400 3401

    if (def->data.vnc.autoport) {
3402
        VIR_WARN("VNC autoport is enabled, but the automatically assigned "
M
Matthias Bolte 已提交
3403 3404 3405 3406 3407 3408 3409
                  "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);
        }

3410
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.port = \"%d\"\n",
M
Matthias Bolte 已提交
3411 3412 3413
                          def->data.vnc.port);
    }

3414
    if ((listenAddr = virDomainGraphicsListenGetAddress(def, 0))) {
3415
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.ip = \"%s\"\n",
3416
                          listenAddr);
M
Matthias Bolte 已提交
3417 3418 3419
    }

    if (def->data.vnc.keymap != NULL) {
3420
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.keymap = \"%s\"\n",
M
Matthias Bolte 已提交
3421 3422 3423
                          def->data.vnc.keymap);
    }

3424
    if (def->data.vnc.auth.passwd != NULL) {
3425
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.password = \"%s\"\n",
3426
                          def->data.vnc.auth.passwd);
M
Matthias Bolte 已提交
3427 3428 3429 3430 3431 3432 3433
    }

    return 0;
}



M
Matthias Bolte 已提交
3434
int
3435 3436
virVMXFormatHardDisk(virVMXContext *ctx, virDomainDiskDefPtr def,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3437
{
3438
    int controllerOrBus, unit;
M
Matthias Bolte 已提交
3439 3440 3441
    const char *busName = NULL;
    const char *entryPrefix = NULL;
    const char *deviceTypePrefix = NULL;
M
Matthias Bolte 已提交
3442
    char *fileName = NULL;
M
Matthias Bolte 已提交
3443 3444

    if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
3445
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3446 3447 3448 3449 3450 3451 3452 3453
        return -1;
    }

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

3454 3455
        if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
                                                  &unit) < 0) {
M
Matthias Bolte 已提交
3456 3457 3458 3459 3460 3461 3462
            return -1;
        }
    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
        busName = "IDE";
        entryPrefix = "ide";
        deviceTypePrefix = "ata";

3463
        if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
3464
                                           &unit) < 0) {
M
Matthias Bolte 已提交
3465 3466 3467
            return -1;
        }
    } else {
3468 3469 3470
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported bus type '%s' for harddisk"),
                       virDomainDiskBusTypeToString(def->bus));
M
Matthias Bolte 已提交
3471 3472 3473 3474
        return -1;
    }

    if (def->type != VIR_DOMAIN_DISK_TYPE_FILE) {
3475 3476 3477 3478
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("%s harddisk '%s' has unsupported type '%s', expecting '%s'"),
                       busName, def->dst, virDomainDiskTypeToString(def->type),
                       virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE));
M
Matthias Bolte 已提交
3479 3480 3481
        return -1;
    }

3482
    virBufferAsprintf(buffer, "%s%d:%d.present = \"true\"\n",
3483
                      entryPrefix, controllerOrBus, unit);
3484
    virBufferAsprintf(buffer, "%s%d:%d.deviceType = \"%s-hardDisk\"\n",
3485
                      entryPrefix, controllerOrBus, unit, deviceTypePrefix);
M
Matthias Bolte 已提交
3486 3487

    if (def->src != NULL) {
3488
        if (! virFileHasSuffix(def->src, ".vmdk")) {
3489 3490 3491
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Image file for %s harddisk '%s' has unsupported suffix, "
                             "expecting '.vmdk'"), busName, def->dst);
M
Matthias Bolte 已提交
3492 3493 3494
            return -1;
        }

3495
        fileName = ctx->formatFileName(def->src, ctx->opaque);
M
Matthias Bolte 已提交
3496 3497 3498 3499 3500

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

3501
        virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3502
                          entryPrefix, controllerOrBus, unit, fileName);
M
Matthias Bolte 已提交
3503 3504

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3505 3506 3507 3508
    }

    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
        if (def->cachemode == VIR_DOMAIN_DISK_CACHE_WRITETHRU) {
3509
            virBufferAsprintf(buffer, "%s%d:%d.writeThrough = \"true\"\n",
3510
                              entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3511
        } else if (def->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) {
3512 3513 3514 3515
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("%s harddisk '%s' has unsupported cache mode '%s'"),
                           busName, def->dst,
                           virDomainDiskCacheTypeToString(def->cachemode));
M
Matthias Bolte 已提交
3516
            return -1;
M
Matthias Bolte 已提交
3517 3518 3519 3520 3521 3522 3523 3524 3525
        }
    }

    return 0;
}



int
3526 3527
virVMXFormatCDROM(virVMXContext *ctx, virDomainDiskDefPtr def,
                  virBufferPtr buffer)
M
Matthias Bolte 已提交
3528
{
3529
    int controllerOrBus, unit;
M
Matthias Bolte 已提交
3530 3531
    const char *busName = NULL;
    const char *entryPrefix = NULL;
M
Matthias Bolte 已提交
3532
    char *fileName = NULL;
M
Matthias Bolte 已提交
3533 3534

    if (def->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
3535
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3536 3537 3538 3539 3540 3541 3542
        return -1;
    }

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

3543 3544
        if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
                                                  &unit) < 0) {
M
Matthias Bolte 已提交
3545 3546 3547 3548 3549 3550
            return -1;
        }
    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
        busName = "IDE";
        entryPrefix = "ide";

3551 3552
        if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
                                          &unit) < 0) {
M
Matthias Bolte 已提交
3553 3554 3555
            return -1;
        }
    } else {
3556 3557 3558
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported bus type '%s' for cdrom"),
                       virDomainDiskBusTypeToString(def->bus));
M
Matthias Bolte 已提交
3559 3560 3561
        return -1;
    }

3562
    virBufferAsprintf(buffer, "%s%d:%d.present = \"true\"\n",
3563
                      entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3564 3565

    if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
3566
        virBufferAsprintf(buffer, "%s%d:%d.deviceType = \"cdrom-image\"\n",
3567
                          entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3568 3569

        if (def->src != NULL) {
3570
            if (! virFileHasSuffix(def->src, ".iso")) {
3571 3572 3573
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Image file for %s cdrom '%s' has unsupported "
                                 "suffix, expecting '.iso'"), busName, def->dst);
M
Matthias Bolte 已提交
3574 3575 3576
                return -1;
            }

3577
            fileName = ctx->formatFileName(def->src, ctx->opaque);
M
Matthias Bolte 已提交
3578 3579 3580 3581 3582

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

3583
            virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3584
                              entryPrefix, controllerOrBus, unit, fileName);
M
Matthias Bolte 已提交
3585 3586 3587

            VIR_FREE(fileName);
        }
M
Matthias Bolte 已提交
3588
    } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
3589
        virBufferAsprintf(buffer, "%s%d:%d.deviceType = \"atapi-cdrom\"\n",
3590
                          entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3591 3592

        if (def->src != NULL) {
3593
            virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3594
                              entryPrefix, controllerOrBus, unit, def->src);
M
Matthias Bolte 已提交
3595
        }
M
Matthias Bolte 已提交
3596
    } else {
3597 3598 3599 3600 3601 3602
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("%s cdrom '%s' has unsupported type '%s', expecting '%s' "
                         "or '%s'"), busName, def->dst,
                       virDomainDiskTypeToString(def->type),
                       virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE),
                       virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_BLOCK));
M
Matthias Bolte 已提交
3603 3604 3605 3606 3607 3608 3609 3610 3611
        return -1;
    }

    return 0;
}



int
3612 3613
virVMXFormatFloppy(virVMXContext *ctx, virDomainDiskDefPtr def,
                   virBufferPtr buffer, bool floppy_present[2])
M
Matthias Bolte 已提交
3614
{
3615
    int unit;
M
Matthias Bolte 已提交
3616
    char *fileName = NULL;
M
Matthias Bolte 已提交
3617 3618

    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
3619
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3620 3621 3622
        return -1;
    }

3623
    if (virVMXFloppyDiskNameToUnit(def->dst, &unit) < 0) {
M
Matthias Bolte 已提交
3624 3625 3626
        return -1;
    }

3627 3628
    floppy_present[unit] = true;

3629
    virBufferAsprintf(buffer, "floppy%d.present = \"true\"\n", unit);
M
Matthias Bolte 已提交
3630 3631

    if (def->type == VIR_DOMAIN_DISK_TYPE_FILE) {
3632
        virBufferAsprintf(buffer, "floppy%d.fileType = \"file\"\n", unit);
M
Matthias Bolte 已提交
3633 3634

        if (def->src != NULL) {
3635
            if (! virFileHasSuffix(def->src, ".flp")) {
3636 3637 3638
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Image file for floppy '%s' has unsupported "
                                 "suffix, expecting '.flp'"), def->dst);
M
Matthias Bolte 已提交
3639 3640 3641
                return -1;
            }

3642
            fileName = ctx->formatFileName(def->src, ctx->opaque);
M
Matthias Bolte 已提交
3643 3644 3645 3646 3647

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

3648
            virBufferAsprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3649
                              unit, fileName);
M
Matthias Bolte 已提交
3650 3651 3652

            VIR_FREE(fileName);
        }
M
Matthias Bolte 已提交
3653
    } else if (def->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
3654
        virBufferAsprintf(buffer, "floppy%d.fileType = \"device\"\n", unit);
M
Matthias Bolte 已提交
3655 3656

        if (def->src != NULL) {
3657
            virBufferAsprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3658
                              unit, def->src);
M
Matthias Bolte 已提交
3659
        }
M
Matthias Bolte 已提交
3660
    } else {
3661 3662 3663 3664 3665 3666
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Floppy '%s' has unsupported type '%s', expecting '%s' "
                         "or '%s'"), def->dst,
                       virDomainDiskTypeToString(def->type),
                       virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_FILE),
                       virDomainDiskTypeToString(VIR_DOMAIN_DISK_TYPE_BLOCK));
M
Matthias Bolte 已提交
3667 3668 3669 3670 3671 3672 3673 3674
        return -1;
    }

    return 0;
}



3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699
int
virVMXFormatFileSystem(virDomainFSDefPtr def, int number, virBufferPtr buffer)
{
    if (def->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Only '%s' filesystem type is supported"),
                       virDomainFSTypeToString(VIR_DOMAIN_FS_TYPE_MOUNT));
        return -1;
    }

    virBufferAsprintf(buffer, "sharedFolder%d.present = \"true\"\n", number);
    virBufferAsprintf(buffer, "sharedFolder%d.enabled = \"true\"\n", number);
    virBufferAsprintf(buffer, "sharedFolder%d.readAccess = \"true\"\n", number);
    virBufferAsprintf(buffer, "sharedFolder%d.writeAccess = \"%s\"\n", number,
                      def->readonly ? "false" : "true");
    virBufferAsprintf(buffer, "sharedFolder%d.hostPath = \"%s\"\n", number,
                      def->src);
    virBufferAsprintf(buffer, "sharedFolder%d.guestName = \"%s\"\n", number,
                      def->dst);

    return 0;
}



M
Matthias Bolte 已提交
3700
int
3701 3702
virVMXFormatEthernet(virDomainNetDefPtr def, int controller,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3703 3704
{
    char mac_string[VIR_MAC_STRING_BUFLEN];
3705
    unsigned int prefix, suffix;
M
Matthias Bolte 已提交
3706 3707

    if (controller < 0 || controller > 3) {
3708 3709 3710
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Ethernet controller index %d out of [0..3] range"),
                       controller);
M
Matthias Bolte 已提交
3711 3712 3713
        return -1;
    }

3714
    virBufferAsprintf(buffer, "ethernet%d.present = \"true\"\n", controller);
M
Matthias Bolte 已提交
3715

3716
    /* def:model -> vmx:virtualDev, vmx:features */
M
Matthias Bolte 已提交
3717 3718 3719
    if (def->model != NULL) {
        if (STRCASENEQ(def->model, "vlance") &&
            STRCASENEQ(def->model, "vmxnet") &&
3720
            STRCASENEQ(def->model, "vmxnet2") &&
3721
            STRCASENEQ(def->model, "vmxnet3") &&
M
Matthias Bolte 已提交
3722
            STRCASENEQ(def->model, "e1000")) {
3723 3724 3725 3726
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting domain XML entry 'devices/interface/model' "
                             "to be 'vlance' or 'vmxnet' or 'vmxnet2' or 'vmxnet3' "
                             "or 'e1000' but found '%s'"), def->model);
M
Matthias Bolte 已提交
3727 3728 3729
            return -1;
        }

3730
        if (STRCASEEQ(def->model, "vmxnet2")) {
3731
            virBufferAsprintf(buffer, "ethernet%d.virtualDev = \"vmxnet\"\n",
3732
                              controller);
3733
            virBufferAsprintf(buffer, "ethernet%d.features = \"15\"\n",
3734 3735
                              controller);
        } else {
3736
            virBufferAsprintf(buffer, "ethernet%d.virtualDev = \"%s\"\n",
3737 3738
                              controller, def->model);
        }
M
Matthias Bolte 已提交
3739 3740 3741 3742 3743
    }

    /* def:type, def:ifname -> vmx:connectionType */
    switch (def->type) {
      case VIR_DOMAIN_NET_TYPE_BRIDGE:
3744 3745 3746
        if (STRNEQ(def->data.bridge.brname, ""))
            virBufferAsprintf(buffer, "ethernet%d.networkName = \"%s\"\n",
                              controller, def->data.bridge.brname);
M
Matthias Bolte 已提交
3747 3748

        if (def->ifname != NULL) {
3749
            virBufferAsprintf(buffer, "ethernet%d.connectionType = \"custom\"\n",
M
Matthias Bolte 已提交
3750
                              controller);
3751
            virBufferAsprintf(buffer, "ethernet%d.vnet = \"%s\"\n",
M
Matthias Bolte 已提交
3752 3753
                              controller, def->ifname);
        } else {
3754
            virBufferAsprintf(buffer, "ethernet%d.connectionType = \"bridged\"\n",
M
Matthias Bolte 已提交
3755 3756 3757 3758 3759
                              controller);
        }

        break;

3760 3761 3762 3763 3764
      case VIR_DOMAIN_NET_TYPE_USER:
        virBufferAsprintf(buffer, "ethernet%d.connectionType = \"nat\"\n",
                          controller);
        break;

M
Matthias Bolte 已提交
3765
      default:
3766 3767
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type '%s'"),
                       virDomainNetTypeToString(def->type));
M
Matthias Bolte 已提交
3768 3769 3770
        return -1;
    }

3771
    /* def:mac -> vmx:addressType, vmx:(generated)Address, vmx:checkMACAddress */
3772
    virMacAddrFormat(&def->mac, mac_string);
M
Matthias Bolte 已提交
3773

3774 3775
    prefix = (def->mac.addr[0] << 16) | (def->mac.addr[1] << 8) | def->mac.addr[2];
    suffix = (def->mac.addr[3] << 16) | (def->mac.addr[4] << 8) | def->mac.addr[5];
3776 3777

    if (prefix == 0x000c29) {
3778
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"generated\"\n",
M
Matthias Bolte 已提交
3779
                          controller);
3780
        virBufferAsprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
M
Matthias Bolte 已提交
3781
                          controller, mac_string);
3782
        virBufferAsprintf(buffer, "ethernet%d.generatedAddressOffset = \"0\"\n",
M
Matthias Bolte 已提交
3783
                          controller);
3784
    } else if (prefix == 0x005056 && suffix <= 0x3fffff) {
3785
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"static\"\n",
3786
                          controller);
3787
        virBufferAsprintf(buffer, "ethernet%d.address = \"%s\"\n",
3788 3789
                          controller, mac_string);
    } else if (prefix == 0x005056 && suffix >= 0x800000 && suffix <= 0xbfffff) {
3790
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"vpx\"\n",
3791
                          controller);
3792
        virBufferAsprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
3793
                          controller, mac_string);
M
Matthias Bolte 已提交
3794
    } else {
3795
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"static\"\n",
3796
                          controller);
3797
        virBufferAsprintf(buffer, "ethernet%d.address = \"%s\"\n",
3798
                          controller, mac_string);
3799
        virBufferAsprintf(buffer, "ethernet%d.checkMACAddress = \"false\"\n",
3800
                          controller);
M
Matthias Bolte 已提交
3801 3802 3803 3804 3805 3806 3807 3808
    }

    return 0;
}



int
3809 3810
virVMXFormatSerial(virVMXContext *ctx, virDomainChrDefPtr def,
                   virBufferPtr buffer)
M
Matthias Bolte 已提交
3811
{
M
Matthias Bolte 已提交
3812
    char *fileName = NULL;
3813
    const char *protocol;
M
Matthias Bolte 已提交
3814

3815
    if (def->target.port < 0 || def->target.port > 3) {
3816 3817 3818
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Serial port index %d out of [0..3] range"),
                       def->target.port);
M
Matthias Bolte 已提交
3819 3820 3821
        return -1;
    }

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

M
Matthias Bolte 已提交
3824
    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
3825
    switch (def->source.type) {
M
Matthias Bolte 已提交
3826
      case VIR_DOMAIN_CHR_TYPE_DEV:
3827
        virBufferAsprintf(buffer, "serial%d.fileType = \"device\"\n",
3828
                          def->target.port);
3829
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3830
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3831 3832 3833
        break;

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

3837
        fileName = ctx->formatFileName(def->source.data.file.path, ctx->opaque);
M
Matthias Bolte 已提交
3838 3839 3840 3841 3842

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

3843
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3844
                          def->target.port, fileName);
M
Matthias Bolte 已提交
3845 3846

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3847 3848 3849
        break;

      case VIR_DOMAIN_CHR_TYPE_PIPE:
3850
        virBufferAsprintf(buffer, "serial%d.fileType = \"pipe\"\n",
3851
                          def->target.port);
M
Matthias Bolte 已提交
3852
        /* FIXME: Based on VI Client GUI default */
3853
        virBufferAsprintf(buffer, "serial%d.pipe.endPoint = \"client\"\n",
3854
                          def->target.port);
M
Matthias Bolte 已提交
3855
        /* FIXME: Based on VI Client GUI default */
3856
        virBufferAsprintf(buffer, "serial%d.tryNoRxLoss = \"false\"\n",
3857
                          def->target.port);
3858
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3859
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3860 3861
        break;

3862
      case VIR_DOMAIN_CHR_TYPE_TCP:
3863
        switch (def->source.data.tcp.protocol) {
3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880
          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:
3881 3882 3883 3884
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported character device TCP protocol '%s'"),
                           virDomainChrTcpProtocolTypeToString(
                               def->source.data.tcp.protocol));
3885 3886 3887
            return -1;
        }

3888
        virBufferAsprintf(buffer, "serial%d.fileType = \"network\"\n",
3889
                          def->target.port);
3890
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s://%s:%s\"\n",
3891 3892
                          def->target.port, protocol, def->source.data.tcp.host,
                          def->source.data.tcp.service);
3893
        virBufferAsprintf(buffer, "serial%d.network.endPoint = \"%s\"\n",
3894
                          def->target.port,
3895
                          def->source.data.tcp.listen ? "server" : "client");
3896 3897
        break;

M
Matthias Bolte 已提交
3898
      default:
3899 3900 3901
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported character device type '%s'"),
                       virDomainChrTypeToString(def->source.type));
M
Matthias Bolte 已提交
3902 3903 3904 3905 3906
        return -1;
    }

    /* vmx:yieldOnMsrRead */
    /* FIXME: Based on VI Client GUI default */
3907
    virBufferAsprintf(buffer, "serial%d.yieldOnMsrRead = \"true\"\n",
3908
                      def->target.port);
M
Matthias Bolte 已提交
3909 3910 3911 3912 3913 3914 3915

    return 0;
}



int
3916 3917
virVMXFormatParallel(virVMXContext *ctx, virDomainChrDefPtr def,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3918
{
M
Matthias Bolte 已提交
3919 3920
    char *fileName = NULL;

3921
    if (def->target.port < 0 || def->target.port > 2) {
3922 3923 3924
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parallel port index %d out of [0..2] range"),
                       def->target.port);
M
Matthias Bolte 已提交
3925 3926 3927
        return -1;
    }

3928
    virBufferAsprintf(buffer, "parallel%d.present = \"true\"\n",
3929
                      def->target.port);
M
Matthias Bolte 已提交
3930

M
Matthias Bolte 已提交
3931
    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
3932
    switch (def->source.type) {
M
Matthias Bolte 已提交
3933
      case VIR_DOMAIN_CHR_TYPE_DEV:
3934
        virBufferAsprintf(buffer, "parallel%d.fileType = \"device\"\n",
3935
                          def->target.port);
3936
        virBufferAsprintf(buffer, "parallel%d.fileName = \"%s\"\n",
3937
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3938 3939 3940
        break;

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

3944
        fileName = ctx->formatFileName(def->source.data.file.path, ctx->opaque);
M
Matthias Bolte 已提交
3945 3946 3947 3948 3949

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

3950
        virBufferAsprintf(buffer, "parallel%d.fileName = \"%s\"\n",
3951
                          def->target.port, fileName);
M
Matthias Bolte 已提交
3952 3953

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3954 3955 3956
        break;

      default:
3957 3958 3959
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported character device type '%s'"),
                       virDomainChrTypeToString(def->source.type));
M
Matthias Bolte 已提交
3960 3961 3962 3963 3964
        return -1;
    }

    return 0;
}
3965 3966 3967 3968 3969 3970



int
virVMXFormatSVGA(virDomainVideoDefPtr def, virBufferPtr buffer)
{
3971 3972
    unsigned long long vram;

3973
    if (def->type != VIR_DOMAIN_VIDEO_TYPE_VMVGA) {
3974 3975 3976
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported video device type '%s'"),
                       virDomainVideoTypeToString(def->type));
3977 3978 3979 3980 3981 3982 3983
        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
     */
3984
    vram = VIR_DIV_UP(def->vram, 64) * 64;
3985 3986

    if (def->heads > 1) {
3987 3988
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Multi-head video devices are unsupported"));
3989 3990 3991
        return -1;
    }

3992
    virBufferAsprintf(buffer, "svga.vramSize = \"%lld\"\n",
3993
                      vram * 1024); /* kilobyte to byte */
3994 3995 3996

    return 0;
}