vmx.c 128.2 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 "virfile.h"
30
#include "virconf.h"
31
#include "viralloc.h"
32
#include "virlog.h"
33
#include "viruuid.h"
34
#include "vmx.h"
M
Martin Kletzander 已提交
35
#include "viruri.h"
36
#include "virstring.h"
37 38 39 40 41 42 43 44 45

/*

mapping:

domain-xml                        <=>   vmx


                                        config.version = "8"                    # essential
46 47
                                        virtualHW.version = "4"                 # essential for ESX 3.5
                                        virtualHW.version = "7"                 # essential for ESX 4.0
P
Patrice LACHANCE 已提交
48
                                        virtualHW.version = "8"                 # essential for ESX 5.0
49
                                        virtualHW.version = "9"                 # essential for ESX 5.1
50 51 52 53 54 55


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



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

def->os

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



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

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

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


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

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


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

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



266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
################################################################################
## 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



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


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


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

312 313 314 315

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

316 317 318 319 320

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

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


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

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


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

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


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

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



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

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



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

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

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

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


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


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


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

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


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

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


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

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

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

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

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


454 455 456 457 458 459 460 461 462 463

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

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

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

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


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


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

495 496
*/

497
#define VIR_FROM_THIS VIR_FROM_NONE
498

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

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

505 506 507
/* 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 */
508 509
VIR_ENUM_DECL(virVMXControllerModelSCSI)
VIR_ENUM_IMPL(virVMXControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
510
              "auto", /* just to match virDomainControllerModel, will never be used */
511 512 513
              "buslogic",
              "lsilogic",
              "lsisas1068",
514
              "pvscsi",
515
              "UNUSED ibmvscsi",
516 517
              "UNUSED virtio-scsi",
              "UNUSED lsisas1078");
518 519


520 521 522 523 524

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

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


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

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 585
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 已提交
586
int
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623
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) {
624 625
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxml2 doesn't handle %s encoding"), encoding);
626 627 628 629 630 631 632
        return NULL;
    }

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

    if (xmlCharEncInFunc(handler, utf8, input) < 0) {
633 634
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not convert from %s to UTF-8 encoding"), encoding);
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
        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;
        }

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

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

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

681 682
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing essential config entry '%s'"), name);
683 684 685
        return -1;
    }

686
    return VIR_STRDUP(*string, value->str);
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
}



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 {
703 704
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing essential config entry '%s'"), name);
705 706 707 708 709
            return -1;
        }
    }

    if (value->type != VIR_CONF_STRING) {
710 711
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Config entry '%s' must be a string"), name);
712 713 714 715 716 717 718
        return -1;
    }

    if (value->str == NULL) {
        if (optional) {
            return 0;
        } else {
719 720
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing essential config entry '%s'"), name);
721 722 723 724 725
            return -1;
        }
    }

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

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
760 761
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing essential config entry '%s'"), name);
762 763 764 765
                return -1;
            }
        }

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

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
809 810
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing essential config entry '%s'"), name);
811 812 813 814 815 816 817 818 819
                return -1;
            }
        }

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

    return 0;
}



static int
virVMXSCSIDiskNameToControllerAndUnit(const char *name, int *controller, int *unit)
M
Matthias Bolte 已提交
838 839 840 841
{
    int idx;

    if (! STRPREFIX(name, "sd")) {
842 843 844
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expecting domain XML attribute 'dev' of entry "
                         "'devices/disk/target' to start with 'sd'"));
M
Matthias Bolte 已提交
845 846 847 848 849 850
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
851 852
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
853 854 855
        return -1;
    }

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

    *controller = idx / 15;
864
    *unit = idx % 15;
M
Matthias Bolte 已提交
865

866 867 868
    /* Skip the controller ifself at unit 7 */
    if (*unit >= 7) {
        ++(*unit);
M
Matthias Bolte 已提交
869 870 871 872 873 874 875
    }

    return 0;
}



876 877
static int
virVMXIDEDiskNameToBusAndUnit(const char *name, int *bus, int *unit)
M
Matthias Bolte 已提交
878 879 880 881
{
    int idx;

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

    idx = virDiskNameToIndex(name);

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

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

903 904
    *bus = idx / 2;
    *unit = idx % 2;
M
Matthias Bolte 已提交
905 906 907 908 909 910

    return 0;
}



911 912
static int
virVMXFloppyDiskNameToUnit(const char *name, int *unit)
M
Matthias Bolte 已提交
913 914 915 916
{
    int idx;

    if (! STRPREFIX(name, "fd")) {
917 918 919
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expecting domain XML attribute 'dev' of entry "
                         "'devices/disk/target' to start with 'fd'"));
M
Matthias Bolte 已提交
920 921 922 923 924 925
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
926 927
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
928 929 930
        return -1;
    }

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

938 939 940 941 942 943 944
    *unit = idx;

    return 0;
}



945
static int
946
virVMXVerifyDiskAddress(virDomainXMLOptionPtr xmlopt, virDomainDiskDefPtr disk)
947 948 949 950 951 952 953
{
    virDomainDiskDef def;
    virDomainDeviceDriveAddressPtr drive;

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

    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
954 955 956
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported disk address type '%s'"),
                       virDomainDeviceAddressTypeToString(disk->info.type));
957 958 959 960 961 962 963 964
        return -1;
    }

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

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

965
    if (virDomainDiskDefAssignAddress(xmlopt, &def) < 0) {
966 967
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not verify disk address"));
968 969 970 971 972 973
        return -1;
    }

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

        if (drive->bus != 0) {
990 991 992
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("SCSI bus index %d out of [0] range"),
                           drive->bus);
993 994 995 996
            return -1;
        }

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

        if (drive->bus > 1) {
1011 1012 1013
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE bus index %d out of [0..1] range"),
                           drive->bus);
1014 1015 1016 1017
            return -1;
        }

        if (drive->unit > 1) {
1018 1019 1020
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE unit index %d out of [0..1] range"),
                           drive->unit);
1021 1022 1023 1024
            return -1;
        }
    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
        if (drive->controller != 0) {
1025 1026 1027
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC controller index %d out of [0] range"),
                           drive->controller);
1028 1029 1030 1031
            return -1;
        }

        if (drive->bus != 0) {
1032 1033 1034
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC bus index %d out of [0] range"),
                           drive->bus);
1035 1036 1037 1038
            return -1;
        }

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

    return 0;
}



1056 1057 1058
static int
virVMXHandleLegacySCSIDiskDriverName(virDomainDefPtr def,
                                     virDomainDiskDefPtr disk)
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
{
    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);
    }

1074
    model = virDomainControllerModelSCSITypeFromString(disk->driverName);
1075 1076

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

    if (controller->model == -1) {
        controller->model = model;
    } else if (controller->model != model) {
1099 1100 1101 1102 1103
        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);
1104 1105
        return -1;
    }
M
Matthias Bolte 已提交
1106 1107 1108 1109 1110 1111

    return 0;
}



1112 1113 1114
static int
virVMXGatherSCSIControllers(virVMXContext *ctx, virDomainDefPtr def,
                            int virtualDev[4], bool present[4])
1115 1116 1117
{
    int result = -1;
    int i, k;
M
Matthias Bolte 已提交
1118
    virDomainDiskDefPtr disk;
1119 1120 1121 1122
    virDomainControllerDefPtr controller;
    bool controllerHasDisksAttached;
    int count = 0;
    int *autodetectedModels;
M
Matthias Bolte 已提交
1123

1124 1125 1126 1127 1128 1129 1130
    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 已提交
1131

1132
        if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
1133
            /* skip non-SCSI controllers */
M
Matthias Bolte 已提交
1134 1135 1136
            continue;
        }

1137
        controllerHasDisksAttached = false;
1138

1139 1140 1141 1142 1143 1144
        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;
1145 1146
                break;
            }
M
Matthias Bolte 已提交
1147 1148
        }

1149
        if (! controllerHasDisksAttached) {
1150
            /* skip SCSI controllers without attached disks */
1151 1152 1153
            continue;
        }

1154
        if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO &&
1155
            ctx->autodetectSCSIControllerModel != NULL) {
1156 1157
            count = 0;

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

                    ++count;
                }
            }

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

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

1190
        if (controller->model != -1 &&
1191 1192 1193 1194
            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) {
1195 1196 1197 1198 1199
            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));
1200
            goto cleanup;
M
Matthias Bolte 已提交
1201
        }
1202 1203 1204

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

1207 1208 1209 1210 1211 1212
    result = 0;

  cleanup:
    VIR_FREE(autodetectedModels);

    return result;
M
Matthias Bolte 已提交
1213 1214 1215 1216 1217 1218 1219 1220
}



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

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

1251
    if (ctx->parseFileName == NULL) {
1252 1253
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("virVMXContext has no parseFileName function set"));
1254 1255 1256
        return NULL;
    }

1257 1258 1259 1260 1261 1262
    conf = virConfReadMem(vmx, strlen(vmx), VIR_CONF_FLAG_VMX_FORMAT);

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

1263
    /* vmx:.encoding */
1264
    if (virVMXGetConfigString(conf, ".encoding", &encoding, true) < 0) {
1265 1266 1267 1268 1269 1270 1271 1272 1273
        goto cleanup;
    }

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

1274
        utf8 = virVMXConvertToUTF8(encoding, vmx);
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289

        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 */
1290
    if (VIR_ALLOC(def) < 0) {
1291
        virReportOOMError();
A
ajia@redhat.com 已提交
1292
        goto cleanup;
1293 1294
    }

1295
    def->virtType = VIR_DOMAIN_VIRT_VMWARE;
1296 1297
    def->id = -1;

M
Matthias Bolte 已提交
1298
    /* vmx:config.version */
1299 1300
    if (virVMXGetConfigLong(conf, "config.version", &config_version, 0,
                            false) < 0) {
M
Matthias Bolte 已提交
1301
        goto cleanup;
1302 1303 1304
    }

    if (config_version != 8) {
1305 1306 1307
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry 'config.version' to be 8 but found "
                         "%lld"), config_version);
M
Matthias Bolte 已提交
1308
        goto cleanup;
1309 1310
    }

M
Matthias Bolte 已提交
1311
    /* vmx:virtualHW.version */
1312 1313
    if (virVMXGetConfigLong(conf, "virtualHW.version", &virtualHW_version, 0,
                            false) < 0) {
M
Matthias Bolte 已提交
1314
        goto cleanup;
1315 1316
    }

P
Patrice LACHANCE 已提交
1317
    if (virtualHW_version != 4 && virtualHW_version != 7 &&
1318
        virtualHW_version != 8 && virtualHW_version != 9) {
1319
        virReportError(VIR_ERR_INTERNAL_ERROR,
1320 1321
                       _("Expecting VMX entry 'virtualHW.version' to be "
                         "4, 7, 8 or 9 but found %lld"),
1322
                       virtualHW_version);
M
Matthias Bolte 已提交
1323
        goto cleanup;
1324 1325
    }

M
Matthias Bolte 已提交
1326
    /* vmx:uuid.bios -> def:uuid */
1327
    /* FIXME: Need to handle 'uuid.action = "create"' */
1328
    if (virVMXGetConfigUUID(conf, "uuid.bios", def->uuid, true) < 0) {
M
Matthias Bolte 已提交
1329
        goto cleanup;
1330 1331
    }

M
Matthias Bolte 已提交
1332
    /* vmx:displayName -> def:name */
1333
    if (virVMXGetConfigString(conf, "displayName", &def->name, true) < 0) {
M
Matthias Bolte 已提交
1334
        goto cleanup;
1335 1336
    }

1337
    if (def->name != NULL) {
1338 1339
        if (virVMXUnescapeHexPercent(def->name) < 0 ||
            virVMXUnescapeHexPipe(def->name) < 0) {
1340 1341
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("VMX entry 'name' contains invalid escape sequence"));
1342 1343 1344 1345
            goto cleanup;
        }
    }

1346
    /* vmx:annotation -> def:description */
1347 1348
    if (virVMXGetConfigString(conf, "annotation", &def->description,
                              true) < 0) {
1349 1350 1351 1352
        goto cleanup;
    }

    if (def->description != NULL) {
1353
        if (virVMXUnescapeHexPipe(def->description) < 0) {
1354 1355 1356
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("VMX entry 'annotation' contains invalid escape "
                             "sequence"));
1357
            goto cleanup;
1358 1359 1360
        }
    }

1361
    /* vmx:memsize -> def:mem.max_balloon */
1362
    if (virVMXGetConfigLong(conf, "memsize", &memsize, 32, true) < 0) {
M
Matthias Bolte 已提交
1363
        goto cleanup;
1364 1365 1366
    }

    if (memsize <= 0 || memsize % 4 != 0) {
1367 1368 1369
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry 'memsize' to be an unsigned "
                         "integer (multiple of 4) but found %lld"), memsize);
M
Matthias Bolte 已提交
1370
        goto cleanup;
1371 1372
    }

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

1375
    /* vmx:sched.mem.max -> def:mem.cur_balloon */
1376 1377
    if (virVMXGetConfigLong(conf, "sched.mem.max", &sched_mem_max, memsize,
                            true) < 0) {
M
Matthias Bolte 已提交
1378
        goto cleanup;
1379 1380
    }

1381 1382
    if (sched_mem_max < 0) {
        sched_mem_max = memsize;
1383 1384
    }

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

1387 1388
    if (def->mem.cur_balloon > def->mem.max_balloon) {
        def->mem.cur_balloon = def->mem.max_balloon;
1389 1390
    }

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

    if (numvcpus <= 0 || (numvcpus % 2 != 0 && numvcpus != 1)) {
1413 1414 1415
        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 已提交
1416
        goto cleanup;
1417 1418
    }

E
Eric Blake 已提交
1419
    def->maxvcpus = def->vcpus = numvcpus;
1420

M
Matthias Bolte 已提交
1421
    /* vmx:sched.cpu.affinity -> def:cpumask */
1422
    /* NOTE: maps to VirtualMachine:config.cpuAffinity.affinitySet */
1423 1424
    if (virVMXGetConfigString(conf, "sched.cpu.affinity", &sched_cpu_affinity,
                              true) < 0) {
M
Matthias Bolte 已提交
1425
        goto cleanup;
1426 1427
    }

1428
    if (sched_cpu_affinity != NULL && STRCASENEQ(sched_cpu_affinity, "all")) {
1429 1430 1431
        const char *current = sched_cpu_affinity;
        int number, count = 0;

H
Hu Tao 已提交
1432
        cpumasklen = 0;
1433

H
Hu Tao 已提交
1434 1435
        def->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN);
        if (!def->cpumask) {
1436
            virReportOOMError();
M
Matthias Bolte 已提交
1437
            goto cleanup;
1438 1439 1440 1441 1442 1443 1444 1445
        }

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

            number = virParseNumber(&current);

            if (number < 0) {
1446 1447 1448 1449
                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 已提交
1450
                goto cleanup;
1451 1452 1453
            }

            if (number >= VIR_DOMAIN_CPUMASK_LEN) {
1454 1455 1456
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("VMX entry 'sched.cpu.affinity' contains a %d, "
                                 "this value is too large"), number);
M
Matthias Bolte 已提交
1457
                goto cleanup;
1458 1459
            }

H
Hu Tao 已提交
1460 1461
            if (number + 1 > cpumasklen) {
                cpumasklen = number + 1;
1462 1463
            }

H
Hu Tao 已提交
1464
            ignore_value(virBitmapSetBit(def->cpumask, number));
1465 1466 1467 1468 1469 1470 1471 1472 1473
            ++count;

            virSkipSpaces(&current);

            if (*current == ',') {
                ++current;
            } else if (*current == '\0') {
                break;
            } else {
1474 1475 1476 1477
                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 已提交
1478
                goto cleanup;
1479 1480 1481 1482 1483 1484
            }

            virSkipSpaces(&current);
        }

        if (count < numvcpus) {
1485 1486 1487 1488
            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 已提交
1489
            goto cleanup;
1490 1491 1492
        }
    }

1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508
    /* 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) {
1509 1510 1511 1512
            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);
1513 1514 1515 1516
            goto cleanup;
        }
    }

1517 1518 1519 1520 1521 1522
    /* def:lifecycle */
    def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
    def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
    def->onCrash = VIR_DOMAIN_LIFECYCLE_DESTROY;

    /* def:os */
1523
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
M
Matthias Bolte 已提交
1524
        goto cleanup;
1525

M
Matthias Bolte 已提交
1526
    /* vmx:guestOS -> def:os.arch */
1527
    if (virVMXGetConfigString(conf, "guestOS", &guestOS, true) < 0) {
M
Matthias Bolte 已提交
1528
        goto cleanup;
M
Matthias Bolte 已提交
1529 1530
    }

1531
    if (guestOS != NULL && virFileHasSuffix(guestOS, "-64")) {
1532
        def->os.arch = VIR_ARCH_X86_64;
M
Matthias Bolte 已提交
1533
    } else {
1534
        def->os.arch = VIR_ARCH_I686;
M
Matthias Bolte 已提交
1535 1536
    }

M
Matthias Bolte 已提交
1537
    /* vmx:smbios.reflecthost -> def:os.smbios_mode */
1538 1539
    if (virVMXGetConfigBoolean(conf, "smbios.reflecthost",
                               &smbios_reflecthost, false, true) < 0) {
M
Matthias Bolte 已提交
1540 1541 1542 1543 1544 1545 1546
        goto cleanup;
    }

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

1547 1548
    /* def:features */
    /* FIXME */
1549

1550 1551
    /* def:clock */
    /* FIXME */
1552 1553

    /* def:graphics */
M
Matthias Bolte 已提交
1554
    if (VIR_ALLOC_N(def->graphics, 1) < 0) {
1555
        virReportOOMError();
M
Matthias Bolte 已提交
1556
        goto cleanup;
M
Matthias Bolte 已提交
1557 1558 1559 1560
    }

    def->ngraphics = 0;

1561
    if (virVMXParseVNC(conf, &def->graphics[def->ngraphics]) < 0) {
M
Matthias Bolte 已提交
1562
        goto cleanup;
M
Matthias Bolte 已提交
1563 1564 1565 1566 1567
    }

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

M
Matthias Bolte 已提交
1569 1570
    /* def:disks: 4 * 15 scsi + 2 * 2 ide + 2 floppy = 66 */
    if (VIR_ALLOC_N(def->disks, 66) < 0) {
1571
        virReportOOMError();
M
Matthias Bolte 已提交
1572
        goto cleanup;
1573 1574 1575 1576 1577 1578
    }

    def->ndisks = 0;

    /* def:disks (scsi) */
    for (controller = 0; controller < 4; ++controller) {
1579 1580
        if (virVMXParseSCSIController(conf, controller, &present,
                                      &scsi_virtualDev[controller]) < 0) {
M
Matthias Bolte 已提交
1581
            goto cleanup;
1582 1583 1584 1585 1586 1587
        }

        if (! present) {
            continue;
        }

1588 1589
        for (unit = 0; unit < 16; ++unit) {
            if (unit == 7) {
1590
                /*
1591
                 * SCSI unit 7 is assigned to the SCSI controller and cannot be
1592 1593 1594 1595 1596
                 * used for disk devices.
                 */
                continue;
            }

1597
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
1598 1599
                                VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
                                &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1600
                goto cleanup;
1601 1602 1603 1604 1605 1606 1607
            }

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

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

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

    /* def:disks (ide) */
1621 1622
    for (bus = 0; bus < 2; ++bus) {
        for (unit = 0; unit < 2; ++unit) {
1623
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
1624 1625
                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
                                &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1626
                goto cleanup;
1627 1628 1629 1630 1631 1632 1633
            }

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

1634
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1635 1636
                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
                                &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1637
                goto cleanup;
1638 1639 1640 1641 1642 1643 1644 1645 1646
            }

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

    /* def:disks (floppy) */
1647
    for (unit = 0; unit < 2; ++unit) {
1648
        if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_FLOPPY,
1649 1650
                            VIR_DOMAIN_DISK_BUS_FDC, 0, unit,
                            &def->disks[def->ndisks]) < 0) {
M
Matthias Bolte 已提交
1651
            goto cleanup;
1652 1653 1654 1655 1656 1657 1658
        }

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

1659 1660
    /* def:controllers */
    if (virDomainDefAddImplicitControllers(def) < 0) {
1661
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not add controllers"));
1662 1663 1664 1665 1666 1667 1668
        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) {
1669 1670 1671
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("SCSI controller index %d out of [0..3] range"),
                               def->controllers[controller]->idx);
1672 1673 1674 1675 1676 1677 1678 1679
                goto cleanup;
            }

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

1680
    /* def:fss */
1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713
    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;
                }
            }
        }
    }
1714 1715 1716

    /* def:nets */
    if (VIR_ALLOC_N(def->nets, 4) < 0) {
1717
        virReportOOMError();
M
Matthias Bolte 已提交
1718
        goto cleanup;
1719 1720 1721 1722 1723
    }

    def->nnets = 0;

    for (controller = 0; controller < 4; ++controller) {
1724 1725
        if (virVMXParseEthernet(conf, controller,
                                &def->nets[def->nnets]) < 0) {
M
Matthias Bolte 已提交
1726
            goto cleanup;
1727 1728 1729 1730 1731 1732 1733 1734 1735 1736
        }

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

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

1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
    /* 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;

1751 1752 1753 1754 1755 1756 1757 1758
    /* def:sounds */
    /* FIXME */

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

    /* def:serials */
    if (VIR_ALLOC_N(def->serials, 4) < 0) {
1759
        virReportOOMError();
M
Matthias Bolte 已提交
1760
        goto cleanup;
1761 1762 1763 1764 1765
    }

    def->nserials = 0;

    for (port = 0; port < 4; ++port) {
1766 1767
        if (virVMXParseSerial(ctx, conf, port,
                              &def->serials[def->nserials]) < 0) {
M
Matthias Bolte 已提交
1768
            goto cleanup;
1769 1770 1771 1772 1773 1774 1775 1776 1777
        }

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

    /* def:parallels */
    if (VIR_ALLOC_N(def->parallels, 3) < 0) {
1778
        virReportOOMError();
M
Matthias Bolte 已提交
1779
        goto cleanup;
1780 1781 1782 1783 1784
    }

    def->nparallels = 0;

    for (port = 0; port < 3; ++port) {
1785 1786
        if (virVMXParseParallel(ctx, conf, port,
                                &def->parallels[def->nparallels]) < 0) {
M
Matthias Bolte 已提交
1787
            goto cleanup;
1788 1789 1790 1791 1792 1793 1794
        }

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

M
Matthias Bolte 已提交
1795 1796
    success = true;

M
Matthias Bolte 已提交
1797
  cleanup:
M
Matthias Bolte 已提交
1798 1799 1800 1801 1802
    if (! success) {
        virDomainDefFree(def);
        def = NULL;
    }

1803
    virConfFree(conf);
1804
    VIR_FREE(encoding);
1805
    VIR_FREE(sched_cpu_affinity);
1806
    VIR_FREE(sched_cpu_shares);
M
Matthias Bolte 已提交
1807
    VIR_FREE(guestOS);
1808 1809 1810 1811 1812 1813

    return def;
}



M
Matthias Bolte 已提交
1814
int
1815
virVMXParseVNC(virConfPtr conf, virDomainGraphicsDefPtr *def)
M
Matthias Bolte 已提交
1816
{
1817
    bool enabled = false;
M
Matthias Bolte 已提交
1818
    long long port = 0;
1819
    char *listenAddr = NULL;
M
Matthias Bolte 已提交
1820 1821

    if (def == NULL || *def != NULL) {
1822
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
1823 1824 1825
        return -1;
    }

1826 1827
    if (virVMXGetConfigBoolean(conf, "RemoteDisplay.vnc.enabled", &enabled,
                               false, true) < 0) {
M
Matthias Bolte 已提交
1828 1829 1830 1831 1832 1833 1834 1835
        return -1;
    }

    if (! enabled) {
        return 0;
    }

    if (VIR_ALLOC(*def) < 0) {
1836
        virReportOOMError();
M
Matthias Bolte 已提交
1837 1838 1839 1840 1841
        goto failure;
    }

    (*def)->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;

1842 1843 1844
    if (virVMXGetConfigLong(conf, "RemoteDisplay.vnc.port", &port, -1,
                            true) < 0 ||
        virVMXGetConfigString(conf, "RemoteDisplay.vnc.ip",
1845
                              &listenAddr, true) < 0 ||
1846 1847 1848 1849
        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 已提交
1850 1851 1852
        goto failure;
    }

1853 1854 1855 1856 1857 1858
    if (listenAddr) {
        if (virDomainGraphicsListenSetAddress(*def, 0, listenAddr, -1, true) < 0)
            goto failure;
        VIR_FREE(listenAddr);
    }

M
Matthias Bolte 已提交
1859
    if (port < 0) {
1860
        VIR_WARN("VNC is enabled but VMX entry 'RemoteDisplay.vnc.port' "
M
Matthias Bolte 已提交
1861 1862 1863
                  "is missing, the VNC port is unknown");

        (*def)->data.vnc.port = 0;
1864
        (*def)->data.vnc.autoport = true;
M
Matthias Bolte 已提交
1865 1866 1867 1868 1869 1870
    } else {
        if (port < 5900 || port > 5964) {
            VIR_WARN("VNC port %lld it out of [5900..5964] range", port);
        }

        (*def)->data.vnc.port = port;
1871
        (*def)->data.vnc.autoport = false;
M
Matthias Bolte 已提交
1872 1873 1874 1875 1876
    }

    return 0;

  failure:
1877
    VIR_FREE(listenAddr);
M
Matthias Bolte 已提交
1878 1879 1880 1881 1882 1883 1884 1885
    virDomainGraphicsDefFree(*def);
    *def = NULL;

    return -1;
}



1886
int
1887 1888
virVMXParseSCSIController(virConfPtr conf, int controller, bool *present,
                          int *virtualDev)
1889
{
1890
    int result = -1;
1891 1892
    char present_name[32];
    char virtualDev_name[32];
1893 1894
    char *virtualDev_string = NULL;
    char *tmp;
1895

1896
    if (virtualDev == NULL || *virtualDev != -1) {
1897
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1898
        return -1;
1899 1900 1901
    }

    if (controller < 0 || controller > 3) {
1902 1903 1904
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("SCSI controller index %d out of [0..3] range"),
                       controller);
1905
        return -1;
1906 1907
    }

1908 1909 1910
    snprintf(present_name, sizeof(present_name), "scsi%d.present", controller);
    snprintf(virtualDev_name, sizeof(virtualDev_name), "scsi%d.virtualDev",
             controller);
1911

1912
    if (virVMXGetConfigBoolean(conf, present_name, present, false, true) < 0) {
1913
        goto cleanup;
1914 1915 1916
    }

    if (! *present) {
1917 1918
        result = 0;
        goto cleanup;
1919 1920
    }

1921 1922
    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev_string,
                              true) < 0) {
1923
        goto cleanup;
1924 1925
    }

1926 1927 1928 1929 1930 1931 1932
    if (virtualDev_string != NULL) {
        tmp = virtualDev_string;

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

1933
        *virtualDev = virVMXControllerModelSCSITypeFromString(virtualDev_string);
1934 1935

        if (*virtualDev == -1 ||
1936 1937 1938 1939
            (*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)) {
1940 1941 1942 1943
            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);
1944
            goto cleanup;
1945
        }
1946 1947
    }

1948
    result = 0;
1949

1950
  cleanup:
1951
    VIR_FREE(virtualDev_string);
1952

1953
    return result;
1954 1955 1956 1957 1958
}



int
1959
virVMXParseDisk(virVMXContext *ctx, virDomainXMLOptionPtr xmlopt, virConfPtr conf,
1960 1961
                int device, int busType, int controllerOrBus, int unit,
                virDomainDiskDefPtr *def)
1962 1963
{
    /*
1964 1965 1966 1967
     *          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]
1968
     *
1969 1970 1971 1972
     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK, VIR_DOMAIN_DISK_DEVICE_CDROM}
     *         busType = VIR_DOMAIN_DISK_BUS_IDE
     * controllerOrBus = [0..1] -> bus
     *            unit = [0..1]
1973
     *
1974 1975 1976 1977
     *          device = VIR_DOMAIN_DISK_DEVICE_FLOPPY
     *         busType = VIR_DOMAIN_DISK_BUS_FDC
     * controllerOrBus = [0]
     *            unit = [0..1]
1978 1979
     */

M
Matthias Bolte 已提交
1980
    int result = -1;
1981 1982 1983
    char *prefix = NULL;

    char present_name[32] = "";
1984
    bool present = false;
1985 1986

    char startConnected_name[32] = "";
1987
    bool startConnected = false;
1988 1989 1990 1991 1992

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

    char clientDevice_name[32] = "";
1993
    bool clientDevice = false;
1994 1995 1996 1997 1998 1999 2000 2001

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

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

    char writeThrough_name[32] = "";
2002
    bool writeThrough = false;
2003 2004

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

    if (VIR_ALLOC(*def) < 0) {
2010
        virReportOOMError();
M
Matthias Bolte 已提交
2011
        return -1;
2012 2013 2014
    }

    (*def)->device = device;
2015
    (*def)->bus = busType;
2016 2017 2018 2019

    /* def:dst, def:driverName */
    if (device == VIR_DOMAIN_DISK_DEVICE_DISK ||
        device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
2020 2021
        if (busType == VIR_DOMAIN_DISK_BUS_SCSI) {
            if (controllerOrBus < 0 || controllerOrBus > 3) {
2022 2023 2024
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("SCSI controller index %d out of [0..3] range"),
                               controllerOrBus);
M
Matthias Bolte 已提交
2025
                goto cleanup;
2026 2027
            }

2028
            if (unit < 0 || unit > 15 || unit == 7) {
2029 2030 2031
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("SCSI unit index %d out of [0..6,8..15] range"),
                               unit);
M
Matthias Bolte 已提交
2032
                goto cleanup;
2033 2034
            }

2035
            if (virAsprintf(&prefix, "scsi%d:%d", controllerOrBus, unit) < 0) {
2036
                virReportOOMError();
M
Matthias Bolte 已提交
2037
                goto cleanup;
2038 2039
            }

M
Matthias Bolte 已提交
2040
            (*def)->dst =
2041
               virIndexToDiskName
2042
                 (controllerOrBus * 15 + (unit < 7 ? unit : unit - 1), "sd");
2043 2044

            if ((*def)->dst == NULL) {
M
Matthias Bolte 已提交
2045
                goto cleanup;
2046
            }
2047 2048
        } else if (busType == VIR_DOMAIN_DISK_BUS_IDE) {
            if (controllerOrBus < 0 || controllerOrBus > 1) {
2049 2050 2051
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("IDE bus index %d out of [0..1] range"),
                               controllerOrBus);
M
Matthias Bolte 已提交
2052
                goto cleanup;
2053 2054
            }

2055
            if (unit < 0 || unit > 1) {
2056 2057
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("IDE unit index %d out of [0..1] range"), unit);
M
Matthias Bolte 已提交
2058
                goto cleanup;
2059 2060
            }

2061
            if (virAsprintf(&prefix, "ide%d:%d", controllerOrBus, unit) < 0) {
2062
                virReportOOMError();
M
Matthias Bolte 已提交
2063
                goto cleanup;
2064 2065
            }

2066
            (*def)->dst = virIndexToDiskName(controllerOrBus * 2 + unit, "hd");
2067 2068

            if ((*def)->dst == NULL) {
M
Matthias Bolte 已提交
2069
                goto cleanup;
2070 2071
            }
        } else {
2072 2073 2074 2075
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported bus type '%s' for device type '%s'"),
                           virDomainDiskBusTypeToString(busType),
                           virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2076
            goto cleanup;
2077 2078
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2079 2080
        if (busType == VIR_DOMAIN_DISK_BUS_FDC) {
            if (controllerOrBus != 0) {
2081 2082 2083
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("FDC controller index %d out of [0] range"),
                               controllerOrBus);
2084 2085 2086 2087
                goto cleanup;
            }

            if (unit < 0 || unit > 1) {
2088 2089 2090
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("FDC unit index %d out of [0..1] range"),
                               unit);
M
Matthias Bolte 已提交
2091
                goto cleanup;
2092 2093
            }

2094
            if (virAsprintf(&prefix, "floppy%d", unit) < 0) {
2095
                virReportOOMError();
M
Matthias Bolte 已提交
2096
                goto cleanup;
2097 2098
            }

2099
            (*def)->dst = virIndexToDiskName(unit, "fd");
2100 2101

            if ((*def)->dst == NULL) {
M
Matthias Bolte 已提交
2102
                goto cleanup;
2103 2104
            }
        } else {
2105 2106 2107 2108
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported bus type '%s' for device type '%s'"),
                           virDomainDiskBusTypeToString(busType),
                           virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2109
            goto cleanup;
2110 2111
        }
    } else {
2112 2113 2114
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported device type '%s'"),
                       virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2115
        goto cleanup;
2116 2117
    }

2118 2119 2120 2121 2122 2123 2124
    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);
2125 2126

    /* vmx:present */
2127
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2128
        goto cleanup;
2129 2130 2131
    }

    /* vmx:startConnected */
2132 2133
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2134
        goto cleanup;
2135 2136 2137 2138 2139 2140 2141 2142
    }

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

    /* vmx:deviceType -> def:type */
2143
    if (virVMXGetConfigString(conf, deviceType_name, &deviceType, true) < 0) {
M
Matthias Bolte 已提交
2144
        goto cleanup;
2145 2146 2147
    }

    /* vmx:clientDevice */
2148 2149
    if (virVMXGetConfigBoolean(conf, clientDevice_name, &clientDevice, false,
                               true) < 0) {
M
Matthias Bolte 已提交
2150
        goto cleanup;
2151 2152 2153 2154 2155
    }

    if (clientDevice) {
        /*
         * Just ignore devices in client mode, because I have no clue how to
M
Matthias Bolte 已提交
2156
         * handle them (e.g. assign an image) without the VI Client GUI.
2157 2158 2159 2160 2161
         */
        goto ignore;
    }

    /* vmx:fileType -> def:type */
2162
    if (virVMXGetConfigString(conf, fileType_name, &fileType, true) < 0) {
M
Matthias Bolte 已提交
2163
        goto cleanup;
2164 2165 2166
    }

    /* vmx:fileName -> def:src, def:type */
2167
    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0) {
M
Matthias Bolte 已提交
2168
        goto cleanup;
2169 2170 2171
    }

    /* vmx:writeThrough -> def:cachemode */
2172 2173
    if (virVMXGetConfigBoolean(conf, writeThrough_name, &writeThrough, false,
                               true) < 0) {
M
Matthias Bolte 已提交
2174
        goto cleanup;
2175 2176 2177 2178
    }

    /* Setup virDomainDiskDef */
    if (device == VIR_DOMAIN_DISK_DEVICE_DISK) {
2179
        if (virFileHasSuffix(fileName, ".vmdk")) {
2180
            if (deviceType != NULL) {
2181
                if (busType == VIR_DOMAIN_DISK_BUS_SCSI &&
2182 2183
                    STRCASENEQ(deviceType, "scsi-hardDisk") &&
                    STRCASENEQ(deviceType, "disk")) {
2184 2185 2186 2187
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'scsi-hardDisk' "
                                     "or 'disk' but found '%s'"), deviceType_name,
                                   deviceType);
M
Matthias Bolte 已提交
2188
                    goto cleanup;
2189
                } else if (busType == VIR_DOMAIN_DISK_BUS_IDE &&
2190 2191
                           STRCASENEQ(deviceType, "ata-hardDisk") &&
                           STRCASENEQ(deviceType, "disk")) {
2192 2193 2194 2195
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'ata-hardDisk' "
                                     "or 'disk' but found '%s'"), deviceType_name,
                                   deviceType);
M
Matthias Bolte 已提交
2196
                    goto cleanup;
2197 2198 2199 2200
                }
            }

            (*def)->type = VIR_DOMAIN_DISK_TYPE_FILE;
2201
            (*def)->src = ctx->parseFileName(fileName, ctx->opaque);
2202 2203 2204
            (*def)->cachemode = writeThrough ? VIR_DOMAIN_DISK_CACHE_WRITETHRU
                                             : VIR_DOMAIN_DISK_CACHE_DEFAULT;

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

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

M
Matthias Bolte 已提交
2237
            if ((*def)->src == NULL) {
M
Matthias Bolte 已提交
2238
                goto cleanup;
M
Matthias Bolte 已提交
2239
            }
2240
        } else if (virFileHasSuffix(fileName, ".vmdk")) {
2241 2242 2243 2244 2245 2246 2247
            /*
             * 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;
2248
        } else if (STRCASEEQ(deviceType, "atapi-cdrom")) {
2249 2250 2251 2252 2253
            (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
            (*def)->src = fileName;

            fileName = NULL;
        } else {
2254 2255 2256
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid or not yet handled value '%s' for VMX entry "
                             "'%s'"), fileName, fileName_name);
M
Matthias Bolte 已提交
2257
            goto cleanup;
2258 2259
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2260
        if (virFileHasSuffix(fileName, ".flp")) {
2261 2262
            if (fileType != NULL) {
                if (STRCASENEQ(fileType, "file")) {
2263 2264 2265
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'file' but "
                                     "found '%s'"), fileType_name, fileType);
M
Matthias Bolte 已提交
2266
                    goto cleanup;
2267 2268 2269 2270
                }
            }

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

M
Matthias Bolte 已提交
2273
            if ((*def)->src == NULL) {
M
Matthias Bolte 已提交
2274
                goto cleanup;
M
Matthias Bolte 已提交
2275
            }
2276
        } else if (fileType != NULL && STRCASEEQ(fileType, "device")) {
2277 2278 2279 2280 2281
            (*def)->type = VIR_DOMAIN_DISK_TYPE_BLOCK;
            (*def)->src = fileName;

            fileName = NULL;
        } else {
2282 2283 2284
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Invalid or not yet handled value '%s' for VMX entry "
                             "'%s'"), fileName, fileName_name);
M
Matthias Bolte 已提交
2285
            goto cleanup;
2286 2287
        }
    } else {
2288 2289
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported device type '%s'"),
                       virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2290
        goto cleanup;
2291 2292
    }

2293
    if (virDomainDiskDefAssignAddress(xmlopt, *def) < 0) {
2294 2295
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not assign address to disk '%s'"), (*def)->src);
2296 2297 2298
        goto cleanup;
    }

M
Matthias Bolte 已提交
2299 2300
    result = 0;

M
Matthias Bolte 已提交
2301
  cleanup:
M
Matthias Bolte 已提交
2302 2303 2304 2305 2306
    if (result < 0) {
        virDomainDiskDefFree(*def);
        *def = NULL;
    }

2307 2308 2309 2310 2311 2312 2313
    VIR_FREE(prefix);
    VIR_FREE(deviceType);
    VIR_FREE(fileType);
    VIR_FREE(fileName);

    return result;

M
Matthias Bolte 已提交
2314
  ignore:
2315 2316 2317
    virDomainDiskDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2318 2319
    result = 0;

2320 2321 2322 2323 2324
    goto cleanup;
}



2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 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
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;
}



2427
int
2428
virVMXParseEthernet(virConfPtr conf, int controller, virDomainNetDefPtr *def)
2429
{
M
Matthias Bolte 已提交
2430
    int result = -1;
2431 2432 2433
    char prefix[48] = "";

    char present_name[48] = "";
2434
    bool present = false;
2435 2436

    char startConnected_name[48] = "";
2437
    bool startConnected = false;
2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453

    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;

2454 2455 2456
    char features_name[48] = "";
    long long features = 0;

2457 2458 2459
    char vnet_name[48] = "";
    char *vnet = NULL;

M
Matthias Bolte 已提交
2460 2461 2462
    char networkName_name[48] = "";
    char *networkName = NULL;

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

    if (controller < 0 || controller > 3) {
2469 2470 2471
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Ethernet controller index %d out of [0..3] range"),
                       controller);
2472
        return -1;
2473 2474 2475
    }

    if (VIR_ALLOC(*def) < 0) {
2476
        virReportOOMError();
M
Matthias Bolte 已提交
2477
        return -1;
2478 2479
    }

2480
    snprintf(prefix, sizeof(prefix), "ethernet%d", controller);
2481

2482 2483 2484 2485 2486 2487 2488 2489 2490 2491
    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);
2492 2493

    /* vmx:present */
2494
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2495
        goto cleanup;
2496 2497 2498
    }

    /* vmx:startConnected */
2499 2500
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2501
        goto cleanup;
2502 2503 2504 2505 2506 2507 2508 2509
    }

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

    /* vmx:connectionType -> def:type */
2510 2511
    if (virVMXGetConfigString(conf, connectionType_name, &connectionType,
                              true) < 0) {
M
Matthias Bolte 已提交
2512
        goto cleanup;
2513 2514 2515
    }

    /* vmx:addressType, vmx:generatedAddress, vmx:address -> def:mac */
2516 2517 2518 2519 2520
    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 已提交
2521
        goto cleanup;
2522 2523
    }

2524 2525
    if (addressType == NULL || STRCASEEQ(addressType, "generated") ||
        STRCASEEQ(addressType, "vpx")) {
2526
        if (generatedAddress != NULL) {
2527
            if (virMacAddrParse(generatedAddress, &(*def)->mac) < 0) {
2528 2529 2530 2531
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry '%s' to be MAC address but "
                                 "found '%s'"), generatedAddress_name,
                               generatedAddress);
M
Matthias Bolte 已提交
2532
                goto cleanup;
2533 2534 2535 2536
            }
        }
    } else if (STRCASEEQ(addressType, "static")) {
        if (address != NULL) {
2537
            if (virMacAddrParse(address, &(*def)->mac) < 0) {
2538 2539 2540
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry '%s' to be MAC address but "
                                 "found '%s'"), address_name, address);
M
Matthias Bolte 已提交
2541
                goto cleanup;
2542 2543 2544
            }
        }
    } else {
2545 2546 2547
        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 已提交
2548
        goto cleanup;
2549 2550
    }

2551
    /* vmx:virtualDev, vmx:features -> def:model */
2552 2553
    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev, true) < 0 ||
        virVMXGetConfigLong(conf, features_name, &features, 0, true) < 0) {
M
Matthias Bolte 已提交
2554
        goto cleanup;
2555 2556
    }

2557 2558 2559 2560 2561
    if (virtualDev != NULL) {
        if (STRCASENEQ(virtualDev, "vlance") &&
            STRCASENEQ(virtualDev, "vmxnet") &&
            STRCASENEQ(virtualDev, "vmxnet3") &&
            STRCASENEQ(virtualDev, "e1000")) {
2562 2563 2564 2565
            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 已提交
2566
            goto cleanup;
2567 2568 2569 2570 2571
        }

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

2572
            if (VIR_STRDUP(virtualDev, "vmxnet2") < 0)
M
Matthias Bolte 已提交
2573
                goto cleanup;
2574
        }
2575 2576
    }

M
Matthias Bolte 已提交
2577
    /* vmx:networkName -> def:data.bridge.brname */
2578 2579 2580 2581 2582 2583 2584
    if (connectionType == NULL ||
        STRCASEEQ(connectionType, "bridged") ||
        STRCASEEQ(connectionType, "custom")) {
        if (virVMXGetConfigString(conf, networkName_name, &networkName,
                                  true) < 0)
            goto cleanup;

2585 2586
        if (!networkName && VIR_STRDUP(networkName, "") < 0)
            goto cleanup;
M
Matthias Bolte 已提交
2587 2588 2589
    }

    /* vmx:vnet -> def:data.ifname */
2590
    if (connectionType != NULL && STRCASEEQ(connectionType, "custom") &&
2591
        virVMXGetConfigString(conf, vnet_name, &vnet, false) < 0) {
M
Matthias Bolte 已提交
2592
        goto cleanup;
2593 2594 2595 2596 2597 2598
    }

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

        virtualDev = NULL;
M
Matthias Bolte 已提交
2602
        networkName = NULL;
2603 2604
    } else if (STRCASEEQ(connectionType, "hostonly")) {
        /* FIXME */
2605 2606 2607
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No yet handled value '%s' for VMX entry '%s'"),
                       connectionType, connectionType_name);
M
Matthias Bolte 已提交
2608
        goto cleanup;
2609
    } else if (STRCASEEQ(connectionType, "nat")) {
2610 2611 2612 2613
        (*def)->type = VIR_DOMAIN_NET_TYPE_USER;
        (*def)->model = virtualDev;

        virtualDev = NULL;
2614 2615 2616
    } else if (STRCASEEQ(connectionType, "custom")) {
        (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
        (*def)->model = virtualDev;
M
Matthias Bolte 已提交
2617 2618
        (*def)->data.bridge.brname = networkName;
        (*def)->ifname = vnet;
2619 2620

        virtualDev = NULL;
M
Matthias Bolte 已提交
2621
        networkName = NULL;
2622 2623
        vnet = NULL;
    } else {
2624 2625 2626
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid value '%s' for VMX entry '%s'"), connectionType,
                       connectionType_name);
M
Matthias Bolte 已提交
2627
        goto cleanup;
2628 2629
    }

M
Matthias Bolte 已提交
2630 2631
    result = 0;

M
Matthias Bolte 已提交
2632
  cleanup:
M
Matthias Bolte 已提交
2633 2634 2635 2636 2637
    if (result < 0) {
        virDomainNetDefFree(*def);
        *def = NULL;
    }

S
Stefan Berger 已提交
2638
    VIR_FREE(networkName);
2639 2640 2641 2642 2643 2644 2645 2646 2647
    VIR_FREE(connectionType);
    VIR_FREE(addressType);
    VIR_FREE(generatedAddress);
    VIR_FREE(address);
    VIR_FREE(virtualDev);
    VIR_FREE(vnet);

    return result;

M
Matthias Bolte 已提交
2648
  ignore:
2649 2650 2651
    virDomainNetDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2652 2653
    result = 0;

2654 2655 2656 2657 2658 2659
    goto cleanup;
}



int
2660 2661
virVMXParseSerial(virVMXContext *ctx, virConfPtr conf, int port,
                  virDomainChrDefPtr *def)
2662
{
M
Matthias Bolte 已提交
2663
    int result = -1;
2664 2665 2666
    char prefix[48] = "";

    char present_name[48] = "";
2667
    bool present = false;
2668 2669

    char startConnected_name[48] = "";
2670
    bool startConnected = false;
2671 2672 2673 2674 2675 2676 2677

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

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

2678 2679 2680
    char network_endPoint_name[48] = "";
    char *network_endPoint = NULL;

M
Martin Kletzander 已提交
2681
    virURIPtr parsedUri = NULL;
2682

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

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

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

2699
    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
2700

2701
    snprintf(prefix, sizeof(prefix), "serial%d", port);
2702

2703 2704 2705 2706 2707
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
    VMX_BUILD_NAME_EXTRA(network_endPoint, "network.endPoint");
2708 2709

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

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

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

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

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

2735
    /* vmx:network.endPoint -> def:data.tcp.listen */
2736 2737
    if (virVMXGetConfigString(conf, network_endPoint_name, &network_endPoint,
                              true) < 0) {
2738 2739 2740
        goto cleanup;
    }

2741 2742
    /* Setup virDomainChrDef */
    if (STRCASEEQ(fileType, "device")) {
2743
        (*def)->target.port = port;
2744 2745
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
        (*def)->source.data.file.path = fileName;
2746 2747 2748

        fileName = NULL;
    } else if (STRCASEEQ(fileType, "file")) {
2749
        (*def)->target.port = port;
2750 2751 2752
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
        (*def)->source.data.file.path = ctx->parseFileName(fileName,
                                                           ctx->opaque);
2753

2754
        if ((*def)->source.data.file.path == NULL) {
M
Matthias Bolte 已提交
2755
            goto cleanup;
M
Matthias Bolte 已提交
2756
        }
2757
    } else if (STRCASEEQ(fileType, "pipe")) {
M
Matthias Bolte 已提交
2758 2759 2760 2761
        /*
         * FIXME: Differences between client/server and VM/application pipes
         *        not representable in domain XML form
         */
2762
        (*def)->target.port = port;
2763 2764
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
        (*def)->source.data.file.path = fileName;
M
Matthias Bolte 已提交
2765 2766

        fileName = NULL;
2767 2768
    } else if (STRCASEEQ(fileType, "network")) {
        (*def)->target.port = port;
2769
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_TCP;
2770

2771
        if (!(parsedUri = virURIParse(fileName)))
2772 2773 2774
            goto cleanup;

        if (parsedUri->port == 0) {
2775 2776 2777
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("VMX entry '%s' doesn't contain a port part"),
                           fileName_name);
2778 2779 2780
            goto cleanup;
        }

2781
        if (VIR_STRDUP((*def)->source.data.tcp.host, parsedUri->server) < 0)
2782 2783
            goto cleanup;

2784 2785
        if (virAsprintf(&(*def)->source.data.tcp.service, "%d",
                        parsedUri->port) < 0) {
2786 2787 2788 2789 2790 2791 2792 2793 2794
            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")) {
2795
            (*def)->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
2796
        } else if (STRCASEEQ(parsedUri->scheme, "telnet")) {
2797 2798
            (*def)->source.data.tcp.protocol
                = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
2799
        } else if (STRCASEEQ(parsedUri->scheme, "telnets")) {
2800 2801
            (*def)->source.data.tcp.protocol
                = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS;
2802 2803 2804 2805
        } else if (STRCASEEQ(parsedUri->scheme, "ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp+ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp4+ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp6+ssl")) {
2806
            (*def)->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS;
2807
        } else {
2808 2809 2810
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("VMX entry '%s' contains unsupported scheme '%s'"),
                           fileName_name, parsedUri->scheme);
2811 2812 2813 2814
            goto cleanup;
        }

        if (network_endPoint == NULL || STRCASEEQ(network_endPoint, "server")) {
2815
            (*def)->source.data.tcp.listen = true;
2816
        } else if (STRCASEEQ(network_endPoint, "client")) {
2817
            (*def)->source.data.tcp.listen = false;
2818
        } else {
2819 2820 2821
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting VMX entry '%s' to be 'server' or 'client' "
                             "but found '%s'"), network_endPoint_name, network_endPoint);
2822 2823
            goto cleanup;
        }
2824
    } else {
2825 2826 2827
        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 已提交
2828
        goto cleanup;
2829 2830
    }

M
Matthias Bolte 已提交
2831 2832
    result = 0;

M
Matthias Bolte 已提交
2833
  cleanup:
M
Matthias Bolte 已提交
2834 2835 2836 2837 2838
    if (result < 0) {
        virDomainChrDefFree(*def);
        *def = NULL;
    }

2839 2840
    VIR_FREE(fileType);
    VIR_FREE(fileName);
2841
    VIR_FREE(network_endPoint);
2842
    virURIFree(parsedUri);
2843 2844 2845

    return result;

M
Matthias Bolte 已提交
2846
  ignore:
2847 2848 2849
    virDomainChrDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2850 2851
    result = 0;

2852 2853 2854 2855 2856 2857
    goto cleanup;
}



int
2858 2859
virVMXParseParallel(virVMXContext *ctx, virConfPtr conf, int port,
                    virDomainChrDefPtr *def)
2860
{
M
Matthias Bolte 已提交
2861
    int result = -1;
2862 2863 2864
    char prefix[48] = "";

    char present_name[48] = "";
2865
    bool present = false;
2866 2867

    char startConnected_name[48] = "";
2868
    bool startConnected = false;
2869 2870 2871 2872 2873 2874 2875 2876

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

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

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

    if (port < 0 || port > 2) {
2882 2883
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parallel port index %d out of [0..2] range"), port);
2884
        return -1;
2885 2886 2887
    }

    if (VIR_ALLOC(*def) < 0) {
2888
        virReportOOMError();
M
Matthias Bolte 已提交
2889
        return -1;
2890 2891
    }

2892
    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
2893

2894
    snprintf(prefix, sizeof(prefix), "parallel%d", port);
2895

2896 2897 2898 2899
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
2900 2901

    /* vmx:present */
2902
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0) {
M
Matthias Bolte 已提交
2903
        goto cleanup;
2904 2905 2906
    }

    /* vmx:startConnected */
2907 2908
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2909
        goto cleanup;
2910 2911 2912 2913 2914 2915 2916 2917
    }

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

    /* vmx:fileType -> def:type */
2918
    if (virVMXGetConfigString(conf, fileType_name, &fileType, false) < 0) {
M
Matthias Bolte 已提交
2919
        goto cleanup;
2920 2921 2922
    }

    /* vmx:fileName -> def:data.file.path */
2923
    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0) {
M
Matthias Bolte 已提交
2924
        goto cleanup;
2925 2926 2927 2928
    }

    /* Setup virDomainChrDef */
    if (STRCASEEQ(fileType, "device")) {
2929
        (*def)->target.port = port;
2930 2931
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
        (*def)->source.data.file.path = fileName;
2932 2933 2934

        fileName = NULL;
    } else if (STRCASEEQ(fileType, "file")) {
2935
        (*def)->target.port = port;
2936 2937 2938
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
        (*def)->source.data.file.path = ctx->parseFileName(fileName,
                                                           ctx->opaque);
2939

2940
        if ((*def)->source.data.file.path == NULL) {
M
Matthias Bolte 已提交
2941
            goto cleanup;
M
Matthias Bolte 已提交
2942
        }
2943
    } else {
2944 2945 2946
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry '%s' to be 'device' or 'file' but "
                         "found '%s'"), fileType_name, fileType);
M
Matthias Bolte 已提交
2947
        goto cleanup;
2948 2949
    }

M
Matthias Bolte 已提交
2950 2951
    result = 0;

M
Matthias Bolte 已提交
2952
  cleanup:
M
Matthias Bolte 已提交
2953 2954 2955 2956 2957
    if (result < 0) {
        virDomainChrDefFree(*def);
        *def = NULL;
    }

2958 2959 2960 2961 2962
    VIR_FREE(fileType);
    VIR_FREE(fileName);

    return result;

M
Matthias Bolte 已提交
2963
  ignore:
2964 2965 2966
    virDomainChrDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2967 2968
    result = 0;

2969 2970
    goto cleanup;
}
M
Matthias Bolte 已提交
2971 2972 2973



2974 2975 2976 2977 2978 2979 2980
int
virVMXParseSVGA(virConfPtr conf, virDomainVideoDefPtr *def)
{
    int result = -1;
    long long svga_vramSize = 0;

    if (def == NULL || *def != NULL) {
2981
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997
        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;
    }

2998
    (*def)->vram = VIR_DIV_UP(svga_vramSize, 1024); /* Scale from bytes to kilobytes */
2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012

    result = 0;

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

    return result;
}



M
Matthias Bolte 已提交
3013 3014 3015 3016 3017
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Domain XML -> VMX
 */

char *
3018
virVMXFormatConfig(virVMXContext *ctx, virDomainXMLOptionPtr xmlopt, virDomainDefPtr def,
3019
                   int virtualHW_version)
M
Matthias Bolte 已提交
3020
{
3021
    char *vmx = NULL;
M
Matthias Bolte 已提交
3022 3023 3024 3025
    int i;
    int sched_cpu_affinity_length;
    unsigned char zero[VIR_UUID_BUFLEN];
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
3026 3027
    char *preliminaryDisplayName = NULL;
    char *displayName = NULL;
3028
    char *annotation = NULL;
3029
    unsigned long long max_balloon;
3030 3031
    bool scsi_present[4] = { false, false, false, false };
    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
3032
    bool floppy_present[2] = { false, false };
M
Matthias Bolte 已提交
3033

3034
    if (ctx->formatFileName == NULL) {
3035 3036
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("virVMXContext has no formatFileName function set"));
3037 3038 3039
        return NULL;
    }

M
Matthias Bolte 已提交
3040 3041
    memset(zero, 0, VIR_UUID_BUFLEN);

3042
    if (def->virtType != VIR_DOMAIN_VIRT_VMWARE) {
3043 3044 3045 3046
        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 已提交
3047 3048 3049
        return NULL;
    }

3050 3051 3052
    /* vmx:.encoding */
    virBufferAddLit(&buffer, ".encoding = \"UTF-8\"\n");

M
Matthias Bolte 已提交
3053 3054 3055 3056
    /* vmx:config.version */
    virBufferAddLit(&buffer, "config.version = \"8\"\n");

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

M
Matthias Bolte 已提交
3060
    /* def:os.arch -> vmx:guestOS */
3061
    if (def->os.arch == VIR_ARCH_I686) {
M
Matthias Bolte 已提交
3062
        virBufferAddLit(&buffer, "guestOS = \"other\"\n");
3063
    } else if (def->os.arch == VIR_ARCH_X86_64) {
M
Matthias Bolte 已提交
3064 3065
        virBufferAddLit(&buffer, "guestOS = \"other-64\"\n");
    } else {
3066 3067
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting domain XML attribute 'arch' of entry 'os/type' "
3068 3069
                         "to be 'i686' or 'x86_64' but found '%s'"),
                       virArchToString(def->os.arch));
3070
        goto cleanup;
M
Matthias Bolte 已提交
3071 3072
    }

M
Matthias Bolte 已提交
3073 3074 3075 3076 3077 3078 3079
    /* 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 {
3080 3081 3082
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported SMBIOS mode '%s'"),
                       virDomainSmbiosModeTypeToString(def->os.smbios_mode));
M
Matthias Bolte 已提交
3083 3084 3085
        goto cleanup;
    }

M
Matthias Bolte 已提交
3086 3087 3088 3089
    /* def:uuid -> vmx:uuid.action, vmx:uuid.bios */
    if (memcmp(def->uuid, zero, VIR_UUID_BUFLEN) == 0) {
        virBufferAddLit(&buffer, "uuid.action = \"create\"\n");
    } else {
3090
        virBufferAsprintf(&buffer, "uuid.bios = \"%02x %02x %02x %02x %02x %02x "
M
Matthias Bolte 已提交
3091 3092 3093 3094 3095 3096 3097 3098 3099
                          "%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 */
3100
    preliminaryDisplayName = virVMXEscapeHexPipe(def->name);
3101

3102 3103 3104
    if (preliminaryDisplayName == NULL) {
        goto cleanup;
    }
3105

3106
    displayName = virVMXEscapeHexPercent(preliminaryDisplayName);
3107

3108 3109 3110
    if (displayName == NULL) {
        goto cleanup;
    }
3111

3112
    virBufferAsprintf(&buffer, "displayName = \"%s\"\n", displayName);
3113

3114 3115
    /* def:description -> vmx:annotation */
    if (def->description != NULL) {
3116
        annotation = virVMXEscapeHexPipe(def->description);
3117

3118
        virBufferAsprintf(&buffer, "annotation = \"%s\"\n", annotation);
3119 3120
    }

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

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

3128
    /* def:mem.cur_balloon -> vmx:sched.mem.max */
3129
    if (def->mem.cur_balloon < max_balloon) {
3130
        virBufferAsprintf(&buffer, "sched.mem.max = \"%llu\"\n",
3131 3132
                          VIR_DIV_UP(def->mem.cur_balloon,
                                     1024)); /* Scale from kilobytes to megabytes */
M
Matthias Bolte 已提交
3133 3134
    }

3135 3136
    /* def:mem.min_guarantee -> vmx:sched.mem.minsize */
    if (def->mem.min_guarantee > 0) {
3137
        virBufferAsprintf(&buffer, "sched.mem.minsize = \"%llu\"\n",
3138 3139
                          VIR_DIV_UP(def->mem.min_guarantee,
                                     1024)); /* Scale from kilobytes to megabytes */
3140 3141
    }

E
Eric Blake 已提交
3142 3143
    /* def:maxvcpus -> vmx:numvcpus */
    if (def->vcpus != def->maxvcpus) {
3144 3145 3146
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("No support for domain XML entry 'vcpu' attribute "
                         "'current'"));
E
Eric Blake 已提交
3147 3148 3149
        goto cleanup;
    }
    if (def->maxvcpus <= 0 || (def->maxvcpus % 2 != 0 && def->maxvcpus != 1)) {
3150 3151 3152 3153
        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);
3154
        goto cleanup;
M
Matthias Bolte 已提交
3155 3156
    }

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

    /* def:cpumask -> vmx:sched.cpu.affinity */
H
Hu Tao 已提交
3160
    if (def->cpumask && virBitmapSize(def->cpumask) > 0) {
M
Matthias Bolte 已提交
3161 3162 3163 3164
        virBufferAddLit(&buffer, "sched.cpu.affinity = \"");

        sched_cpu_affinity_length = 0;

H
Hu Tao 已提交
3165 3166 3167
        i = -1;
        while ((i = virBitmapNextSetBit(def->cpumask, i)) >= 0) {
            ++sched_cpu_affinity_length;
M
Matthias Bolte 已提交
3168 3169
        }

E
Eric Blake 已提交
3170
        if (sched_cpu_affinity_length < def->maxvcpus) {
3171 3172 3173 3174
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting domain XML attribute 'cpuset' of entry "
                             "'vcpu' to contain at least %d CPU(s)"),
                           def->maxvcpus);
3175
            goto cleanup;
M
Matthias Bolte 已提交
3176 3177
        }

H
Hu Tao 已提交
3178 3179 3180
        i = -1;
        while ((i = virBitmapNextSetBit(def->cpumask, i)) >= 0) {
            virBufferAsprintf(&buffer, "%d", i);
M
Matthias Bolte 已提交
3181

H
Hu Tao 已提交
3182 3183
            if (sched_cpu_affinity_length > 1) {
                virBufferAddChar(&buffer, ',');
M
Matthias Bolte 已提交
3184
            }
H
Hu Tao 已提交
3185 3186

            --sched_cpu_affinity_length;
M
Matthias Bolte 已提交
3187 3188 3189 3190 3191
        }

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

3192 3193 3194 3195 3196 3197 3198 3199 3200 3201
    /* 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 {
3202
            virBufferAsprintf(&buffer, "sched.cpu.shares = \"%lu\"\n",
3203 3204 3205 3206
                              def->cputune.shares);
        }
    }

M
Matthias Bolte 已提交
3207 3208 3209 3210
    /* def:graphics */
    for (i = 0; i < def->ngraphics; ++i) {
        switch (def->graphics[i]->type) {
          case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
3211
            if (virVMXFormatVNC(def->graphics[i], &buffer) < 0) {
3212
                goto cleanup;
M
Matthias Bolte 已提交
3213 3214 3215 3216 3217
            }

            break;

          default:
3218 3219 3220
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported graphics type '%s'"),
                           virDomainGraphicsTypeToString(def->graphics[i]->type));
3221
            goto cleanup;
M
Matthias Bolte 已提交
3222 3223 3224
        }
    }

M
Matthias Bolte 已提交
3225
    /* def:disks */
3226
    for (i = 0; i < def->ndisks; ++i) {
3227
        if (virVMXVerifyDiskAddress(xmlopt, def->disks[i]) < 0 ||
3228
            virVMXHandleLegacySCSIDiskDriverName(def, def->disks[i]) < 0) {
3229
            goto cleanup;
3230 3231
        }
    }
M
Matthias Bolte 已提交
3232

3233 3234
    if (virVMXGatherSCSIControllers(ctx, def, scsi_virtualDev,
                                    scsi_present) < 0) {
3235
        goto cleanup;
M
Matthias Bolte 已提交
3236 3237 3238 3239
    }

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

3242
            if (scsi_virtualDev[i] != -1) {
3243
                virBufferAsprintf(&buffer, "scsi%d.virtualDev = \"%s\"\n", i,
3244
                                  virVMXControllerModelSCSITypeToString
3245
                                    (scsi_virtualDev[i]));
M
Matthias Bolte 已提交
3246 3247 3248 3249 3250 3251 3252
            }
        }
    }

    for (i = 0; i < def->ndisks; ++i) {
        switch (def->disks[i]->device) {
          case VIR_DOMAIN_DISK_DEVICE_DISK:
3253
            if (virVMXFormatHardDisk(ctx, def->disks[i], &buffer) < 0) {
3254
                goto cleanup;
M
Matthias Bolte 已提交
3255 3256 3257 3258 3259
            }

            break;

          case VIR_DOMAIN_DISK_DEVICE_CDROM:
3260
            if (virVMXFormatCDROM(ctx, def->disks[i], &buffer) < 0) {
3261
                goto cleanup;
M
Matthias Bolte 已提交
3262 3263 3264 3265 3266
            }

            break;

          case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
3267 3268
            if (virVMXFormatFloppy(ctx, def->disks[i], &buffer,
                                   floppy_present) < 0) {
3269
                goto cleanup;
M
Matthias Bolte 已提交
3270 3271 3272 3273 3274
            }

            break;

          default:
3275 3276 3277
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported disk device type '%s'"),
                           virDomainDiskDeviceTypeToString(def->disks[i]->device));
3278
            goto cleanup;
M
Matthias Bolte 已提交
3279 3280 3281
        }
    }

3282 3283 3284
    for (i = 0; i < 2; ++i) {
        /* floppy[0..1].present defaults to true, disable it explicitly */
        if (! floppy_present[i]) {
3285
            virBufferAsprintf(&buffer, "floppy%d.present = \"false\"\n", i);
3286 3287 3288
        }
    }

M
Matthias Bolte 已提交
3289
    /* def:fss */
3290 3291
    if (def->nfss > 0) {
        virBufferAddLit(&buffer, "isolation.tools.hgfs.disable = \"false\"\n");
3292
        virBufferAsprintf(&buffer, "sharedFolder.maxNum = \"%zu\"\n", def->nfss);
3293 3294 3295 3296 3297 3298 3299
    }

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

    /* def:nets */
    for (i = 0; i < def->nnets; ++i) {
3303
        if (virVMXFormatEthernet(def->nets[i], i, &buffer) < 0) {
3304
            goto cleanup;
M
Matthias Bolte 已提交
3305 3306 3307 3308 3309 3310 3311 3312 3313
        }
    }

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

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

3314 3315 3316
    /* def:videos */
    if (def->nvideos > 0) {
        if (def->nvideos > 1) {
3317 3318
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No support for multiple video devices"));
3319 3320 3321 3322 3323 3324 3325 3326
            goto cleanup;
        }

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

M
Matthias Bolte 已提交
3327 3328 3329 3330 3331
    /* def:hostdevs */
    /* FIXME */

    /* def:serials */
    for (i = 0; i < def->nserials; ++i) {
3332
        if (virVMXFormatSerial(ctx, def->serials[i], &buffer) < 0) {
3333
            goto cleanup;
M
Matthias Bolte 已提交
3334 3335 3336 3337 3338
        }
    }

    /* def:parallels */
    for (i = 0; i < def->nparallels; ++i) {
3339
        if (virVMXFormatParallel(ctx, def->parallels[i], &buffer) < 0) {
3340
            goto cleanup;
M
Matthias Bolte 已提交
3341 3342 3343 3344 3345
        }
    }

    /* Get final VMX output */
    if (virBufferError(&buffer)) {
3346
        virReportOOMError();
3347
        goto cleanup;
M
Matthias Bolte 已提交
3348 3349
    }

3350
    vmx = virBufferContentAndReset(&buffer);
M
Matthias Bolte 已提交
3351

3352 3353 3354 3355 3356
  cleanup:
    if (vmx == NULL) {
        virBufferFreeAndReset(&buffer);
    }

3357 3358
    VIR_FREE(preliminaryDisplayName);
    VIR_FREE(displayName);
3359
    VIR_FREE(annotation);
M
Matthias Bolte 已提交
3360

3361
    return vmx;
M
Matthias Bolte 已提交
3362 3363 3364 3365
}



M
Matthias Bolte 已提交
3366
int
3367
virVMXFormatVNC(virDomainGraphicsDefPtr def, virBufferPtr buffer)
M
Matthias Bolte 已提交
3368
{
3369 3370
    const char *listenAddr;

M
Matthias Bolte 已提交
3371
    if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
3372
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3373 3374 3375
        return -1;
    }

3376
    virBufferAddLit(buffer, "RemoteDisplay.vnc.enabled = \"true\"\n");
M
Matthias Bolte 已提交
3377 3378

    if (def->data.vnc.autoport) {
3379
        VIR_WARN("VNC autoport is enabled, but the automatically assigned "
M
Matthias Bolte 已提交
3380 3381 3382 3383 3384 3385 3386
                  "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);
        }

3387
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.port = \"%d\"\n",
M
Matthias Bolte 已提交
3388 3389 3390
                          def->data.vnc.port);
    }

3391
    if ((listenAddr = virDomainGraphicsListenGetAddress(def, 0))) {
3392
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.ip = \"%s\"\n",
3393
                          listenAddr);
M
Matthias Bolte 已提交
3394 3395 3396
    }

    if (def->data.vnc.keymap != NULL) {
3397
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.keymap = \"%s\"\n",
M
Matthias Bolte 已提交
3398 3399 3400
                          def->data.vnc.keymap);
    }

3401
    if (def->data.vnc.auth.passwd != NULL) {
3402
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.password = \"%s\"\n",
3403
                          def->data.vnc.auth.passwd);
M
Matthias Bolte 已提交
3404 3405 3406 3407 3408 3409 3410
    }

    return 0;
}



M
Matthias Bolte 已提交
3411
int
3412 3413
virVMXFormatHardDisk(virVMXContext *ctx, virDomainDiskDefPtr def,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3414
{
3415
    int controllerOrBus, unit;
M
Matthias Bolte 已提交
3416 3417 3418
    const char *busName = NULL;
    const char *entryPrefix = NULL;
    const char *deviceTypePrefix = NULL;
M
Matthias Bolte 已提交
3419
    char *fileName = NULL;
M
Matthias Bolte 已提交
3420 3421

    if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK) {
3422
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3423 3424 3425 3426 3427 3428 3429 3430
        return -1;
    }

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

3431 3432
        if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
                                                  &unit) < 0) {
M
Matthias Bolte 已提交
3433 3434 3435 3436 3437 3438 3439
            return -1;
        }
    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
        busName = "IDE";
        entryPrefix = "ide";
        deviceTypePrefix = "ata";

3440
        if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
3441
                                           &unit) < 0) {
M
Matthias Bolte 已提交
3442 3443 3444
            return -1;
        }
    } else {
3445 3446 3447
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported bus type '%s' for harddisk"),
                       virDomainDiskBusTypeToString(def->bus));
M
Matthias Bolte 已提交
3448 3449 3450 3451
        return -1;
    }

    if (def->type != VIR_DOMAIN_DISK_TYPE_FILE) {
3452 3453 3454 3455
        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 已提交
3456 3457 3458
        return -1;
    }

3459
    virBufferAsprintf(buffer, "%s%d:%d.present = \"true\"\n",
3460
                      entryPrefix, controllerOrBus, unit);
3461
    virBufferAsprintf(buffer, "%s%d:%d.deviceType = \"%s-hardDisk\"\n",
3462
                      entryPrefix, controllerOrBus, unit, deviceTypePrefix);
M
Matthias Bolte 已提交
3463 3464

    if (def->src != NULL) {
3465
        if (! virFileHasSuffix(def->src, ".vmdk")) {
3466 3467 3468
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Image file for %s harddisk '%s' has unsupported suffix, "
                             "expecting '.vmdk'"), busName, def->dst);
M
Matthias Bolte 已提交
3469 3470 3471
            return -1;
        }

3472
        fileName = ctx->formatFileName(def->src, ctx->opaque);
M
Matthias Bolte 已提交
3473 3474 3475 3476 3477

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

3478
        virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3479
                          entryPrefix, controllerOrBus, unit, fileName);
M
Matthias Bolte 已提交
3480 3481

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3482 3483 3484 3485
    }

    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
        if (def->cachemode == VIR_DOMAIN_DISK_CACHE_WRITETHRU) {
3486
            virBufferAsprintf(buffer, "%s%d:%d.writeThrough = \"true\"\n",
3487
                              entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3488
        } else if (def->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) {
3489 3490 3491 3492
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("%s harddisk '%s' has unsupported cache mode '%s'"),
                           busName, def->dst,
                           virDomainDiskCacheTypeToString(def->cachemode));
M
Matthias Bolte 已提交
3493
            return -1;
M
Matthias Bolte 已提交
3494 3495 3496 3497 3498 3499 3500 3501 3502
        }
    }

    return 0;
}



int
3503 3504
virVMXFormatCDROM(virVMXContext *ctx, virDomainDiskDefPtr def,
                  virBufferPtr buffer)
M
Matthias Bolte 已提交
3505
{
3506
    int controllerOrBus, unit;
M
Matthias Bolte 已提交
3507 3508
    const char *busName = NULL;
    const char *entryPrefix = NULL;
M
Matthias Bolte 已提交
3509
    char *fileName = NULL;
M
Matthias Bolte 已提交
3510 3511

    if (def->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
3512
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3513 3514 3515 3516 3517 3518 3519
        return -1;
    }

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

3520 3521
        if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
                                                  &unit) < 0) {
M
Matthias Bolte 已提交
3522 3523 3524 3525 3526 3527
            return -1;
        }
    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
        busName = "IDE";
        entryPrefix = "ide";

3528 3529
        if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
                                          &unit) < 0) {
M
Matthias Bolte 已提交
3530 3531 3532
            return -1;
        }
    } else {
3533 3534 3535
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported bus type '%s' for cdrom"),
                       virDomainDiskBusTypeToString(def->bus));
M
Matthias Bolte 已提交
3536 3537 3538
        return -1;
    }

3539
    virBufferAsprintf(buffer, "%s%d:%d.present = \"true\"\n",
3540
                      entryPrefix, controllerOrBus, unit);
M
Matthias Bolte 已提交
3541 3542

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

        if (def->src != NULL) {
3547
            if (! virFileHasSuffix(def->src, ".iso")) {
3548 3549 3550
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Image file for %s cdrom '%s' has unsupported "
                                 "suffix, expecting '.iso'"), busName, def->dst);
M
Matthias Bolte 已提交
3551 3552 3553
                return -1;
            }

3554
            fileName = ctx->formatFileName(def->src, ctx->opaque);
M
Matthias Bolte 已提交
3555 3556 3557 3558 3559

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

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

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

        if (def->src != NULL) {
3570
            virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3571
                              entryPrefix, controllerOrBus, unit, def->src);
M
Matthias Bolte 已提交
3572
        }
M
Matthias Bolte 已提交
3573
    } else {
3574 3575 3576 3577 3578 3579
        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 已提交
3580 3581 3582 3583 3584 3585 3586 3587 3588
        return -1;
    }

    return 0;
}



int
3589 3590
virVMXFormatFloppy(virVMXContext *ctx, virDomainDiskDefPtr def,
                   virBufferPtr buffer, bool floppy_present[2])
M
Matthias Bolte 已提交
3591
{
3592
    int unit;
M
Matthias Bolte 已提交
3593
    char *fileName = NULL;
M
Matthias Bolte 已提交
3594 3595

    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
3596
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3597 3598 3599
        return -1;
    }

3600
    if (virVMXFloppyDiskNameToUnit(def->dst, &unit) < 0) {
M
Matthias Bolte 已提交
3601 3602 3603
        return -1;
    }

3604 3605
    floppy_present[unit] = true;

3606
    virBufferAsprintf(buffer, "floppy%d.present = \"true\"\n", unit);
M
Matthias Bolte 已提交
3607 3608

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

        if (def->src != NULL) {
3612
            if (! virFileHasSuffix(def->src, ".flp")) {
3613 3614 3615
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Image file for floppy '%s' has unsupported "
                                 "suffix, expecting '.flp'"), def->dst);
M
Matthias Bolte 已提交
3616 3617 3618
                return -1;
            }

3619
            fileName = ctx->formatFileName(def->src, ctx->opaque);
M
Matthias Bolte 已提交
3620 3621 3622 3623 3624

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

3625
            virBufferAsprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3626
                              unit, fileName);
M
Matthias Bolte 已提交
3627 3628 3629

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

        if (def->src != NULL) {
3634
            virBufferAsprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3635
                              unit, def->src);
M
Matthias Bolte 已提交
3636
        }
M
Matthias Bolte 已提交
3637
    } else {
3638 3639 3640 3641 3642 3643
        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 已提交
3644 3645 3646 3647 3648 3649 3650 3651
        return -1;
    }

    return 0;
}



3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676
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 已提交
3677
int
3678 3679
virVMXFormatEthernet(virDomainNetDefPtr def, int controller,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3680 3681
{
    char mac_string[VIR_MAC_STRING_BUFLEN];
3682
    unsigned int prefix, suffix;
M
Matthias Bolte 已提交
3683 3684

    if (controller < 0 || controller > 3) {
3685 3686 3687
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Ethernet controller index %d out of [0..3] range"),
                       controller);
M
Matthias Bolte 已提交
3688 3689 3690
        return -1;
    }

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

3693
    /* def:model -> vmx:virtualDev, vmx:features */
M
Matthias Bolte 已提交
3694 3695 3696
    if (def->model != NULL) {
        if (STRCASENEQ(def->model, "vlance") &&
            STRCASENEQ(def->model, "vmxnet") &&
3697
            STRCASENEQ(def->model, "vmxnet2") &&
3698
            STRCASENEQ(def->model, "vmxnet3") &&
M
Matthias Bolte 已提交
3699
            STRCASENEQ(def->model, "e1000")) {
3700 3701 3702 3703
            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 已提交
3704 3705 3706
            return -1;
        }

3707
        if (STRCASEEQ(def->model, "vmxnet2")) {
3708
            virBufferAsprintf(buffer, "ethernet%d.virtualDev = \"vmxnet\"\n",
3709
                              controller);
3710
            virBufferAsprintf(buffer, "ethernet%d.features = \"15\"\n",
3711 3712
                              controller);
        } else {
3713
            virBufferAsprintf(buffer, "ethernet%d.virtualDev = \"%s\"\n",
3714 3715
                              controller, def->model);
        }
M
Matthias Bolte 已提交
3716 3717 3718 3719 3720
    }

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

        if (def->ifname != NULL) {
3726
            virBufferAsprintf(buffer, "ethernet%d.connectionType = \"custom\"\n",
M
Matthias Bolte 已提交
3727
                              controller);
3728
            virBufferAsprintf(buffer, "ethernet%d.vnet = \"%s\"\n",
M
Matthias Bolte 已提交
3729 3730
                              controller, def->ifname);
        } else {
3731
            virBufferAsprintf(buffer, "ethernet%d.connectionType = \"bridged\"\n",
M
Matthias Bolte 已提交
3732 3733 3734 3735 3736
                              controller);
        }

        break;

3737 3738 3739 3740 3741
      case VIR_DOMAIN_NET_TYPE_USER:
        virBufferAsprintf(buffer, "ethernet%d.connectionType = \"nat\"\n",
                          controller);
        break;

M
Matthias Bolte 已提交
3742
      default:
3743 3744
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type '%s'"),
                       virDomainNetTypeToString(def->type));
M
Matthias Bolte 已提交
3745 3746 3747
        return -1;
    }

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

3751 3752
    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];
3753 3754

    if (prefix == 0x000c29) {
3755
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"generated\"\n",
M
Matthias Bolte 已提交
3756
                          controller);
3757
        virBufferAsprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
M
Matthias Bolte 已提交
3758
                          controller, mac_string);
3759
        virBufferAsprintf(buffer, "ethernet%d.generatedAddressOffset = \"0\"\n",
M
Matthias Bolte 已提交
3760
                          controller);
3761
    } else if (prefix == 0x005056 && suffix <= 0x3fffff) {
3762
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"static\"\n",
3763
                          controller);
3764
        virBufferAsprintf(buffer, "ethernet%d.address = \"%s\"\n",
3765 3766
                          controller, mac_string);
    } else if (prefix == 0x005056 && suffix >= 0x800000 && suffix <= 0xbfffff) {
3767
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"vpx\"\n",
3768
                          controller);
3769
        virBufferAsprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
3770
                          controller, mac_string);
M
Matthias Bolte 已提交
3771
    } else {
3772
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"static\"\n",
3773
                          controller);
3774
        virBufferAsprintf(buffer, "ethernet%d.address = \"%s\"\n",
3775
                          controller, mac_string);
3776
        virBufferAsprintf(buffer, "ethernet%d.checkMACAddress = \"false\"\n",
3777
                          controller);
M
Matthias Bolte 已提交
3778 3779 3780 3781 3782 3783 3784 3785
    }

    return 0;
}



int
3786 3787
virVMXFormatSerial(virVMXContext *ctx, virDomainChrDefPtr def,
                   virBufferPtr buffer)
M
Matthias Bolte 已提交
3788
{
M
Matthias Bolte 已提交
3789
    char *fileName = NULL;
3790
    const char *protocol;
M
Matthias Bolte 已提交
3791

3792
    if (def->target.port < 0 || def->target.port > 3) {
3793 3794 3795
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Serial port index %d out of [0..3] range"),
                       def->target.port);
M
Matthias Bolte 已提交
3796 3797 3798
        return -1;
    }

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

M
Matthias Bolte 已提交
3801
    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
3802
    switch (def->source.type) {
M
Matthias Bolte 已提交
3803
      case VIR_DOMAIN_CHR_TYPE_DEV:
3804
        virBufferAsprintf(buffer, "serial%d.fileType = \"device\"\n",
3805
                          def->target.port);
3806
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3807
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3808 3809 3810
        break;

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

3814
        fileName = ctx->formatFileName(def->source.data.file.path, ctx->opaque);
M
Matthias Bolte 已提交
3815 3816 3817 3818 3819

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

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

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3824 3825 3826
        break;

      case VIR_DOMAIN_CHR_TYPE_PIPE:
3827
        virBufferAsprintf(buffer, "serial%d.fileType = \"pipe\"\n",
3828
                          def->target.port);
M
Matthias Bolte 已提交
3829
        /* FIXME: Based on VI Client GUI default */
3830
        virBufferAsprintf(buffer, "serial%d.pipe.endPoint = \"client\"\n",
3831
                          def->target.port);
M
Matthias Bolte 已提交
3832
        /* FIXME: Based on VI Client GUI default */
3833
        virBufferAsprintf(buffer, "serial%d.tryNoRxLoss = \"false\"\n",
3834
                          def->target.port);
3835
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3836
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3837 3838
        break;

3839
      case VIR_DOMAIN_CHR_TYPE_TCP:
3840
        switch (def->source.data.tcp.protocol) {
3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857
          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:
3858 3859 3860 3861
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported character device TCP protocol '%s'"),
                           virDomainChrTcpProtocolTypeToString(
                               def->source.data.tcp.protocol));
3862 3863 3864
            return -1;
        }

3865
        virBufferAsprintf(buffer, "serial%d.fileType = \"network\"\n",
3866
                          def->target.port);
3867
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s://%s:%s\"\n",
3868 3869
                          def->target.port, protocol, def->source.data.tcp.host,
                          def->source.data.tcp.service);
3870
        virBufferAsprintf(buffer, "serial%d.network.endPoint = \"%s\"\n",
3871
                          def->target.port,
3872
                          def->source.data.tcp.listen ? "server" : "client");
3873 3874
        break;

M
Matthias Bolte 已提交
3875
      default:
3876 3877 3878
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported character device type '%s'"),
                       virDomainChrTypeToString(def->source.type));
M
Matthias Bolte 已提交
3879 3880 3881 3882 3883
        return -1;
    }

    /* vmx:yieldOnMsrRead */
    /* FIXME: Based on VI Client GUI default */
3884
    virBufferAsprintf(buffer, "serial%d.yieldOnMsrRead = \"true\"\n",
3885
                      def->target.port);
M
Matthias Bolte 已提交
3886 3887 3888 3889 3890 3891 3892

    return 0;
}



int
3893 3894
virVMXFormatParallel(virVMXContext *ctx, virDomainChrDefPtr def,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3895
{
M
Matthias Bolte 已提交
3896 3897
    char *fileName = NULL;

3898
    if (def->target.port < 0 || def->target.port > 2) {
3899 3900 3901
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parallel port index %d out of [0..2] range"),
                       def->target.port);
M
Matthias Bolte 已提交
3902 3903 3904
        return -1;
    }

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

M
Matthias Bolte 已提交
3908
    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
3909
    switch (def->source.type) {
M
Matthias Bolte 已提交
3910
      case VIR_DOMAIN_CHR_TYPE_DEV:
3911
        virBufferAsprintf(buffer, "parallel%d.fileType = \"device\"\n",
3912
                          def->target.port);
3913
        virBufferAsprintf(buffer, "parallel%d.fileName = \"%s\"\n",
3914
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3915 3916 3917
        break;

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

3921
        fileName = ctx->formatFileName(def->source.data.file.path, ctx->opaque);
M
Matthias Bolte 已提交
3922 3923 3924 3925 3926

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

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

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3931 3932 3933
        break;

      default:
3934 3935 3936
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported character device type '%s'"),
                       virDomainChrTypeToString(def->source.type));
M
Matthias Bolte 已提交
3937 3938 3939 3940 3941
        return -1;
    }

    return 0;
}
3942 3943 3944 3945 3946 3947



int
virVMXFormatSVGA(virDomainVideoDefPtr def, virBufferPtr buffer)
{
3948 3949
    unsigned long long vram;

3950
    if (def->type != VIR_DOMAIN_VIDEO_TYPE_VMVGA) {
3951 3952 3953
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported video device type '%s'"),
                       virDomainVideoTypeToString(def->type));
3954 3955 3956 3957 3958 3959 3960
        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
     */
3961
    vram = VIR_DIV_UP(def->vram, 64) * 64;
3962 3963

    if (def->heads > 1) {
3964 3965
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Multi-head video devices are unsupported"));
3966 3967 3968
        return -1;
    }

3969
    virBufferAsprintf(buffer, "svga.vramSize = \"%lld\"\n",
3970
                      vram * 1024); /* kilobyte to byte */
3971 3972 3973

    return 0;
}