vmx.c 135.5 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
P
Pino Toscano 已提交
62
def->maxvcpus = <value>           <=>   numvcpus = "<value>"                    # must be greater than 0, 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
#define VMX_BUILD_NAME(_suffix) \
506
    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
VIR_ENUM_DECL(virVMXControllerModelSCSI);
512 513
VIR_ENUM_IMPL(virVMXControllerModelSCSI,
              VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
514
              "auto", /* just to match virDomainControllerModel, will never be used */
515 516 517
              "buslogic",
              "lsilogic",
              "lsisas1068",
518
              "pvscsi",
519
              "UNUSED ibmvscsi",
520
              "UNUSED virtio-scsi",
521 522 523 524
              "UNUSED lsisas1078",
              "UNUSED virtio-transitional",
              "UNUSED virtio-non-transitional",
);
525 526


527 528 529
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Helpers
 */
530

531
static int
532
virVMXDomainDefPostParse(virDomainDefPtr def ATTRIBUTE_UNUSED,
533
                         virCapsPtr caps ATTRIBUTE_UNUSED,
534
                         unsigned int parseFlags ATTRIBUTE_UNUSED,
535 536
                         void *opaque ATTRIBUTE_UNUSED,
                         void *parseOpaque ATTRIBUTE_UNUSED)
537 538 539 540 541
{
    return 0;
}

static int
542 543 544
virVMXDomainDevicesDefPostParse(virDomainDeviceDefPtr dev ATTRIBUTE_UNUSED,
                                const virDomainDef *def ATTRIBUTE_UNUSED,
                                virCapsPtr caps ATTRIBUTE_UNUSED,
545
                                unsigned int parseFlags ATTRIBUTE_UNUSED,
546 547
                                void *opaque ATTRIBUTE_UNUSED,
                                void *parseOpaque ATTRIBUTE_UNUSED)
548 549 550
{
    return 0;
}
551

552
static virDomainDefParserConfig virVMXDomainDefParserConfig = {
553
    .macPrefix = {0x00, 0x0c, 0x29},
554 555
    .devicesPostParseCallback = virVMXDomainDevicesDefPostParse,
    .domainPostParseCallback = virVMXDomainDefPostParse,
556
    .features = (VIR_DOMAIN_DEF_FEATURE_WIDE_SCSI |
557 558
                 VIR_DOMAIN_DEF_FEATURE_NAME_SLASH |
                 VIR_DOMAIN_DEF_FEATURE_NO_BOOT_ORDER),
559 560
};

561 562 563 564 565
struct virVMXDomainDefNamespaceData {
    char *datacenterPath;
    char *moref;
};

566 567 568
static void
virVMXDomainDefNamespaceFree(void *nsdata)
{
569 570 571 572 573 574 575
    struct virVMXDomainDefNamespaceData *data = nsdata;

    if (data) {
        VIR_FREE(data->datacenterPath);
        VIR_FREE(data->moref);
    }
    VIR_FREE(data);
576 577 578 579 580
}

static int
virVMXDomainDefNamespaceFormatXML(virBufferPtr buf, void *nsdata)
{
581
    struct virVMXDomainDefNamespaceData *data = nsdata;
582

583
    if (!data)
584 585
        return 0;

586 587 588 589 590 591 592 593 594 595
    if (data->datacenterPath) {
        virBufferAddLit(buf, "<vmware:datacenterpath>");
        virBufferEscapeString(buf, "%s", data->datacenterPath);
        virBufferAddLit(buf, "</vmware:datacenterpath>\n");
    }
    if (data->moref) {
        virBufferAddLit(buf, "<vmware:moref>");
        virBufferEscapeString(buf, "%s", data->moref);
        virBufferAddLit(buf, "</vmware:moref>\n");
    }
596 597 598 599

    return 0;
}

600
static virXMLNamespace virVMXDomainXMLNamespace = {
601 602 603
    .parse = NULL,
    .free = virVMXDomainDefNamespaceFree,
    .format = virVMXDomainDefNamespaceFormatXML,
604
    .prefix = "vmware",
605
    .uri = "http://libvirt.org/schemas/domain/vmware/1.0",
606
};
607 608 609 610

virDomainXMLOptionPtr
virVMXDomainXMLConfInit(void)
{
611
    return virDomainXMLOptionNew(&virVMXDomainDefParserConfig, NULL,
612
                                 &virVMXDomainXMLNamespace, NULL, NULL);
613 614
}

615 616 617 618 619 620 621 622 623 624
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') {
625
        if (*tmp1 == escape || strspn(tmp1, special) > 0)
626 627 628 629 630 631
            length += 2;

        ++tmp1;
        ++length;
    }

632
    if (VIR_ALLOC_N(escaped, length) < 0)
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
        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 已提交
660
int
661 662 663 664 665 666 667 668
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) {
669
            if (!c_isxdigit(tmp1[1]) || !c_isxdigit(tmp1[2]))
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
                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) {
697 698
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxml2 doesn't handle %s encoding"), encoding);
699 700 701 702 703 704 705
        return NULL;
    }

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

    if (xmlCharEncInFunc(handler, utf8, input) < 0) {
706 707
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not convert from %s to UTF-8 encoding"), encoding);
708 709 710 711 712 713
        goto cleanup;
    }

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

714
 cleanup:
715 716 717 718 719 720 721 722 723 724
    xmlCharEncCloseFunc(handler);
    xmlBufferFree(input);
    xmlBufferFree(utf8);

    return result;
}



static int
725 726
virVMXGetConfigStringHelper(virConfPtr conf, const char *name, char **string,
                            bool optional)
727
{
728
    int rc;
729 730
    *string = NULL;

731 732 733
    rc = virConfGetValueString(conf, name, string);
    if (rc == 1 && *string != NULL)
        return 1;
734

735 736
    if (optional)
        return 0;
737

738 739 740 741
    virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Missing essential config entry '%s'"), name);
    return -1;
}
742 743


744 745 746 747 748 749 750 751

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

    if (virVMXGetConfigStringHelper(conf, name, string, optional) < 0)
752 753
        return -1;

754
    return 0;
755 756 757 758 759 760 761 762
}



static int
virVMXGetConfigUUID(virConfPtr conf, const char *name, unsigned char *uuid,
                    bool optional)
{
763 764 765
    char *string = NULL;
    int ret = -1;
    int rc;
766

767 768 769
    rc = virVMXGetConfigStringHelper(conf, name, &string, optional);
    if (rc <= 0)
        return rc;
770

771 772
    rc = virUUIDParse(string, uuid);
    if (rc < 0) {
773
        virReportError(VIR_ERR_INTERNAL_ERROR,
774 775
                       _("Could not parse UUID from string '%s'"), string);
        goto cleanup;
776 777
    }

778
    ret = 0;
779

780 781 782
 cleanup:
    VIR_FREE(string);
    return ret;
783 784 785 786 787 788 789 790
}



static int
virVMXGetConfigLong(virConfPtr conf, const char *name, long long *number,
                    long long default_, bool optional)
{
791 792 793
    char *string = NULL;
    int ret = -1;
    int rc;
794 795 796

    *number = default_;

797 798 799
    rc = virVMXGetConfigStringHelper(conf, name, &string, optional);
    if (rc <= 0)
        return rc;
800

801 802 803
    if (STRCASEEQ(string, "unlimited")) {
        *number = -1;
    } else if (virStrToLong_ll(string, NULL, 10, number) < 0) {
804
        virReportError(VIR_ERR_INTERNAL_ERROR,
805 806 807
                _("Config entry '%s' must represent an integer value"),
                name);
        goto cleanup;
808 809
    }

810 811 812 813 814
    ret = 0;

 cleanup:
    VIR_FREE(string);
    return ret;
815 816 817 818 819 820 821 822
}



static int
virVMXGetConfigBoolean(virConfPtr conf, const char *name, bool *boolean_,
                       bool default_, bool optional)
{
823 824 825
    char *string = NULL;
    int ret = -1;
    int rc;
826 827 828

    *boolean_ = default_;

829 830 831
    rc = virVMXGetConfigStringHelper(conf, name, &string, optional);
    if (rc <= 0)
        return rc;
832

833 834 835 836
    if (STRCASEEQ(string, "true")) {
        *boolean_ = 1;
    } else if (STRCASEEQ(string, "false")) {
        *boolean_ = 0;
837
    } else {
838
        virReportError(VIR_ERR_INTERNAL_ERROR,
839 840 841
                       _("Config entry '%s' must represent a boolean value "
                         "(true|false)"), name);
        goto cleanup;
842 843
    }

844 845 846 847 848
    ret = 0;

 cleanup:
    VIR_FREE(string);
    return ret;
849 850 851 852 853 854
}



static int
virVMXSCSIDiskNameToControllerAndUnit(const char *name, int *controller, int *unit)
M
Matthias Bolte 已提交
855 856 857 858
{
    int idx;

    if (! STRPREFIX(name, "sd")) {
859 860 861
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expecting domain XML attribute 'dev' of entry "
                         "'devices/disk/target' to start with 'sd'"));
M
Matthias Bolte 已提交
862 863 864 865 866 867
        return -1;
    }

    idx = virDiskNameToIndex(name);

    if (idx < 0) {
868 869
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not parse valid disk index from '%s'"), name);
M
Matthias Bolte 已提交
870 871 872
        return -1;
    }

873
    /* Each of the 4 SCSI controllers has 1 bus with 15 units each for devices */
M
Matthias Bolte 已提交
874
    if (idx >= (4 * 15)) {
875 876
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("SCSI disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
877 878 879 880
        return -1;
    }

    *controller = idx / 15;
881
    *unit = idx % 15;
M
Matthias Bolte 已提交
882

883
    /* Skip the controller ifself at unit 7 */
884
    if (*unit >= 7)
885
        ++(*unit);
M
Matthias Bolte 已提交
886 887 888 889 890 891

    return 0;
}



892 893
static int
virVMXIDEDiskNameToBusAndUnit(const char *name, int *bus, int *unit)
M
Matthias Bolte 已提交
894 895 896 897
{
    int idx;

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

    idx = virDiskNameToIndex(name);

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

912
    /* The IDE controller has 2 buses with 2 units each for devices */
M
Matthias Bolte 已提交
913
    if (idx >= (2 * 2)) {
914 915
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("IDE disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
916 917 918
        return -1;
    }

919 920
    *bus = idx / 2;
    *unit = idx % 2;
M
Matthias Bolte 已提交
921 922 923 924 925 926

    return 0;
}



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

    if (! STRPREFIX(name, "fd")) {
933 934 935
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expecting domain XML attribute 'dev' of entry "
                         "'devices/disk/target' to start with 'fd'"));
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 FDC controller has 1 bus with 2 units for devices */
M
Matthias Bolte 已提交
948
    if (idx >= 2) {
949 950
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Floppy disk index (parsed from '%s') is too large"), name);
M
Matthias Bolte 已提交
951 952 953
        return -1;
    }

954 955 956 957 958 959 960
    *unit = idx;

    return 0;
}



961
static int
962 963 964
virVMXVerifyDiskAddress(virDomainXMLOptionPtr xmlopt,
                        virDomainDiskDefPtr disk,
                        virDomainDefPtr vmdef)
965 966 967 968 969 970 971
{
    virDomainDiskDef def;
    virDomainDeviceDriveAddressPtr drive;

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

    if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
972 973 974
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported disk address type '%s'"),
                       virDomainDeviceAddressTypeToString(disk->info.type));
975 976 977 978 979 980 981 982
        return -1;
    }

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

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

983
    if (virDomainDiskDefAssignAddress(xmlopt, &def, vmdef) < 0) {
984 985
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not verify disk address"));
986 987 988 989 990 991
        return -1;
    }

    if (def.info.addr.drive.controller != drive->controller ||
        def.info.addr.drive.bus != drive->bus ||
        def.info.addr.drive.unit != drive->unit) {
992 993 994
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Disk address %d:%d:%d doesn't match target device '%s'"),
                       drive->controller, drive->bus, drive->unit, disk->dst);
995 996 997 998 999 1000
        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) {
1001 1002 1003
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("SCSI controller index %d out of [0..3] range"),
                           drive->controller);
1004 1005 1006 1007
            return -1;
        }

        if (drive->bus != 0) {
1008 1009 1010
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("SCSI bus index %d out of [0] range"),
                           drive->bus);
1011 1012 1013 1014
            return -1;
        }

        if (drive->unit > 15 || drive->unit == 7) {
1015 1016 1017
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("SCSI unit index %d out of [0..6,8..15] range"),
                           drive->unit);
1018 1019 1020 1021
            return -1;
        }
    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
        if (drive->controller != 0) {
1022 1023 1024
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE controller index %d out of [0] range"),
                           drive->controller);
1025 1026 1027 1028
            return -1;
        }

        if (drive->bus > 1) {
1029 1030 1031
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE bus index %d out of [0..1] range"),
                           drive->bus);
1032 1033 1034 1035
            return -1;
        }

        if (drive->unit > 1) {
1036 1037 1038
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("IDE unit index %d out of [0..1] range"),
                           drive->unit);
1039 1040 1041 1042
            return -1;
        }
    } else if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
        if (drive->controller != 0) {
1043 1044 1045
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC controller index %d out of [0] range"),
                           drive->controller);
1046 1047 1048 1049
            return -1;
        }

        if (drive->bus != 0) {
1050 1051 1052
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC bus index %d out of [0] range"),
                           drive->bus);
1053 1054 1055 1056
            return -1;
        }

        if (drive->unit > 1) {
1057 1058 1059
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("FDC unit index %d out of [0..1] range"),
                           drive->unit);
1060 1061 1062
            return -1;
        }
    } else {
1063 1064 1065
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported bus type '%s'"),
                       virDomainDiskBusTypeToString(disk->bus));
1066 1067 1068 1069 1070 1071 1072 1073
        return -1;
    }

    return 0;
}



1074 1075 1076
static int
virVMXHandleLegacySCSIDiskDriverName(virDomainDefPtr def,
                                     virDomainDiskDefPtr disk)
1077 1078
{
    char *tmp;
1079 1080
    int model;
    size_t i;
1081
    virDomainControllerDefPtr controller = NULL;
1082 1083
    const char *driver = virDomainDiskGetDriver(disk);
    char *copy;
1084

1085
    if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI || !driver)
1086 1087
        return 0;

1088 1089 1090
    if (VIR_STRDUP(copy, driver) < 0)
        return -1;
    tmp = copy;
1091

1092
    for (; *tmp != '\0'; ++tmp)
1093 1094
        *tmp = c_tolower(*tmp);

1095 1096
    model = virDomainControllerModelSCSITypeFromString(copy);
    VIR_FREE(copy);
1097 1098

    if (model < 0) {
1099
        virReportError(VIR_ERR_INTERNAL_ERROR,
1100
                       _("Unknown driver name '%s'"), driver);
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
        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) {
1112 1113 1114
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Missing SCSI controller for index %d"),
                       disk->info.addr.drive.controller);
1115 1116 1117
        return -1;
    }

1118
    if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT) {
1119 1120
        controller->model = model;
    } else if (controller->model != model) {
1121 1122
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Inconsistent SCSI controller model ('%s' is not '%s') "
1123
                         "for SCSI controller index %d"), driver,
1124 1125
                       virDomainControllerModelSCSITypeToString(controller->model),
                       controller->idx);
1126 1127
        return -1;
    }
M
Matthias Bolte 已提交
1128 1129 1130 1131 1132 1133

    return 0;
}



1134 1135 1136
static int
virVMXGatherSCSIControllers(virVMXContext *ctx, virDomainDefPtr def,
                            int virtualDev[4], bool present[4])
1137 1138
{
    int result = -1;
1139
    size_t i, k;
M
Matthias Bolte 已提交
1140
    virDomainDiskDefPtr disk;
1141 1142 1143 1144
    virDomainControllerDefPtr controller;
    bool controllerHasDisksAttached;
    int count = 0;
    int *autodetectedModels;
M
Matthias Bolte 已提交
1145

1146
    if (VIR_ALLOC_N(autodetectedModels, def->ndisks) < 0)
1147 1148 1149 1150
        return -1;

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

1152
        if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
1153
            /* skip non-SCSI controllers */
M
Matthias Bolte 已提交
1154 1155 1156
            continue;
        }

1157
        controllerHasDisksAttached = false;
1158

1159 1160 1161 1162 1163 1164
        for (k = 0; k < def->ndisks; ++k) {
            disk = def->disks[k];

            if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
                disk->info.addr.drive.controller == controller->idx) {
                controllerHasDisksAttached = true;
1165 1166
                break;
            }
M
Matthias Bolte 已提交
1167 1168
        }

1169
        if (! controllerHasDisksAttached) {
1170
            /* skip SCSI controllers without attached disks */
1171 1172 1173
            continue;
        }

1174
        if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO &&
1175
            ctx->autodetectSCSIControllerModel != NULL) {
1176 1177
            count = 0;

1178 1179
            /* try to autodetect the SCSI controller model by collecting
             * SCSI controller model of all disks attached to this controller */
1180 1181 1182 1183 1184
            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) {
1185 1186 1187
                    if (ctx->autodetectSCSIControllerModel
                               (disk, &autodetectedModels[count],
                                ctx->opaque) < 0) {
1188 1189 1190 1191 1192 1193 1194
                        goto cleanup;
                    }

                    ++count;
                }
            }

1195 1196
            /* autodetection fails when the disks attached to one controller
             * have inconsistent SCSI controller models */
1197 1198
            for (k = 0; k < count; ++k) {
                if (autodetectedModels[k] != autodetectedModels[0]) {
1199 1200 1201 1202
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Disks on SCSI controller %d have inconsistent "
                                     "controller models, cannot autodetect model"),
                                   controller->idx);
1203 1204 1205 1206 1207
                    goto cleanup;
                }
            }

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

1210
        if (controller->model != -1 &&
1211 1212 1213 1214
            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) {
1215 1216 1217 1218 1219
            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));
1220
            goto cleanup;
M
Matthias Bolte 已提交
1221
        }
1222 1223 1224

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

1227 1228
    result = 0;

1229
 cleanup:
1230 1231 1232
    VIR_FREE(autodetectedModels);

    return result;
M
Matthias Bolte 已提交
1233 1234
}

P
Pino Toscano 已提交
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257
struct virVMXConfigScanResults {
    int networks_max_index;
};

static int
virVMXConfigScanResultsCollector(const char* name,
                                 virConfValuePtr value ATTRIBUTE_UNUSED,
                                 void *opaque)
{
    struct virVMXConfigScanResults *results = opaque;

    if (STRCASEPREFIX(name, "ethernet")) {
        unsigned int idx;
        char *p;

        if (virStrToLong_uip(name + 8, &p, 10, &idx) < 0 ||
            *p != '.') {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("failed to parse the index of the VMX key '%s'"),
                           name);
            return -1;
        }

1258 1259
        if ((int)idx > results->networks_max_index)
            results->networks_max_index = (int)idx;
P
Pino Toscano 已提交
1260 1261 1262 1263 1264
    }

    return 0;
}

M
Matthias Bolte 已提交
1265 1266 1267 1268 1269 1270


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

1271
virDomainDefPtr
1272 1273
virVMXParseConfig(virVMXContext *ctx,
                  virDomainXMLOptionPtr xmlopt,
1274
                  virCapsPtr caps,
1275
                  const char *vmx)
1276
{
M
Matthias Bolte 已提交
1277
    bool success = false;
1278
    virConfPtr conf = NULL;
1279 1280
    char *encoding = NULL;
    char *utf8;
1281 1282 1283 1284
    virDomainDefPtr def = NULL;
    long long config_version = 0;
    long long virtualHW_version = 0;
    long long memsize = 0;
1285 1286
    long long sched_mem_max = 0;
    long long sched_mem_minsize = 0;
1287 1288
    long long numvcpus = 0;
    char *sched_cpu_affinity = NULL;
1289
    char *sched_cpu_shares = NULL;
M
Matthias Bolte 已提交
1290
    char *guestOS = NULL;
M
Matthias Bolte 已提交
1291
    bool smbios_reflecthost = false;
1292
    int controller;
1293
    int bus;
1294
    int port;
1295
    bool present;
1296 1297
    int scsi_virtualDev[4] = { -1, -1, -1, -1 };
    int unit;
1298 1299
    bool hgfs_disabled = true;
    long long sharedFolder_maxNum = 0;
P
Pino Toscano 已提交
1300
    struct virVMXConfigScanResults results = { -1 };
1301 1302
    long long coresPerSocket = 0;
    virCPUDefPtr cpu = NULL;
1303
    char *firmware = NULL;
1304

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

J
Ján Tomko 已提交
1311
    conf = virConfReadString(vmx, VIR_CONF_FLAG_VMX_FORMAT);
1312

1313
    if (conf == NULL)
1314 1315
        return NULL;

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

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

1326
        utf8 = virVMXConvertToUTF8(encoding, vmx);
1327

1328
        if (utf8 == NULL)
1329 1330
            goto cleanup;

J
Ján Tomko 已提交
1331
        conf = virConfReadString(utf8, VIR_CONF_FLAG_VMX_FORMAT);
1332 1333 1334

        VIR_FREE(utf8);

1335
        if (conf == NULL)
1336 1337 1338
            goto cleanup;
    }

P
Pino Toscano 已提交
1339 1340 1341
    if (virConfWalk(conf, virVMXConfigScanResultsCollector, &results) < 0)
        goto cleanup;

1342
    /* 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 > virDomainDefGetMemoryTotal(def))
        def->mem.cur_balloon = virDomainDefGetMemoryTotal(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 > virDomainDefGetMemoryTotal(def))
        def->mem.min_guarantee = virDomainDefGetMemoryTotal(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

P
Pino Toscano 已提交
1454
    if (numvcpus <= 0) {
1455 1456
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Expecting VMX entry 'numvcpus' to be an unsigned "
P
Pino Toscano 已提交
1457
                         "integer greater than 0 but found %lld"), numvcpus);
M
Matthias Bolte 已提交
1458
        goto cleanup;
1459 1460
    }

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

1464 1465
    if (virDomainDefSetVcpus(def, numvcpus) < 0)
        goto cleanup;
1466

1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
    /* vmx:cpuid.coresPerSocket -> def:cpu */
    if (virVMXGetConfigLong(conf, "cpuid.coresPerSocket", &coresPerSocket, 1,
                            true) < 0)
        goto cleanup;

    if (coresPerSocket > 1) {
        if (VIR_ALLOC(cpu) < 0)
            goto cleanup;

        cpu->type = VIR_CPU_TYPE_GUEST;
        cpu->mode = VIR_CPU_MODE_CUSTOM;

        cpu->sockets = numvcpus / coresPerSocket;
        if (cpu->sockets <= 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("VMX entry 'cpuid.coresPerSocket' smaller than "
                             "'numvcpus'"));
            goto cleanup;
        }
        cpu->cores = coresPerSocket;
        cpu->threads = 1;

        VIR_STEAL_PTR(def->cpu, cpu);
    }

M
Matthias Bolte 已提交
1492
    /* vmx:sched.cpu.affinity -> def:cpumask */
1493
    /* NOTE: maps to VirtualMachine:config.cpuAffinity.affinitySet */
1494 1495
    if (virVMXGetConfigString(conf, "sched.cpu.affinity", &sched_cpu_affinity,
                              true) < 0) {
M
Matthias Bolte 已提交
1496
        goto cleanup;
1497 1498
    }

1499
    if (sched_cpu_affinity != NULL && STRCASENEQ(sched_cpu_affinity, "all")) {
1500 1501 1502
        VIR_AUTOSTRINGLIST afflist = NULL;
        char **aff;
        size_t naffs;
1503

H
Hu Tao 已提交
1504
        def->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN);
1505
        if (!def->cpumask)
M
Matthias Bolte 已提交
1506
            goto cleanup;
1507

1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
        if (!(afflist = virStringSplitCount(sched_cpu_affinity, ",", 0, &naffs)))
            goto cleanup;

        if (naffs < numvcpus) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting VMX entry 'sched.cpu.affinity' to contain "
                             "at least as many values as 'numvcpus' (%lld) but "
                             "found only %zu value(s)"), numvcpus, naffs);
            goto cleanup;
        }
1518

1519 1520 1521 1522
        for (aff = afflist; *aff; aff++) {
            const char *current = *aff;
            unsigned int number;
            int rc;
1523

1524 1525 1526 1527 1528
            virSkipSpaces(&current);
            rc = virStrToLong_uip(current, (char **) &current, 10, &number);
            virSkipSpaces(&current);

            if (rc < 0 || *current != '\0') {
1529 1530 1531 1532
                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 已提交
1533
                goto cleanup;
1534 1535 1536
            }

            if (number >= VIR_DOMAIN_CPUMASK_LEN) {
1537 1538 1539
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("VMX entry 'sched.cpu.affinity' contains a %d, "
                                 "this value is too large"), number);
M
Matthias Bolte 已提交
1540
                goto cleanup;
1541 1542
            }

H
Hu Tao 已提交
1543
            ignore_value(virBitmapSetBit(def->cpumask, number));
1544 1545 1546
        }
    }

1547 1548 1549 1550 1551 1552 1553
    /* 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) {
1554
        unsigned int vcpus = virDomainDefGetVcpus(def);
1555 1556
        /* See http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.SharesInfo.Level.html */
        if (STRCASEEQ(sched_cpu_shares, "low")) {
1557
            def->cputune.shares = vcpus * 500;
1558
        } else if (STRCASEEQ(sched_cpu_shares, "normal")) {
1559
            def->cputune.shares = vcpus * 1000;
1560
        } else if (STRCASEEQ(sched_cpu_shares, "high")) {
1561
            def->cputune.shares = vcpus * 2000;
1562 1563
        } else if (virStrToLong_ull(sched_cpu_shares, NULL, 10,
                                    &def->cputune.shares) < 0) {
1564 1565 1566 1567
            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);
1568 1569
            goto cleanup;
        }
1570
        def->cputune.sharesSpecified = true;
1571 1572
    }

1573
    /* def:lifecycle */
1574 1575
    def->onReboot = VIR_DOMAIN_LIFECYCLE_ACTION_RESTART;
    def->onPoweroff = VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY;
1576
    def->onCrash = VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY;
1577 1578

    /* def:os */
1579
    def->os.type = VIR_DOMAIN_OSTYPE_HVM;
1580

M
Matthias Bolte 已提交
1581
    /* vmx:guestOS -> def:os.arch */
1582
    if (virVMXGetConfigString(conf, "guestOS", &guestOS, true) < 0)
M
Matthias Bolte 已提交
1583
        goto cleanup;
M
Matthias Bolte 已提交
1584

1585
    if (guestOS != NULL && virStringHasSuffix(guestOS, "-64")) {
1586
        def->os.arch = VIR_ARCH_X86_64;
M
Matthias Bolte 已提交
1587
    } else {
1588
        def->os.arch = VIR_ARCH_I686;
M
Matthias Bolte 已提交
1589 1590
    }

M
Matthias Bolte 已提交
1591
    /* vmx:smbios.reflecthost -> def:os.smbios_mode */
1592 1593
    if (virVMXGetConfigBoolean(conf, "smbios.reflecthost",
                               &smbios_reflecthost, false, true) < 0) {
M
Matthias Bolte 已提交
1594 1595 1596
        goto cleanup;
    }

1597
    if (smbios_reflecthost)
M
Matthias Bolte 已提交
1598 1599
        def->os.smbios_mode = VIR_DOMAIN_SMBIOS_HOST;

1600 1601
    /* def:features */
    /* FIXME */
1602

1603 1604
    /* def:clock */
    /* FIXME */
1605 1606

    /* def:graphics */
1607
    if (VIR_ALLOC_N(def->graphics, 1) < 0)
M
Matthias Bolte 已提交
1608
        goto cleanup;
M
Matthias Bolte 已提交
1609 1610 1611

    def->ngraphics = 0;

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

1615
    if (def->graphics[def->ngraphics] != NULL)
M
Matthias Bolte 已提交
1616
        ++def->ngraphics;
1617

M
Matthias Bolte 已提交
1618
    /* def:disks: 4 * 15 scsi + 2 * 2 ide + 2 floppy = 66 */
1619
    if (VIR_ALLOC_N(def->disks, 66) < 0)
M
Matthias Bolte 已提交
1620
        goto cleanup;
1621 1622 1623 1624 1625

    def->ndisks = 0;

    /* def:disks (scsi) */
    for (controller = 0; controller < 4; ++controller) {
1626 1627
        if (virVMXParseSCSIController(conf, controller, &present,
                                      &scsi_virtualDev[controller]) < 0) {
M
Matthias Bolte 已提交
1628
            goto cleanup;
1629 1630
        }

1631
        if (! present)
1632 1633
            continue;

1634 1635
        for (unit = 0; unit < 16; ++unit) {
            if (unit == 7) {
1636
                /*
1637
                 * SCSI unit 7 is assigned to the SCSI controller and cannot be
1638 1639 1640 1641 1642
                 * used for disk devices.
                 */
                continue;
            }

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

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

1654
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1655
                                 VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
1656
                                 &def->disks[def->ndisks], def) < 0) {
M
Matthias Bolte 已提交
1657
                goto cleanup;
1658 1659
            }

1660
            if (def->disks[def->ndisks] != NULL)
1661 1662
                ++def->ndisks;
        }
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674

    }

    /* add all the SCSI controllers we've seen, up until the last one that is
     * currently used by a disk */
    if (def->ndisks != 0) {
        virDomainDeviceInfoPtr info = &def->disks[def->ndisks - 1]->info;
        for (controller = 0; controller <= info->addr.drive.controller; controller++) {
            if (!virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
                                           controller, scsi_virtualDev[controller]))
                goto cleanup;
        }
1675 1676 1677
    }

    /* def:disks (ide) */
1678 1679
    for (bus = 0; bus < 2; ++bus) {
        for (unit = 0; unit < 2; ++unit) {
1680
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
1681
                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
1682
                                &def->disks[def->ndisks], def) < 0) {
M
Matthias Bolte 已提交
1683
                goto cleanup;
1684 1685 1686 1687 1688 1689 1690
            }

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

1691
            if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1692
                                VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
1693
                                &def->disks[def->ndisks], def) < 0) {
M
Matthias Bolte 已提交
1694
                goto cleanup;
1695 1696
            }

1697
            if (def->disks[def->ndisks] != NULL)
1698 1699 1700 1701 1702
                ++def->ndisks;
        }
    }

    /* def:disks (floppy) */
1703
    for (unit = 0; unit < 2; ++unit) {
1704
        if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_FLOPPY,
1705
                            VIR_DOMAIN_DISK_BUS_FDC, 0, unit,
1706
                            &def->disks[def->ndisks], def) < 0) {
M
Matthias Bolte 已提交
1707
            goto cleanup;
1708 1709
        }

1710
        if (def->disks[def->ndisks] != NULL)
1711 1712 1713 1714
            ++def->ndisks;
    }

    /* def:fss */
1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728
    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;

1729
            if (VIR_ALLOC_N(def->fss, sharedFolder_maxNum) < 0)
1730 1731 1732 1733 1734 1735 1736 1737 1738 1739
                goto cleanup;

            def->nfss = 0;

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

1740
                if (def->fss[def->nfss] != NULL)
1741 1742 1743 1744
                    ++def->nfss;
            }
        }
    }
1745 1746

    /* def:nets */
P
Pino Toscano 已提交
1747
    for (controller = 0; controller <= results.networks_max_index; ++controller) {
1748 1749
        virDomainNetDefPtr net = NULL;
        if (virVMXParseEthernet(conf, controller, &net) < 0)
M
Matthias Bolte 已提交
1750
            goto cleanup;
1751

1752 1753 1754 1755 1756
        if (!net)
            continue;

        if (VIR_APPEND_ELEMENT(def->nets, def->nnets, net) < 0)
            goto cleanup;
1757 1758 1759 1760 1761
    }

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

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

    def->nvideos = 0;

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

    def->nvideos = 1;

1773 1774 1775 1776 1777 1778 1779
    /* def:sounds */
    /* FIXME */

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

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

    def->nserials = 0;

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

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

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

    def->nparallels = 0;

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

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

1811
    /* ctx:datacenterPath -> def:namespaceData */
1812 1813 1814 1815 1816 1817 1818
    if (ctx->datacenterPath || ctx->moref) {
        struct virVMXDomainDefNamespaceData *nsdata = NULL;

        if (VIR_ALLOC(nsdata) < 0 ||
            VIR_STRDUP(nsdata->datacenterPath, ctx->datacenterPath) < 0 ||
            VIR_STRDUP(nsdata->moref, ctx->moref) < 0) {
            virVMXDomainDefNamespaceFree(nsdata);
1819
            goto cleanup;
1820
        }
1821 1822

        def->ns = *virDomainXMLOptionGetNamespace(xmlopt);
1823
        def->namespaceData = nsdata;
1824 1825
    }

1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840
    /* vmx:firmware */
    if (virVMXGetConfigString(conf, "firmware", &firmware, true) < 0)
        goto cleanup;

    if (firmware != NULL) {
        if (STREQ(firmware, "efi")) {
            def->os.firmware = VIR_DOMAIN_OS_DEF_FIRMWARE_EFI;
        } else {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("VMX entry 'firmware' has unknown value '%s'"),
                           firmware);
            goto cleanup;
        }
    }

1841
    if (virDomainDefPostParse(def, caps, VIR_DOMAIN_DEF_PARSE_ABI_UPDATE,
1842
                              xmlopt, NULL) < 0)
1843 1844
        goto cleanup;

M
Matthias Bolte 已提交
1845 1846
    success = true;

1847
 cleanup:
M
Matthias Bolte 已提交
1848 1849 1850 1851 1852
    if (! success) {
        virDomainDefFree(def);
        def = NULL;
    }

1853
    virConfFree(conf);
1854
    VIR_FREE(encoding);
1855
    VIR_FREE(sched_cpu_affinity);
1856
    VIR_FREE(sched_cpu_shares);
M
Matthias Bolte 已提交
1857
    VIR_FREE(guestOS);
1858
    virCPUDefFree(cpu);
1859
    VIR_FREE(firmware);
1860 1861 1862 1863 1864 1865

    return def;
}



M
Matthias Bolte 已提交
1866
int
1867
virVMXParseVNC(virConfPtr conf, virDomainGraphicsDefPtr *def)
M
Matthias Bolte 已提交
1868
{
1869
    bool enabled = false;
M
Matthias Bolte 已提交
1870
    long long port = 0;
1871
    char *listenAddr = NULL;
M
Matthias Bolte 已提交
1872 1873

    if (def == NULL || *def != NULL) {
1874
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
1875 1876 1877
        return -1;
    }

1878 1879
    if (virVMXGetConfigBoolean(conf, "RemoteDisplay.vnc.enabled", &enabled,
                               false, true) < 0) {
M
Matthias Bolte 已提交
1880 1881 1882
        return -1;
    }

1883
    if (! enabled)
M
Matthias Bolte 已提交
1884 1885
        return 0;

1886
    if (VIR_ALLOC(*def) < 0)
M
Matthias Bolte 已提交
1887 1888 1889 1890
        goto failure;

    (*def)->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;

1891 1892 1893
    if (virVMXGetConfigLong(conf, "RemoteDisplay.vnc.port", &port, -1,
                            true) < 0 ||
        virVMXGetConfigString(conf, "RemoteDisplay.vnc.ip",
1894
                              &listenAddr, true) < 0 ||
1895 1896 1897 1898
        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 已提交
1899 1900 1901
        goto failure;
    }

1902 1903 1904
    if (virDomainGraphicsListenAppendAddress(*def, listenAddr) < 0)
        goto failure;
    VIR_FREE(listenAddr);
1905

M
Matthias Bolte 已提交
1906
    if (port < 0) {
1907
        VIR_WARN("VNC is enabled but VMX entry 'RemoteDisplay.vnc.port' "
M
Matthias Bolte 已提交
1908 1909 1910
                  "is missing, the VNC port is unknown");

        (*def)->data.vnc.port = 0;
1911
        (*def)->data.vnc.autoport = true;
M
Matthias Bolte 已提交
1912
    } else {
1913
        if (port < 5900 || port > 5964)
M
Matthias Bolte 已提交
1914 1915 1916
            VIR_WARN("VNC port %lld it out of [5900..5964] range", port);

        (*def)->data.vnc.port = port;
1917
        (*def)->data.vnc.autoport = false;
M
Matthias Bolte 已提交
1918 1919 1920 1921
    }

    return 0;

1922
 failure:
1923
    VIR_FREE(listenAddr);
M
Matthias Bolte 已提交
1924 1925 1926 1927 1928 1929 1930 1931
    virDomainGraphicsDefFree(*def);
    *def = NULL;

    return -1;
}



1932
int
1933 1934
virVMXParseSCSIController(virConfPtr conf, int controller, bool *present,
                          int *virtualDev)
1935
{
1936
    int result = -1;
1937 1938
    char present_name[32];
    char virtualDev_name[32];
1939 1940
    char *virtualDev_string = NULL;
    char *tmp;
1941

1942
    if (virtualDev == NULL || *virtualDev != -1) {
1943
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
1944
        return -1;
1945 1946 1947
    }

    if (controller < 0 || controller > 3) {
1948 1949 1950
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("SCSI controller index %d out of [0..3] range"),
                       controller);
1951
        return -1;
1952 1953
    }

1954 1955 1956
    snprintf(present_name, sizeof(present_name), "scsi%d.present", controller);
    snprintf(virtualDev_name, sizeof(virtualDev_name), "scsi%d.virtualDev",
             controller);
1957

1958
    if (virVMXGetConfigBoolean(conf, present_name, present, false, true) < 0)
1959
        goto cleanup;
1960 1961

    if (! *present) {
1962 1963
        result = 0;
        goto cleanup;
1964 1965
    }

1966 1967
    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev_string,
                              true) < 0) {
1968
        goto cleanup;
1969 1970
    }

1971 1972 1973
    if (virtualDev_string != NULL) {
        tmp = virtualDev_string;

1974
        for (; *tmp != '\0'; ++tmp)
1975 1976
            *tmp = c_tolower(*tmp);

1977
        *virtualDev = virVMXControllerModelSCSITypeFromString(virtualDev_string);
1978 1979

        if (*virtualDev == -1 ||
1980 1981 1982 1983
            (*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)) {
1984 1985 1986 1987
            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);
1988
            goto cleanup;
1989
        }
1990 1991
    }

1992
    result = 0;
1993

1994
 cleanup:
1995
    VIR_FREE(virtualDev_string);
1996

1997
    return result;
1998 1999 2000 2001 2002
}



int
2003
virVMXParseDisk(virVMXContext *ctx, virDomainXMLOptionPtr xmlopt, virConfPtr conf,
2004
                int device, int busType, int controllerOrBus, int unit,
2005
                virDomainDiskDefPtr *def, virDomainDefPtr vmdef)
2006 2007
{
    /*
2008 2009 2010
     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK,
     *                    VIR_DOMAIN_DISK_DEVICE_CDROM,
     *                    VIR_DOMAIN_DISK_DEVICE_LUN}
2011 2012 2013
     *         busType = VIR_DOMAIN_DISK_BUS_SCSI
     * controllerOrBus = [0..3] -> controller
     *            unit = [0..6,8..15]
2014
     *
2015 2016 2017
     *          device = {VIR_DOMAIN_DISK_DEVICE_DISK,
     *                    VIR_DOMAIN_DISK_DEVICE_CDROM,
     *                    VIR_DOMAIN_DISK_DEVICE_LUN}
2018 2019 2020
     *         busType = VIR_DOMAIN_DISK_BUS_IDE
     * controllerOrBus = [0..1] -> bus
     *            unit = [0..1]
2021
     *
2022 2023 2024 2025
     *          device = VIR_DOMAIN_DISK_DEVICE_FLOPPY
     *         busType = VIR_DOMAIN_DISK_BUS_FDC
     * controllerOrBus = [0]
     *            unit = [0..1]
2026 2027
     */

M
Matthias Bolte 已提交
2028
    int result = -1;
2029 2030 2031
    char *prefix = NULL;

    char present_name[32] = "";
2032
    bool present = false;
2033 2034

    char startConnected_name[32] = "";
2035
    bool startConnected = false;
2036 2037 2038 2039 2040

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

    char clientDevice_name[32] = "";
2041
    bool clientDevice = false;
2042 2043 2044 2045 2046 2047 2048 2049

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

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

    char writeThrough_name[32] = "";
2050
    bool writeThrough = false;
2051

2052 2053 2054
    char mode_name[32] = "";
    char *mode = NULL;

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

2060
    if (!(*def = virDomainDiskDefNew(xmlopt)))
M
Matthias Bolte 已提交
2061
        return -1;
2062 2063

    (*def)->device = device;
2064
    (*def)->bus = busType;
2065 2066 2067 2068

    /* def:dst, def:driverName */
    if (device == VIR_DOMAIN_DISK_DEVICE_DISK ||
        device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
2069 2070
        if (busType == VIR_DOMAIN_DISK_BUS_SCSI) {
            if (controllerOrBus < 0 || controllerOrBus > 3) {
2071 2072 2073
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("SCSI controller index %d out of [0..3] range"),
                               controllerOrBus);
M
Matthias Bolte 已提交
2074
                goto cleanup;
2075 2076
            }

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

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

M
Matthias Bolte 已提交
2087
            (*def)->dst =
2088
               virIndexToDiskName
2089
                 (controllerOrBus * 15 + (unit < 7 ? unit : unit - 1), "sd");
2090

2091
            if ((*def)->dst == NULL)
M
Matthias Bolte 已提交
2092
                goto cleanup;
2093 2094
        } else if (busType == VIR_DOMAIN_DISK_BUS_IDE) {
            if (controllerOrBus < 0 || controllerOrBus > 1) {
2095 2096 2097
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("IDE bus index %d out of [0..1] range"),
                               controllerOrBus);
M
Matthias Bolte 已提交
2098
                goto cleanup;
2099 2100
            }

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

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

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

2112
            if ((*def)->dst == NULL)
M
Matthias Bolte 已提交
2113
                goto cleanup;
2114
        } else {
2115 2116 2117 2118
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported bus type '%s' for device type '%s'"),
                           virDomainDiskBusTypeToString(busType),
                           virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2119
            goto cleanup;
2120 2121
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2122 2123
        if (busType == VIR_DOMAIN_DISK_BUS_FDC) {
            if (controllerOrBus != 0) {
2124 2125 2126
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("FDC controller index %d out of [0] range"),
                               controllerOrBus);
2127 2128 2129 2130
                goto cleanup;
            }

            if (unit < 0 || unit > 1) {
2131 2132 2133
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("FDC unit index %d out of [0..1] range"),
                               unit);
M
Matthias Bolte 已提交
2134
                goto cleanup;
2135 2136
            }

2137
            if (virAsprintf(&prefix, "floppy%d", unit) < 0)
M
Matthias Bolte 已提交
2138
                goto cleanup;
2139

2140
            (*def)->dst = virIndexToDiskName(unit, "fd");
2141

2142
            if ((*def)->dst == NULL)
M
Matthias Bolte 已提交
2143
                goto cleanup;
2144
        } else {
2145 2146 2147 2148
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported bus type '%s' for device type '%s'"),
                           virDomainDiskBusTypeToString(busType),
                           virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2149
            goto cleanup;
2150 2151
        }
    } else {
2152 2153 2154
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported device type '%s'"),
                       virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2155
        goto cleanup;
2156 2157
    }

2158 2159 2160 2161 2162 2163 2164
    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);
2165
    VMX_BUILD_NAME(mode);
2166 2167

    /* vmx:present */
2168
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
M
Matthias Bolte 已提交
2169
        goto cleanup;
2170 2171

    /* vmx:startConnected */
2172 2173
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
M
Matthias Bolte 已提交
2174
        goto cleanup;
2175 2176
    }

2177
    /* FIXME: Need to distinguish between active and inactive domains here */
2178
    if (! present/* && ! startConnected*/)
2179 2180 2181
        goto ignore;

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

    /* vmx:clientDevice */
2186 2187
    if (virVMXGetConfigBoolean(conf, clientDevice_name, &clientDevice, false,
                               true) < 0) {
M
Matthias Bolte 已提交
2188
        goto cleanup;
2189 2190
    }

2191
    /* vmx:mode -> def:transient */
2192
    if (virVMXGetConfigString(conf, mode_name, &mode, true) < 0)
2193 2194
        goto cleanup;

2195 2196 2197
    if (clientDevice) {
        /*
         * Just ignore devices in client mode, because I have no clue how to
M
Matthias Bolte 已提交
2198
         * handle them (e.g. assign an image) without the VI Client GUI.
2199 2200 2201 2202 2203
         */
        goto ignore;
    }

    /* vmx:fileType -> def:type */
2204
    if (virVMXGetConfigString(conf, fileType_name, &fileType, true) < 0)
M
Matthias Bolte 已提交
2205
        goto cleanup;
2206 2207

    /* vmx:fileName -> def:src, def:type */
2208
    if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0)
M
Matthias Bolte 已提交
2209
        goto cleanup;
2210 2211

    /* vmx:writeThrough -> def:cachemode */
2212 2213
    if (virVMXGetConfigBoolean(conf, writeThrough_name, &writeThrough, false,
                               true) < 0) {
M
Matthias Bolte 已提交
2214
        goto cleanup;
2215 2216 2217 2218
    }

    /* Setup virDomainDiskDef */
    if (device == VIR_DOMAIN_DISK_DEVICE_DISK) {
2219
        if (virStringHasCaseSuffix(fileName, ".vmdk")) {
2220 2221
            char *tmp;

2222
            if (deviceType != NULL) {
2223
                if (busType == VIR_DOMAIN_DISK_BUS_SCSI &&
2224 2225
                    STRCASENEQ(deviceType, "scsi-hardDisk") &&
                    STRCASENEQ(deviceType, "disk")) {
2226 2227 2228 2229
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'scsi-hardDisk' "
                                     "or 'disk' but found '%s'"), deviceType_name,
                                   deviceType);
M
Matthias Bolte 已提交
2230
                    goto cleanup;
2231
                } else if (busType == VIR_DOMAIN_DISK_BUS_IDE &&
2232 2233
                           STRCASENEQ(deviceType, "ata-hardDisk") &&
                           STRCASENEQ(deviceType, "disk")) {
2234 2235 2236 2237
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Expecting VMX entry '%s' to be 'ata-hardDisk' "
                                     "or 'disk' but found '%s'"), deviceType_name,
                                   deviceType);
M
Matthias Bolte 已提交
2238
                    goto cleanup;
2239 2240 2241
                }
            }

E
Eric Blake 已提交
2242
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
2243 2244 2245 2246 2247 2248 2249
            if (!(tmp = ctx->parseFileName(fileName, ctx->opaque)))
                goto cleanup;
            if (virDomainDiskSetSource(*def, tmp) < 0) {
                VIR_FREE(tmp);
                goto cleanup;
            }
            VIR_FREE(tmp);
2250 2251
            (*def)->cachemode = writeThrough ? VIR_DOMAIN_DISK_CACHE_WRITETHRU
                                             : VIR_DOMAIN_DISK_CACHE_DEFAULT;
2252 2253 2254
            if (mode)
                (*def)->transient = STRCASEEQ(mode,
                                              "independent-nonpersistent");
2255
        } else if (virStringHasCaseSuffix(fileName, ".iso") ||
2256
                   STREQ(fileName, "emptyBackingString") ||
2257 2258
                   (deviceType &&
                    (STRCASEEQ(deviceType, "atapi-cdrom") ||
2259 2260 2261
                     STRCASEEQ(deviceType, "cdrom-raw") ||
                     (STRCASEEQ(deviceType, "scsi-passthru") &&
                      STRPREFIX(fileName, "/vmfs/devices/cdrom/"))))) {
2262 2263
            /*
             * This function was called in order to parse a harddisk device,
2264 2265 2266
             * 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.
2267 2268 2269
             */
            goto ignore;
        } else {
2270
            virReportError(VIR_ERR_INTERNAL_ERROR,
2271 2272
                           _("Invalid or not yet handled value '%s' "
                             "for VMX entry '%s' for device type '%s'"),
M
Matthias Bolte 已提交
2273 2274
                           fileName, fileName_name,
                           deviceType ? deviceType : "unknown");
M
Matthias Bolte 已提交
2275
            goto cleanup;
2276 2277
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
2278
        if (virStringHasCaseSuffix(fileName, ".iso")) {
2279 2280
            char *tmp;

2281 2282 2283 2284 2285
            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;
2286 2287
            }

E
Eric Blake 已提交
2288
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
2289 2290 2291 2292
            if (!(tmp = ctx->parseFileName(fileName, ctx->opaque)))
                goto cleanup;
            if (virDomainDiskSetSource(*def, tmp) < 0) {
                VIR_FREE(tmp);
M
Matthias Bolte 已提交
2293
                goto cleanup;
M
Matthias Bolte 已提交
2294
            }
2295
            VIR_FREE(tmp);
2296
        } else if (virStringHasCaseSuffix(fileName, ".vmdk")) {
2297 2298 2299 2300 2301 2302 2303
            /*
             * 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;
2304
        } else if (deviceType && STRCASEEQ(deviceType, "atapi-cdrom")) {
E
Eric Blake 已提交
2305
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);
2306 2307

            if (STRCASEEQ(fileName, "auto detect")) {
2308
                ignore_value(virDomainDiskSetSource(*def, NULL));
2309
                (*def)->startupPolicy = VIR_DOMAIN_STARTUP_POLICY_OPTIONAL;
2310 2311
            } else if (virDomainDiskSetSource(*def, fileName) < 0) {
                goto cleanup;
2312
            }
2313
        } else if (deviceType && STRCASEEQ(deviceType, "cdrom-raw")) {
2314 2315
            /* Raw access CD-ROMs actually are device='lun' */
            (*def)->device = VIR_DOMAIN_DISK_DEVICE_LUN;
E
Eric Blake 已提交
2316
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);
2317 2318

            if (STRCASEEQ(fileName, "auto detect")) {
2319
                ignore_value(virDomainDiskSetSource(*def, NULL));
2320
                (*def)->startupPolicy = VIR_DOMAIN_STARTUP_POLICY_OPTIONAL;
2321 2322
            } else if (virDomainDiskSetSource(*def, fileName) < 0) {
                goto cleanup;
2323
            }
2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341
        } 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;
            }
2342 2343 2344 2345 2346 2347 2348 2349 2350 2351
        } else if (STREQ(fileName, "emptyBackingString")) {
            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;
            }

            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
            ignore_value(virDomainDiskSetSource(*def, NULL));
2352
        } else {
2353
            virReportError(VIR_ERR_INTERNAL_ERROR,
2354 2355
                           _("Invalid or not yet handled value '%s' "
                             "for VMX entry '%s' for device type '%s'"),
M
Matthias Bolte 已提交
2356 2357
                           fileName, fileName_name,
                           deviceType ? deviceType : "unknown");
M
Matthias Bolte 已提交
2358
            goto cleanup;
2359 2360
        }
    } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2361
        if (fileType != NULL && STRCASEEQ(fileType, "device")) {
E
Eric Blake 已提交
2362
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);
2363 2364
            if (virDomainDiskSetSource(*def, fileName) < 0)
                goto cleanup;
2365
        } else if (fileType != NULL && STRCASEEQ(fileType, "file")) {
2366 2367
            char *tmp;

E
Eric Blake 已提交
2368
            virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
2369 2370 2371 2372 2373 2374 2375
            if (!(tmp = ctx->parseFileName(fileName, ctx->opaque)))
                goto cleanup;
            if (virDomainDiskSetSource(*def, tmp) < 0) {
                VIR_FREE(tmp);
                goto cleanup;
            }
            VIR_FREE(tmp);
2376
        } else {
2377
            virReportError(VIR_ERR_INTERNAL_ERROR,
2378 2379
                           _("Invalid or not yet handled value '%s' "
                             "for VMX entry '%s' for device type '%s'"),
M
Matthias Bolte 已提交
2380 2381
                           fileName, fileName_name,
                           deviceType ? deviceType : "unknown");
M
Matthias Bolte 已提交
2382
            goto cleanup;
2383 2384
        }
    } else {
2385 2386
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported device type '%s'"),
                       virDomainDiskDeviceTypeToString(device));
M
Matthias Bolte 已提交
2387
        goto cleanup;
2388 2389
    }

2390
    if (virDomainDiskDefAssignAddress(xmlopt, *def, vmdef) < 0) {
2391
        virReportError(VIR_ERR_INTERNAL_ERROR,
2392 2393
                       _("Could not assign address to disk '%s'"),
                       virDomainDiskGetSource(*def));
2394 2395 2396
        goto cleanup;
    }

M
Matthias Bolte 已提交
2397 2398
    result = 0;

2399
 cleanup:
M
Matthias Bolte 已提交
2400 2401 2402 2403 2404
    if (result < 0) {
        virDomainDiskDefFree(*def);
        *def = NULL;
    }

2405 2406 2407 2408
    VIR_FREE(prefix);
    VIR_FREE(deviceType);
    VIR_FREE(fileType);
    VIR_FREE(fileName);
2409
    VIR_FREE(mode);
2410 2411 2412

    return result;

2413
 ignore:
2414 2415 2416
    virDomainDiskDefFree(*def);
    *def = NULL;

M
Matthias Bolte 已提交
2417 2418
    result = 0;

2419 2420 2421 2422 2423
    goto cleanup;
}



2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457
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;
    }

    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 */
2458
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
2459
        return -1;
2460 2461

    /* vmx:enabled */
2462
    if (virVMXGetConfigBoolean(conf, enabled_name, &enabled, false, true) < 0)
2463
        return -1;
2464

2465
    if (!(present && enabled))
2466 2467 2468 2469 2470 2471
        return 0;

    if (!(*def = virDomainFSDefNew()))
        return -1;

    (*def)->type = VIR_DOMAIN_FS_TYPE_MOUNT;
2472 2473

    /* vmx:hostPath */
2474
    if (virVMXGetConfigString(conf, hostPath_name, &hostPath, false) < 0)
2475 2476
        goto cleanup;

2477
    (*def)->src->path = hostPath;
2478 2479 2480
    hostPath = NULL;

    /* vmx:guestName */
2481
    if (virVMXGetConfigString(conf, guestName_name, &guestName, false) < 0)
2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496
        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;

2497
 cleanup:
2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510
    if (result < 0) {
        virDomainFSDefFree(*def);
        *def = NULL;
    }

    VIR_FREE(hostPath);
    VIR_FREE(guestName);

    return result;
}



2511
int
2512
virVMXParseEthernet(virConfPtr conf, int controller, virDomainNetDefPtr *def)
2513
{
M
Matthias Bolte 已提交
2514
    int result = -1;
2515 2516 2517
    char prefix[48] = "";

    char present_name[48] = "";
2518
    bool present = false;
2519 2520

    char startConnected_name[48] = "";
2521
    bool startConnected = false;
2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537

    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;

2538 2539 2540
    char features_name[48] = "";
    long long features = 0;

2541 2542 2543
    char vnet_name[48] = "";
    char *vnet = NULL;

M
Matthias Bolte 已提交
2544 2545 2546
    char networkName_name[48] = "";
    char *networkName = NULL;

C
Cole Robinson 已提交
2547 2548
    int netmodel = VIR_DOMAIN_NET_MODEL_UNKNOWN;

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

2554
    snprintf(prefix, sizeof(prefix), "ethernet%d", controller);
2555

2556 2557 2558 2559 2560 2561 2562 2563 2564 2565
    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);
2566 2567

    /* vmx:present */
2568
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
2569
        return -1;
2570 2571

    /* vmx:startConnected */
2572 2573
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
2574
        return -1;
2575 2576
    }

2577
    /* FIXME: Need to distinguish between active and inactive domains here */
2578
    if (! present/* && ! startConnected*/)
2579 2580 2581 2582
        return 0;

    if (VIR_ALLOC(*def) < 0)
        return -1;
2583 2584

    /* vmx:connectionType -> def:type */
2585 2586
    if (virVMXGetConfigString(conf, connectionType_name, &connectionType,
                              true) < 0) {
M
Matthias Bolte 已提交
2587
        goto cleanup;
2588 2589 2590
    }

    /* vmx:addressType, vmx:generatedAddress, vmx:address -> def:mac */
2591 2592 2593 2594 2595
    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 已提交
2596
        goto cleanup;
2597 2598
    }

2599 2600
    if (addressType == NULL || STRCASEEQ(addressType, "generated") ||
        STRCASEEQ(addressType, "vpx")) {
2601
        if (generatedAddress != NULL) {
2602
            if (virMacAddrParse(generatedAddress, &(*def)->mac) < 0) {
2603 2604 2605 2606
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry '%s' to be MAC address but "
                                 "found '%s'"), generatedAddress_name,
                               generatedAddress);
M
Matthias Bolte 已提交
2607
                goto cleanup;
2608 2609 2610 2611
            }
        }
    } else if (STRCASEEQ(addressType, "static")) {
        if (address != NULL) {
2612
            if (virMacAddrParse(address, &(*def)->mac) < 0) {
2613 2614 2615
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Expecting VMX entry '%s' to be MAC address but "
                                 "found '%s'"), address_name, address);
M
Matthias Bolte 已提交
2616
                goto cleanup;
2617 2618 2619
            }
        }
    } else {
2620 2621 2622
        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 已提交
2623
        goto cleanup;
2624 2625
    }

2626
    /* vmx:virtualDev, vmx:features -> def:model */
2627 2628
    if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev, true) < 0 ||
        virVMXGetConfigLong(conf, features_name, &features, 0, true) < 0) {
M
Matthias Bolte 已提交
2629
        goto cleanup;
2630 2631
    }

2632
    if (virtualDev != NULL) {
C
Cole Robinson 已提交
2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643
        if (STRCASEEQ(virtualDev, "vlance")) {
            netmodel = VIR_DOMAIN_NET_MODEL_VLANCE;
        } else if (STRCASEEQ(virtualDev, "vmxnet")) {
            netmodel = VIR_DOMAIN_NET_MODEL_VMXNET;
        } else if (STRCASEEQ(virtualDev, "vmxnet3")) {
            netmodel = VIR_DOMAIN_NET_MODEL_VMXNET3;
        } else if (STRCASEEQ(virtualDev, "e1000")) {
            netmodel = VIR_DOMAIN_NET_MODEL_E1000;
        } else if (STRCASEEQ(virtualDev, "e1000e")) {
            netmodel = VIR_DOMAIN_NET_MODEL_E1000E;
        } else {
2644 2645
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting VMX entry '%s' to be 'vlance' or 'vmxnet' or "
Y
Yuri Chornoivan 已提交
2646
                             "'vmxnet3' or 'e1000' or 'e1000e' but found '%s'"),
M
Matthias Bolte 已提交
2647
                           virtualDev_name, virtualDev);
M
Matthias Bolte 已提交
2648
            goto cleanup;
2649 2650
        }

C
Cole Robinson 已提交
2651 2652
        if (netmodel == VIR_DOMAIN_NET_MODEL_VMXNET && features == 15)
            netmodel = VIR_DOMAIN_NET_MODEL_VMXNET2;
2653 2654
    }

M
Matthias Bolte 已提交
2655
    /* vmx:networkName -> def:data.bridge.brname */
2656 2657 2658 2659 2660 2661 2662
    if (connectionType == NULL ||
        STRCASEEQ(connectionType, "bridged") ||
        STRCASEEQ(connectionType, "custom")) {
        if (virVMXGetConfigString(conf, networkName_name, &networkName,
                                  true) < 0)
            goto cleanup;

2663 2664
        if (!networkName && VIR_STRDUP(networkName, "") < 0)
            goto cleanup;
M
Matthias Bolte 已提交
2665 2666 2667
    }

    /* vmx:vnet -> def:data.ifname */
2668
    if (connectionType != NULL && STRCASEEQ(connectionType, "custom") &&
2669
        virVMXGetConfigString(conf, vnet_name, &vnet, false) < 0) {
M
Matthias Bolte 已提交
2670
        goto cleanup;
2671 2672 2673 2674 2675
    }

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

M
Matthias Bolte 已提交
2678
        networkName = NULL;
2679 2680
    } else if (STRCASEEQ(connectionType, "hostonly")) {
        /* FIXME */
2681 2682 2683
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No yet handled value '%s' for VMX entry '%s'"),
                       connectionType, connectionType_name);
M
Matthias Bolte 已提交
2684
        goto cleanup;
2685
    } else if (STRCASEEQ(connectionType, "nat")) {
2686 2687
        (*def)->type = VIR_DOMAIN_NET_TYPE_USER;

2688 2689
    } else if (STRCASEEQ(connectionType, "custom")) {
        (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
M
Matthias Bolte 已提交
2690 2691
        (*def)->data.bridge.brname = networkName;
        (*def)->ifname = vnet;
2692

M
Matthias Bolte 已提交
2693
        networkName = NULL;
2694 2695
        vnet = NULL;
    } else {
2696 2697 2698
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid value '%s' for VMX entry '%s'"), connectionType,
                       connectionType_name);
M
Matthias Bolte 已提交
2699
        goto cleanup;
2700 2701
    }

C
Cole Robinson 已提交
2702
    (*def)->model = netmodel;
M
Matthias Bolte 已提交
2703 2704
    result = 0;

2705
 cleanup:
M
Matthias Bolte 已提交
2706 2707 2708 2709 2710
    if (result < 0) {
        virDomainNetDefFree(*def);
        *def = NULL;
    }

S
Stefan Berger 已提交
2711
    VIR_FREE(networkName);
2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724
    VIR_FREE(connectionType);
    VIR_FREE(addressType);
    VIR_FREE(generatedAddress);
    VIR_FREE(address);
    VIR_FREE(virtualDev);
    VIR_FREE(vnet);

    return result;
}



int
2725 2726
virVMXParseSerial(virVMXContext *ctx, virConfPtr conf, int port,
                  virDomainChrDefPtr *def)
2727
{
M
Matthias Bolte 已提交
2728
    int result = -1;
2729 2730 2731
    char prefix[48] = "";

    char present_name[48] = "";
2732
    bool present = false;
2733 2734

    char startConnected_name[48] = "";
2735
    bool startConnected = false;
2736 2737 2738 2739 2740 2741 2742

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

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

2743 2744 2745
    char network_endPoint_name[48] = "";
    char *network_endPoint = NULL;

M
Martin Kletzander 已提交
2746
    virURIPtr parsedUri = NULL;
2747

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

    if (port < 0 || port > 3) {
2754 2755
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Serial port index %d out of [0..3] range"), port);
2756
        return -1;
2757 2758
    }

2759
    snprintf(prefix, sizeof(prefix), "serial%d", port);
2760

2761 2762 2763 2764 2765
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
    VMX_BUILD_NAME_EXTRA(network_endPoint, "network.endPoint");
2766 2767

    /* vmx:present */
2768
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
2769
        return -1;
2770 2771

    /* vmx:startConnected */
2772 2773
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
2774
        return -1;
2775 2776
    }

2777
    /* FIXME: Need to distinguish between active and inactive domains here */
2778
    if (! present/* && ! startConnected*/)
2779 2780 2781 2782 2783 2784
        return 0;

    if (!(*def = virDomainChrDefNew(NULL)))
        return -1;

    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
2785 2786

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

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

2794
    /* vmx:network.endPoint -> def:data.tcp.listen */
2795 2796
    if (virVMXGetConfigString(conf, network_endPoint_name, &network_endPoint,
                              true) < 0) {
2797 2798 2799
        goto cleanup;
    }

G
Geoff Hickey 已提交
2800 2801 2802 2803 2804 2805
    /*
     * 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")) {
2806
        (*def)->target.port = port;
2807 2808
        (*def)->source->type = VIR_DOMAIN_CHR_TYPE_DEV;
        (*def)->source->data.file.path = fileName;
2809 2810 2811

        fileName = NULL;
    } else if (STRCASEEQ(fileType, "file")) {
2812
        (*def)->target.port = port;
2813 2814 2815
        (*def)->source->type = VIR_DOMAIN_CHR_TYPE_FILE;
        (*def)->source->data.file.path = ctx->parseFileName(fileName,
                                                            ctx->opaque);
2816

2817
        if ((*def)->source->data.file.path == NULL)
M
Matthias Bolte 已提交
2818
            goto cleanup;
2819
    } else if (STRCASEEQ(fileType, "pipe")) {
M
Matthias Bolte 已提交
2820 2821 2822 2823
        /*
         * FIXME: Differences between client/server and VM/application pipes
         *        not representable in domain XML form
         */
2824
        (*def)->target.port = port;
2825 2826
        (*def)->source->type = VIR_DOMAIN_CHR_TYPE_PIPE;
        (*def)->source->data.file.path = fileName;
M
Matthias Bolte 已提交
2827 2828

        fileName = NULL;
2829 2830
    } else if (STRCASEEQ(fileType, "network")) {
        (*def)->target.port = port;
2831
        (*def)->source->type = VIR_DOMAIN_CHR_TYPE_TCP;
2832

2833
        if (!(parsedUri = virURIParse(fileName)))
2834 2835 2836
            goto cleanup;

        if (parsedUri->port == 0) {
2837 2838 2839
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("VMX entry '%s' doesn't contain a port part"),
                           fileName_name);
2840 2841 2842
            goto cleanup;
        }

2843
        if (VIR_STRDUP((*def)->source->data.tcp.host, parsedUri->server) < 0)
2844 2845
            goto cleanup;

2846
        if (virAsprintf(&(*def)->source->data.tcp.service, "%d",
2847
                        parsedUri->port) < 0)
2848 2849 2850 2851 2852 2853 2854
            goto cleanup;

        /* See vSphere API documentation about VirtualSerialPortURIBackingInfo */
        if (parsedUri->scheme == NULL ||
            STRCASEEQ(parsedUri->scheme, "tcp") ||
            STRCASEEQ(parsedUri->scheme, "tcp4") ||
            STRCASEEQ(parsedUri->scheme, "tcp6")) {
2855
            (*def)->source->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
2856
        } else if (STRCASEEQ(parsedUri->scheme, "telnet")) {
2857
            (*def)->source->data.tcp.protocol
2858
                = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
2859
        } else if (STRCASEEQ(parsedUri->scheme, "telnets")) {
2860
            (*def)->source->data.tcp.protocol
2861
                = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS;
2862 2863 2864 2865
        } else if (STRCASEEQ(parsedUri->scheme, "ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp+ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp4+ssl") ||
                   STRCASEEQ(parsedUri->scheme, "tcp6+ssl")) {
2866
            (*def)->source->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS;
2867
        } else {
2868 2869 2870
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("VMX entry '%s' contains unsupported scheme '%s'"),
                           fileName_name, parsedUri->scheme);
2871 2872 2873 2874
            goto cleanup;
        }

        if (network_endPoint == NULL || STRCASEEQ(network_endPoint, "server")) {
2875
            (*def)->source->data.tcp.listen = true;
2876
        } else if (STRCASEEQ(network_endPoint, "client")) {
2877
            (*def)->source->data.tcp.listen = false;
2878
        } else {
2879 2880 2881
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting VMX entry '%s' to be 'server' or 'client' "
                             "but found '%s'"), network_endPoint_name, network_endPoint);
2882 2883
            goto cleanup;
        }
2884
    } else {
2885 2886 2887
        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 已提交
2888
        goto cleanup;
2889 2890
    }

M
Matthias Bolte 已提交
2891 2892
    result = 0;

2893
 cleanup:
M
Matthias Bolte 已提交
2894 2895 2896 2897 2898
    if (result < 0) {
        virDomainChrDefFree(*def);
        *def = NULL;
    }

2899 2900
    VIR_FREE(fileType);
    VIR_FREE(fileName);
2901
    VIR_FREE(network_endPoint);
2902
    virURIFree(parsedUri);
2903 2904 2905 2906 2907 2908 2909

    return result;
}



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

    char present_name[48] = "";
2917
    bool present = false;
2918 2919

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

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

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

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

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

2939
    snprintf(prefix, sizeof(prefix), "parallel%d", port);
2940

2941 2942 2943 2944
    VMX_BUILD_NAME(present);
    VMX_BUILD_NAME(startConnected);
    VMX_BUILD_NAME(fileType);
    VMX_BUILD_NAME(fileName);
2945 2946

    /* vmx:present */
2947
    if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
2948
        return -1;
2949 2950

    /* vmx:startConnected */
2951 2952
    if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
                               true, true) < 0) {
2953
        return -1;
2954 2955
    }

2956
    /* FIXME: Need to distinguish between active and inactive domains here */
2957
    if (! present/* && ! startConnected*/)
2958 2959 2960 2961 2962 2963
        return 0;

    if (!(*def = virDomainChrDefNew(NULL)))
        return -1;

    (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
2964 2965

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

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

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

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

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

M
Matthias Bolte 已提交
2995 2996
    result = 0;

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

3003 3004 3005 3006 3007
    VIR_FREE(fileType);
    VIR_FREE(fileName);

    return result;
}
M
Matthias Bolte 已提交
3008 3009 3010



3011 3012 3013 3014 3015 3016 3017
int
virVMXParseSVGA(virConfPtr conf, virDomainVideoDefPtr *def)
{
    int result = -1;
    long long svga_vramSize = 0;

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

3022
    if (VIR_ALLOC(*def) < 0)
3023 3024 3025 3026 3027 3028 3029 3030 3031 3032
        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;
    }

3033
    (*def)->vram = VIR_DIV_UP(svga_vramSize, 1024); /* Scale from bytes to kilobytes */
3034 3035 3036

    result = 0;

3037
 cleanup:
3038 3039 3040 3041 3042 3043 3044 3045 3046 3047
    if (result < 0) {
        virDomainVideoDefFree(*def);
        *def = NULL;
    }

    return result;
}



M
Matthias Bolte 已提交
3048 3049 3050 3051 3052
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Domain XML -> VMX
 */

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

3071
    if (ctx->formatFileName == NULL) {
3072 3073
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("virVMXContext has no formatFileName function set"));
3074 3075 3076
        return NULL;
    }

M
Matthias Bolte 已提交
3077 3078
    memset(zero, 0, VIR_UUID_BUFLEN);

3079
    if (def->virtType != VIR_DOMAIN_VIRT_VMWARE) {
3080 3081 3082 3083
        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 已提交
3084 3085 3086
        return NULL;
    }

3087 3088 3089
    /* vmx:.encoding */
    virBufferAddLit(&buffer, ".encoding = \"UTF-8\"\n");

M
Matthias Bolte 已提交
3090 3091 3092 3093
    /* vmx:config.version */
    virBufferAddLit(&buffer, "config.version = \"8\"\n");

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

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

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

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

3139
    if (preliminaryDisplayName == NULL)
3140
        goto cleanup;
3141

3142
    displayName = virVMXEscapeHexPercent(preliminaryDisplayName);
3143

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

3147
    virBufferAsprintf(&buffer, "displayName = \"%s\"\n", displayName);
3148

3149 3150
    /* def:description -> vmx:annotation */
    if (def->description != NULL) {
3151 3152
        if (!(annotation = virVMXEscapeHexPipe(def->description)))
            goto cleanup;
3153

3154
        virBufferAsprintf(&buffer, "annotation = \"%s\"\n", annotation);
3155 3156
    }

3157
    /* def:mem.max_balloon -> vmx:memsize */
3158
    /* max-memory must be a multiple of 4096 kilobyte */
3159
    max_balloon = VIR_DIV_UP(virDomainDefGetMemoryTotal(def), 4096) * 4096;
M
Matthias Bolte 已提交
3160

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

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

3171 3172
    /* def:mem.min_guarantee -> vmx:sched.mem.minsize */
    if (def->mem.min_guarantee > 0) {
3173
        virBufferAsprintf(&buffer, "sched.mem.minsize = \"%llu\"\n",
3174 3175
                          VIR_DIV_UP(def->mem.min_guarantee,
                                     1024)); /* Scale from kilobytes to megabytes */
3176 3177
    }

E
Eric Blake 已提交
3178
    /* def:maxvcpus -> vmx:numvcpus */
3179
    if (virDomainDefHasVcpusOffline(def)) {
3180 3181 3182
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("No support for domain XML entry 'vcpu' attribute "
                         "'current'"));
E
Eric Blake 已提交
3183 3184
        goto cleanup;
    }
3185
    maxvcpus = virDomainDefGetVcpusMax(def);
P
Pino Toscano 已提交
3186 3187 3188 3189
    if (maxvcpus == 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Expecting domain XML entry 'vcpu' to be greater "
                         "than 0"));
3190
        goto cleanup;
M
Matthias Bolte 已提交
3191 3192
    }

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

3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223
    if (def->cpu) {
        unsigned int calculated_vcpus;

        if (def->cpu->mode != VIR_CPU_MODE_CUSTOM) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting domain XML CPU mode 'custom' but "
                             "found '%s'"),
                           virCPUModeTypeToString(def->cpu->mode));
            goto cleanup;
        }

        if (def->cpu->threads != 1) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Only 1 thread per core is supported"));
            goto cleanup;
        }

        calculated_vcpus = def->cpu->sockets * def->cpu->cores;
        if (calculated_vcpus != maxvcpus) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting domain XML CPU sockets per core as %d "
                             "but found %d"),
                           maxvcpus, calculated_vcpus);
            goto cleanup;
        }

        virBufferAsprintf(&buffer, "cpuid.coresPerSocket = \"%d\"\n", def->cpu->cores);
    }

M
Matthias Bolte 已提交
3224
    /* def:cpumask -> vmx:sched.cpu.affinity */
H
Hu Tao 已提交
3225
    if (def->cpumask && virBitmapSize(def->cpumask) > 0) {
3226
        int bit;
M
Matthias Bolte 已提交
3227 3228 3229 3230
        virBufferAddLit(&buffer, "sched.cpu.affinity = \"");

        sched_cpu_affinity_length = 0;

3231
        bit = -1;
3232
        while ((bit = virBitmapNextSetBit(def->cpumask, bit)) >= 0)
H
Hu Tao 已提交
3233
            ++sched_cpu_affinity_length;
M
Matthias Bolte 已提交
3234

3235
        if (sched_cpu_affinity_length < maxvcpus) {
3236 3237 3238
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting domain XML attribute 'cpuset' of entry "
                             "'vcpu' to contain at least %d CPU(s)"),
3239
                           maxvcpus);
3240
            goto cleanup;
M
Matthias Bolte 已提交
3241 3242
        }

3243 3244 3245
        bit = -1;
        while ((bit = virBitmapNextSetBit(def->cpumask, bit)) >= 0) {
            virBufferAsprintf(&buffer, "%d", bit);
M
Matthias Bolte 已提交
3246

3247
            if (sched_cpu_affinity_length > 1)
H
Hu Tao 已提交
3248 3249 3250
                virBufferAddChar(&buffer, ',');

            --sched_cpu_affinity_length;
M
Matthias Bolte 已提交
3251 3252 3253 3254 3255
        }

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

3256
    /* def:cputune.shares -> vmx:sched.cpu.shares */
3257
    if (def->cputune.sharesSpecified) {
3258
        unsigned int vcpus = virDomainDefGetVcpus(def);
3259
        /* See http://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.SharesInfo.Level.html */
3260
        if (def->cputune.shares == vcpus * 500) {
3261
            virBufferAddLit(&buffer, "sched.cpu.shares = \"low\"\n");
3262
        } else if (def->cputune.shares == vcpus * 1000) {
3263
            virBufferAddLit(&buffer, "sched.cpu.shares = \"normal\"\n");
3264
        } else if (def->cputune.shares == vcpus * 2000) {
3265 3266
            virBufferAddLit(&buffer, "sched.cpu.shares = \"high\"\n");
        } else {
3267
            virBufferAsprintf(&buffer, "sched.cpu.shares = \"%llu\"\n",
3268 3269 3270 3271
                              def->cputune.shares);
        }
    }

M
Matthias Bolte 已提交
3272 3273 3274 3275
    /* def:graphics */
    for (i = 0; i < def->ngraphics; ++i) {
        switch (def->graphics[i]->type) {
          case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
3276
            if (virVMXFormatVNC(def->graphics[i], &buffer) < 0)
3277
                goto cleanup;
M
Matthias Bolte 已提交
3278 3279 3280

            break;

3281 3282 3283 3284
          case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
          case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
          case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
          case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
3285
          case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
3286 3287 3288
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported graphics type '%s'"),
                           virDomainGraphicsTypeToString(def->graphics[i]->type));
3289
            goto cleanup;
3290 3291 3292 3293 3294

          case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
          default:
              virReportEnumRangeError(virDomainGraphicsType, def->graphics[i]->type);
              goto cleanup;
M
Matthias Bolte 已提交
3295 3296 3297
        }
    }

M
Matthias Bolte 已提交
3298
    /* def:disks */
3299
    for (i = 0; i < def->ndisks; ++i) {
3300
        if (virVMXVerifyDiskAddress(xmlopt, def->disks[i], def) < 0 ||
3301
            virVMXHandleLegacySCSIDiskDriverName(def, def->disks[i]) < 0) {
3302
            goto cleanup;
3303 3304
        }
    }
M
Matthias Bolte 已提交
3305

3306 3307
    if (virVMXGatherSCSIControllers(ctx, def, scsi_virtualDev,
                                    scsi_present) < 0) {
3308
        goto cleanup;
M
Matthias Bolte 已提交
3309 3310 3311 3312
    }

    for (i = 0; i < 4; ++i) {
        if (scsi_present[i]) {
3313 3314
            hasSCSI = true;

3315
            virBufferAsprintf(&buffer, "scsi%zu.present = \"true\"\n", i);
M
Matthias Bolte 已提交
3316

3317
            if (scsi_virtualDev[i] != -1) {
3318
                virBufferAsprintf(&buffer, "scsi%zu.virtualDev = \"%s\"\n", i,
3319
                                  virVMXControllerModelSCSITypeToString
3320
                                    (scsi_virtualDev[i]));
M
Matthias Bolte 已提交
3321 3322 3323 3324 3325 3326 3327 3328
            }
        }
    }

    for (i = 0; i < def->ndisks; ++i) {
        switch (def->disks[i]->device) {
          case VIR_DOMAIN_DISK_DEVICE_DISK:
          case VIR_DOMAIN_DISK_DEVICE_CDROM:
3329
          case VIR_DOMAIN_DISK_DEVICE_LUN:
3330
            if (virVMXFormatDisk(ctx, def->disks[i], &buffer) < 0)
3331
                goto cleanup;
M
Matthias Bolte 已提交
3332 3333 3334 3335

            break;

          case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
3336 3337
            if (virVMXFormatFloppy(ctx, def->disks[i], &buffer,
                                   floppy_present) < 0) {
3338
                goto cleanup;
M
Matthias Bolte 已提交
3339 3340 3341 3342 3343
            }

            break;

          default:
3344 3345 3346
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported disk device type '%s'"),
                           virDomainDiskDeviceTypeToString(def->disks[i]->device));
3347
            goto cleanup;
M
Matthias Bolte 已提交
3348 3349 3350
        }
    }

3351 3352
    for (i = 0; i < 2; ++i) {
        /* floppy[0..1].present defaults to true, disable it explicitly */
3353
        if (! floppy_present[i])
3354
            virBufferAsprintf(&buffer, "floppy%zu.present = \"false\"\n", i);
3355 3356
    }

M
Matthias Bolte 已提交
3357
    /* def:fss */
3358 3359
    if (def->nfss > 0) {
        virBufferAddLit(&buffer, "isolation.tools.hgfs.disable = \"false\"\n");
3360
        virBufferAsprintf(&buffer, "sharedFolder.maxNum = \"%zu\"\n", def->nfss);
3361 3362 3363
    }

    for (i = 0; i < def->nfss; ++i) {
3364
        if (virVMXFormatFileSystem(def->fss[i], i, &buffer) < 0)
3365 3366
            goto cleanup;
    }
M
Matthias Bolte 已提交
3367 3368 3369

    /* def:nets */
    for (i = 0; i < def->nnets; ++i) {
3370
        if (virVMXFormatEthernet(def->nets[i], i, &buffer) < 0)
3371
            goto cleanup;
M
Matthias Bolte 已提交
3372 3373 3374 3375 3376 3377 3378 3379
    }

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

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

3380 3381 3382
    /* def:videos */
    if (def->nvideos > 0) {
        if (def->nvideos > 1) {
3383 3384
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No support for multiple video devices"));
3385 3386 3387
            goto cleanup;
        }

3388
        if (virVMXFormatSVGA(def->videos[0], &buffer) < 0)
3389 3390 3391
            goto cleanup;
    }

M
Matthias Bolte 已提交
3392 3393 3394 3395 3396
    /* def:hostdevs */
    /* FIXME */

    /* def:serials */
    for (i = 0; i < def->nserials; ++i) {
3397
        if (virVMXFormatSerial(ctx, def->serials[i], &buffer) < 0)
3398
            goto cleanup;
M
Matthias Bolte 已提交
3399 3400 3401 3402
    }

    /* def:parallels */
    for (i = 0; i < def->nparallels; ++i) {
3403
        if (virVMXFormatParallel(ctx, def->parallels[i], &buffer) < 0)
3404
            goto cleanup;
M
Matthias Bolte 已提交
3405 3406
    }

3407 3408 3409 3410
    /* vmx:firmware */
    if (def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_EFI)
        virBufferAddLit(&buffer, "firmware = \"efi\"\n");

3411 3412 3413
    if (virtualHW_version >= 7) {
        if (hasSCSI) {
            virBufferAddLit(&buffer, "pciBridge0.present = \"true\"\n");
3414

3415 3416 3417
            virBufferAddLit(&buffer, "pciBridge4.present = \"true\"\n");
            virBufferAddLit(&buffer, "pciBridge4.virtualDev = \"pcieRootPort\"\n");
            virBufferAddLit(&buffer, "pciBridge4.functions = \"8\"\n");
3418

3419 3420 3421
            virBufferAddLit(&buffer, "pciBridge5.present = \"true\"\n");
            virBufferAddLit(&buffer, "pciBridge5.virtualDev = \"pcieRootPort\"\n");
            virBufferAddLit(&buffer, "pciBridge5.functions = \"8\"\n");
3422

3423 3424 3425
            virBufferAddLit(&buffer, "pciBridge6.present = \"true\"\n");
            virBufferAddLit(&buffer, "pciBridge6.virtualDev = \"pcieRootPort\"\n");
            virBufferAddLit(&buffer, "pciBridge6.functions = \"8\"\n");
3426

3427 3428 3429 3430 3431 3432
            virBufferAddLit(&buffer, "pciBridge7.present = \"true\"\n");
            virBufferAddLit(&buffer, "pciBridge7.virtualDev = \"pcieRootPort\"\n");
            virBufferAddLit(&buffer, "pciBridge7.functions = \"8\"\n");
        }

        virBufferAddLit(&buffer, "vmci0.present = \"true\"\n");
3433 3434
    }

M
Matthias Bolte 已提交
3435
    /* Get final VMX output */
3436
    if (virBufferCheckError(&buffer) < 0)
3437
        goto cleanup;
M
Matthias Bolte 已提交
3438

3439
    vmx = virBufferContentAndReset(&buffer);
M
Matthias Bolte 已提交
3440

3441
 cleanup:
3442
    if (vmx == NULL)
3443 3444
        virBufferFreeAndReset(&buffer);

3445 3446
    VIR_FREE(preliminaryDisplayName);
    VIR_FREE(displayName);
3447
    VIR_FREE(annotation);
M
Matthias Bolte 已提交
3448

3449
    return vmx;
M
Matthias Bolte 已提交
3450 3451 3452 3453
}



M
Matthias Bolte 已提交
3454
int
3455
virVMXFormatVNC(virDomainGraphicsDefPtr def, virBufferPtr buffer)
M
Matthias Bolte 已提交
3456
{
3457
    virDomainGraphicsListenDefPtr glisten;
3458

M
Matthias Bolte 已提交
3459
    if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
3460
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3461 3462 3463
        return -1;
    }

3464
    virBufferAddLit(buffer, "RemoteDisplay.vnc.enabled = \"true\"\n");
M
Matthias Bolte 已提交
3465 3466

    if (def->data.vnc.autoport) {
3467
        VIR_WARN("VNC autoport is enabled, but the automatically assigned "
M
Matthias Bolte 已提交
3468 3469 3470 3471 3472 3473 3474
                  "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);
        }

3475
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.port = \"%d\"\n",
M
Matthias Bolte 已提交
3476 3477 3478
                          def->data.vnc.port);
    }

3479 3480
    if ((glisten = virDomainGraphicsGetListen(def, 0)) &&
        glisten->address) {
3481
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.ip = \"%s\"\n",
3482
                          glisten->address);
M
Matthias Bolte 已提交
3483 3484 3485
    }

    if (def->data.vnc.keymap != NULL) {
3486
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.keymap = \"%s\"\n",
M
Matthias Bolte 已提交
3487 3488 3489
                          def->data.vnc.keymap);
    }

3490
    if (def->data.vnc.auth.passwd != NULL) {
3491
        virBufferAsprintf(buffer, "RemoteDisplay.vnc.password = \"%s\"\n",
3492
                          def->data.vnc.auth.passwd);
M
Matthias Bolte 已提交
3493 3494 3495 3496 3497
    }

    return 0;
}

M
Matthias Bolte 已提交
3498
int
3499
virVMXFormatDisk(virVMXContext *ctx, virDomainDiskDefPtr def,
M
Matthias Bolte 已提交
3500
                 virBufferPtr buffer)
M
Matthias Bolte 已提交
3501
{
3502
    int controllerOrBus, unit;
3503
    const char *vmxDeviceType = NULL;
M
Matthias Bolte 已提交
3504
    char *fileName = NULL;
3505
    int type = virDomainDiskGetType(def);
M
Matthias Bolte 已提交
3506

3507 3508 3509
    /* Convert a handful of types to their string values */
    const char *busType = virDomainDiskBusTypeToString(def->bus);
    const char *deviceType = virDomainDeviceTypeToString(def->device);
3510
    const char *diskType = virDomainDeviceTypeToString(type);
3511 3512 3513 3514 3515

    /* 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 已提交
3516
                           ".vmdk" : ".iso";
3517 3518 3519

    /* Check that we got a valid device type */
    if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK &&
3520 3521
        def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
        def->device != VIR_DOMAIN_DISK_DEVICE_LUN) {
3522 3523
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Invalid device type supplied: %s"), deviceType);
M
Matthias Bolte 已提交
3524 3525 3526
        return -1;
    }

3527
    /* We only support type='file' and type='block' */
E
Eric Blake 已提交
3528 3529
    if (type != VIR_STORAGE_TYPE_FILE &&
        type != VIR_STORAGE_TYPE_BLOCK) {
3530 3531 3532 3533
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("%s %s '%s' has unsupported type '%s', expecting "
                         "'%s' or '%s'"), busType, deviceType, def->dst,
                       diskType,
E
Eric Blake 已提交
3534 3535
                       virStorageTypeToString(VIR_STORAGE_TYPE_FILE),
                       virStorageTypeToString(VIR_STORAGE_TYPE_BLOCK));
3536 3537
        return -1;
    }
M
Matthias Bolte 已提交
3538

3539
    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
3540 3541
        if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
                                                  &unit) < 0) {
M
Matthias Bolte 已提交
3542 3543 3544
            return -1;
        }
    } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
3545
        if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
3546
                                          &unit) < 0) {
M
Matthias Bolte 已提交
3547 3548 3549
            return -1;
        }
    } else {
3550
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3551 3552
                       _("Unsupported bus type '%s' for %s"),
                       busType, deviceType);
M
Matthias Bolte 已提交
3553 3554 3555
        return -1;
    }

3556
    if (def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
E
Eric Blake 已提交
3557
        type == VIR_STORAGE_TYPE_FILE) {
3558
        vmxDeviceType = (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) ?
M
Matthias Bolte 已提交
3559
                        "scsi-hardDisk" : "ata-hardDisk";
3560
    } else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
E
Eric Blake 已提交
3561
        if (type == VIR_STORAGE_TYPE_FILE)
3562 3563 3564
            vmxDeviceType = "cdrom-image";
        else
            vmxDeviceType = "atapi-cdrom";
3565
    } else if (def->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
3566 3567 3568 3569 3570 3571 3572
        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";
3573
    } else {
3574
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3575 3576
                       _("%s %s '%s' has an unsupported type '%s'"),
                       busType, deviceType, def->dst, diskType);
M
Matthias Bolte 已提交
3577 3578 3579
        return -1;
    }

3580
    virBufferAsprintf(buffer, "%s%d:%d.present = \"true\"\n",
3581 3582 3583
                      busType, controllerOrBus, unit);
    virBufferAsprintf(buffer, "%s%d:%d.deviceType = \"%s\"\n",
                      busType, controllerOrBus, unit, vmxDeviceType);
M
Matthias Bolte 已提交
3584

E
Eric Blake 已提交
3585
    if (type == VIR_STORAGE_TYPE_FILE) {
3586 3587
        const char *src = virDomainDiskGetSource(def);

3588
        if (src) {
3589
            if (!virStringHasCaseSuffix(src, fileExt)) {
3590 3591 3592 3593
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Image file for %s %s '%s' has "
                                 "unsupported suffix, expecting '%s'"),
                               busType, deviceType, def->dst, fileExt);
3594
                return -1;
3595
            }
M
Matthias Bolte 已提交
3596

3597 3598 3599 3600
            fileName = ctx->formatFileName(src, ctx->opaque);
        } else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
            ignore_value(VIR_STRDUP(fileName, "emptyBackingString"));
        }
M
Matthias Bolte 已提交
3601

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

3605
        virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3606
                          busType, controllerOrBus, unit, fileName);
M
Matthias Bolte 已提交
3607 3608

        VIR_FREE(fileName);
E
Eric Blake 已提交
3609
    } else if (type == VIR_STORAGE_TYPE_BLOCK) {
3610 3611 3612
        const char *src = virDomainDiskGetSource(def);

        if (!src &&
3613 3614 3615 3616 3617 3618
            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 {
3619
            virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3620
                              busType, controllerOrBus, unit, src);
3621
        }
M
Matthias Bolte 已提交
3622 3623 3624 3625
    }

    if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
        if (def->cachemode == VIR_DOMAIN_DISK_CACHE_WRITETHRU) {
3626
            virBufferAsprintf(buffer, "%s%d:%d.writeThrough = \"true\"\n",
3627
                              busType, controllerOrBus, unit);
M
Matthias Bolte 已提交
3628
        } else if (def->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) {
3629 3630
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("%s harddisk '%s' has unsupported cache mode '%s'"),
3631
                           busType, def->dst,
3632
                           virDomainDiskCacheTypeToString(def->cachemode));
M
Matthias Bolte 已提交
3633
            return -1;
M
Matthias Bolte 已提交
3634 3635 3636
        }
    }

3637 3638 3639 3640
    if (def->transient)
        virBufferAsprintf(buffer,
                          "%s%d:%d.mode = \"independent-nonpersistent\"\n",
                          busType, controllerOrBus, unit);
M
Matthias Bolte 已提交
3641

M
Matthias Bolte 已提交
3642 3643 3644 3645
    return 0;
}

int
3646 3647
virVMXFormatFloppy(virVMXContext *ctx, virDomainDiskDefPtr def,
                   virBufferPtr buffer, bool floppy_present[2])
M
Matthias Bolte 已提交
3648
{
3649
    int unit;
M
Matthias Bolte 已提交
3650
    char *fileName = NULL;
3651 3652
    int type = virDomainDiskGetType(def);
    const char *src = virDomainDiskGetSource(def);
M
Matthias Bolte 已提交
3653 3654

    if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
3655
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
M
Matthias Bolte 已提交
3656 3657 3658
        return -1;
    }

3659
    if (virVMXFloppyDiskNameToUnit(def->dst, &unit) < 0)
M
Matthias Bolte 已提交
3660 3661
        return -1;

3662 3663
    floppy_present[unit] = true;

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

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

3669 3670
        if (src) {
            fileName = ctx->formatFileName(src, ctx->opaque);
M
Matthias Bolte 已提交
3671

3672
            if (fileName == NULL)
M
Matthias Bolte 已提交
3673 3674
                return -1;

3675
            virBufferAsprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3676
                              unit, fileName);
M
Matthias Bolte 已提交
3677 3678 3679

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

3683
        if (src) {
3684
            virBufferAsprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3685
                              unit, src);
M
Matthias Bolte 已提交
3686
        }
M
Matthias Bolte 已提交
3687
    } else {
3688 3689 3690
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Floppy '%s' has unsupported type '%s', expecting '%s' "
                         "or '%s'"), def->dst,
E
Eric Blake 已提交
3691 3692 3693
                       virStorageTypeToString(type),
                       virStorageTypeToString(VIR_STORAGE_TYPE_FILE),
                       virStorageTypeToString(VIR_STORAGE_TYPE_BLOCK));
M
Matthias Bolte 已提交
3694 3695 3696 3697 3698 3699 3700 3701
        return -1;
    }

    return 0;
}



3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717
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,
3718
                      def->src->path);
3719 3720 3721 3722 3723 3724 3725 3726
    virBufferAsprintf(buffer, "sharedFolder%d.guestName = \"%s\"\n", number,
                      def->dst);

    return 0;
}



M
Matthias Bolte 已提交
3727
int
3728 3729
virVMXFormatEthernet(virDomainNetDefPtr def, int controller,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3730 3731
{
    char mac_string[VIR_MAC_STRING_BUFLEN];
3732
    unsigned int prefix, suffix;
M
Matthias Bolte 已提交
3733 3734

    if (controller < 0 || controller > 3) {
3735 3736 3737
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Ethernet controller index %d out of [0..3] range"),
                       controller);
M
Matthias Bolte 已提交
3738 3739 3740
        return -1;
    }

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

3743
    /* def:model -> vmx:virtualDev, vmx:features */
C
Cole Robinson 已提交
3744 3745 3746 3747 3748 3749 3750
    if (def->model) {
        if (def->model != VIR_DOMAIN_NET_MODEL_VLANCE &&
            def->model != VIR_DOMAIN_NET_MODEL_VMXNET &&
            def->model != VIR_DOMAIN_NET_MODEL_VMXNET2 &&
            def->model != VIR_DOMAIN_NET_MODEL_VMXNET3 &&
            def->model != VIR_DOMAIN_NET_MODEL_E1000 &&
            def->model != VIR_DOMAIN_NET_MODEL_E1000E) {
3751 3752 3753
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Expecting domain XML entry 'devices/interface/model' "
                             "to be 'vlance' or 'vmxnet' or 'vmxnet2' or 'vmxnet3' "
3754
                             "or 'e1000' or 'e1000e' but found '%s'"),
C
Cole Robinson 已提交
3755
                            virDomainNetModelTypeToString(def->model));
M
Matthias Bolte 已提交
3756 3757 3758
            return -1;
        }

C
Cole Robinson 已提交
3759
        if (def->model == VIR_DOMAIN_NET_MODEL_VMXNET2) {
3760
            virBufferAsprintf(buffer, "ethernet%d.virtualDev = \"vmxnet\"\n",
3761
                              controller);
3762
            virBufferAsprintf(buffer, "ethernet%d.features = \"15\"\n",
3763 3764
                              controller);
        } else {
3765
            virBufferAsprintf(buffer, "ethernet%d.virtualDev = \"%s\"\n",
C
Cole Robinson 已提交
3766 3767
                              controller,
                              virDomainNetModelTypeToString(def->model));
3768
        }
M
Matthias Bolte 已提交
3769 3770 3771 3772 3773
    }

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

        if (def->ifname != NULL) {
3779
            virBufferAsprintf(buffer, "ethernet%d.connectionType = \"custom\"\n",
M
Matthias Bolte 已提交
3780
                              controller);
3781
            virBufferAsprintf(buffer, "ethernet%d.vnet = \"%s\"\n",
M
Matthias Bolte 已提交
3782 3783
                              controller, def->ifname);
        } else {
3784
            virBufferAsprintf(buffer, "ethernet%d.connectionType = \"bridged\"\n",
M
Matthias Bolte 已提交
3785 3786 3787 3788 3789
                              controller);
        }

        break;

3790 3791 3792 3793 3794
      case VIR_DOMAIN_NET_TYPE_USER:
        virBufferAsprintf(buffer, "ethernet%d.connectionType = \"nat\"\n",
                          controller);
        break;

3795 3796 3797 3798 3799 3800 3801 3802 3803 3804
      case VIR_DOMAIN_NET_TYPE_ETHERNET:
      case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
      case VIR_DOMAIN_NET_TYPE_SERVER:
      case VIR_DOMAIN_NET_TYPE_CLIENT:
      case VIR_DOMAIN_NET_TYPE_MCAST:
      case VIR_DOMAIN_NET_TYPE_NETWORK:
      case VIR_DOMAIN_NET_TYPE_INTERNAL:
      case VIR_DOMAIN_NET_TYPE_DIRECT:
      case VIR_DOMAIN_NET_TYPE_HOSTDEV:
      case VIR_DOMAIN_NET_TYPE_UDP:
3805 3806
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type '%s'"),
                       virDomainNetTypeToString(def->type));
M
Matthias Bolte 已提交
3807
        return -1;
3808 3809 3810 3811 3812

      case VIR_DOMAIN_NET_TYPE_LAST:
      default:
          virReportEnumRangeError(virDomainNetType, def->type);
          return -1;
M
Matthias Bolte 已提交
3813 3814
    }

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

3818 3819
    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];
3820 3821

    if (prefix == 0x000c29) {
3822
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"generated\"\n",
M
Matthias Bolte 已提交
3823
                          controller);
3824
        virBufferAsprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
M
Matthias Bolte 已提交
3825
                          controller, mac_string);
3826
        virBufferAsprintf(buffer, "ethernet%d.generatedAddressOffset = \"0\"\n",
M
Matthias Bolte 已提交
3827
                          controller);
3828
    } else if (prefix == 0x005056 && suffix <= 0x3fffff) {
3829
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"static\"\n",
3830
                          controller);
3831
        virBufferAsprintf(buffer, "ethernet%d.address = \"%s\"\n",
3832 3833
                          controller, mac_string);
    } else if (prefix == 0x005056 && suffix >= 0x800000 && suffix <= 0xbfffff) {
3834
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"vpx\"\n",
3835
                          controller);
3836
        virBufferAsprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
3837
                          controller, mac_string);
M
Matthias Bolte 已提交
3838
    } else {
3839
        virBufferAsprintf(buffer, "ethernet%d.addressType = \"static\"\n",
3840
                          controller);
3841
        virBufferAsprintf(buffer, "ethernet%d.address = \"%s\"\n",
3842
                          controller, mac_string);
3843
        virBufferAsprintf(buffer, "ethernet%d.checkMACAddress = \"false\"\n",
3844
                          controller);
M
Matthias Bolte 已提交
3845 3846 3847 3848 3849 3850 3851 3852
    }

    return 0;
}



int
3853 3854
virVMXFormatSerial(virVMXContext *ctx, virDomainChrDefPtr def,
                   virBufferPtr buffer)
M
Matthias Bolte 已提交
3855
{
M
Matthias Bolte 已提交
3856
    char *fileName = NULL;
3857
    const char *protocol;
M
Matthias Bolte 已提交
3858

3859
    if (def->target.port < 0 || def->target.port > 3) {
3860 3861 3862
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Serial port index %d out of [0..3] range"),
                       def->target.port);
M
Matthias Bolte 已提交
3863 3864 3865
        return -1;
    }

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

M
Matthias Bolte 已提交
3868
    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
3869
    switch (def->source->type) {
M
Matthias Bolte 已提交
3870
      case VIR_DOMAIN_CHR_TYPE_DEV:
3871
        virBufferAsprintf(buffer, "serial%d.fileType = \"device\"\n",
3872
                          def->target.port);
3873
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3874
                          def->target.port, def->source->data.file.path);
M
Matthias Bolte 已提交
3875 3876 3877
        break;

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

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

3883
        if (fileName == NULL)
M
Matthias Bolte 已提交
3884 3885
            return -1;

3886
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3887
                          def->target.port, fileName);
M
Matthias Bolte 已提交
3888 3889

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3890 3891 3892
        break;

      case VIR_DOMAIN_CHR_TYPE_PIPE:
3893
        virBufferAsprintf(buffer, "serial%d.fileType = \"pipe\"\n",
3894
                          def->target.port);
M
Matthias Bolte 已提交
3895
        /* FIXME: Based on VI Client GUI default */
3896
        virBufferAsprintf(buffer, "serial%d.pipe.endPoint = \"client\"\n",
3897
                          def->target.port);
M
Matthias Bolte 已提交
3898
        /* FIXME: Based on VI Client GUI default */
3899
        virBufferAsprintf(buffer, "serial%d.tryNoRxLoss = \"false\"\n",
3900
                          def->target.port);
3901
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
3902
                          def->target.port, def->source->data.file.path);
M
Matthias Bolte 已提交
3903 3904
        break;

3905
      case VIR_DOMAIN_CHR_TYPE_TCP:
3906
        switch (def->source->data.tcp.protocol) {
3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923
          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:
3924 3925 3926
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported character device TCP protocol '%s'"),
                           virDomainChrTcpProtocolTypeToString(
3927
                               def->source->data.tcp.protocol));
3928 3929 3930
            return -1;
        }

3931
        virBufferAsprintf(buffer, "serial%d.fileType = \"network\"\n",
3932
                          def->target.port);
3933
        virBufferAsprintf(buffer, "serial%d.fileName = \"%s://%s:%s\"\n",
3934 3935
                          def->target.port, protocol, def->source->data.tcp.host,
                          def->source->data.tcp.service);
3936
        virBufferAsprintf(buffer, "serial%d.network.endPoint = \"%s\"\n",
3937
                          def->target.port,
3938
                          def->source->data.tcp.listen ? "server" : "client");
3939 3940
        break;

M
Matthias Bolte 已提交
3941
      default:
3942 3943
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported character device type '%s'"),
3944
                       virDomainChrTypeToString(def->source->type));
M
Matthias Bolte 已提交
3945 3946 3947 3948 3949
        return -1;
    }

    /* vmx:yieldOnMsrRead */
    /* FIXME: Based on VI Client GUI default */
3950
    virBufferAsprintf(buffer, "serial%d.yieldOnMsrRead = \"true\"\n",
3951
                      def->target.port);
M
Matthias Bolte 已提交
3952 3953 3954 3955 3956 3957 3958

    return 0;
}



int
3959 3960
virVMXFormatParallel(virVMXContext *ctx, virDomainChrDefPtr def,
                     virBufferPtr buffer)
M
Matthias Bolte 已提交
3961
{
M
Matthias Bolte 已提交
3962 3963
    char *fileName = NULL;

3964
    if (def->target.port < 0 || def->target.port > 2) {
3965 3966 3967
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Parallel port index %d out of [0..2] range"),
                       def->target.port);
M
Matthias Bolte 已提交
3968 3969 3970
        return -1;
    }

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

M
Matthias Bolte 已提交
3974
    /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
3975
    switch (def->source->type) {
M
Matthias Bolte 已提交
3976
      case VIR_DOMAIN_CHR_TYPE_DEV:
3977
        virBufferAsprintf(buffer, "parallel%d.fileType = \"device\"\n",
3978
                          def->target.port);
3979
        virBufferAsprintf(buffer, "parallel%d.fileName = \"%s\"\n",
3980
                          def->target.port, def->source->data.file.path);
M
Matthias Bolte 已提交
3981 3982 3983
        break;

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

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

3989
        if (fileName == NULL)
M
Matthias Bolte 已提交
3990 3991
            return -1;

3992
        virBufferAsprintf(buffer, "parallel%d.fileName = \"%s\"\n",
3993
                          def->target.port, fileName);
M
Matthias Bolte 已提交
3994 3995

        VIR_FREE(fileName);
M
Matthias Bolte 已提交
3996 3997 3998
        break;

      default:
3999 4000
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported character device type '%s'"),
4001
                       virDomainChrTypeToString(def->source->type));
M
Matthias Bolte 已提交
4002 4003 4004 4005 4006
        return -1;
    }

    return 0;
}
4007 4008 4009 4010 4011 4012



int
virVMXFormatSVGA(virDomainVideoDefPtr def, virBufferPtr buffer)
{
4013 4014
    unsigned long long vram;

4015
    if (def->type != VIR_DOMAIN_VIDEO_TYPE_VMVGA) {
4016 4017 4018
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unsupported video device type '%s'"),
                       virDomainVideoTypeToString(def->type));
4019 4020 4021 4022 4023 4024 4025
        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
     */
4026
    vram = VIR_DIV_UP(def->vram, 64) * 64;
4027 4028

    if (def->heads > 1) {
4029 4030
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Multi-head video devices are unsupported"));
4031 4032 4033
        return -1;
    }

4034
    virBufferAsprintf(buffer, "svga.vramSize = \"%lld\"\n",
4035
                      vram * 1024); /* kilobyte to byte */
4036 4037 4038

    return 0;
}