vmx.c 131.2 KB
Newer Older
1
/*
2
 * vmx.c: VMware VMX parsing/formatting functions
3
 *
4
 * Copyright (C) 2010-2014 Red Hat, Inc.
M
Matthias Bolte 已提交
5
 * Copyright (C) 2009-2011, 2014-2015 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
VIR_LOG_INIT("vmx.vmx");

40 41
/*

42
 mapping:
43 44 45 46 47

domain-xml                        <=>   vmx


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


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



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

def->os

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



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

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

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


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

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


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

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



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



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


                                        ethernet0.addressType = "generated"     # default to "generated"
->mac = <value>                   <=>   ethernet0.generatedAddress = "<value>"
309
                                        ethernet0.generatedAddressOffset = "0"  # ?
310 311 312 313 314


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

315 316 317 318

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

319 320 321 322 323

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

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


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

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


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

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


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

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



359 360 361 362 363 364 365 366 367 368
################################################################################
## video #######################################################################

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



369 370 371 372 373 374 375 376 377
################################################################################
## serials #####################################################################

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

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

def->serials[0]...
378
->target.port = <port>
379 380 381 382 383 384 385


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


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


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

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


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

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


427 428 429 430 431 432 433 434
## 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>

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

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

450
->data.tcp.listen = false         <=>   serial0.network.endPoint = "client"     # defaults to "server"
451 452 453 454 455 456

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


457 458 459 460 461 462 463 464 465 466

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

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

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

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


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


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

498 499
*/

500
#define VIR_FROM_THIS VIR_FROM_NONE
501

502
#define VMX_BUILD_NAME_EXTRA(_suffix, _extra)                                 \
503 504
    snprintf(_suffix##_name, sizeof(_suffix##_name), "%s."_extra, prefix);

505 506
#define VMX_BUILD_NAME(_suffix)                                               \
    VMX_BUILD_NAME_EXTRA(_suffix, #_suffix)
507

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


523 524 525
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Helpers
 */
526

527
static int
528 529 530
virVMXDomainDefPostParse(virDomainDefPtr def,
                         virCapsPtr caps ATTRIBUTE_UNUSED,
                         void *opaque ATTRIBUTE_UNUSED)
531
{
532 533 534 535
    /* memory hotplug tunables are not supported by this driver */
    if (virDomainDefCheckUnsupportedMemoryHotplug(def) < 0)
        return -1;

536 537 538 539
    return 0;
}

static int
540 541 542 543
virVMXDomainDevicesDefPostParse(virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
                                const virDomainDef *def ATTRIBUTE_UNUSED,
                                virCapsPtr caps ATTRIBUTE_UNUSED,
                                void *opaque ATTRIBUTE_UNUSED)
544 545 546
{
    return 0;
}
547

548
static virDomainDefParserConfig virVMXDomainDefParserConfig = {
549
    .hasWideSCSIBus = true,
550
    .macPrefix = {0x00, 0x0c, 0x29},
551 552
    .devicesPostParseCallback = virVMXDomainDevicesDefPostParse,
    .domainPostParseCallback = virVMXDomainDefPostParse,
553 554
};

555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
static void
virVMXDomainDefNamespaceFree(void *nsdata)
{
    VIR_FREE(nsdata);
}

static int
virVMXDomainDefNamespaceFormatXML(virBufferPtr buf, void *nsdata)
{
    const char *datacenterPath = nsdata;

    if (!datacenterPath)
        return 0;

    virBufferAddLit(buf, "<vmware:datacenterpath>");
    virBufferEscapeString(buf, "%s", datacenterPath);
    virBufferAddLit(buf, "</vmware:datacenterpath>\n");

    return 0;
}

static const char *
virVMXDomainDefNamespaceHref(void)
{
    return "xmlns:vmware='http://libvirt.org/schemas/domain/vmware/1.0'";
}

static virDomainXMLNamespace virVMXDomainXMLNamespace = {
    .parse = NULL,
    .free = virVMXDomainDefNamespaceFree,
    .format = virVMXDomainDefNamespaceFormatXML,
    .href = virVMXDomainDefNamespaceHref,
};
588 589 590 591

virDomainXMLOptionPtr
virVMXDomainXMLConfInit(void)
{
592 593
    return virDomainXMLOptionNew(&virVMXDomainDefParserConfig, NULL,
                                 &virVMXDomainXMLNamespace);
594 595
}

596 597 598 599 600 601 602 603 604 605
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') {
606
        if (*tmp1 == escape || strspn(tmp1, special) > 0)
607 608 609 610 611 612
            length += 2;

        ++tmp1;
        ++length;
    }

613
    if (VIR_ALLOC_N(escaped, length) < 0)
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
        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 已提交
641
int
642 643 644 645 646 647 648 649
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) {
650
            if (!c_isxdigit(tmp1[1]) || !c_isxdigit(tmp1[2]))
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
                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) {
678 679
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxml2 doesn't handle %s encoding"), encoding);
680 681 682 683 684 685 686
        return NULL;
    }

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

    if (xmlCharEncInFunc(handler, utf8, input) < 0) {
687 688
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not convert from %s to UTF-8 encoding"), encoding);
689 690 691 692 693 694
        goto cleanup;
    }

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

695
 cleanup:
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
    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) {
715
        if (optional)
716 717
            return 0;

718 719
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing essential config entry '%s'"), name);
720 721 722 723
        return -1;
    }

    if (value->type != VIR_CONF_STRING) {
724 725
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Config entry '%s' must be a string"), name);
726 727 728 729
        return -1;
    }

    if (value->str == NULL) {
730
        if (optional)
731 732
            return 0;

733 734
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing essential config entry '%s'"), name);
735 736 737
        return -1;
    }

738
    return VIR_STRDUP(*string, value->str);
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
}



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 {
755 756
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing essential config entry '%s'"), name);
757 758 759 760 761
            return -1;
        }
    }

    if (value->type != VIR_CONF_STRING) {
762 763
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Config entry '%s' must be a string"), name);
764 765 766 767 768 769 770
        return -1;
    }

    if (value->str == NULL) {
        if (optional) {
            return 0;
        } else {
771 772
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing essential config entry '%s'"), name);
773 774 775 776 777
            return -1;
        }
    }

    if (virUUIDParse(value->str, uuid) < 0) {
778 779
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse UUID from string '%s'"), value->str);
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
        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 {
801 802
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing essential config entry '%s'"), name);
803 804 805 806 807 808 809 810 811
            return -1;
        }
    }

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

818
        if (STRCASEEQ(value->str, "unlimited")) {
819 820
            *number = -1;
        } else if (virStrToLong_ll(value->str, NULL, 10, number) < 0) {
821 822 823
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Config entry '%s' must represent an integer value"),
                           name);
824 825 826
            return -1;
        }
    } else {
827 828
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Config entry '%s' must be a string"), name);
829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
        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 {
850 851
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Missing essential config entry '%s'"), name);
852 853 854 855 856 857 858 859 860
            return -1;
        }
    }

    if (value->type == VIR_CONF_STRING) {
        if (value->str == NULL) {
            if (optional) {
                return 0;
            } else {
861 862
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Missing essential config entry '%s'"), name);
863 864 865 866 867 868 869 870 871
                return -1;
            }
        }

        if (STRCASEEQ(value->str, "true")) {
            *boolean_ = 1;
        } else if (STRCASEEQ(value->str, "false")) {
            *boolean_ = 0;
        } else {
872 873 874
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Config entry '%s' must represent a boolean value "
                             "(true|false)"), name);
875 876 877
            return -1;
        }
    } else {
878 879
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Config entry '%s' must be a string"), name);
880 881 882 883 884 885 886 887 888 889
        return -1;
    }

    return 0;
}



static int
virVMXSCSIDiskNameToControllerAndUnit(const char *name, int *controller, int *unit)
M
Matthias Bolte 已提交
890 891 892 893
{
    int idx;

    if (! STRPREFIX(name, "sd")) {
894 895 896
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expecting domain XML attribute 'dev' of entry "
                         "'devices/disk/target' to start with 'sd'"));
M
Matthias Bolte 已提交
897 898 899 900 901 902
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
903 904
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
905 906 907
        return -1;
    }

908
    /* Each of the 4 SCSI controllers has 1 bus with 15 units each for devices */
M
Matthias Bolte 已提交
909
    if (idx >= (4 * 15)) {
910 911
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("SCSI disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
912 913 914 915
        return -1;
    }

    *controller = idx / 15;
916
    *unit = idx % 15;
M
Matthias Bolte 已提交
917

918
    /* Skip the controller ifself at unit 7 */
919
    if (*unit >= 7)
920
        ++(*unit);
M
Matthias Bolte 已提交
921 922 923 924 925 926

    return 0;
}



927 928
static int
virVMXIDEDiskNameToBusAndUnit(const char *name, int *bus, int *unit)
M
Matthias Bolte 已提交
929 930 931 932
{
    int idx;

    if (! STRPREFIX(name, "hd")) {
933 934 935
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expecting domain XML attribute 'dev' of entry "
                         "'devices/disk/target' to start with 'hd'"));
M
Matthias Bolte 已提交
936 937 938 939 940 941
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
942 943
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
944 945 946
        return -1;
    }

947
    /* The IDE controller has 2 buses with 2 units each for devices */
M
Matthias Bolte 已提交
948
    if (idx >= (2 * 2)) {
949 950
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("IDE disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
951 952 953
        return -1;
    }

954 955
    *bus = idx / 2;
    *unit = idx % 2;
M
Matthias Bolte 已提交
956 957 958 959 960 961

    return 0;
}



962 963
static int
virVMXFloppyDiskNameToUnit(const char *name, int *unit)
M
Matthias Bolte 已提交
964 965 966 967
{
    int idx;

    if (! STRPREFIX(name, "fd")) {
968 969 970
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expecting domain XML attribute 'dev' of entry "
                         "'devices/disk/target' to start with 'fd'"));
M
Matthias Bolte 已提交
971 972 973 974 975 976
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
977 978
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
979 980 981
        return -1;
    }

982
    /* The FDC controller has 1 bus with 2 units for devices */
M
Matthias Bolte 已提交
983
    if (idx >= 2) {
984 985
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Floppy disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
986 987 988
        return -1;
    }

989 990 991 992 993 994 995
    *unit = idx;

    return 0;
}



996
static int
997 998 999
virVMXVerifyDiskAddress(virDomainXMLOptionPtr xmlopt,
                        virDomainDiskDefPtr disk,
                        virDomainDefPtr vmdef)
1000 1001 1002 1003 1004 1005 1006
{
    virDomainDiskDef def;
    virDomainDeviceDriveAddressPtr drive;

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

    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
1007 1008 1009
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported disk address type '%s'"),
                       virDomainDeviceAddressTypeToString(disk->info.type));
1010 1011 1012 1013 1014 1015 1016 1017
        return -1;
    }

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

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

1018
    if (virDomainDiskDefAssignAddress(xmlopt, &def, vmdef) < 0) {
1019 1020
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not verify disk address"));
1021 1022 1023 1024 1025 1026
        return -1;
    }

    if (def.info.addr.drive.controller != drive->controller ||
        def.info.addr.drive.bus != drive->bus ||
        def.info.addr.drive.unit != drive->unit) {
1027 1028 1029
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Disk address %d:%d:%d doesn't match target device '%s'"),
                       drive->controller, drive->bus, drive->unit, disk->dst);
1030 1031 1032 1033 1034 1035
        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) {
1036 1037 1038
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("SCSI controller index %d out of [0..3] range"),
                           drive->controller);
1039 1040 1041 1042
            return -1;
        }

        if (drive->bus != 0) {
1043 1044 1045
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("SCSI bus index %d out of [0] range"),
                           drive->bus);
1046 1047 1048 1049
            return -1;
        }

        if (drive->unit > 15 || drive->unit == 7) {
1050 1051 1052
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("SCSI unit index %d out of [0..6,8..15] range"),
                           drive->unit);
1053 1054 1055 1056
            return -1;
        }
    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
        if (drive->controller != 0) {
1057 1058 1059
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE controller index %d out of [0] range"),
                           drive->controller);
1060 1061 1062 1063
            return -1;
        }

        if (drive->bus > 1) {
1064 1065 1066
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE bus index %d out of [0..1] range"),
                           drive->bus);
1067 1068 1069 1070
            return -1;
        }

        if (drive->unit > 1) {
1071 1072 1073
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE unit index %d out of [0..1] range"),
                           drive->unit);
1074 1075 1076 1077
            return -1;
        }
    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
        if (drive->controller != 0) {
1078 1079 1080
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC controller index %d out of [0] range"),
                           drive->controller);
1081 1082 1083 1084
            return -1;
        }

        if (drive->bus != 0) {
1085 1086 1087
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC bus index %d out of [0] range"),
                           drive->bus);
1088 1089 1090 1091
            return -1;
        }

        if (drive->unit > 1) {
1092 1093 1094
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC unit index %d out of [0..1] range"),
                           drive->unit);
1095 1096 1097
            return -1;
        }
    } else {
1098 1099 1100
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported bus type '%s'"),
                       virDomainDiskBusTypeToString(disk->bus));
1101 1102 1103 1104 1105 1106 1107 1108
        return -1;
    }

    return 0;
}



1109 1110 1111
static int
virVMXHandleLegacySCSIDiskDriverName(virDomainDefPtr def,
                                     virDomainDiskDefPtr disk)
1112 1113
{
    char *tmp;
1114 1115
    int model;
    size_t i;
1116
    virDomainControllerDefPtr controller = NULL;
1117 1118
    const char *driver = virDomainDiskGetDriver(disk);
    char *copy;
1119

1120
    if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI || !driver)
1121 1122
        return 0;

1123 1124 1125
    if (VIR_STRDUP(copy, driver) < 0)
        return -1;
    tmp = copy;
1126

1127
    for (; *tmp != '\0'; ++tmp)
1128 1129
        *tmp = c_tolower(*tmp);

1130 1131
    model = virDomainControllerModelSCSITypeFromString(copy);
    VIR_FREE(copy);
1132 1133

    if (model < 0) {
1134
        virReportError(VIR_ERR_INTERNAL_ERROR,
1135
                       _("Unknown driver name '%s'"), driver);
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
        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) {
1147 1148 1149
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing SCSI controller for index %d"),
                       disk->info.addr.drive.controller);
1150 1151 1152 1153 1154 1155
        return -1;
    }

    if (controller->model == -1) {
        controller->model = model;
    } else if (controller->model != model) {
1156 1157
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Inconsistent SCSI controller model ('%s' is not '%s') "
1158
                         "for SCSI controller index %d"), driver,
1159 1160
                       virDomainControllerModelSCSITypeToString(controller->model),
                       controller->idx);
1161 1162
        return -1;
    }
M
Matthias Bolte 已提交
1163 1164 1165 1166 1167 1168

    return 0;
}



1169 1170 1171
static int
virVMXGatherSCSIControllers(virVMXContext *ctx, virDomainDefPtr def,
                            int virtualDev[4], bool present[4])
1172 1173
{
    int result = -1;
1174
    size_t i, k;
M
Matthias Bolte 已提交
1175
    virDomainDiskDefPtr disk;
1176 1177 1178 1179
    virDomainControllerDefPtr controller;
    bool controllerHasDisksAttached;
    int count = 0;
    int *autodetectedModels;
M
Matthias Bolte 已提交
1180

1181
    if (VIR_ALLOC_N(autodetectedModels, def->ndisks) < 0)
1182 1183 1184 1185
        return -1;

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

1187
        if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
1188
            /* skip non-SCSI controllers */
M
Matthias Bolte 已提交
1189 1190 1191
            continue;
        }

1192
        controllerHasDisksAttached = false;
1193

1194 1195 1196 1197 1198 1199
        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;
1200 1201
                break;
            }
M
Matthias Bolte 已提交
1202 1203
        }

1204
        if (! controllerHasDisksAttached) {
1205
            /* skip SCSI controllers without attached disks */
1206 1207 1208
            continue;
        }

1209
        if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO &&
1210
            ctx->autodetectSCSIControllerModel != NULL) {
1211 1212
            count = 0;

1213 1214
            /* try to autodetect the SCSI controller model by collecting
             * SCSI controller model of all disks attached to this controller */
1215 1216 1217 1218 1219
            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) {
1220 1221 1222
                    if (ctx->autodetectSCSIControllerModel
                               (disk, &autodetectedModels[count],
                                ctx->opaque) < 0) {
1223 1224 1225 1226 1227 1228 1229
                        goto cleanup;
                    }

                    ++count;
                }
            }

1230 1231
            /* autodetection fails when the disks attached to one controller
             * have inconsistent SCSI controller models */
1232 1233
            for (k = 0; k < count; ++k) {
                if (autodetectedModels[k] != autodetectedModels[0]) {
1234 1235 1236 1237
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Disks on SCSI controller %d have inconsistent "
                                     "controller models, cannot autodetect model"),
                                   controller->idx);
1238 1239 1240 1241 1242
                    goto cleanup;
                }
            }

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

1245
        if (controller->model != -1 &&
1246 1247 1248 1249
            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) {
1250 1251 1252 1253 1254
            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));
1255
            goto cleanup;
M
Matthias Bolte 已提交
1256
        }
1257 1258 1259

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

1262 1263
    result = 0;

1264
 cleanup:
1265 1266 1267
    VIR_FREE(autodetectedModels);

    return result;
M
Matthias Bolte 已提交
1268 1269 1270 1271 1272 1273 1274 1275
}



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

1276
virDomainDefPtr
1277 1278
virVMXParseConfig(virVMXContext *ctx,
                  virDomainXMLOptionPtr xmlopt,
1279
                  virCapsPtr caps,
1280
                  const char *vmx)
1281
{
M
Matthias Bolte 已提交
1282
    bool success = false;
1283
    virConfPtr conf = NULL;
1284 1285
    char *encoding = NULL;
    char *utf8;
1286 1287 1288 1289
    virDomainDefPtr def = NULL;
    long long config_version = 0;
    long long virtualHW_version = 0;
    long long memsize = 0;
1290 1291
    long long sched_mem_max = 0;
    long long sched_mem_minsize = 0;
1292 1293
    long long numvcpus = 0;
    char *sched_cpu_affinity = NULL;
1294
    char *sched_cpu_shares = NULL;
M
Matthias Bolte 已提交
1295
    char *guestOS = NULL;
M
Matthias Bolte 已提交
1296
    bool smbios_reflecthost = false;
1297
    int controller;
1298
    int bus;
1299
    int port;
1300
    bool present;
1301 1302
    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
    int unit;
1303 1304
    bool hgfs_disabled = true;
    long long sharedFolder_maxNum = 0;
H
Hu Tao 已提交
1305
    int cpumasklen;
1306
    char *namespaceData;
1307

1308
    if (ctx->parseFileName == NULL) {
1309 1310
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("virVMXContext has no parseFileName function set"));
1311 1312 1313
        return NULL;
    }

1314 1315
    conf = virConfReadMem(vmx, strlen(vmx), VIR_CONF_FLAG_VMX_FORMAT);

1316
    if (conf == NULL)
1317 1318
        return NULL;

1319
    /* vmx:.encoding */
1320
    if (virVMXGetConfigString(conf, ".encoding", &encoding, true) < 0)
1321 1322 1323 1324 1325 1326 1327 1328
        goto cleanup;

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

1329
        utf8 = virVMXConvertToUTF8(encoding, vmx);
1330

1331
        if (utf8 == NULL)
1332 1333 1334 1335 1336 1337
            goto cleanup;

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

        VIR_FREE(utf8);

1338
        if (conf == NULL)
1339 1340 1341 1342
            goto cleanup;
    }

    /* Allocate domain def */
1343
    if (!(def = virDomainDefNew()))
A
ajia@redhat.com 已提交
1344
        goto cleanup;
1345

1346
    def->virtType = VIR_DOMAIN_VIRT_VMWARE;
1347 1348
    def->id = -1;

M
Matthias Bolte 已提交
1349
    /* vmx:config.version */
1350 1351
    if (virVMXGetConfigLong(conf, "config.version", &config_version, 0,
                            false) < 0) {
M
Matthias Bolte 已提交
1352
        goto cleanup;
1353 1354 1355
    }

    if (config_version != 8) {
1356 1357 1358
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry 'config.version' to be 8 but found "
                         "%lld"), config_version);
M
Matthias Bolte 已提交
1359
        goto cleanup;
1360 1361
    }

M
Matthias Bolte 已提交
1362
    /* vmx:virtualHW.version */
1363 1364
    if (virVMXGetConfigLong(conf, "virtualHW.version", &virtualHW_version, 0,
                            false) < 0) {
M
Matthias Bolte 已提交
1365
        goto cleanup;
1366 1367
    }

1368
    if (virtualHW_version < 4) {
1369
        virReportError(VIR_ERR_INTERNAL_ERROR,
1370
                       _("Expecting VMX entry 'virtualHW.version' to be "
1371
                         "4 or higher but found %lld"),
1372
                       virtualHW_version);
M
Matthias Bolte 已提交
1373
        goto cleanup;
1374 1375
    }

M
Matthias Bolte 已提交
1376
    /* vmx:uuid.bios -> def:uuid */
1377
    /* FIXME: Need to handle 'uuid.action = "create"' */
1378
    if (virVMXGetConfigUUID(conf, "uuid.bios", def->uuid, true) < 0)
M
Matthias Bolte 已提交
1379
        goto cleanup;
1380

M
Matthias Bolte 已提交
1381
    /* vmx:displayName -> def:name */
1382
    if (virVMXGetConfigString(conf, "displayName", &def->name, true) < 0)
M
Matthias Bolte 已提交
1383
        goto cleanup;
1384

1385
    if (def->name != NULL) {
1386 1387
        if (virVMXUnescapeHexPercent(def->name) < 0 ||
            virVMXUnescapeHexPipe(def->name) < 0) {
1388 1389
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("VMX entry 'name' contains invalid escape sequence"));
1390 1391 1392 1393
            goto cleanup;
        }
    }

1394
    /* vmx:annotation -> def:description */
1395 1396
    if (virVMXGetConfigString(conf, "annotation", &def->description,
                              true) < 0) {
1397 1398 1399 1400
        goto cleanup;
    }

    if (def->description != NULL) {
1401
        if (virVMXUnescapeHexPipe(def->description) < 0) {
1402 1403 1404
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("VMX entry 'annotation' contains invalid escape "
                             "sequence"));
1405
            goto cleanup;
1406 1407 1408
        }
    }

1409
    /* vmx:memsize -> def:mem.max_balloon */
1410
    if (virVMXGetConfigLong(conf, "memsize", &memsize, 32, true) < 0)
M
Matthias Bolte 已提交
1411
        goto cleanup;
1412 1413

    if (memsize <= 0 || memsize % 4 != 0) {
1414 1415 1416
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry 'memsize' to be an unsigned "
                         "integer (multiple of 4) but found %lld"), memsize);
M
Matthias Bolte 已提交
1417
        goto cleanup;
1418 1419
    }

1420
    virDomainDefSetMemoryTotal(def, memsize * 1024); /* Scale from megabytes to kilobytes */
1421

1422
    /* vmx:sched.mem.max -> def:mem.cur_balloon */
1423 1424
    if (virVMXGetConfigLong(conf, "sched.mem.max", &sched_mem_max, memsize,
                            true) < 0) {
M
Matthias Bolte 已提交
1425
        goto cleanup;
1426 1427
    }

1428
    if (sched_mem_max < 0)
1429
        sched_mem_max = memsize;
1430

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

1433 1434
    if (def->mem.cur_balloon > virDomainDefGetMemoryActual(def))
        def->mem.cur_balloon = virDomainDefGetMemoryActual(def);
1435

1436
    /* vmx:sched.mem.minsize -> def:mem.min_guarantee */
1437 1438
    if (virVMXGetConfigLong(conf, "sched.mem.minsize", &sched_mem_minsize, 0,
                            true) < 0) {
1439 1440 1441
        goto cleanup;
    }

1442
    if (sched_mem_minsize < 0)
1443 1444 1445 1446
        sched_mem_minsize = 0;

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

1447 1448
    if (def->mem.min_guarantee > virDomainDefGetMemoryActual(def))
        def->mem.min_guarantee = virDomainDefGetMemoryActual(def);
1449

M
Matthias Bolte 已提交
1450
    /* vmx:numvcpus -> def:vcpus */
1451
    if (virVMXGetConfigLong(conf, "numvcpus", &numvcpus, 1, true) < 0)
M
Matthias Bolte 已提交
1452
        goto cleanup;
1453 1454

    if (numvcpus <= 0 || (numvcpus % 2 != 0 && numvcpus != 1)) {
1455 1456 1457
        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 已提交
1458
        goto cleanup;
1459 1460
    }

1461 1462 1463 1464
    if (virDomainDefSetVcpusMax(def, numvcpus) < 0)
        goto cleanup;

    def->vcpus = numvcpus;
1465

M
Matthias Bolte 已提交
1466
    /* vmx:sched.cpu.affinity -> def:cpumask */
1467
    /* NOTE: maps to VirtualMachine:config.cpuAffinity.affinitySet */
1468 1469
    if (virVMXGetConfigString(conf, "sched.cpu.affinity", &sched_cpu_affinity,
                              true) < 0) {
M
Matthias Bolte 已提交
1470
        goto cleanup;
1471 1472
    }

1473
    if (sched_cpu_affinity != NULL && STRCASENEQ(sched_cpu_affinity, "all")) {
1474 1475 1476
        const char *current = sched_cpu_affinity;
        int number, count = 0;

H
Hu Tao 已提交
1477
        cpumasklen = 0;
1478

H
Hu Tao 已提交
1479
        def->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN);
1480
        if (!def->cpumask)
M
Matthias Bolte 已提交
1481
            goto cleanup;
1482 1483 1484 1485 1486 1487 1488

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

            number = virParseNumber(&current);

            if (number < 0) {
1489 1490 1491 1492
                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 已提交
1493
                goto cleanup;
1494 1495 1496
            }

            if (number >= VIR_DOMAIN_CPUMASK_LEN) {
1497 1498 1499
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("VMX entry 'sched.cpu.affinity' contains a %d, "
                                 "this value is too large"), number);
M
Matthias Bolte 已提交
1500
                goto cleanup;
1501 1502
            }

1503
            if (number + 1 > cpumasklen)
H
Hu Tao 已提交
1504
                cpumasklen = number + 1;
1505

H
Hu Tao 已提交
1506
            ignore_value(virBitmapSetBit(def->cpumask, number));
1507 1508 1509 1510 1511 1512 1513 1514 1515
            ++count;

            virSkipSpaces(&current);

            if (*current == ',') {
                ++current;
            } else if (*current == '\0') {
                break;
            } else {
1516 1517 1518 1519
                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 已提交
1520
                goto cleanup;
1521 1522 1523 1524 1525 1526
            }

            virSkipSpaces(&current);
        }

        if (count < numvcpus) {
1527 1528 1529 1530
            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 已提交
1531
            goto cleanup;
1532 1533 1534
        }
    }

1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550
    /* 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) {
1551 1552 1553 1554
            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);
1555 1556
            goto cleanup;
        }
1557
        def->cputune.sharesSpecified = true;
1558 1559
    }

1560 1561 1562
    /* def:lifecycle */
    def->onReboot = VIR_DOMAIN_LIFECYCLE_RESTART;
    def->onPoweroff = VIR_DOMAIN_LIFECYCLE_DESTROY;
1563
    def->onCrash = VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY;
1564 1565

    /* def:os */
1566
    def->os.type = VIR_DOMAIN_OSTYPE_HVM;
1567

M
Matthias Bolte 已提交
1568
    /* vmx:guestOS -> def:os.arch */
1569
    if (virVMXGetConfigString(conf, "guestOS", &guestOS, true) < 0)
M
Matthias Bolte 已提交
1570
        goto cleanup;
M
Matthias Bolte 已提交
1571

1572
    if (guestOS != NULL && virFileHasSuffix(guestOS, "-64")) {
1573
        def->os.arch = VIR_ARCH_X86_64;
M
Matthias Bolte 已提交
1574
    } else {
1575
        def->os.arch = VIR_ARCH_I686;
M
Matthias Bolte 已提交
1576 1577
    }

M
Matthias Bolte 已提交
1578
    /* vmx:smbios.reflecthost -> def:os.smbios_mode */
1579 1580
    if (virVMXGetConfigBoolean(conf, "smbios.reflecthost",
                               &smbios_reflecthost, false, true) < 0) {
M
Matthias Bolte 已提交
1581 1582 1583
        goto cleanup;
    }

1584
    if (smbios_reflecthost)
M
Matthias Bolte 已提交
1585 1586
        def->os.smbios_mode = VIR_DOMAIN_SMBIOS_HOST;

1587 1588
    /* def:features */
    /* FIXME */
1589

1590 1591
    /* def:clock */
    /* FIXME */
1592 1593

    /* def:graphics */
1594
    if (VIR_ALLOC_N(def->graphics, 1) < 0)
M
Matthias Bolte 已提交
1595
        goto cleanup;
M
Matthias Bolte 已提交
1596 1597 1598

    def->ngraphics = 0;

1599
    if (virVMXParseVNC(conf, &def->graphics[def->ngraphics]) < 0)
M
Matthias Bolte 已提交
1600
        goto cleanup;
M
Matthias Bolte 已提交
1601

1602
    if (def->graphics[def->ngraphics] != NULL)
M
Matthias Bolte 已提交
1603
        ++def->ngraphics;
1604

M
Matthias Bolte 已提交
1605
    /* def:disks: 4 * 15 scsi + 2 * 2 ide + 2 floppy = 66 */
1606
    if (VIR_ALLOC_N(def->disks, 66) < 0)
M
Matthias Bolte 已提交
1607
        goto cleanup;
1608 1609 1610 1611 1612

    def->ndisks = 0;

    /* def:disks (scsi) */
    for (controller = 0; controller < 4; ++controller) {
1613 1614
        if (virVMXParseSCSIController(conf, controller, &present,
                                      &scsi_virtualDev[controller]) < 0) {
M
Matthias Bolte 已提交
1615
            goto cleanup;
1616 1617
        }

1618
        if (! present)
1619 1620
            continue;

1621 1622
        for (unit = 0; unit < 16; ++unit) {
            if (unit == 7) {
1623
                /*
1624
                 * SCSI unit 7 is assigned to the SCSI controller and cannot be
1625 1626 1627 1628 1629
                 * used for disk devices.
                 */
                continue;
            }

1630
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
1631
                                VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
1632
                                &def->disks[def->ndisks], def) < 0) {
M
Matthias Bolte 已提交
1633
                goto cleanup;
1634 1635 1636 1637 1638 1639 1640
            }

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

1641
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1642
                                 VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
1643
                                 &def->disks[def->ndisks], def) < 0) {
M
Matthias Bolte 已提交
1644
                goto cleanup;
1645 1646
            }

1647
            if (def->disks[def->ndisks] != NULL)
1648 1649 1650 1651 1652
                ++def->ndisks;
        }
    }

    /* def:disks (ide) */
1653 1654
    for (bus = 0; bus < 2; ++bus) {
        for (unit = 0; unit < 2; ++unit) {
1655
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
1656
                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
1657
                                &def->disks[def->ndisks], def) < 0) {
M
Matthias Bolte 已提交
1658
                goto cleanup;
1659 1660 1661 1662 1663 1664 1665
            }

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

1666
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1667
                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
1668
                                &def->disks[def->ndisks], def) < 0) {
M
Matthias Bolte 已提交
1669
                goto cleanup;
1670 1671
            }

1672
            if (def->disks[def->ndisks] != NULL)
1673 1674 1675 1676 1677
                ++def->ndisks;
        }
    }

    /* def:disks (floppy) */
1678
    for (unit = 0; unit < 2; ++unit) {
1679
        if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_FLOPPY,
1680
                            VIR_DOMAIN_DISK_BUS_FDC, 0, unit,
1681
                            &def->disks[def->ndisks], def) < 0) {
M
Matthias Bolte 已提交
1682
            goto cleanup;
1683 1684
        }

1685
        if (def->disks[def->ndisks] != NULL)
1686 1687 1688
            ++def->ndisks;
    }

1689 1690
    /* def:controllers */
    if (virDomainDefAddImplicitControllers(def) < 0) {
1691
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Could not add controllers"));
1692 1693 1694 1695 1696
        goto cleanup;
    }

    for (controller = 0; controller < def->ncontrollers; ++controller) {
        if (def->controllers[controller]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
1697
            if (def->controllers[controller]->idx > 3) {
1698 1699 1700
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("SCSI controller index %d out of [0..3] range"),
                               def->controllers[controller]->idx);
1701 1702 1703 1704 1705 1706 1707 1708
                goto cleanup;
            }

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

1709
    /* def:fss */
1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723
    if (virVMXGetConfigBoolean(conf, "isolation.tools.hgfs.disable",
                               &hgfs_disabled, true, true) < 0) {
        goto cleanup;
    }

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

        if (sharedFolder_maxNum > 0) {
            int number;

1724
            if (VIR_ALLOC_N(def->fss, sharedFolder_maxNum) < 0)
1725 1726 1727 1728 1729 1730 1731 1732 1733 1734
                goto cleanup;

            def->nfss = 0;

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

1735
                if (def->fss[def->nfss] != NULL)
1736 1737 1738 1739
                    ++def->nfss;
            }
        }
    }
1740 1741

    /* def:nets */
1742
    if (VIR_ALLOC_N(def->nets, 4) < 0)
M
Matthias Bolte 已提交
1743
        goto cleanup;
1744 1745 1746 1747

    def->nnets = 0;

    for (controller = 0; controller < 4; ++controller) {
1748 1749
        if (virVMXParseEthernet(conf, controller,
                                &def->nets[def->nnets]) < 0) {
M
Matthias Bolte 已提交
1750
            goto cleanup;
1751 1752
        }

1753
        if (def->nets[def->nnets] != NULL)
1754 1755 1756 1757 1758 1759
            ++def->nnets;
    }

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

1760
    /* def:videos */
1761
    if (VIR_ALLOC_N(def->videos, 1) < 0)
1762 1763 1764 1765
        goto cleanup;

    def->nvideos = 0;

1766
    if (virVMXParseSVGA(conf, &def->videos[def->nvideos]) < 0)
1767 1768 1769 1770
        goto cleanup;

    def->nvideos = 1;

1771 1772 1773 1774 1775 1776 1777
    /* def:sounds */
    /* FIXME */

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

    /* def:serials */
1778
    if (VIR_ALLOC_N(def->serials, 4) < 0)
M
Matthias Bolte 已提交
1779
        goto cleanup;
1780 1781 1782 1783

    def->nserials = 0;

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

1789
        if (def->serials[def->nserials] != NULL)
1790 1791 1792 1793
            ++def->nserials;
    }

    /* def:parallels */
1794
    if (VIR_ALLOC_N(def->parallels, 3) < 0)
M
Matthias Bolte 已提交
1795
        goto cleanup;
1796 1797 1798 1799

    def->nparallels = 0;

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

1805
        if (def->parallels[def->nparallels] != NULL)
1806 1807 1808
            ++def->nparallels;
    }

1809 1810 1811 1812 1813 1814 1815 1816 1817
    /* ctx:datacenterPath -> def:namespaceData */
    if (ctx->datacenterPath) {
        if (VIR_STRDUP(namespaceData, ctx->datacenterPath) < 0)
            goto cleanup;

        def->ns = *virDomainXMLOptionGetNamespace(xmlopt);
        def->namespaceData = namespaceData;
    }

1818 1819 1820 1821
    if (virDomainDefPostParse(def, caps, VIR_DOMAIN_DEF_PARSE_ABI_UPDATE,
                              xmlopt) < 0)
        goto cleanup;

M
Matthias Bolte 已提交
1822 1823
    success = true;

1824
 cleanup:
M
Matthias Bolte 已提交
1825 1826 1827 1828 1829
    if (! success) {
        virDomainDefFree(def);
        def = NULL;
    }

1830
    virConfFree(conf);
1831
    VIR_FREE(encoding);
1832
    VIR_FREE(sched_cpu_affinity);
1833
    VIR_FREE(sched_cpu_shares);
M
Matthias Bolte 已提交
1834
    VIR_FREE(guestOS);
1835 1836 1837 1838 1839 1840

    return def;
}



M
Matthias Bolte 已提交
1841
int
1842
virVMXParseVNC(virConfPtr conf, virDomainGraphicsDefPtr *def)
M
Matthias Bolte 已提交
1843
{
1844
    bool enabled = false;
M
Matthias Bolte 已提交
1845
    long long port = 0;
1846
    char *listenAddr = NULL;
M
Matthias Bolte 已提交
1847 1848

    if (def == NULL || *def != NULL) {
1849
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
1850 1851 1852
        return -1;
    }

1853 1854
    if (virVMXGetConfigBoolean(conf, "RemoteDisplay.vnc.enabled", &enabled,
                               false, true) < 0) {
M
Matthias Bolte 已提交
1855 1856 1857
        return -1;
    }

1858
    if (! enabled)
M
Matthias Bolte 已提交
1859 1860
        return 0;

1861
    if (VIR_ALLOC(*def) < 0)
M
Matthias Bolte 已提交
1862 1863 1864 1865
        goto failure;

    (*def)->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;

1866 1867 1868
    if (virVMXGetConfigLong(conf, "RemoteDisplay.vnc.port", &port, -1,
                            true) < 0 ||
        virVMXGetConfigString(conf, "RemoteDisplay.vnc.ip",
1869
                              &listenAddr, true) < 0 ||
1870 1871 1872 1873
        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 已提交
1874 1875 1876
        goto failure;
    }

1877 1878 1879 1880 1881 1882
    if (listenAddr) {
        if (virDomainGraphicsListenSetAddress(*def, 0, listenAddr, -1, true) < 0)
            goto failure;
        VIR_FREE(listenAddr);
    }

M
Matthias Bolte 已提交
1883
    if (port < 0) {
1884
        VIR_WARN("VNC is enabled but VMX entry 'RemoteDisplay.vnc.port' "
M
Matthias Bolte 已提交
1885 1886 1887
                  "is missing, the VNC port is unknown");

        (*def)->data.vnc.port = 0;
1888
        (*def)->data.vnc.autoport = true;
M
Matthias Bolte 已提交
1889
    } else {
1890
        if (port < 5900 || port > 5964)
M
Matthias Bolte 已提交
1891 1892 1893
            VIR_WARN("VNC port %lld it out of [5900..5964] range", port);

        (*def)->data.vnc.port = port;
1894
        (*def)->data.vnc.autoport = false;
M
Matthias Bolte 已提交
1895 1896 1897 1898
    }

    return 0;

1899
 failure:
1900
    VIR_FREE(listenAddr);
M
Matthias Bolte 已提交
1901 1902 1903 1904 1905 1906 1907 1908
    virDomainGraphicsDefFree(*def);
    *def = NULL;

    return -1;
}



1909
int
1910 1911
virVMXParseSCSIController(virConfPtr conf, int controller, bool *present,
                          int *virtualDev)
1912
{
1913
    int result = -1;
1914 1915
    char present_name[32];
    char virtualDev_name[32];
1916 1917
    char *virtualDev_string = NULL;
    char *tmp;
1918

1919
    if (virtualDev == NULL || *virtualDev != -1) {
1920
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1921
        return -1;
1922 1923 1924
    }

    if (controller < 0 || controller > 3) {
1925 1926 1927
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("SCSI controller index %d out of [0..3] range"),
                       controller);
1928
        return -1;
1929 1930
    }

1931 1932 1933
    snprintf(present_name, sizeof(present_name), "scsi%d.present", controller);
    snprintf(virtualDev_name, sizeof(virtualDev_name), "scsi%d.virtualDev",
             controller);
1934

1935
    if (virVMXGetConfigBoolean(conf, present_name, present, false, true) < 0)
1936
        goto cleanup;
1937 1938

    if (! *present) {
1939 1940
        result = 0;
        goto cleanup;
1941 1942
    }

1943 1944
    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev_string,
                              true) < 0) {
1945
        goto cleanup;
1946 1947
    }

1948 1949 1950
    if (virtualDev_string != NULL) {
        tmp = virtualDev_string;

1951
        for (; *tmp != '\0'; ++tmp)
1952 1953
            *tmp = c_tolower(*tmp);

1954
        *virtualDev = virVMXControllerModelSCSITypeFromString(virtualDev_string);
1955 1956

        if (*virtualDev == -1 ||
1957 1958 1959 1960
            (*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)) {
1961 1962 1963 1964
            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);
1965
            goto cleanup;
1966
        }
1967 1968
    }

1969
    result = 0;
1970

1971
 cleanup:
1972
    VIR_FREE(virtualDev_string);
1973

1974
    return result;
1975 1976 1977 1978 1979
}



int
1980
virVMXParseDisk(virVMXContext *ctx, virDomainXMLOptionPtr xmlopt, virConfPtr conf,
1981
                int device, int busType, int controllerOrBus, int unit,
1982
                virDomainDiskDefPtr *def, virDomainDefPtr vmdef)
1983 1984
{
    /*
1985 1986 1987
     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK,
     *                    VIR_DOMAIN_DISK_DEVICE_CDROM,
     *                    VIR_DOMAIN_DISK_DEVICE_LUN}
1988 1989 1990
     *         busType = VIR_DOMAIN_DISK_BUS_SCSI
     * controllerOrBus = [0..3] -> controller
     *            unit = [0..6,8..15]
1991
     *
1992 1993 1994
     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK,
     *                    VIR_DOMAIN_DISK_DEVICE_CDROM,
     *                    VIR_DOMAIN_DISK_DEVICE_LUN}
1995 1996 1997
     *         busType = VIR_DOMAIN_DISK_BUS_IDE
     * controllerOrBus = [0..1] -> bus
     *            unit = [0..1]
1998
     *
1999 2000 2001 2002
     *          device = VIR_DOMAIN_DISK_DEVICE_FLOPPY
     *         busType = VIR_DOMAIN_DISK_BUS_FDC
     * controllerOrBus = [0]
     *            unit = [0..1]
2003 2004
     */

M
Matthias Bolte 已提交
2005
    int result = -1;
2006 2007 2008
    char *prefix = NULL;

    char present_name[32] = "";
2009
    bool present = false;
2010 2011

    char startConnected_name[32] = "";
2012
    bool startConnected = false;
2013 2014 2015 2016 2017

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

    char clientDevice_name[32] = "";
2018
    bool clientDevice = false;
2019 2020 2021 2022 2023 2024 2025 2026

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

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

    char writeThrough_name[32] = "";
2027
    bool writeThrough = false;
2028

2029 2030 2031
    char mode_name[32] = "";
    char *mode = NULL;

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

2037
    if (!(*def = virDomainDiskDefNew(xmlopt)))
M
Matthias Bolte 已提交
2038
        return -1;
2039 2040

    (*def)->device = device;
2041
    (*def)->bus = busType;
2042 2043 2044 2045

    /* def:dst, def:driverName */
    if (device == VIR_DOMAIN_DISK_DEVICE_DISK ||
        device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
2046 2047
        if (busType == VIR_DOMAIN_DISK_BUS_SCSI) {
            if (controllerOrBus < 0 || controllerOrBus > 3) {
2048 2049 2050
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("SCSI controller index %d out of [0..3] range"),
                               controllerOrBus);
M
Matthias Bolte 已提交
2051
                goto cleanup;
2052 2053
            }

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

2061
            if (virAsprintf(&prefix, "scsi%d:%d", controllerOrBus, unit) < 0)
M
Matthias Bolte 已提交
2062
                goto cleanup;
2063

M
Matthias Bolte 已提交
2064
            (*def)->dst =
2065
               virIndexToDiskName
2066
                 (controllerOrBus * 15 + (unit < 7 ? unit : unit - 1), "sd");
2067

2068
            if ((*def)->dst == NULL)
M
Matthias Bolte 已提交
2069
                goto cleanup;
2070 2071
        } else if (busType == VIR_DOMAIN_DISK_BUS_IDE) {
            if (controllerOrBus < 0 || controllerOrBus > 1) {
2072 2073 2074
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("IDE bus index %d out of [0..1] range"),
                               controllerOrBus);
M
Matthias Bolte 已提交
2075
                goto cleanup;
2076 2077
            }

2078
            if (unit < 0 || unit > 1) {
2079 2080
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("IDE unit index %d out of [0..1] range"), unit);
M
Matthias Bolte 已提交
2081
                goto cleanup;
2082 2083
            }

2084
            if (virAsprintf(&prefix, "ide%d:%d", controllerOrBus, unit) < 0)
M
Matthias Bolte 已提交
2085
                goto cleanup;
2086

2087
            (*def)->dst = virIndexToDiskName(controllerOrBus * 2 + unit, "hd");
2088

2089
            if ((*def)->dst == NULL)
M
Matthias Bolte 已提交
2090
                goto cleanup;
2091
        } else {
2092 2093 2094 2095
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported bus type '%s' for device type '%s'"),
                           virDomainDiskBusTypeToString(busType),
                           virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2096
            goto cleanup;
2097 2098
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2099 2100
        if (busType == VIR_DOMAIN_DISK_BUS_FDC) {
            if (controllerOrBus != 0) {
2101 2102 2103
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("FDC controller index %d out of [0] range"),
                               controllerOrBus);
2104 2105 2106 2107
                goto cleanup;
            }

            if (unit < 0 || unit > 1) {
2108 2109 2110
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("FDC unit index %d out of [0..1] range"),
                               unit);
M
Matthias Bolte 已提交
2111
                goto cleanup;
2112 2113
            }

2114
            if (virAsprintf(&prefix, "floppy%d", unit) < 0)
M
Matthias Bolte 已提交
2115
                goto cleanup;
2116

2117
            (*def)->dst = virIndexToDiskName(unit, "fd");
2118

2119
            if ((*def)->dst == NULL)
M
Matthias Bolte 已提交
2120
                goto cleanup;
2121
        } else {
2122 2123 2124 2125
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported bus type '%s' for device type '%s'"),
                           virDomainDiskBusTypeToString(busType),
                           virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2126
            goto cleanup;
2127 2128
        }
    } else {
2129 2130 2131
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported device type '%s'"),
                       virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2132
        goto cleanup;
2133 2134
    }

2135 2136 2137 2138 2139 2140 2141
    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);
2142
    VMX_BUILD_NAME(mode);
2143 2144

    /* vmx:present */
2145
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
M
Matthias Bolte 已提交
2146
        goto cleanup;
2147 2148

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

    /* FIXME: Need to distiguish between active and inactive domains here */
2155
    if (! present/* && ! startConnected*/)
2156 2157 2158
        goto ignore;

    /* vmx:deviceType -> def:type */
2159
    if (virVMXGetConfigString(conf, deviceType_name, &deviceType, true) < 0)
M
Matthias Bolte 已提交
2160
        goto cleanup;
2161 2162

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

2168
    /* vmx:mode -> def:transient */
2169
    if (virVMXGetConfigString(conf, mode_name, &mode, true) < 0)
2170 2171
        goto cleanup;

2172 2173 2174
    if (clientDevice) {
        /*
         * Just ignore devices in client mode, because I have no clue how to
M
Matthias Bolte 已提交
2175
         * handle them (e.g. assign an image) without the VI Client GUI.
2176 2177 2178 2179 2180
         */
        goto ignore;
    }

    /* vmx:fileType -> def:type */
2181
    if (virVMXGetConfigString(conf, fileType_name, &fileType, true) < 0)
M
Matthias Bolte 已提交
2182
        goto cleanup;
2183 2184

    /* vmx:fileName -> def:src, def:type */
2185
    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0)
M
Matthias Bolte 已提交
2186
        goto cleanup;
2187 2188

    /* vmx:writeThrough -> def:cachemode */
2189 2190
    if (virVMXGetConfigBoolean(conf, writeThrough_name, &writeThrough, false,
                               true) < 0) {
M
Matthias Bolte 已提交
2191
        goto cleanup;
2192 2193 2194 2195
    }

    /* Setup virDomainDiskDef */
    if (device == VIR_DOMAIN_DISK_DEVICE_DISK) {
2196
        if (virFileHasSuffix(fileName, ".vmdk")) {
2197 2198
            char *tmp;

2199
            if (deviceType != NULL) {
2200
                if (busType == VIR_DOMAIN_DISK_BUS_SCSI &&
2201 2202
                    STRCASENEQ(deviceType, "scsi-hardDisk") &&
                    STRCASENEQ(deviceType, "disk")) {
2203 2204 2205 2206
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'scsi-hardDisk' "
                                     "or 'disk' but found '%s'"), deviceType_name,
                                   deviceType);
M
Matthias Bolte 已提交
2207
                    goto cleanup;
2208
                } else if (busType == VIR_DOMAIN_DISK_BUS_IDE &&
2209 2210
                           STRCASENEQ(deviceType, "ata-hardDisk") &&
                           STRCASENEQ(deviceType, "disk")) {
2211 2212 2213 2214
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'ata-hardDisk' "
                                     "or 'disk' but found '%s'"), deviceType_name,
                                   deviceType);
M
Matthias Bolte 已提交
2215
                    goto cleanup;
2216 2217 2218
                }
            }

E
Eric Blake 已提交
2219
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
2220 2221 2222 2223 2224 2225 2226
            if (!(tmp = ctx->parseFileName(fileName, ctx->opaque)))
                goto cleanup;
            if (virDomainDiskSetSource(*def, tmp) < 0) {
                VIR_FREE(tmp);
                goto cleanup;
            }
            VIR_FREE(tmp);
2227 2228
            (*def)->cachemode = writeThrough ? VIR_DOMAIN_DISK_CACHE_WRITETHRU
                                             : VIR_DOMAIN_DISK_CACHE_DEFAULT;
2229 2230 2231
            if (mode)
                (*def)->transient = STRCASEEQ(mode,
                                              "independent-nonpersistent");
2232
        } else if (virFileHasSuffix(fileName, ".iso") ||
2233 2234
                   (deviceType &&
                    (STRCASEEQ(deviceType, "atapi-cdrom") ||
2235 2236 2237
                     STRCASEEQ(deviceType, "cdrom-raw") ||
                     (STRCASEEQ(deviceType, "scsi-passthru") &&
                      STRPREFIX(fileName, "/vmfs/devices/cdrom/"))))) {
2238 2239
            /*
             * This function was called in order to parse a harddisk device,
2240 2241 2242
             * but .iso files, 'atapi-cdrom', 'cdrom-raw', and 'scsi-passthru'
             * CDROM devices are for CDROM devices only. Just ignore it, another
             * call to this function to parse a CDROM device may handle it.
2243 2244 2245
             */
            goto ignore;
        } else {
2246
            virReportError(VIR_ERR_INTERNAL_ERROR,
2247 2248
                           _("Invalid or not yet handled value '%s' "
                             "for VMX entry '%s' for device type '%s'"),
M
Matthias Bolte 已提交
2249 2250
                           fileName, fileName_name,
                           deviceType ? deviceType : "unknown");
M
Matthias Bolte 已提交
2251
            goto cleanup;
2252 2253
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
2254
        if (virFileHasSuffix(fileName, ".iso")) {
2255 2256
            char *tmp;

2257 2258 2259 2260 2261
            if (deviceType && STRCASENEQ(deviceType, "cdrom-image")) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry '%s' to be 'cdrom-image' "
                                 "but found '%s'"), deviceType_name, deviceType);
                goto cleanup;
2262 2263
            }

E
Eric Blake 已提交
2264
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
2265 2266 2267 2268
            if (!(tmp = ctx->parseFileName(fileName, ctx->opaque)))
                goto cleanup;
            if (virDomainDiskSetSource(*def, tmp) < 0) {
                VIR_FREE(tmp);
M
Matthias Bolte 已提交
2269
                goto cleanup;
M
Matthias Bolte 已提交
2270
            }
2271
            VIR_FREE(tmp);
2272
        } else if (virFileHasSuffix(fileName, ".vmdk")) {
2273 2274 2275 2276 2277 2278 2279
            /*
             * 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;
2280
        } else if (deviceType && STRCASEEQ(deviceType, "atapi-cdrom")) {
E
Eric Blake 已提交
2281
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);
2282 2283

            if (STRCASEEQ(fileName, "auto detect")) {
2284
                ignore_value(virDomainDiskSetSource(*def, NULL));
2285
                (*def)->startupPolicy = VIR_DOMAIN_STARTUP_POLICY_OPTIONAL;
2286 2287
            } else if (virDomainDiskSetSource(*def, fileName) < 0) {
                goto cleanup;
2288
            }
2289
        } else if (deviceType && STRCASEEQ(deviceType, "cdrom-raw")) {
2290 2291
            /* Raw access CD-ROMs actually are device='lun' */
            (*def)->device = VIR_DOMAIN_DISK_DEVICE_LUN;
E
Eric Blake 已提交
2292
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);
2293 2294

            if (STRCASEEQ(fileName, "auto detect")) {
2295
                ignore_value(virDomainDiskSetSource(*def, NULL));
2296
                (*def)->startupPolicy = VIR_DOMAIN_STARTUP_POLICY_OPTIONAL;
2297 2298
            } else if (virDomainDiskSetSource(*def, fileName) < 0) {
                goto cleanup;
2299
            }
2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317
        } else if (busType == VIR_DOMAIN_DISK_BUS_SCSI &&
                   deviceType && STRCASEEQ(deviceType, "scsi-passthru")) {
            if (STRPREFIX(fileName, "/vmfs/devices/cdrom/")) {
                /* SCSI-passthru CD-ROMs actually are device='lun' */
                (*def)->device = VIR_DOMAIN_DISK_DEVICE_LUN;
                virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);

                if (virDomainDiskSetSource(*def, fileName) < 0)
                    goto cleanup;
            } else {
                /*
                 * This function was called in order to parse a CDROM device,
                 * but the filename does not indicate a CDROM device. Just ignore
                 * it, another call to this function to parse a harddisk device
                 * may handle it.
                 */
                goto ignore;
            }
2318
        } else {
2319
            virReportError(VIR_ERR_INTERNAL_ERROR,
2320 2321
                           _("Invalid or not yet handled value '%s' "
                             "for VMX entry '%s' for device type '%s'"),
M
Matthias Bolte 已提交
2322 2323
                           fileName, fileName_name,
                           deviceType ? deviceType : "unknown");
M
Matthias Bolte 已提交
2324
            goto cleanup;
2325 2326
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2327
        if (fileType != NULL && STRCASEEQ(fileType, "device")) {
E
Eric Blake 已提交
2328
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);
2329 2330
            if (virDomainDiskSetSource(*def, fileName) < 0)
                goto cleanup;
2331
        } else if (fileType != NULL && STRCASEEQ(fileType, "file")) {
2332 2333
            char *tmp;

E
Eric Blake 已提交
2334
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
2335 2336 2337 2338 2339 2340 2341
            if (!(tmp = ctx->parseFileName(fileName, ctx->opaque)))
                goto cleanup;
            if (virDomainDiskSetSource(*def, tmp) < 0) {
                VIR_FREE(tmp);
                goto cleanup;
            }
            VIR_FREE(tmp);
2342
        } else {
2343
            virReportError(VIR_ERR_INTERNAL_ERROR,
2344 2345
                           _("Invalid or not yet handled value '%s' "
                             "for VMX entry '%s' for device type '%s'"),
M
Matthias Bolte 已提交
2346 2347
                           fileName, fileName_name,
                           deviceType ? deviceType : "unknown");
M
Matthias Bolte 已提交
2348
            goto cleanup;
2349 2350
        }
    } else {
2351 2352
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported device type '%s'"),
                       virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2353
        goto cleanup;
2354 2355
    }

2356
    if (virDomainDiskDefAssignAddress(xmlopt, *def, vmdef) < 0) {
2357
        virReportError(VIR_ERR_INTERNAL_ERROR,
2358 2359
                       _("Could not assign address to disk '%s'"),
                       virDomainDiskGetSource(*def));
2360 2361 2362
        goto cleanup;
    }

M
Matthias Bolte 已提交
2363 2364
    result = 0;

2365
 cleanup:
M
Matthias Bolte 已提交
2366 2367 2368 2369 2370
    if (result < 0) {
        virDomainDiskDefFree(*def);
        *def = NULL;
    }

2371 2372 2373 2374
    VIR_FREE(prefix);
    VIR_FREE(deviceType);
    VIR_FREE(fileType);
    VIR_FREE(fileName);
2375
    VIR_FREE(mode);
2376 2377 2378

    return result;

2379
 ignore:
2380 2381 2382
    virDomainDiskDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2383 2384
    result = 0;

2385 2386 2387 2388 2389
    goto cleanup;
}



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
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;
    }

2415
    if (VIR_ALLOC(*def) < 0)
2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428
        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 */
2429
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
2430 2431 2432
        goto cleanup;

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

2436
    if (!(present && enabled))
2437 2438 2439
        goto ignore;

    /* vmx:hostPath */
2440
    if (virVMXGetConfigString(conf, hostPath_name, &hostPath, false) < 0)
2441 2442 2443 2444 2445 2446
        goto cleanup;

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

    /* vmx:guestName */
2447
    if (virVMXGetConfigString(conf, guestName_name, &guestName, false) < 0)
2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462
        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;

2463
 cleanup:
2464 2465 2466 2467 2468 2469 2470 2471 2472 2473
    if (result < 0) {
        virDomainFSDefFree(*def);
        *def = NULL;
    }

    VIR_FREE(hostPath);
    VIR_FREE(guestName);

    return result;

2474
 ignore:
2475 2476 2477 2478 2479 2480 2481 2482 2483 2484
    virDomainFSDefFree(*def);
    *def = NULL;

    result = 0;

    goto cleanup;
}



2485
int
2486
virVMXParseEthernet(virConfPtr conf, int controller, virDomainNetDefPtr *def)
2487
{
M
Matthias Bolte 已提交
2488
    int result = -1;
2489 2490 2491
    char prefix[48] = "";

    char present_name[48] = "";
2492
    bool present = false;
2493 2494

    char startConnected_name[48] = "";
2495
    bool startConnected = false;
2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511

    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;

2512 2513 2514
    char features_name[48] = "";
    long long features = 0;

2515 2516 2517
    char vnet_name[48] = "";
    char *vnet = NULL;

M
Matthias Bolte 已提交
2518 2519 2520
    char networkName_name[48] = "";
    char *networkName = NULL;

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

    if (controller < 0 || controller > 3) {
2527 2528 2529
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Ethernet controller index %d out of [0..3] range"),
                       controller);
2530
        return -1;
2531 2532
    }

2533
    if (VIR_ALLOC(*def) < 0)
M
Matthias Bolte 已提交
2534
        return -1;
2535

2536
    snprintf(prefix, sizeof(prefix), "ethernet%d", controller);
2537

2538 2539 2540 2541 2542 2543 2544 2545 2546 2547
    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);
2548 2549

    /* vmx:present */
2550
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
M
Matthias Bolte 已提交
2551
        goto cleanup;
2552 2553

    /* vmx:startConnected */
2554 2555
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2556
        goto cleanup;
2557 2558 2559
    }

    /* FIXME: Need to distiguish between active and inactive domains here */
2560
    if (! present/* && ! startConnected*/)
2561 2562 2563
        goto ignore;

    /* vmx:connectionType -> def:type */
2564 2565
    if (virVMXGetConfigString(conf, connectionType_name, &connectionType,
                              true) < 0) {
M
Matthias Bolte 已提交
2566
        goto cleanup;
2567 2568 2569
    }

    /* vmx:addressType, vmx:generatedAddress, vmx:address -> def:mac */
2570 2571 2572 2573 2574
    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 已提交
2575
        goto cleanup;
2576 2577
    }

2578 2579
    if (addressType == NULL || STRCASEEQ(addressType, "generated") ||
        STRCASEEQ(addressType, "vpx")) {
2580
        if (generatedAddress != NULL) {
2581
            if (virMacAddrParse(generatedAddress, &(*def)->mac) < 0) {
2582 2583 2584 2585
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry '%s' to be MAC address but "
                                 "found '%s'"), generatedAddress_name,
                               generatedAddress);
M
Matthias Bolte 已提交
2586
                goto cleanup;
2587 2588 2589 2590
            }
        }
    } else if (STRCASEEQ(addressType, "static")) {
        if (address != NULL) {
2591
            if (virMacAddrParse(address, &(*def)->mac) < 0) {
2592 2593 2594
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry '%s' to be MAC address but "
                                 "found '%s'"), address_name, address);
M
Matthias Bolte 已提交
2595
                goto cleanup;
2596 2597 2598
            }
        }
    } else {
2599 2600 2601
        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 已提交
2602
        goto cleanup;
2603 2604
    }

2605
    /* vmx:virtualDev, vmx:features -> def:model */
2606 2607
    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev, true) < 0 ||
        virVMXGetConfigLong(conf, features_name, &features, 0, true) < 0) {
M
Matthias Bolte 已提交
2608
        goto cleanup;
2609 2610
    }

2611 2612 2613 2614
    if (virtualDev != NULL) {
        if (STRCASENEQ(virtualDev, "vlance") &&
            STRCASENEQ(virtualDev, "vmxnet") &&
            STRCASENEQ(virtualDev, "vmxnet3") &&
2615 2616
            STRCASENEQ(virtualDev, "e1000") &&
            STRCASENEQ(virtualDev, "e1000e")) {
2617 2618
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting VMX entry '%s' to be 'vlance' or 'vmxnet' or "
M
Matthias Bolte 已提交
2619 2620
                             "'vmxnet3' or 'e1000e' or 'e1000e' but found '%s'"),
                           virtualDev_name, virtualDev);
M
Matthias Bolte 已提交
2621
            goto cleanup;
2622 2623 2624 2625 2626
        }

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

2627
            if (VIR_STRDUP(virtualDev, "vmxnet2") < 0)
M
Matthias Bolte 已提交
2628
                goto cleanup;
2629
        }
2630 2631
    }

M
Matthias Bolte 已提交
2632
    /* vmx:networkName -> def:data.bridge.brname */
2633 2634 2635 2636 2637 2638 2639
    if (connectionType == NULL ||
        STRCASEEQ(connectionType, "bridged") ||
        STRCASEEQ(connectionType, "custom")) {
        if (virVMXGetConfigString(conf, networkName_name, &networkName,
                                  true) < 0)
            goto cleanup;

2640 2641
        if (!networkName && VIR_STRDUP(networkName, "") < 0)
            goto cleanup;
M
Matthias Bolte 已提交
2642 2643 2644
    }

    /* vmx:vnet -> def:data.ifname */
2645
    if (connectionType != NULL && STRCASEEQ(connectionType, "custom") &&
2646
        virVMXGetConfigString(conf, vnet_name, &vnet, false) < 0) {
M
Matthias Bolte 已提交
2647
        goto cleanup;
2648 2649 2650 2651 2652 2653
    }

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

        virtualDev = NULL;
M
Matthias Bolte 已提交
2657
        networkName = NULL;
2658 2659
    } else if (STRCASEEQ(connectionType, "hostonly")) {
        /* FIXME */
2660 2661 2662
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No yet handled value '%s' for VMX entry '%s'"),
                       connectionType, connectionType_name);
M
Matthias Bolte 已提交
2663
        goto cleanup;
2664
    } else if (STRCASEEQ(connectionType, "nat")) {
2665 2666 2667 2668
        (*def)->type = VIR_DOMAIN_NET_TYPE_USER;
        (*def)->model = virtualDev;

        virtualDev = NULL;
2669 2670 2671
    } else if (STRCASEEQ(connectionType, "custom")) {
        (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
        (*def)->model = virtualDev;
M
Matthias Bolte 已提交
2672 2673
        (*def)->data.bridge.brname = networkName;
        (*def)->ifname = vnet;
2674 2675

        virtualDev = NULL;
M
Matthias Bolte 已提交
2676
        networkName = NULL;
2677 2678
        vnet = NULL;
    } else {
2679 2680 2681
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid value '%s' for VMX entry '%s'"), connectionType,
                       connectionType_name);
M
Matthias Bolte 已提交
2682
        goto cleanup;
2683 2684
    }

M
Matthias Bolte 已提交
2685 2686
    result = 0;

2687
 cleanup:
M
Matthias Bolte 已提交
2688 2689 2690 2691 2692
    if (result < 0) {
        virDomainNetDefFree(*def);
        *def = NULL;
    }

S
Stefan Berger 已提交
2693
    VIR_FREE(networkName);
2694 2695 2696 2697 2698 2699 2700 2701 2702
    VIR_FREE(connectionType);
    VIR_FREE(addressType);
    VIR_FREE(generatedAddress);
    VIR_FREE(address);
    VIR_FREE(virtualDev);
    VIR_FREE(vnet);

    return result;

2703
 ignore:
2704 2705 2706
    virDomainNetDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2707 2708
    result = 0;

2709 2710 2711 2712 2713 2714
    goto cleanup;
}



int
2715 2716
virVMXParseSerial(virVMXContext *ctx, virConfPtr conf, int port,
                  virDomainChrDefPtr *def)
2717
{
M
Matthias Bolte 已提交
2718
    int result = -1;
2719 2720 2721
    char prefix[48] = "";

    char present_name[48] = "";
2722
    bool present = false;
2723 2724

    char startConnected_name[48] = "";
2725
    bool startConnected = false;
2726 2727 2728 2729 2730 2731 2732

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

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

2733 2734 2735
    char network_endPoint_name[48] = "";
    char *network_endPoint = NULL;

M
Martin Kletzander 已提交
2736
    virURIPtr parsedUri = NULL;
2737

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

    if (port < 0 || port > 3) {
2744 2745
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Serial port index %d out of [0..3] range"), port);
2746
        return -1;
2747 2748
    }

2749
    if (VIR_ALLOC(*def) < 0)
M
Matthias Bolte 已提交
2750
        return -1;
2751

2752
    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
2753

2754
    snprintf(prefix, sizeof(prefix), "serial%d", port);
2755

2756 2757 2758 2759 2760
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
    VMX_BUILD_NAME_EXTRA(network_endPoint, "network.endPoint");
2761 2762

    /* vmx:present */
2763
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
M
Matthias Bolte 已提交
2764
        goto cleanup;
2765 2766

    /* vmx:startConnected */
2767 2768
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2769
        goto cleanup;
2770 2771 2772
    }

    /* FIXME: Need to distiguish between active and inactive domains here */
2773
    if (! present/* && ! startConnected*/)
2774 2775 2776
        goto ignore;

    /* vmx:fileType -> def:type */
G
Geoff Hickey 已提交
2777
    if (virVMXGetConfigString(conf, fileType_name, &fileType, true) < 0)
M
Matthias Bolte 已提交
2778
        goto cleanup;
2779 2780

    /* vmx:fileName -> def:data.file.path */
2781
    if (virVMXGetConfigString(conf, fileName_name, &fileName, true) < 0)
2782
        goto cleanup;
2783

2784
    /* vmx:network.endPoint -> def:data.tcp.listen */
2785 2786
    if (virVMXGetConfigString(conf, network_endPoint_name, &network_endPoint,
                              true) < 0) {
2787 2788 2789
        goto cleanup;
    }

G
Geoff Hickey 已提交
2790 2791 2792 2793 2794 2795
    /*
     * Setup virDomainChrDef. The default fileType is "device", and vmware
     * will sometimes omit this tag when adding a new serial port of this
     * type.
     */
    if (!fileType || STRCASEEQ(fileType, "device")) {
2796
        (*def)->target.port = port;
2797 2798
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
        (*def)->source.data.file.path = fileName;
2799 2800 2801

        fileName = NULL;
    } else if (STRCASEEQ(fileType, "file")) {
2802
        (*def)->target.port = port;
2803 2804 2805
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
        (*def)->source.data.file.path = ctx->parseFileName(fileName,
                                                           ctx->opaque);
2806

2807
        if ((*def)->source.data.file.path == NULL)
M
Matthias Bolte 已提交
2808
            goto cleanup;
2809
    } else if (STRCASEEQ(fileType, "pipe")) {
M
Matthias Bolte 已提交
2810 2811 2812 2813
        /*
         * FIXME: Differences between client/server and VM/application pipes
         *        not representable in domain XML form
         */
2814
        (*def)->target.port = port;
2815 2816
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
        (*def)->source.data.file.path = fileName;
M
Matthias Bolte 已提交
2817 2818

        fileName = NULL;
2819 2820
    } else if (STRCASEEQ(fileType, "network")) {
        (*def)->target.port = port;
2821
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_TCP;
2822

2823
        if (!(parsedUri = virURIParse(fileName)))
2824 2825 2826
            goto cleanup;

        if (parsedUri->port == 0) {
2827 2828 2829
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("VMX entry '%s' doesn't contain a port part"),
                           fileName_name);
2830 2831 2832
            goto cleanup;
        }

2833
        if (VIR_STRDUP((*def)->source.data.tcp.host, parsedUri->server) < 0)
2834 2835
            goto cleanup;

2836
        if (virAsprintf(&(*def)->source.data.tcp.service, "%d",
2837
                        parsedUri->port) < 0)
2838 2839 2840 2841 2842 2843 2844
            goto cleanup;

        /* See vSphere API documentation about VirtualSerialPortURIBackingInfo */
        if (parsedUri->scheme == NULL ||
            STRCASEEQ(parsedUri->scheme, "tcp") ||
            STRCASEEQ(parsedUri->scheme, "tcp4") ||
            STRCASEEQ(parsedUri->scheme, "tcp6")) {
2845
            (*def)->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
2846
        } else if (STRCASEEQ(parsedUri->scheme, "telnet")) {
2847 2848
            (*def)->source.data.tcp.protocol
                = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
2849
        } else if (STRCASEEQ(parsedUri->scheme, "telnets")) {
2850 2851
            (*def)->source.data.tcp.protocol
                = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS;
2852 2853 2854 2855
        } else if (STRCASEEQ(parsedUri->scheme, "ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp+ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp4+ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp6+ssl")) {
2856
            (*def)->source.data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS;
2857
        } else {
2858 2859 2860
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("VMX entry '%s' contains unsupported scheme '%s'"),
                           fileName_name, parsedUri->scheme);
2861 2862 2863 2864
            goto cleanup;
        }

        if (network_endPoint == NULL || STRCASEEQ(network_endPoint, "server")) {
2865
            (*def)->source.data.tcp.listen = true;
2866
        } else if (STRCASEEQ(network_endPoint, "client")) {
2867
            (*def)->source.data.tcp.listen = false;
2868
        } else {
2869 2870 2871
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting VMX entry '%s' to be 'server' or 'client' "
                             "but found '%s'"), network_endPoint_name, network_endPoint);
2872 2873
            goto cleanup;
        }
2874
    } else {
2875 2876 2877
        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 已提交
2878
        goto cleanup;
2879 2880
    }

M
Matthias Bolte 已提交
2881 2882
    result = 0;

2883
 cleanup:
M
Matthias Bolte 已提交
2884 2885 2886 2887 2888
    if (result < 0) {
        virDomainChrDefFree(*def);
        *def = NULL;
    }

2889 2890
    VIR_FREE(fileType);
    VIR_FREE(fileName);
2891
    VIR_FREE(network_endPoint);
2892
    virURIFree(parsedUri);
2893 2894 2895

    return result;

2896
 ignore:
2897 2898 2899
    virDomainChrDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2900 2901
    result = 0;

2902 2903 2904 2905 2906 2907
    goto cleanup;
}



int
2908 2909
virVMXParseParallel(virVMXContext *ctx, virConfPtr conf, int port,
                    virDomainChrDefPtr *def)
2910
{
M
Matthias Bolte 已提交
2911
    int result = -1;
2912 2913 2914
    char prefix[48] = "";

    char present_name[48] = "";
2915
    bool present = false;
2916 2917

    char startConnected_name[48] = "";
2918
    bool startConnected = false;
2919 2920 2921 2922 2923 2924 2925 2926

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

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

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

    if (port < 0 || port > 2) {
2932 2933
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parallel port index %d out of [0..2] range"), port);
2934
        return -1;
2935 2936
    }

2937
    if (VIR_ALLOC(*def) < 0)
M
Matthias Bolte 已提交
2938
        return -1;
2939

2940
    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
2941

2942
    snprintf(prefix, sizeof(prefix), "parallel%d", port);
2943

2944 2945 2946 2947
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
2948 2949

    /* vmx:present */
2950
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
M
Matthias Bolte 已提交
2951
        goto cleanup;
2952 2953

    /* vmx:startConnected */
2954 2955
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2956
        goto cleanup;
2957 2958 2959
    }

    /* FIXME: Need to distiguish between active and inactive domains here */
2960
    if (! present/* && ! startConnected*/)
2961 2962 2963
        goto ignore;

    /* vmx:fileType -> def:type */
2964
    if (virVMXGetConfigString(conf, fileType_name, &fileType, false) < 0)
M
Matthias Bolte 已提交
2965
        goto cleanup;
2966 2967

    /* vmx:fileName -> def:data.file.path */
2968
    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0)
M
Matthias Bolte 已提交
2969
        goto cleanup;
2970 2971 2972

    /* Setup virDomainChrDef */
    if (STRCASEEQ(fileType, "device")) {
2973
        (*def)->target.port = port;
2974 2975
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
        (*def)->source.data.file.path = fileName;
2976 2977 2978

        fileName = NULL;
    } else if (STRCASEEQ(fileType, "file")) {
2979
        (*def)->target.port = port;
2980 2981 2982
        (*def)->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
        (*def)->source.data.file.path = ctx->parseFileName(fileName,
                                                           ctx->opaque);
2983

2984
        if ((*def)->source.data.file.path == NULL)
M
Matthias Bolte 已提交
2985
            goto cleanup;
2986
    } else {
2987 2988 2989
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry '%s' to be 'device' or 'file' but "
                         "found '%s'"), fileType_name, fileType);
M
Matthias Bolte 已提交
2990
        goto cleanup;
2991 2992
    }

M
Matthias Bolte 已提交
2993 2994
    result = 0;

2995
 cleanup:
M
Matthias Bolte 已提交
2996 2997 2998 2999 3000
    if (result < 0) {
        virDomainChrDefFree(*def);
        *def = NULL;
    }

3001 3002 3003 3004 3005
    VIR_FREE(fileType);
    VIR_FREE(fileName);

    return result;

3006
 ignore:
3007 3008 3009
    virDomainChrDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
3010 3011
    result = 0;

3012 3013
    goto cleanup;
}
M
Matthias Bolte 已提交
3014 3015 3016



3017 3018 3019 3020 3021 3022 3023
int
virVMXParseSVGA(virConfPtr conf, virDomainVideoDefPtr *def)
{
    int result = -1;
    long long svga_vramSize = 0;

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

3028
    if (VIR_ALLOC(*def) < 0)
3029 3030 3031 3032 3033 3034 3035 3036 3037 3038
        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;
    }

3039
    (*def)->vram = VIR_DIV_UP(svga_vramSize, 1024); /* Scale from bytes to kilobytes */
3040 3041 3042

    result = 0;

3043
 cleanup:
3044 3045 3046 3047 3048 3049 3050 3051 3052 3053
    if (result < 0) {
        virDomainVideoDefFree(*def);
        *def = NULL;
    }

    return result;
}



M
Matthias Bolte 已提交
3054 3055 3056 3057 3058
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Domain XML -> VMX
 */

char *
3059
virVMXFormatConfig(virVMXContext *ctx, virDomainXMLOptionPtr xmlopt, virDomainDefPtr def,
3060
                   int virtualHW_version)
M
Matthias Bolte 已提交
3061
{
3062
    char *vmx = NULL;
3063
    size_t i;
M
Matthias Bolte 已提交
3064 3065 3066
    int sched_cpu_affinity_length;
    unsigned char zero[VIR_UUID_BUFLEN];
    virBuffer buffer = VIR_BUFFER_INITIALIZER;
3067 3068
    char *preliminaryDisplayName = NULL;
    char *displayName = NULL;
3069
    char *annotation = NULL;
3070
    unsigned long long max_balloon;
3071 3072
    bool scsi_present[4] = { false, false, false, false };
    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
3073
    bool floppy_present[2] = { false, false };
3074
    unsigned int maxvcpus;
M
Matthias Bolte 已提交
3075

3076
    if (ctx->formatFileName == NULL) {
3077 3078
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("virVMXContext has no formatFileName function set"));
3079 3080 3081
        return NULL;
    }

M
Matthias Bolte 已提交
3082 3083
    memset(zero, 0, VIR_UUID_BUFLEN);

3084
    if (def->virtType != VIR_DOMAIN_VIRT_VMWARE) {
3085 3086 3087 3088
        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 已提交
3089 3090 3091
        return NULL;
    }

3092 3093 3094
    /* vmx:.encoding */
    virBufferAddLit(&buffer, ".encoding = \"UTF-8\"\n");

M
Matthias Bolte 已提交
3095 3096 3097 3098
    /* vmx:config.version */
    virBufferAddLit(&buffer, "config.version = \"8\"\n");

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

M
Matthias Bolte 已提交
3102
    /* def:os.arch -> vmx:guestOS */
3103
    if (def->os.arch == VIR_ARCH_I686) {
M
Matthias Bolte 已提交
3104
        virBufferAddLit(&buffer, "guestOS = \"other\"\n");
3105
    } else if (def->os.arch == VIR_ARCH_X86_64) {
M
Matthias Bolte 已提交
3106 3107
        virBufferAddLit(&buffer, "guestOS = \"other-64\"\n");
    } else {
3108 3109
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting domain XML attribute 'arch' of entry 'os/type' "
3110 3111
                         "to be 'i686' or 'x86_64' but found '%s'"),
                       virArchToString(def->os.arch));
3112
        goto cleanup;
M
Matthias Bolte 已提交
3113 3114
    }

M
Matthias Bolte 已提交
3115 3116 3117 3118 3119 3120 3121
    /* 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 {
3122 3123 3124
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported SMBIOS mode '%s'"),
                       virDomainSmbiosModeTypeToString(def->os.smbios_mode));
M
Matthias Bolte 已提交
3125 3126 3127
        goto cleanup;
    }

M
Matthias Bolte 已提交
3128 3129 3130 3131
    /* def:uuid -> vmx:uuid.action, vmx:uuid.bios */
    if (memcmp(def->uuid, zero, VIR_UUID_BUFLEN) == 0) {
        virBufferAddLit(&buffer, "uuid.action = \"create\"\n");
    } else {
3132
        virBufferAsprintf(&buffer, "uuid.bios = \"%02x %02x %02x %02x %02x %02x "
M
Matthias Bolte 已提交
3133 3134 3135 3136 3137 3138 3139 3140 3141
                          "%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 */
3142
    preliminaryDisplayName = virVMXEscapeHexPipe(def->name);
3143

3144
    if (preliminaryDisplayName == NULL)
3145
        goto cleanup;
3146

3147
    displayName = virVMXEscapeHexPercent(preliminaryDisplayName);
3148

3149
    if (displayName == NULL)
3150
        goto cleanup;
3151

3152
    virBufferAsprintf(&buffer, "displayName = \"%s\"\n", displayName);
3153

3154 3155
    /* def:description -> vmx:annotation */
    if (def->description != NULL) {
3156 3157
        if (!(annotation = virVMXEscapeHexPipe(def->description)))
            goto cleanup;
3158

3159
        virBufferAsprintf(&buffer, "annotation = \"%s\"\n", annotation);
3160 3161
    }

3162
    /* def:mem.max_balloon -> vmx:memsize */
3163
    /* max-memory must be a multiple of 4096 kilobyte */
3164
    max_balloon = VIR_DIV_UP(virDomainDefGetMemoryActual(def), 4096) * 4096;
M
Matthias Bolte 已提交
3165

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

3169
    /* def:mem.cur_balloon -> vmx:sched.mem.max */
3170
    if (def->mem.cur_balloon < max_balloon) {
3171
        virBufferAsprintf(&buffer, "sched.mem.max = \"%llu\"\n",
3172 3173
                          VIR_DIV_UP(def->mem.cur_balloon,
                                     1024)); /* Scale from kilobytes to megabytes */
M
Matthias Bolte 已提交
3174 3175
    }

3176 3177
    /* def:mem.min_guarantee -> vmx:sched.mem.minsize */
    if (def->mem.min_guarantee > 0) {
3178
        virBufferAsprintf(&buffer, "sched.mem.minsize = \"%llu\"\n",
3179 3180
                          VIR_DIV_UP(def->mem.min_guarantee,
                                     1024)); /* Scale from kilobytes to megabytes */
3181 3182
    }

E
Eric Blake 已提交
3183
    /* def:maxvcpus -> vmx:numvcpus */
3184
    if (virDomainDefHasVcpusOffline(def)) {
3185 3186 3187
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("No support for domain XML entry 'vcpu' attribute "
                         "'current'"));
E
Eric Blake 已提交
3188 3189
        goto cleanup;
    }
3190 3191
    maxvcpus = virDomainDefGetVcpusMax(def);
    if (maxvcpus == 0 || (maxvcpus % 2 != 0 && maxvcpus != 1)) {
3192
        virReportError(VIR_ERR_INTERNAL_ERROR,
3193 3194 3195
                       _("Expecting domain XML entry 'vcpu' to be 1 or a "
                         "multiple of 2 but found %d"),
                       maxvcpus);
3196
        goto cleanup;
M
Matthias Bolte 已提交
3197 3198
    }

3199
    virBufferAsprintf(&buffer, "numvcpus = \"%d\"\n", maxvcpus);
M
Matthias Bolte 已提交
3200 3201

    /* def:cpumask -> vmx:sched.cpu.affinity */
H
Hu Tao 已提交
3202
    if (def->cpumask && virBitmapSize(def->cpumask) > 0) {
3203
        int bit;
M
Matthias Bolte 已提交
3204 3205 3206 3207
        virBufferAddLit(&buffer, "sched.cpu.affinity = \"");

        sched_cpu_affinity_length = 0;

3208
        bit = -1;
3209
        while ((bit = virBitmapNextSetBit(def->cpumask, bit)) >= 0)
H
Hu Tao 已提交
3210
            ++sched_cpu_affinity_length;
M
Matthias Bolte 已提交
3211

3212
        if (sched_cpu_affinity_length < maxvcpus) {
3213 3214 3215
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting domain XML attribute 'cpuset' of entry "
                             "'vcpu' to contain at least %d CPU(s)"),
3216
                           maxvcpus);
3217
            goto cleanup;
M
Matthias Bolte 已提交
3218 3219
        }

3220 3221 3222
        bit = -1;
        while ((bit = virBitmapNextSetBit(def->cpumask, bit)) >= 0) {
            virBufferAsprintf(&buffer, "%d", bit);
M
Matthias Bolte 已提交
3223

3224
            if (sched_cpu_affinity_length > 1)
H
Hu Tao 已提交
3225 3226 3227
                virBufferAddChar(&buffer, ',');

            --sched_cpu_affinity_length;
M
Matthias Bolte 已提交
3228 3229 3230 3231 3232
        }

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

3233
    /* def:cputune.shares -> vmx:sched.cpu.shares */
3234
    if (def->cputune.sharesSpecified) {
3235 3236 3237 3238 3239 3240 3241 3242
        /* 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 {
3243
            virBufferAsprintf(&buffer, "sched.cpu.shares = \"%lu\"\n",
3244 3245 3246 3247
                              def->cputune.shares);
        }
    }

M
Matthias Bolte 已提交
3248 3249 3250 3251
    /* def:graphics */
    for (i = 0; i < def->ngraphics; ++i) {
        switch (def->graphics[i]->type) {
          case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
3252
            if (virVMXFormatVNC(def->graphics[i], &buffer) < 0)
3253
                goto cleanup;
M
Matthias Bolte 已提交
3254 3255 3256 3257

            break;

          default:
3258 3259 3260
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported graphics type '%s'"),
                           virDomainGraphicsTypeToString(def->graphics[i]->type));
3261
            goto cleanup;
M
Matthias Bolte 已提交
3262 3263 3264
        }
    }

M
Matthias Bolte 已提交
3265
    /* def:disks */
3266
    for (i = 0; i < def->ndisks; ++i) {
3267
        if (virVMXVerifyDiskAddress(xmlopt, def->disks[i], def) < 0 ||
3268
            virVMXHandleLegacySCSIDiskDriverName(def, def->disks[i]) < 0) {
3269
            goto cleanup;
3270 3271
        }
    }
M
Matthias Bolte 已提交
3272

3273 3274
    if (virVMXGatherSCSIControllers(ctx, def, scsi_virtualDev,
                                    scsi_present) < 0) {
3275
        goto cleanup;
M
Matthias Bolte 已提交
3276 3277 3278 3279
    }

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

3282
            if (scsi_virtualDev[i] != -1) {
3283
                virBufferAsprintf(&buffer, "scsi%zu.virtualDev = \"%s\"\n", i,
3284
                                  virVMXControllerModelSCSITypeToString
3285
                                    (scsi_virtualDev[i]));
M
Matthias Bolte 已提交
3286 3287 3288 3289 3290 3291 3292 3293
            }
        }
    }

    for (i = 0; i < def->ndisks; ++i) {
        switch (def->disks[i]->device) {
          case VIR_DOMAIN_DISK_DEVICE_DISK:
          case VIR_DOMAIN_DISK_DEVICE_CDROM:
3294
          case VIR_DOMAIN_DISK_DEVICE_LUN:
3295
            if (virVMXFormatDisk(ctx, def->disks[i], &buffer) < 0)
3296
                goto cleanup;
M
Matthias Bolte 已提交
3297 3298 3299 3300

            break;

          case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
3301 3302
            if (virVMXFormatFloppy(ctx, def->disks[i], &buffer,
                                   floppy_present) < 0) {
3303
                goto cleanup;
M
Matthias Bolte 已提交
3304 3305 3306 3307 3308
            }

            break;

          default:
3309 3310 3311
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported disk device type '%s'"),
                           virDomainDiskDeviceTypeToString(def->disks[i]->device));
3312
            goto cleanup;
M
Matthias Bolte 已提交
3313 3314 3315
        }
    }

3316 3317
    for (i = 0; i < 2; ++i) {
        /* floppy[0..1].present defaults to true, disable it explicitly */
3318
        if (! floppy_present[i])
3319
            virBufferAsprintf(&buffer, "floppy%zu.present = \"false\"\n", i);
3320 3321
    }

M
Matthias Bolte 已提交
3322
    /* def:fss */
3323 3324
    if (def->nfss > 0) {
        virBufferAddLit(&buffer, "isolation.tools.hgfs.disable = \"false\"\n");
3325
        virBufferAsprintf(&buffer, "sharedFolder.maxNum = \"%zu\"\n", def->nfss);
3326 3327 3328
    }

    for (i = 0; i < def->nfss; ++i) {
3329
        if (virVMXFormatFileSystem(def->fss[i], i, &buffer) < 0)
3330 3331
            goto cleanup;
    }
M
Matthias Bolte 已提交
3332 3333 3334

    /* def:nets */
    for (i = 0; i < def->nnets; ++i) {
3335
        if (virVMXFormatEthernet(def->nets[i], i, &buffer) < 0)
3336
            goto cleanup;
M
Matthias Bolte 已提交
3337 3338 3339 3340 3341 3342 3343 3344
    }

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

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

3345 3346 3347
    /* def:videos */
    if (def->nvideos > 0) {
        if (def->nvideos > 1) {
3348 3349
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No support for multiple video devices"));
3350 3351 3352
            goto cleanup;
        }

3353
        if (virVMXFormatSVGA(def->videos[0], &buffer) < 0)
3354 3355 3356
            goto cleanup;
    }

M
Matthias Bolte 已提交
3357 3358 3359 3360 3361
    /* def:hostdevs */
    /* FIXME */

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

    /* def:parallels */
    for (i = 0; i < def->nparallels; ++i) {
3368
        if (virVMXFormatParallel(ctx, def->parallels[i], &buffer) < 0)
3369
            goto cleanup;
M
Matthias Bolte 已提交
3370 3371 3372
    }

    /* Get final VMX output */
3373
    if (virBufferCheckError(&buffer) < 0)
3374
        goto cleanup;
M
Matthias Bolte 已提交
3375

3376
    vmx = virBufferContentAndReset(&buffer);
M
Matthias Bolte 已提交
3377

3378
 cleanup:
3379
    if (vmx == NULL)
3380 3381
        virBufferFreeAndReset(&buffer);

3382 3383
    VIR_FREE(preliminaryDisplayName);
    VIR_FREE(displayName);
3384
    VIR_FREE(annotation);
M
Matthias Bolte 已提交
3385

3386
    return vmx;
M
Matthias Bolte 已提交
3387 3388 3389 3390
}



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

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

3401
    virBufferAddLit(buffer, "RemoteDisplay.vnc.enabled = \"true\"\n");
M
Matthias Bolte 已提交
3402 3403

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

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

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

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

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

    return 0;
}

M
Matthias Bolte 已提交
3434
int
3435
virVMXFormatDisk(virVMXContext *ctx, virDomainDiskDefPtr def,
M
Matthias Bolte 已提交
3436
                 virBufferPtr buffer)
M
Matthias Bolte 已提交
3437
{
3438
    int controllerOrBus, unit;
3439
    const char *vmxDeviceType = NULL;
M
Matthias Bolte 已提交
3440
    char *fileName = NULL;
3441
    int type = virDomainDiskGetType(def);
M
Matthias Bolte 已提交
3442

3443 3444 3445
    /* Convert a handful of types to their string values */
    const char *busType = virDomainDiskBusTypeToString(def->bus);
    const char *deviceType = virDomainDeviceTypeToString(def->device);
3446
    const char *diskType = virDomainDeviceTypeToString(type);
3447 3448 3449 3450 3451

    /* If we are dealing with a disk its a .vmdk, otherwise it must be
     * an ISO.
     */
    const char *fileExt = (def->device == VIR_DOMAIN_DISK_DEVICE_DISK) ?
M
Matthias Bolte 已提交
3452
                           ".vmdk" : ".iso";
3453 3454 3455

    /* Check that we got a valid device type */
    if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK &&
3456 3457
        def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
        def->device != VIR_DOMAIN_DISK_DEVICE_LUN) {
3458 3459
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid device type supplied: %s"), deviceType);
M
Matthias Bolte 已提交
3460 3461 3462
        return -1;
    }

3463
    /* We only support type='file' and type='block' */
E
Eric Blake 已提交
3464 3465
    if (type != VIR_STORAGE_TYPE_FILE &&
        type != VIR_STORAGE_TYPE_BLOCK) {
3466 3467 3468 3469
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("%s %s '%s' has unsupported type '%s', expecting "
                         "'%s' or '%s'"), busType, deviceType, def->dst,
                       diskType,
E
Eric Blake 已提交
3470 3471
                       virStorageTypeToString(VIR_STORAGE_TYPE_FILE),
                       virStorageTypeToString(VIR_STORAGE_TYPE_BLOCK));
3472 3473
        return -1;
    }
M
Matthias Bolte 已提交
3474

3475
    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
3476 3477
        if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
                                                  &unit) < 0) {
M
Matthias Bolte 已提交
3478 3479 3480
            return -1;
        }
    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
3481
        if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
3482
                                          &unit) < 0) {
M
Matthias Bolte 已提交
3483 3484 3485
            return -1;
        }
    } else {
3486
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3487 3488
                       _("Unsupported bus type '%s' for %s"),
                       busType, deviceType);
M
Matthias Bolte 已提交
3489 3490 3491
        return -1;
    }

3492
    if (def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
E
Eric Blake 已提交
3493
        type == VIR_STORAGE_TYPE_FILE) {
3494
        vmxDeviceType = (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) ?
M
Matthias Bolte 已提交
3495
                        "scsi-hardDisk" : "ata-hardDisk";
3496
    } else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
3497
        if (type == VIR_STORAGE_TYPE_FILE)
3498 3499 3500
            vmxDeviceType = "cdrom-image";
        else
            vmxDeviceType = "atapi-cdrom";
3501
    } else if (def->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
3502 3503 3504 3505 3506 3507 3508
        const char *src = virDomainDiskGetSource(def);

        if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
            src && STRPREFIX(src, "/vmfs/devices/cdrom/"))
            vmxDeviceType = "scsi-passthru";
        else
            vmxDeviceType = "cdrom-raw";
3509
    } else {
3510
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3511 3512
                       _("%s %s '%s' has an unsupported type '%s'"),
                       busType, deviceType, def->dst, diskType);
M
Matthias Bolte 已提交
3513 3514 3515
        return -1;
    }

3516
    virBufferAsprintf(buffer, "%s%d:%d.present = \"true\"\n",
3517 3518 3519
                      busType, controllerOrBus, unit);
    virBufferAsprintf(buffer, "%s%d:%d.deviceType = \"%s\"\n",
                      busType, controllerOrBus, unit, vmxDeviceType);
M
Matthias Bolte 已提交
3520

E
Eric Blake 已提交
3521
    if (type == VIR_STORAGE_TYPE_FILE) {
3522 3523 3524
        const char *src = virDomainDiskGetSource(def);

        if (src && ! virFileHasSuffix(src, fileExt)) {
3525
            virReportError(VIR_ERR_INTERNAL_ERROR,
3526 3527 3528 3529
                           _("Image file for %s %s '%s' has "
                             "unsupported suffix, expecting '%s'"),
                           busType, deviceType, def->dst, fileExt);
                return -1;
M
Matthias Bolte 已提交
3530 3531
        }

3532
        fileName = ctx->formatFileName(src, ctx->opaque);
M
Matthias Bolte 已提交
3533

3534
        if (fileName == NULL)
M
Matthias Bolte 已提交
3535 3536
            return -1;

3537
        virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3538
                          busType, controllerOrBus, unit, fileName);
M
Matthias Bolte 已提交
3539 3540

        VIR_FREE(fileName);
E
Eric Blake 已提交
3541
    } else if (type == VIR_STORAGE_TYPE_BLOCK) {
3542 3543 3544
        const char *src = virDomainDiskGetSource(def);

        if (!src &&
3545 3546 3547 3548 3549 3550
            def->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL) {
            virBufferAsprintf(buffer, "%s%d:%d.autodetect = \"true\"\n",
                              busType, controllerOrBus, unit);
            virBufferAsprintf(buffer, "%s%d:%d.fileName = \"auto detect\"\n",
                              busType, controllerOrBus, unit);
        } else {
3551
            virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3552
                              busType, controllerOrBus, unit, src);
3553
        }
M
Matthias Bolte 已提交
3554 3555 3556 3557
    }

    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
        if (def->cachemode == VIR_DOMAIN_DISK_CACHE_WRITETHRU) {
3558
            virBufferAsprintf(buffer, "%s%d:%d.writeThrough = \"true\"\n",
3559
                              busType, controllerOrBus, unit);
M
Matthias Bolte 已提交
3560
        } else if (def->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) {
3561 3562
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("%s harddisk '%s' has unsupported cache mode '%s'"),
3563
                           busType, def->dst,
3564
                           virDomainDiskCacheTypeToString(def->cachemode));
M
Matthias Bolte 已提交
3565
            return -1;
M
Matthias Bolte 已提交
3566 3567 3568
        }
    }

3569 3570 3571 3572
    if (def->transient)
        virBufferAsprintf(buffer,
                          "%s%d:%d.mode = \"independent-nonpersistent\"\n",
                          busType, controllerOrBus, unit);
M
Matthias Bolte 已提交
3573

M
Matthias Bolte 已提交
3574 3575 3576 3577
    return 0;
}

int
3578 3579
virVMXFormatFloppy(virVMXContext *ctx, virDomainDiskDefPtr def,
                   virBufferPtr buffer, bool floppy_present[2])
M
Matthias Bolte 已提交
3580
{
3581
    int unit;
M
Matthias Bolte 已提交
3582
    char *fileName = NULL;
3583 3584
    int type = virDomainDiskGetType(def);
    const char *src = virDomainDiskGetSource(def);
M
Matthias Bolte 已提交
3585 3586

    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
3587
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3588 3589 3590
        return -1;
    }

3591
    if (virVMXFloppyDiskNameToUnit(def->dst, &unit) < 0)
M
Matthias Bolte 已提交
3592 3593
        return -1;

3594 3595
    floppy_present[unit] = true;

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

E
Eric Blake 已提交
3598
    if (type == VIR_STORAGE_TYPE_FILE) {
3599
        virBufferAsprintf(buffer, "floppy%d.fileType = \"file\"\n", unit);
M
Matthias Bolte 已提交
3600

3601 3602
        if (src) {
            fileName = ctx->formatFileName(src, ctx->opaque);
M
Matthias Bolte 已提交
3603

3604
            if (fileName == NULL)
M
Matthias Bolte 已提交
3605 3606
                return -1;

3607
            virBufferAsprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3608
                              unit, fileName);
M
Matthias Bolte 已提交
3609 3610 3611

            VIR_FREE(fileName);
        }
E
Eric Blake 已提交
3612
    } else if (type == VIR_STORAGE_TYPE_BLOCK) {
3613
        virBufferAsprintf(buffer, "floppy%d.fileType = \"device\"\n", unit);
M
Matthias Bolte 已提交
3614

3615
        if (src) {
3616
            virBufferAsprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3617
                              unit, src);
M
Matthias Bolte 已提交
3618
        }
M
Matthias Bolte 已提交
3619
    } else {
3620 3621 3622
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Floppy '%s' has unsupported type '%s', expecting '%s' "
                         "or '%s'"), def->dst,
E
Eric Blake 已提交
3623 3624 3625
                       virStorageTypeToString(type),
                       virStorageTypeToString(VIR_STORAGE_TYPE_FILE),
                       virStorageTypeToString(VIR_STORAGE_TYPE_BLOCK));
M
Matthias Bolte 已提交
3626 3627 3628 3629 3630 3631 3632 3633
        return -1;
    }

    return 0;
}



3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658
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 已提交
3659
int
3660 3661
virVMXFormatEthernet(virDomainNetDefPtr def, int controller,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3662 3663
{
    char mac_string[VIR_MAC_STRING_BUFLEN];
3664
    unsigned int prefix, suffix;
M
Matthias Bolte 已提交
3665 3666

    if (controller < 0 || controller > 3) {
3667 3668 3669
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Ethernet controller index %d out of [0..3] range"),
                       controller);
M
Matthias Bolte 已提交
3670 3671 3672
        return -1;
    }

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

3675
    /* def:model -> vmx:virtualDev, vmx:features */
M
Matthias Bolte 已提交
3676 3677 3678
    if (def->model != NULL) {
        if (STRCASENEQ(def->model, "vlance") &&
            STRCASENEQ(def->model, "vmxnet") &&
3679
            STRCASENEQ(def->model, "vmxnet2") &&
3680
            STRCASENEQ(def->model, "vmxnet3") &&
3681 3682
            STRCASENEQ(def->model, "e1000") &&
            STRCASENEQ(def->model, "e1000e")) {
3683 3684 3685
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting domain XML entry 'devices/interface/model' "
                             "to be 'vlance' or 'vmxnet' or 'vmxnet2' or 'vmxnet3' "
3686
                             "or 'e1000' or 'e1000e' but found '%s'"), def->model);
M
Matthias Bolte 已提交
3687 3688 3689
            return -1;
        }

3690
        if (STRCASEEQ(def->model, "vmxnet2")) {
3691
            virBufferAsprintf(buffer, "ethernet%d.virtualDev = \"vmxnet\"\n",
3692
                              controller);
3693
            virBufferAsprintf(buffer, "ethernet%d.features = \"15\"\n",
3694 3695
                              controller);
        } else {
3696
            virBufferAsprintf(buffer, "ethernet%d.virtualDev = \"%s\"\n",
3697 3698
                              controller, def->model);
        }
M
Matthias Bolte 已提交
3699 3700 3701 3702 3703
    }

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

        if (def->ifname != NULL) {
3709
            virBufferAsprintf(buffer, "ethernet%d.connectionType = \"custom\"\n",
M
Matthias Bolte 已提交
3710
                              controller);
3711
            virBufferAsprintf(buffer, "ethernet%d.vnet = \"%s\"\n",
M
Matthias Bolte 已提交
3712 3713
                              controller, def->ifname);
        } else {
3714
            virBufferAsprintf(buffer, "ethernet%d.connectionType = \"bridged\"\n",
M
Matthias Bolte 已提交
3715 3716 3717 3718 3719
                              controller);
        }

        break;

3720 3721 3722 3723 3724
      case VIR_DOMAIN_NET_TYPE_USER:
        virBufferAsprintf(buffer, "ethernet%d.connectionType = \"nat\"\n",
                          controller);
        break;

M
Matthias Bolte 已提交
3725
      default:
3726 3727
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type '%s'"),
                       virDomainNetTypeToString(def->type));
M
Matthias Bolte 已提交
3728 3729 3730
        return -1;
    }

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

3734 3735
    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];
3736 3737

    if (prefix == 0x000c29) {
3738
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"generated\"\n",
M
Matthias Bolte 已提交
3739
                          controller);
3740
        virBufferAsprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
M
Matthias Bolte 已提交
3741
                          controller, mac_string);
3742
        virBufferAsprintf(buffer, "ethernet%d.generatedAddressOffset = \"0\"\n",
M
Matthias Bolte 已提交
3743
                          controller);
3744
    } else if (prefix == 0x005056 && suffix <= 0x3fffff) {
3745
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"static\"\n",
3746
                          controller);
3747
        virBufferAsprintf(buffer, "ethernet%d.address = \"%s\"\n",
3748 3749
                          controller, mac_string);
    } else if (prefix == 0x005056 && suffix >= 0x800000 && suffix <= 0xbfffff) {
3750
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"vpx\"\n",
3751
                          controller);
3752
        virBufferAsprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
3753
                          controller, mac_string);
M
Matthias Bolte 已提交
3754
    } else {
3755
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"static\"\n",
3756
                          controller);
3757
        virBufferAsprintf(buffer, "ethernet%d.address = \"%s\"\n",
3758
                          controller, mac_string);
3759
        virBufferAsprintf(buffer, "ethernet%d.checkMACAddress = \"false\"\n",
3760
                          controller);
M
Matthias Bolte 已提交
3761 3762 3763 3764 3765 3766 3767 3768
    }

    return 0;
}



int
3769 3770
virVMXFormatSerial(virVMXContext *ctx, virDomainChrDefPtr def,
                   virBufferPtr buffer)
M
Matthias Bolte 已提交
3771
{
M
Matthias Bolte 已提交
3772
    char *fileName = NULL;
3773
    const char *protocol;
M
Matthias Bolte 已提交
3774

3775
    if (def->target.port < 0 || def->target.port > 3) {
3776 3777 3778
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Serial port index %d out of [0..3] range"),
                       def->target.port);
M
Matthias Bolte 已提交
3779 3780 3781
        return -1;
    }

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

M
Matthias Bolte 已提交
3784
    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
3785
    switch (def->source.type) {
M
Matthias Bolte 已提交
3786
      case VIR_DOMAIN_CHR_TYPE_DEV:
3787
        virBufferAsprintf(buffer, "serial%d.fileType = \"device\"\n",
3788
                          def->target.port);
3789
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3790
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3791 3792 3793
        break;

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

3797
        fileName = ctx->formatFileName(def->source.data.file.path, ctx->opaque);
M
Matthias Bolte 已提交
3798

3799
        if (fileName == NULL)
M
Matthias Bolte 已提交
3800 3801
            return -1;

3802
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3803
                          def->target.port, fileName);
M
Matthias Bolte 已提交
3804 3805

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3806 3807 3808
        break;

      case VIR_DOMAIN_CHR_TYPE_PIPE:
3809
        virBufferAsprintf(buffer, "serial%d.fileType = \"pipe\"\n",
3810
                          def->target.port);
M
Matthias Bolte 已提交
3811
        /* FIXME: Based on VI Client GUI default */
3812
        virBufferAsprintf(buffer, "serial%d.pipe.endPoint = \"client\"\n",
3813
                          def->target.port);
M
Matthias Bolte 已提交
3814
        /* FIXME: Based on VI Client GUI default */
3815
        virBufferAsprintf(buffer, "serial%d.tryNoRxLoss = \"false\"\n",
3816
                          def->target.port);
3817
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3818
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3819 3820
        break;

3821
      case VIR_DOMAIN_CHR_TYPE_TCP:
3822
        switch (def->source.data.tcp.protocol) {
3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839
          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:
3840 3841 3842 3843
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported character device TCP protocol '%s'"),
                           virDomainChrTcpProtocolTypeToString(
                               def->source.data.tcp.protocol));
3844 3845 3846
            return -1;
        }

3847
        virBufferAsprintf(buffer, "serial%d.fileType = \"network\"\n",
3848
                          def->target.port);
3849
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s://%s:%s\"\n",
3850 3851
                          def->target.port, protocol, def->source.data.tcp.host,
                          def->source.data.tcp.service);
3852
        virBufferAsprintf(buffer, "serial%d.network.endPoint = \"%s\"\n",
3853
                          def->target.port,
3854
                          def->source.data.tcp.listen ? "server" : "client");
3855 3856
        break;

M
Matthias Bolte 已提交
3857
      default:
3858 3859 3860
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported character device type '%s'"),
                       virDomainChrTypeToString(def->source.type));
M
Matthias Bolte 已提交
3861 3862 3863 3864 3865
        return -1;
    }

    /* vmx:yieldOnMsrRead */
    /* FIXME: Based on VI Client GUI default */
3866
    virBufferAsprintf(buffer, "serial%d.yieldOnMsrRead = \"true\"\n",
3867
                      def->target.port);
M
Matthias Bolte 已提交
3868 3869 3870 3871 3872 3873 3874

    return 0;
}



int
3875 3876
virVMXFormatParallel(virVMXContext *ctx, virDomainChrDefPtr def,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3877
{
M
Matthias Bolte 已提交
3878 3879
    char *fileName = NULL;

3880
    if (def->target.port < 0 || def->target.port > 2) {
3881 3882 3883
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parallel port index %d out of [0..2] range"),
                       def->target.port);
M
Matthias Bolte 已提交
3884 3885 3886
        return -1;
    }

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

M
Matthias Bolte 已提交
3890
    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
3891
    switch (def->source.type) {
M
Matthias Bolte 已提交
3892
      case VIR_DOMAIN_CHR_TYPE_DEV:
3893
        virBufferAsprintf(buffer, "parallel%d.fileType = \"device\"\n",
3894
                          def->target.port);
3895
        virBufferAsprintf(buffer, "parallel%d.fileName = \"%s\"\n",
3896
                          def->target.port, def->source.data.file.path);
M
Matthias Bolte 已提交
3897 3898 3899
        break;

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

3903
        fileName = ctx->formatFileName(def->source.data.file.path, ctx->opaque);
M
Matthias Bolte 已提交
3904

3905
        if (fileName == NULL)
M
Matthias Bolte 已提交
3906 3907
            return -1;

3908
        virBufferAsprintf(buffer, "parallel%d.fileName = \"%s\"\n",
3909
                          def->target.port, fileName);
M
Matthias Bolte 已提交
3910 3911

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3912 3913 3914
        break;

      default:
3915 3916 3917
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported character device type '%s'"),
                       virDomainChrTypeToString(def->source.type));
M
Matthias Bolte 已提交
3918 3919 3920 3921 3922
        return -1;
    }

    return 0;
}
3923 3924 3925 3926 3927 3928



int
virVMXFormatSVGA(virDomainVideoDefPtr def, virBufferPtr buffer)
{
3929 3930
    unsigned long long vram;

3931
    if (def->type != VIR_DOMAIN_VIDEO_TYPE_VMVGA) {
3932 3933 3934
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported video device type '%s'"),
                       virDomainVideoTypeToString(def->type));
3935 3936 3937 3938 3939 3940 3941
        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
     */
3942
    vram = VIR_DIV_UP(def->vram, 64) * 64;
3943 3944

    if (def->heads > 1) {
3945 3946
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Multi-head video devices are unsupported"));
3947 3948 3949
        return -1;
    }

3950
    virBufferAsprintf(buffer, "svga.vramSize = \"%lld\"\n",
3951
                      vram * 1024); /* kilobyte to byte */
3952 3953 3954

    return 0;
}