1 /*
2  * vmx.c: VMware VMX parsing/formatting functions
3  *
4  * Copyright (C) 2010-2014 Red Hat, Inc.
5  * Copyright (C) 2009-2011, 2014-2015 Matthias Bolte <matthias.bolte@googlemail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library.  If not, see
19  * <http://www.gnu.org/licenses/>.
20  *
21  */
22 
23 #include <config.h>
24 
25 #include "internal.h"
26 #include "virerror.h"
27 #include "virfile.h"
28 #include "virconf.h"
29 #include "viralloc.h"
30 #include "virlog.h"
31 #include "vmx.h"
32 #include "viruri.h"
33 #include "virstring.h"
34 #include "virutil.h"
35 
36 VIR_LOG_INIT("vmx.vmx");
37 
38 /*
39 
40  mapping:
41 
42 domain-xml                        <=>   vmx
43 
44 
45                                         config.version = "8"                    # essential
46                                         virtualHW.version = "4"                 # essential for ESX 3.5
47                                         virtualHW.version = "7"                 # essential for ESX 4.0
48                                         virtualHW.version = "8"                 # essential for ESX 5.0
49                                         virtualHW.version = "9"                 # essential for ESX 5.1
50                                         virtualHW.version = "10"                # essential for ESX 5.5
51                                         virtualHW.version = "11"                # essential for ESX 6.0
52                                         virtualHW.version = "13"                # essential for ESX 6.5
53                                         virtualHW.version = "14"                # essential for ESX 6.7
54                                         virtualHW.version = "17"                # essential for ESX 7.0
55 
56 
57 ???                               <=>   guestOS = "<value>"                     # essential, FIXME: not representable
58 def->id = <value>                 <=>   ???                                     # not representable
59 def->uuid = <value>               <=>   uuid.bios = "<value>"
60 def->name = <value>               <=>   displayName = "<value>"
61 def->mem.max_balloon = <value kilobyte>    <=>   memsize = "<value megabyte>"            # must be a multiple of 4, defaults to 32
62 def->mem.cur_balloon = <value kilobyte>    <=>   sched.mem.max = "<value megabyte>"      # defaults to "unlimited" -> def->mem.cur_balloon = def->mem.max_balloon
63 def->mem.min_guarantee = <value kilobyte>  <=>   sched.mem.minsize = "<value megabyte>"  # defaults to 0
64 def->maxvcpus = <value>           <=>   numvcpus = "<value>"                    # must be greater than 0, defaults to 1
65 def->cpumask = <uint list>        <=>   sched.cpu.affinity = "<uint list>"
66 def->cputune.shares = <value>     <=>   sched.cpu.shares = "<value>"            # with handling for special values
67                                                                                 # "high", "normal", "low"
68 
69 
70 
71 ################################################################################
72 ## os ##########################################################################
73 
74 def->os
75 
76 ->type = "hvm"
77 ->arch = <arch>                   <=>   guestOS = "<value>"                     # if <value> ends with -64 than <arch> is x86_64, otherwise <arch> is i686
78 ->machine
79 ->nBootDevs
80 ->bootDevs
81 ->init
82 ->kernel
83 ->initrd
84 ->cmdline
85 ->root
86 ->loader
87 ->bootloader
88 ->bootloaderArgs
89 ->smbios_mode                     <=>   smbios.reflecthost = "<value>"          # <value> == true means SMBIOS_HOST, otherwise it's SMBIOS_EMULATE, defaults to "false"
90 
91 
92 
93 ################################################################################
94 ## disks #######################################################################
95 
96                                         scsi[0..3]:[0..6,8..15] -> <controller>:<unit> with 1 bus per controller
97                                         sata[0..3]:[0..29] -> <controller>:<unit> with 1 bus per controller
98                                         ide[0..1]:[0..1]        -> <bus>:<unit> with 1 controller
99                                         floppy[0..1]            -> <unit> with 1 controller and 1 bus per controller
100 
101 def->disks[0]...
102 
103 ## disks: scsi hard drive from .vmdk image #####################################
104 
105                                         scsi0.present = "true"                  # defaults to "false"
106                                         scsi0:0.present = "true"                # defaults to "false"
107                                         scsi0:0.startConnected = "true"         # defaults to "true"
108 
109 ???                               <=>   scsi0:0.mode = "persistent"             # defaults to "persistent"
110                                         scsi0:0.mode = "undoable"
111                                         scsi0:0.mode = "independent-persistent"
112                                         scsi0:0.mode = "independent-nonpersistent"
113 
114 ...
115 ->type = _DISK_TYPE_FILE          <=>   scsi0:0.deviceType = "scsi-hardDisk"    # defaults to ?
116 ->device = _DISK_DEVICE_DISK      <=>   scsi0:0.deviceType = "scsi-hardDisk"    # defaults to ?
117 ->bus = _DISK_BUS_SCSI
118 ->src = <value>.vmdk              <=>   scsi0:0.fileName = "<value>.vmdk"
119 ->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
120 ->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
121 ->driverType
122 ->cachemode                       <=>   scsi0:0.writeThrough = "<value>"        # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT
123 ->readonly
124 ->shared
125 ->slotnum
126 
127 
128 ## disks: sata hard drive from .vmdk image #####################################
129 
130                                         sata0.present = "true"                  # defaults to "false"
131                                         sata0:0.present = "true"                # defaults to "false"
132                                         sata0:0.startConnected = "true"         # defaults to "true"
133 
134 ...
135 ->type = _DISK_TYPE_FILE          <=>   sata0:0.deviceType = "???"              # defaults to ?
136 ->device = _DISK_DEVICE_DISK      <=>   sata0:0.deviceType = "???"              # defaults to ?
137 ->bus = _DISK_BUS_SATA
138 ->src = <value>.vmdk              <=>   sata0:0.fileName = "<value>.vmdk"
139 ->dst = sd[<controller> * 30 + <unit> mapped to [a-z]+]
140 ->driverName = <driver>           <=>   sata0.virtualDev = "<driver>"           # default depends on guestOS value
141 ->driverType
142 ->cachemode                       <=>   sata0:0.writeThrough = "<value>"        # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT
143 ->readonly
144 ->shared
145 ->slotnum
146 
147 
148 ## disks: ide hard drive from .vmdk image ######################################
149 
150                                         ide0:0.present = "true"                 # defaults to "false"
151                                         ide0:0.startConnected = "true"          # defaults to "true"
152 
153 ???                               <=>   ide0:0.mode = "persistent"              # defaults to "persistent"
154                                         ide0:0.mode = "undoable"
155                                         ide0:0.mode = "independent-persistent"
156                                         ide0:0.mode = "independent-nonpersistent"
157 
158 ...
159 ->type = _DISK_TYPE_FILE          <=>   ide0:0.deviceType = "ata-hardDisk"      # defaults to ?
160 ->device = _DISK_DEVICE_DISK      <=>   ide0:0.deviceType = "ata-hardDisk"      # defaults to ?
161 ->bus = _DISK_BUS_IDE
162 ->src = <value>.vmdk              <=>   ide0:0.fileName = "<value>.vmdk"
163 ->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
164 ->driverName
165 ->driverType
166 ->cachemode                       <=>   ide0:0.writeThrough = "<value>"         # defaults to false, true -> _DISK_CACHE_WRITETHRU, false _DISK_CACHE_DEFAULT
167 ->readonly
168 ->shared
169 ->slotnum
170 
171 
172 ## disks: scsi cdrom from .iso image ###########################################
173 
174                                         scsi0.present = "true"                  # defaults to "false"
175                                         scsi0:0.present = "true"                # defaults to "false"
176                                         scsi0:0.startConnected = "true"         # defaults to "true"
177 
178 ...
179 ->type = _DISK_TYPE_FILE          <=>   scsi0:0.deviceType = "cdrom-image"      # defaults to ?
180 ->device = _DISK_DEVICE_CDROM     <=>   scsi0:0.deviceType = "cdrom-image"      # defaults to ?
181 ->bus = _DISK_BUS_SCSI
182 ->src = <value>.iso               <=>   scsi0:0.fileName = "<value>.iso"
183 ->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
184 ->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
185 ->driverType
186 ->cachemode
187 ->readonly
188 ->shared
189 ->slotnum
190 
191 
192 ## disks: sata cdrom from .iso image ###########################################
193 
194                                         sata0.present = "true"                  # defaults to "false"
195                                         sata0:0.present = "true"                # defaults to "false"
196                                         sata0:0.startConnected = "true"         # defaults to "true"
197 
198 ...
199 ->type = _DISK_TYPE_FILE          <=>   sata0:0.deviceType = "cdrom-image"      # defaults to ?
200 ->device = _DISK_DEVICE_CDROM     <=>   sata0:0.deviceType = "cdrom-image"      # defaults to ?
201 ->bus = _DISK_BUS_SATA
202 ->src = <value>.iso               <=>   sata0:0.fileName = "<value>.iso"
203 ->dst = sd[<controller> * 30 + <unit> mapped to [a-z]+]
204 ->driverName = <driver>           <=>   sata0.virtualDev = "<driver>"           # default depends on guestOS value
205 ->driverType
206 ->cachemode
207 ->readonly
208 ->shared
209 ->slotnum
210 
211 
212 ## disks: ide cdrom from .iso image ############################################
213 
214                                         ide0:0.present = "true"                 # defaults to "false"
215                                         ide0:0.startConnected = "true"          # defaults to "true"
216 
217 ...
218 ->type = _DISK_TYPE_FILE          <=>   ide0:0.deviceType = "cdrom-image"       # defaults to ?
219 ->device = _DISK_DEVICE_CDROM     <=>   ide0:0.deviceType = "cdrom-image"       # defaults to ?
220 ->bus = _DISK_BUS_IDE
221 ->src = <value>.iso               <=>   ide0:0.fileName = "<value>.iso"
222 ->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
223 ->driverName
224 ->driverType
225 ->cachemode
226 ->readonly
227 ->shared
228 ->slotnum
229 
230 
231 ## disks: scsi cdrom from host device ##########################################
232 
233                                         scsi0.present = "true"                  # defaults to "false"
234                                         scsi0:0.present = "true"                # defaults to "false"
235                                         scsi0:0.startConnected = "true"         # defaults to "true"
236 
237 ...
238 ->type = _DISK_TYPE_BLOCK         <=>   scsi0:0.deviceType = "atapi-cdrom"      # defaults to ?
239 ->device = _DISK_DEVICE_CDROM     <=>   scsi0:0.deviceType = "atapi-cdrom"      # defaults to ?
240 ->bus = _DISK_BUS_SCSI
241 ->src = <value>                   <=>   scsi0:0.fileName = "<value>"            # e.g. "/dev/scd0" ?
242 ->dst = sd[<controller> * 15 + <unit> mapped to [a-z]+]
243 ->driverName = <driver>           <=>   scsi0.virtualDev = "<driver>"           # default depends on guestOS value
244 ->driverType
245 ->cachemode
246 ->readonly
247 ->shared
248 ->slotnum
249 
250 
251 ## disks: ide cdrom from host device ###########################################
252 
253                                         ide0:0.present = "true"                 # defaults to "false"
254                                         ide0:0.startConnected = "true"          # defaults to "true"
255                                         ide0:0.clientDevice = "false"           # defaults to "false"
256 
257 ...
258 ->type = _DISK_TYPE_BLOCK         <=>   ide0:0.deviceType = "atapi-cdrom"       # defaults to ?
259 ->device = _DISK_DEVICE_CDROM     <=>   ide0:0.deviceType = "atapi-cdrom"       # defaults to ?
260 ->bus = _DISK_BUS_IDE
261 ->src = <value>                   <=>   ide0:0.fileName = "<value>"             # e.g. "/dev/scd0"
262 ->dst = hd[<bus> * 2 + <unit> mapped to [a-z]+]
263 ->driverName
264 ->driverType
265 ->cachemode
266 ->readonly
267 ->shared
268 ->slotnum
269 
270 
271 ## disks: floppy from .flp image ###############################################
272 
273                                         floppy0.present = "true"                # defaults to "true"
274                                         floppy0.startConnected = "true"         # defaults to "true"
275                                         floppy0.clientDevice = "false"          # defaults to "false"
276 
277 ...
278 ->type = _DISK_TYPE_FILE          <=>   floppy0.fileType = "file"               # defaults to ?
279 ->device = _DISK_DEVICE_FLOPPY
280 ->bus = _DISK_BUS_FDC
281 ->src = <value>.flp               <=>   floppy0.fileName = "<value>.flp"
282 ->dst = fd[<unit> mapped to [a-z]+]
283 ->driverName
284 ->driverType
285 ->cachemode
286 ->readonly
287 ->shared
288 ->slotnum
289 
290 
291 ## disks: floppy from host device ##############################################
292 
293                                         floppy0.present = "true"                # defaults to "true"
294                                         floppy0.startConnected = "true"         # defaults to "true"
295                                         floppy0.clientDevice = "false"          # defaults to "false"
296 
297 ...
298 ->type = _DISK_TYPE_BLOCK         <=>   floppy0.fileType = "device"             # defaults to ?
299 ->device = _DISK_DEVICE_FLOPPY
300 ->bus = _DISK_BUS_FDC
301 ->src = <value>                   <=>   floppy0.fileName = "<value>"            # e.g. "/dev/fd0"
302 ->dst = fd[<unit> mapped to [a-z]+]
303 ->driverName
304 ->driverType
305 ->cachemode
306 ->readonly
307 ->shared
308 ->slotnum
309 
310 
311 
312 ################################################################################
313 ## filesystems #################################################################
314 
315                                         isolation.tools.hgfs.disable = "false"  # defaults to "true"
316 
317 def->nfss = 1                     <=>   sharedFolder.maxNum = "1"               # must match the number of shared folders
318 
319                                         sharedFolder[0..n] -> <filesystem>
320 
321 def->fss[0]...                    <=>   sharedFolder0.present = "true"          # defaults to "false"
322                                         sharedFolder0.enabled = "true"          # defaults to "false"
323                                         sharedFolder0.expiration = "never"      # defaults to "never"
324                                         sharedFolder0.readAccess = "true"       # defaults to "false"
325 ->type = _FS_TYPE_MOUNT
326 ->fsdriver
327 ->accessmode
328 ->wrpolicy
329 ->src = <value>                   <=>   sharedFolder0.hostPath = "<value>"      # defaults to ?
330 ->dst = <value>                   <=>   sharedFolder0.guestName = "<value>"
331 ->readonly = <readonly>           <=>   sharedFolder0.writeAccess = "<value>"   # "true" -> <readonly> = 0, "false" -> <readonly> = 1
332 
333 
334 
335 ################################################################################
336 ## nets ########################################################################
337 
338                                         ethernet[0..9] -> <controller>
339 
340                                         ethernet0.present = "true"              # defaults to "false"
341                                         ethernet0.startConnected = "true"       # defaults to "true"
342 
343                                         ethernet0.networkName = "VM Network"    # FIXME
344 
345 def->nets[0]...
346 ->model = <model>                 <=>   ethernet0.virtualDev = "<model>"        # default depends on guestOS value
347                                         ethernet0.features = "15"               # if present and virtualDev is "vmxnet" => vmxnet2 (enhanced)
348 
349 
350                                         ethernet0.addressType = "generated"     # default to "generated"
351 ->mac = <value>                   <=>   ethernet0.generatedAddress = "<value>"
352                                         ethernet0.generatedAddressOffset = "0"  # ?
353 
354 
355                                         ethernet0.addressType = "static"        # default to "generated"
356 ->mac = <value>                   <=>   ethernet0.address = "<value>"
357 
358 
359                                         ethernet0.addressType = "vpx"           # default to "generated"
360 ->mac = <value>                   <=>   ethernet0.generatedAddress = "<value>"
361 
362 
363                                         ethernet0.addressType = "static"        # default to "generated"
364 ->mac = <value>                   <=>   ethernet0.address = "<value>"
365                                         ethernet0.checkMACAddress = "false"     # mac address outside the VMware prefixes
366 
367                                                                                 # 00:0c:29 prefix for autogenerated mac's -> ethernet0.addressType = "generated"
368                                                                                 # 00:50:56 prefix for manual configured mac's
369                                                                                 #          00:50:56:00:00:00 - 00:50:56:3f:ff:ff -> ethernet0.addressType = "static"
370                                                                                 #          00:50:56:80:00:00 - 00:50:56:bf:ff:ff -> ethernet0.addressType = "vpx"
371                                                                                 # 00:05:69 old prefix from esx 1.5
372 
373 
374 ## nets: bridged ###############################################################
375 
376 ...
377 ->type = _NET_TYPE_BRIDGE         <=>   ethernet0.connectionType = "bridged"    # defaults to "bridged"
378 ->data.bridge.brname = <value>    <=>   ethernet0.networkName = "<value>"
379 
380 
381 ## nets: hostonly ##############################################################
382 
383 ...                                                                             # FIXME: Investigate if ESX supports this
384 ->type = _NET_TYPE_NETWORK        <=>   ethernet0.connectionType = "hostonly"   # defaults to "bridged"
385 
386 
387 ## nets: nat ###################################################################
388 
389 ...                                                                             # FIXME: Investigate if ESX supports this
390 ->type = _NET_TYPE_USER           <=>   ethernet0.connectionType = "nat"        # defaults to "bridged"
391 
392 
393 ## nets: custom ################################################################
394 
395 ...
396 ->type = _NET_TYPE_BRIDGE         <=>   ethernet0.connectionType = "custom"     # defaults to "bridged"
397 ->data.bridge.brname = <value>    <=>   ethernet0.networkName = "<value>"
398 ->ifname = <value>                <=>   ethernet0.vnet = "<value>"
399 
400 
401 
402 ################################################################################
403 ## video #######################################################################
404 
405 def->videos[0]...
406 ->type = _VIDEO_TYPE_VMVGA
407 ->vram = <value kilobyte>         <=>   svga.vramSize = "<value byte>"
408 ->heads = 1
409 
410 
411 
412 ################################################################################
413 ## serials #####################################################################
414 
415                                         serial[0..3] -> <port>
416 
417                                         serial0.present = "true"                # defaults to "false"
418                                         serial0.startConnected = "true"         # defaults to "true"
419 
420 def->serials[0]...
421 ->target.port = <port>
422 
423 
424 ## serials: device #############################################################
425 
426 ->type = _CHR_TYPE_DEV            <=>   serial0.fileType = "device"
427 ->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "/dev/ttyS0"
428 ???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
429 ???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
430 
431 
432 ## serials: file ###############################################################
433 
434 ->type = _CHR_TYPE_FILE           <=>   serial0.fileType = "file"
435 ->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.file"
436 ???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
437 ???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
438 
439 
440 ## serials: pipe, far end -> app ###############################################
441 
442 ->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
443 ->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
444 ???                               <=>   serial0.pipe.endPoint = "client"        # defaults to ?, FIXME: not representable
445 ???                               <=>   serial0.tryNoRxLoss = "true"            # defaults to "false", FIXME: not representable
446 ???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
447 
448 ->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
449 ->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
450 ???                               <=>   serial0.pipe.endPoint = "server"        # defaults to ?, FIXME: not representable
451 ???                               <=>   serial0.tryNoRxLoss = "true"            # defaults to "false", FIXME: not representable
452 ???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
453 
454 
455 ## serials: pipe, far end -> vm ################################################
456 
457 ->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
458 ->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
459 ???                               <=>   serial0.pipe.endPoint = "client"        # defaults to ?, FIXME: not representable
460 ???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
461 ???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
462 
463 ->type = _CHR_TYPE_PIPE           <=>   serial0.fileType = "pipe"
464 ->data.file.path = <value>        <=>   serial0.fileName = "<value>"            # e.g. "serial0.pipe"
465 ???                               <=>   serial0.pipe.endPoint = "server"        # defaults to ?, FIXME: not representable
466 ???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
467 ???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
468 
469 
470 ## serials: network, server (since vSphere 4.1) ################################
471 
472 ->type = _CHR_TYPE_TCP            <=>   serial0.fileType = "network"
473 
474 ->data.tcp.host = <host>          <=>   serial0.fileName = "<protocol>://<host>:<service>"
475 ->data.tcp.service = <service>                                                  # e.g. "telnet://0.0.0.0:42001"
476 ->data.tcp.protocol = <protocol>
477 
478 ->data.tcp.listen = true          <=>   serial0.network.endPoint = "server"     # defaults to "server"
479 
480 ???                               <=>   serial0.vspc = "foobar"                 # defaults to <not present>, FIXME: not representable
481 ???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
482 ???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
483 
484 
485 ## serials: network, client (since vSphere 4.1) ################################
486 
487 ->type = _CHR_TYPE_TCP            <=>   serial0.fileType = "network"
488 
489 ->data.tcp.host = <host>          <=>   serial0.fileName = "<protocol>://<host>:<service>"
490 ->data.tcp.service = <service>                                                  # e.g. "telnet://192.168.0.17:42001"
491 ->data.tcp.protocol = <protocol>
492 
493 ->data.tcp.listen = false         <=>   serial0.network.endPoint = "client"     # defaults to "server"
494 
495 ???                               <=>   serial0.vspc = "foobar"                 # defaults to <not present>, FIXME: not representable
496 ???                               <=>   serial0.tryNoRxLoss = "false"           # defaults to "false", FIXME: not representable
497 ???                               <=>   serial0.yieldOnMsrRead = "true"         # defaults to "false", FIXME: not representable
498 
499 
500 
501 ################################################################################
502 ## parallels ###################################################################
503 
504                                         parallel[0..2] -> <port>
505 
506                                         parallel0.present = "true"              # defaults to "false"
507                                         parallel0.startConnected = "true"       # defaults to "true"
508 
509 def->parallels[0]...
510 ->target.port = <port>
511 
512 
513 ## parallels: device #############################################################
514 
515 ->type = _CHR_TYPE_DEV            <=>   parallel0.fileType = "device"
516 ->data.file.path = <value>        <=>   parallel0.fileName = "<value>"          # e.g. "/dev/parport0"
517 ???                               <=>   parallel0.bidirectional = "<value>"     # defaults to ?, FIXME: not representable
518 
519 
520 ## parallels: file #############################################################
521 
522 ->type = _CHR_TYPE_FILE           <=>   parallel0.fileType = "file"
523 ->data.file.path = <value>        <=>   parallel0.fileName = "<value>"          # e.g. "parallel0.file"
524 ???                               <=>   parallel0.bidirectional = "<value>"     # must be "false" for fileType = "file", FIXME: not representable
525 
526 
527 
528 ################################################################################
529 ## sound #######################################################################
530 
531                                         sound.present = "true"                  # defaults to "false"
532                                         sound.startConnected = "true"           # defaults to "true"
533                                         sound.autodetect = "true"
534                                         sound.fileName = "-1"
535 
536                                         FIXME: Investigate if ESX supports this,
537                                                at least the VI Client GUI has no
538                                                options to add a sound device, but
539                                                the VI API contains a VirtualSoundCard
540 
541 */
542 
543 #define VIR_FROM_THIS VIR_FROM_NONE
544 
545 #define VMX_BUILD_NAME_EXTRA(_suffix, _extra) \
546     g_snprintf(_suffix##_name, sizeof(_suffix##_name), "%s."_extra, prefix);
547 
548 #define VMX_BUILD_NAME(_suffix) \
549     VMX_BUILD_NAME_EXTRA(_suffix, #_suffix)
550 
551 /* directly map the virDomainControllerModel to virVMXSCSIControllerModel,
552  * this is good enough for now because all virDomainControllerModel values
553  * are actually SCSI controller models in the ESX case */
554 VIR_ENUM_DECL(virVMXControllerModelSCSI);
555 VIR_ENUM_IMPL(virVMXControllerModelSCSI,
556               VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST,
557               "auto", /* just to match virDomainControllerModel, will never be used */
558               "buslogic",
559               "lsilogic",
560               "lsisas1068",
561               "pvscsi",
562               "UNUSED ibmvscsi",
563               "UNUSED virtio-scsi",
564               "UNUSED lsisas1078",
565               "UNUSED virtio-transitional",
566               "UNUSED virtio-non-transitional",
567               "UNUSED ncr53c90",
568               "UNUSED dc390",
569               "UNUSED am53c974",
570 );
571 
572 static int virVMXParseVNC(virConf *conf, virDomainGraphicsDef **def);
573 static int virVMXParseSCSIController(virConf *conf, int controller, bool *present,
574                                      int *virtualDev);
575 static int virVMXParseSATAController(virConf *conf, int controller, bool *present);
576 static int virVMXParseDisk(virVMXContext *ctx, virDomainXMLOption *xmlopt,
577                            virConf *conf, int device, int busType,
578                            int controllerOrBus, int unit, virDomainDiskDef **def,
579                            virDomainDef *vmdef);
580 static int virVMXParseFileSystem(virConf *conf, int number, virDomainFSDef **def);
581 static int virVMXParseEthernet(virConf *conf, int controller, virDomainNetDef **def);
582 static int virVMXParseSerial(virVMXContext *ctx, virConf *conf, int port,
583                              virDomainChrDef **def);
584 static int virVMXParseParallel(virVMXContext *ctx, virConf *conf, int port,
585                                virDomainChrDef **def);
586 static int virVMXParseSVGA(virConf *conf, virDomainVideoDef **def);
587 
588 static int virVMXFormatVNC(virDomainGraphicsDef *def, virBuffer *buffer);
589 static int virVMXFormatDisk(virVMXContext *ctx, virDomainDiskDef *def,
590                                    virBuffer *buffer);
591 static int virVMXFormatFloppy(virVMXContext *ctx, virDomainDiskDef *def,
592                               virBuffer *buffer, bool floppy_present[2]);
593 static int virVMXFormatFileSystem(virDomainFSDef *def, int number,
594                                   virBuffer *buffer);
595 static int virVMXFormatEthernet(virDomainNetDef *def, int controller,
596                                 virBuffer *buffer, int virtualHW_version);
597 static int virVMXFormatSerial(virVMXContext *ctx, virDomainChrDef *def,
598                               virBuffer *buffer);
599 static int virVMXFormatParallel(virVMXContext *ctx, virDomainChrDef *def,
600                                 virBuffer *buffer);
601 static int virVMXFormatSVGA(virDomainVideoDef *def, virBuffer *buffer);
602 
603 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
604  * Helpers
605  */
606 
607 static int
virVMXDomainDefPostParse(virDomainDef * def,unsigned int parseFlags G_GNUC_UNUSED,void * opaque,void * parseOpaque G_GNUC_UNUSED)608 virVMXDomainDefPostParse(virDomainDef *def,
609                          unsigned int parseFlags G_GNUC_UNUSED,
610                          void *opaque,
611                          void *parseOpaque G_GNUC_UNUSED)
612 {
613     virCaps *caps = opaque;
614     if (!virCapabilitiesDomainSupported(caps, def->os.type,
615                                         def->os.arch,
616                                         def->virtType))
617         return -1;
618 
619     return 0;
620 }
621 
622 static int
virVMXDomainDevicesDefPostParse(virDomainDeviceDef * dev G_GNUC_UNUSED,const virDomainDef * def G_GNUC_UNUSED,unsigned int parseFlags G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED,void * parseOpaque G_GNUC_UNUSED)623 virVMXDomainDevicesDefPostParse(virDomainDeviceDef *dev G_GNUC_UNUSED,
624                                 const virDomainDef *def G_GNUC_UNUSED,
625                                 unsigned int parseFlags G_GNUC_UNUSED,
626                                 void *opaque G_GNUC_UNUSED,
627                                 void *parseOpaque G_GNUC_UNUSED)
628 {
629     if (dev->type == VIR_DOMAIN_DEVICE_VIDEO &&
630         dev->data.video->type == VIR_DOMAIN_VIDEO_TYPE_DEFAULT)
631         dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_VMVGA;
632 
633     return 0;
634 }
635 
636 static virDomainDefParserConfig virVMXDomainDefParserConfig = {
637     .macPrefix = {0x00, 0x0c, 0x29},
638     .devicesPostParseCallback = virVMXDomainDevicesDefPostParse,
639     .domainPostParseCallback = virVMXDomainDefPostParse,
640     .features = (VIR_DOMAIN_DEF_FEATURE_WIDE_SCSI |
641                  VIR_DOMAIN_DEF_FEATURE_NAME_SLASH |
642                  VIR_DOMAIN_DEF_FEATURE_NO_BOOT_ORDER),
643     .defArch = VIR_ARCH_I686,
644 };
645 
646 struct virVMXDomainDefNamespaceData {
647     char *datacenterPath;
648     char *moref;
649 };
650 
651 static void
virVMXDomainDefNamespaceFree(void * nsdata)652 virVMXDomainDefNamespaceFree(void *nsdata)
653 {
654     struct virVMXDomainDefNamespaceData *data = nsdata;
655 
656     if (data) {
657         g_free(data->datacenterPath);
658         g_free(data->moref);
659     }
660     g_free(data);
661 }
662 
663 static int
virVMXDomainDefNamespaceFormatXML(virBuffer * buf,void * nsdata)664 virVMXDomainDefNamespaceFormatXML(virBuffer *buf, void *nsdata)
665 {
666     struct virVMXDomainDefNamespaceData *data = nsdata;
667 
668     if (!data)
669         return 0;
670 
671     if (data->datacenterPath) {
672         virBufferAddLit(buf, "<vmware:datacenterpath>");
673         virBufferEscapeString(buf, "%s", data->datacenterPath);
674         virBufferAddLit(buf, "</vmware:datacenterpath>\n");
675     }
676     if (data->moref) {
677         virBufferAddLit(buf, "<vmware:moref>");
678         virBufferEscapeString(buf, "%s", data->moref);
679         virBufferAddLit(buf, "</vmware:moref>\n");
680     }
681 
682     return 0;
683 }
684 
685 static virXMLNamespace virVMXDomainXMLNamespace = {
686     .parse = NULL,
687     .free = virVMXDomainDefNamespaceFree,
688     .format = virVMXDomainDefNamespaceFormatXML,
689     .prefix = "vmware",
690     .uri = "http://libvirt.org/schemas/domain/vmware/1.0",
691 };
692 
693 virDomainXMLOption *
virVMXDomainXMLConfInit(virCaps * caps)694 virVMXDomainXMLConfInit(virCaps *caps)
695 {
696     virVMXDomainDefParserConfig.priv = caps;
697     return virDomainXMLOptionNew(&virVMXDomainDefParserConfig, NULL,
698                                  &virVMXDomainXMLNamespace, NULL, NULL);
699 }
700 
701 char *
virVMXEscapeHex(const char * string,char escape,const char * special)702 virVMXEscapeHex(const char *string, char escape, const char *special)
703 {
704     char *escaped = NULL;
705     size_t length = 1; /* 1 byte for termination */
706     const char *tmp1 = string;
707     char *tmp2;
708 
709     /* Calculate length of escaped string */
710     while (*tmp1 != '\0') {
711         if (*tmp1 == escape || strspn(tmp1, special) > 0)
712             length += 2;
713 
714         ++tmp1;
715         ++length;
716     }
717 
718     escaped = g_new0(char, length);
719 
720     tmp1 = string; /* reading from this one */
721     tmp2 = escaped; /* writing to this one */
722 
723     /* Escape to 'cXX' where c is the escape char and X is a hex digit */
724     while (*tmp1 != '\0') {
725         if (*tmp1 == escape || strspn(tmp1, special) > 0) {
726             *tmp2++ = escape;
727 
728             g_snprintf(tmp2, 3, "%02x", (unsigned int)*tmp1);
729 
730             tmp2 += 2;
731         } else {
732             *tmp2++ = *tmp1;
733         }
734 
735         ++tmp1;
736     }
737 
738     *tmp2 = '\0';
739 
740     return escaped;
741 }
742 
743 
744 
745 int
virVMXUnescapeHex(char * string,char escape)746 virVMXUnescapeHex(char *string, char escape)
747 {
748     char *tmp1 = string; /* reading from this one */
749     char *tmp2 = string; /* writing to this one */
750 
751     /* Unescape from 'cXX' where c is the escape char and X is a hex digit */
752     while (*tmp1 != '\0') {
753         if (*tmp1 == escape) {
754             if (!g_ascii_isxdigit(tmp1[1]) || !g_ascii_isxdigit(tmp1[2]))
755                 return -1;
756 
757             *tmp2++ = g_ascii_xdigit_value(tmp1[1]) * 16 +
758                 g_ascii_xdigit_value(tmp1[2]);
759             tmp1 += 3;
760         } else {
761             *tmp2++ = *tmp1++;
762         }
763     }
764 
765     *tmp2 = '\0';
766 
767     return 0;
768 }
769 
770 
771 
772 char *
virVMXConvertToUTF8(const char * encoding,const char * string)773 virVMXConvertToUTF8(const char *encoding, const char *string)
774 {
775     char *result = NULL;
776     xmlCharEncodingHandlerPtr handler;
777     g_autoptr(xmlBuffer) input = NULL;
778     g_autoptr(xmlBuffer) utf8 = virXMLBufferCreate();
779 
780     handler = xmlFindCharEncodingHandler(encoding);
781 
782     if (handler == NULL) {
783         virReportError(VIR_ERR_INTERNAL_ERROR,
784                        _("libxml2 doesn't handle %s encoding"), encoding);
785         return NULL;
786     }
787 
788     if (!(input = xmlBufferCreateStatic((char *)string, strlen(string))) ||
789         xmlCharEncInFunc(handler, utf8, input) < 0) {
790         virReportError(VIR_ERR_INTERNAL_ERROR,
791                        _("Could not convert from %s to UTF-8 encoding"), encoding);
792         goto cleanup;
793     }
794 
795     result = (char *)g_steal_pointer(&utf8->content);
796 
797  cleanup:
798     xmlCharEncCloseFunc(handler);
799     return result;
800 }
801 
802 
803 
804 static int
virVMXGetConfigStringHelper(virConf * conf,const char * name,char ** string,bool optional)805 virVMXGetConfigStringHelper(virConf *conf, const char *name, char **string,
806                             bool optional)
807 {
808     int rc;
809     *string = NULL;
810 
811     rc = virConfGetValueString(conf, name, string);
812     if (rc == 1 && *string != NULL)
813         return 1;
814 
815     if (optional)
816         return 0;
817 
818     virReportError(VIR_ERR_INTERNAL_ERROR,
819                    _("Missing essential config entry '%s'"), name);
820     return -1;
821 }
822 
823 
824 
825 static int
virVMXGetConfigString(virConf * conf,const char * name,char ** string,bool optional)826 virVMXGetConfigString(virConf *conf, const char *name, char **string,
827                       bool optional)
828 {
829     *string = NULL;
830 
831     if (virVMXGetConfigStringHelper(conf, name, string, optional) < 0)
832         return -1;
833 
834     return 0;
835 }
836 
837 
838 
839 static int
virVMXGetConfigUUID(virConf * conf,const char * name,unsigned char * uuid,bool optional)840 virVMXGetConfigUUID(virConf *conf, const char *name, unsigned char *uuid,
841                     bool optional)
842 {
843     char *string = NULL;
844     int ret = -1;
845     int rc;
846 
847     rc = virVMXGetConfigStringHelper(conf, name, &string, optional);
848     if (rc <= 0)
849         return rc;
850 
851     rc = virUUIDParse(string, uuid);
852     if (rc < 0) {
853         virReportError(VIR_ERR_INTERNAL_ERROR,
854                        _("Could not parse UUID from string '%s'"), string);
855         goto cleanup;
856     }
857 
858     ret = 0;
859 
860  cleanup:
861     VIR_FREE(string);
862     return ret;
863 }
864 
865 
866 
867 static int
virVMXGetConfigLong(virConf * conf,const char * name,long long * number,long long default_,bool optional)868 virVMXGetConfigLong(virConf *conf, const char *name, long long *number,
869                     long long default_, bool optional)
870 {
871     char *string = NULL;
872     int ret = -1;
873     int rc;
874 
875     *number = default_;
876 
877     rc = virVMXGetConfigStringHelper(conf, name, &string, optional);
878     if (rc <= 0)
879         return rc;
880 
881     if (STRCASEEQ(string, "unlimited")) {
882         *number = -1;
883     } else if (virStrToLong_ll(string, NULL, 10, number) < 0) {
884         virReportError(VIR_ERR_INTERNAL_ERROR,
885                 _("Config entry '%s' must represent an integer value"),
886                 name);
887         goto cleanup;
888     }
889 
890     ret = 0;
891 
892  cleanup:
893     VIR_FREE(string);
894     return ret;
895 }
896 
897 
898 
899 static int
virVMXGetConfigBoolean(virConf * conf,const char * name,bool * boolean_,bool default_,bool optional)900 virVMXGetConfigBoolean(virConf *conf, const char *name, bool *boolean_,
901                        bool default_, bool optional)
902 {
903     char *string = NULL;
904     int ret = -1;
905     int rc;
906 
907     *boolean_ = default_;
908 
909     rc = virVMXGetConfigStringHelper(conf, name, &string, optional);
910     if (rc <= 0)
911         return rc;
912 
913     if (STRCASEEQ(string, "true")) {
914         *boolean_ = true;
915     } else if (STRCASEEQ(string, "false")) {
916         *boolean_ = false;
917     } else {
918         virReportError(VIR_ERR_INTERNAL_ERROR,
919                        _("Config entry '%s' must represent a boolean value "
920                          "(true|false)"), name);
921         goto cleanup;
922     }
923 
924     ret = 0;
925 
926  cleanup:
927     VIR_FREE(string);
928     return ret;
929 }
930 
931 
932 
933 static int
virVMXSCSIDiskNameToControllerAndUnit(const char * name,int * controller,int * unit)934 virVMXSCSIDiskNameToControllerAndUnit(const char *name, int *controller, int *unit)
935 {
936     int idx;
937 
938     if (! STRPREFIX(name, "sd")) {
939         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
940                        _("Expecting domain XML attribute 'dev' of entry "
941                          "'devices/disk/target' to start with 'sd'"));
942         return -1;
943     }
944 
945     idx = virDiskNameToIndex(name);
946 
947     if (idx < 0) {
948         virReportError(VIR_ERR_INTERNAL_ERROR,
949                        _("Could not parse valid disk index from '%s'"), name);
950         return -1;
951     }
952 
953     /* Each of the 4 SCSI controllers has 1 bus with 15 units each for devices */
954     if (idx >= (4 * 15)) {
955         virReportError(VIR_ERR_INTERNAL_ERROR,
956                        _("SCSI disk index (parsed from '%s') is too large"), name);
957         return -1;
958     }
959 
960     *controller = idx / 15;
961     *unit = idx % 15;
962 
963     /* Skip the controller itself at unit 7 */
964     if (*unit >= 7)
965         ++(*unit);
966 
967     return 0;
968 }
969 
970 
971 
972 static int
virVMXIDEDiskNameToBusAndUnit(const char * name,int * bus,int * unit)973 virVMXIDEDiskNameToBusAndUnit(const char *name, int *bus, int *unit)
974 {
975     int idx;
976 
977     if (! STRPREFIX(name, "hd")) {
978         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
979                        _("Expecting domain XML attribute 'dev' of entry "
980                          "'devices/disk/target' to start with 'hd'"));
981         return -1;
982     }
983 
984     idx = virDiskNameToIndex(name);
985 
986     if (idx < 0) {
987         virReportError(VIR_ERR_INTERNAL_ERROR,
988                        _("Could not parse valid disk index from '%s'"), name);
989         return -1;
990     }
991 
992     /* The IDE controller has 2 buses with 2 units each for devices */
993     if (idx >= (2 * 2)) {
994         virReportError(VIR_ERR_INTERNAL_ERROR,
995                        _("IDE disk index (parsed from '%s') is too large"), name);
996         return -1;
997     }
998 
999     *bus = idx / 2;
1000     *unit = idx % 2;
1001 
1002     return 0;
1003 }
1004 
1005 
1006 
1007 static int
virVMXFloppyDiskNameToUnit(const char * name,int * unit)1008 virVMXFloppyDiskNameToUnit(const char *name, int *unit)
1009 {
1010     int idx;
1011 
1012     if (! STRPREFIX(name, "fd")) {
1013         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1014                        _("Expecting domain XML attribute 'dev' of entry "
1015                          "'devices/disk/target' to start with 'fd'"));
1016         return -1;
1017     }
1018 
1019     idx = virDiskNameToIndex(name);
1020 
1021     if (idx < 0) {
1022         virReportError(VIR_ERR_INTERNAL_ERROR,
1023                        _("Could not parse valid disk index from '%s'"), name);
1024         return -1;
1025     }
1026 
1027     /* The FDC controller has 1 bus with 2 units for devices */
1028     if (idx >= 2) {
1029         virReportError(VIR_ERR_INTERNAL_ERROR,
1030                        _("Floppy disk index (parsed from '%s') is too large"), name);
1031         return -1;
1032     }
1033 
1034     *unit = idx;
1035 
1036     return 0;
1037 }
1038 
1039 
1040 
1041 static int
virVMXVerifyDiskAddress(virDomainXMLOption * xmlopt,virDomainDiskDef * disk,virDomainDef * vmdef)1042 virVMXVerifyDiskAddress(virDomainXMLOption *xmlopt,
1043                         virDomainDiskDef *disk,
1044                         virDomainDef *vmdef)
1045 {
1046     virDomainDiskDef def;
1047     virDomainDeviceDriveAddress *drive;
1048 
1049     memset(&def, 0, sizeof(def));
1050 
1051     if (disk->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
1052         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1053                        _("Unsupported disk address type '%s'"),
1054                        virDomainDeviceAddressTypeToString(disk->info.type));
1055         return -1;
1056     }
1057 
1058     drive = &disk->info.addr.drive;
1059 
1060     def.dst = disk->dst;
1061     def.bus = disk->bus;
1062 
1063     if (virDomainDiskDefAssignAddress(xmlopt, &def, vmdef) < 0) {
1064         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1065                        _("Could not verify disk address"));
1066         return -1;
1067     }
1068 
1069     if (def.info.addr.drive.controller != drive->controller ||
1070         def.info.addr.drive.bus != drive->bus ||
1071         def.info.addr.drive.unit != drive->unit) {
1072         virReportError(VIR_ERR_INTERNAL_ERROR,
1073                        _("Disk address %d:%d:%d doesn't match target device '%s'"),
1074                        drive->controller, drive->bus, drive->unit, disk->dst);
1075         return -1;
1076     }
1077 
1078     /* drive->{controller|bus|unit} is unsigned, no >= 0 checks are necessary */
1079     if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
1080         if (drive->controller > 3) {
1081             virReportError(VIR_ERR_INTERNAL_ERROR,
1082                            _("SCSI controller index %d out of [0..3] range"),
1083                            drive->controller);
1084             return -1;
1085         }
1086 
1087         if (drive->bus != 0) {
1088             virReportError(VIR_ERR_INTERNAL_ERROR,
1089                            _("SCSI bus index %d out of [0] range"),
1090                            drive->bus);
1091             return -1;
1092         }
1093 
1094         if (drive->unit > 15 || drive->unit == 7) {
1095             virReportError(VIR_ERR_INTERNAL_ERROR,
1096                            _("SCSI unit index %d out of [0..6,8..15] range"),
1097                            drive->unit);
1098             return -1;
1099         }
1100     } else if (disk->bus == VIR_DOMAIN_DISK_BUS_IDE) {
1101         if (drive->controller != 0) {
1102             virReportError(VIR_ERR_INTERNAL_ERROR,
1103                            _("IDE controller index %d out of [0] range"),
1104                            drive->controller);
1105             return -1;
1106         }
1107 
1108         if (drive->bus > 1) {
1109             virReportError(VIR_ERR_INTERNAL_ERROR,
1110                            _("IDE bus index %d out of [0..1] range"),
1111                            drive->bus);
1112             return -1;
1113         }
1114 
1115         if (drive->unit > 1) {
1116             virReportError(VIR_ERR_INTERNAL_ERROR,
1117                            _("IDE unit index %d out of [0..1] range"),
1118                            drive->unit);
1119             return -1;
1120         }
1121     } else if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
1122         if (drive->controller != 0) {
1123             virReportError(VIR_ERR_INTERNAL_ERROR,
1124                            _("FDC controller index %d out of [0] range"),
1125                            drive->controller);
1126             return -1;
1127         }
1128 
1129         if (drive->bus != 0) {
1130             virReportError(VIR_ERR_INTERNAL_ERROR,
1131                            _("FDC bus index %d out of [0] range"),
1132                            drive->bus);
1133             return -1;
1134         }
1135 
1136         if (drive->unit > 1) {
1137             virReportError(VIR_ERR_INTERNAL_ERROR,
1138                            _("FDC unit index %d out of [0..1] range"),
1139                            drive->unit);
1140             return -1;
1141         }
1142     } else {
1143         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1144                        _("Unsupported bus type '%s'"),
1145                        virDomainDiskBusTypeToString(disk->bus));
1146         return -1;
1147     }
1148 
1149     return 0;
1150 }
1151 
1152 
1153 
1154 static int
virVMXHandleLegacySCSIDiskDriverName(virDomainDef * def,virDomainDiskDef * disk)1155 virVMXHandleLegacySCSIDiskDriverName(virDomainDef *def,
1156                                      virDomainDiskDef *disk)
1157 {
1158     char *tmp;
1159     int model;
1160     size_t i;
1161     virDomainControllerDef *controller = NULL;
1162     const char *driver = virDomainDiskGetDriver(disk);
1163     char *copy;
1164 
1165     if (disk->bus != VIR_DOMAIN_DISK_BUS_SCSI || !driver)
1166         return 0;
1167 
1168     copy = g_strdup(driver);
1169     tmp = copy;
1170 
1171     for (; *tmp != '\0'; ++tmp)
1172         *tmp = g_ascii_tolower(*tmp);
1173 
1174     model = virDomainControllerModelSCSITypeFromString(copy);
1175     VIR_FREE(copy);
1176 
1177     if (model < 0) {
1178         virReportError(VIR_ERR_INTERNAL_ERROR,
1179                        _("Unknown driver name '%s'"), driver);
1180         return -1;
1181     }
1182 
1183     for (i = 0; i < def->ncontrollers; ++i) {
1184         if (def->controllers[i]->idx == disk->info.addr.drive.controller) {
1185             controller = def->controllers[i];
1186             break;
1187         }
1188     }
1189 
1190     if (controller == NULL) {
1191         virReportError(VIR_ERR_INTERNAL_ERROR,
1192                        _("Missing SCSI controller for index %d"),
1193                        disk->info.addr.drive.controller);
1194         return -1;
1195     }
1196 
1197     if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT) {
1198         controller->model = model;
1199     } else if (controller->model != model) {
1200         virReportError(VIR_ERR_INTERNAL_ERROR,
1201                        _("Inconsistent SCSI controller model ('%s' is not '%s') "
1202                          "for SCSI controller index %d"), driver,
1203                        virDomainControllerModelSCSITypeToString(controller->model),
1204                        controller->idx);
1205         return -1;
1206     }
1207 
1208     return 0;
1209 }
1210 
1211 
1212 
1213 static int
virVMXGatherSCSIControllers(virVMXContext * ctx,virDomainDef * def,int virtualDev[4],bool present[4])1214 virVMXGatherSCSIControllers(virVMXContext *ctx, virDomainDef *def,
1215                             int virtualDev[4], bool present[4])
1216 {
1217     int result = -1;
1218     size_t i, k;
1219     virDomainDiskDef *disk;
1220     virDomainControllerDef *controller;
1221     bool controllerHasDisksAttached;
1222     int count = 0;
1223     int *autodetectedModels;
1224 
1225     autodetectedModels = g_new0(int, def->ndisks);
1226 
1227     for (i = 0; i < def->ncontrollers; ++i) {
1228         controller = def->controllers[i];
1229 
1230         if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
1231             /* skip non-SCSI controllers */
1232             continue;
1233         }
1234 
1235         controllerHasDisksAttached = false;
1236 
1237         for (k = 0; k < def->ndisks; ++k) {
1238             disk = def->disks[k];
1239 
1240             if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
1241                 disk->info.addr.drive.controller == controller->idx) {
1242                 controllerHasDisksAttached = true;
1243                 break;
1244             }
1245         }
1246 
1247         if (! controllerHasDisksAttached) {
1248             /* skip SCSI controllers without attached disks */
1249             continue;
1250         }
1251 
1252         if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO &&
1253             ctx->autodetectSCSIControllerModel != NULL) {
1254             count = 0;
1255 
1256             /* try to autodetect the SCSI controller model by collecting
1257              * SCSI controller model of all disks attached to this controller */
1258             for (k = 0; k < def->ndisks; ++k) {
1259                 disk = def->disks[k];
1260 
1261                 if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
1262                     disk->info.addr.drive.controller == controller->idx) {
1263                     if (ctx->autodetectSCSIControllerModel
1264                                (disk, &autodetectedModels[count],
1265                                 ctx->opaque) < 0) {
1266                         goto cleanup;
1267                     }
1268 
1269                     ++count;
1270                 }
1271             }
1272 
1273             /* autodetection fails when the disks attached to one controller
1274              * have inconsistent SCSI controller models */
1275             for (k = 0; k < count; ++k) {
1276                 if (autodetectedModels[k] != autodetectedModels[0]) {
1277                     virReportError(VIR_ERR_INTERNAL_ERROR,
1278                                    _("Disks on SCSI controller %d have inconsistent "
1279                                      "controller models, cannot autodetect model"),
1280                                    controller->idx);
1281                     goto cleanup;
1282                 }
1283             }
1284 
1285             controller->model = autodetectedModels[0];
1286         }
1287 
1288         if (controller->model != -1 &&
1289             controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC &&
1290             controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC &&
1291             controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068 &&
1292             controller->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI) {
1293             virReportError(VIR_ERR_INTERNAL_ERROR,
1294                            _("Expecting domain XML attribute 'model' of entry "
1295                              "'controller' to be 'buslogic' or 'lsilogic' or "
1296                              "'lsisas1068' or 'vmpvscsi' but found '%s'"),
1297                            virDomainControllerModelSCSITypeToString(controller->model));
1298             goto cleanup;
1299         }
1300 
1301         present[controller->idx] = true;
1302         virtualDev[controller->idx] = controller->model;
1303     }
1304 
1305     result = 0;
1306 
1307  cleanup:
1308     VIR_FREE(autodetectedModels);
1309 
1310     return result;
1311 }
1312 
1313 struct virVMXConfigScanResults {
1314     int networks_max_index;
1315 };
1316 
1317 static int
virVMXConfigScanResultsCollector(const char * name,virConfValue * value G_GNUC_UNUSED,void * opaque)1318 virVMXConfigScanResultsCollector(const char* name,
1319                                  virConfValue *value G_GNUC_UNUSED,
1320                                  void *opaque)
1321 {
1322     struct virVMXConfigScanResults *results = opaque;
1323 
1324     if (STRCASEPREFIX(name, "ethernet")) {
1325         unsigned int idx;
1326         char *p;
1327 
1328         if (virStrToLong_uip(name + 8, &p, 10, &idx) < 0 ||
1329             *p != '.') {
1330             virReportError(VIR_ERR_INTERNAL_ERROR,
1331                            _("failed to parse the index of the VMX key '%s'"),
1332                            name);
1333             return -1;
1334         }
1335 
1336         if ((int)idx > results->networks_max_index)
1337             results->networks_max_index = (int)idx;
1338     }
1339 
1340     return 0;
1341 }
1342 
1343 
1344 static int
virVMXParseGenID(virConf * conf,virDomainDef * def)1345 virVMXParseGenID(virConf *conf,
1346                  virDomainDef *def)
1347 {
1348     long long vmid[2] = { 0 };
1349     g_autofree char *uuidstr = NULL;
1350 
1351     if (virVMXGetConfigLong(conf, "vm.genid", &vmid[0], 0, true) < 0 ||
1352         virVMXGetConfigLong(conf, "vm.genidX", &vmid[1], 0, true) < 0)
1353         return -1;
1354 
1355     if (vmid[0] == 0 && vmid[1] == 0)
1356         return 0;
1357 
1358     uuidstr = g_strdup_printf("%.16llx%.16llx", vmid[0], vmid[1]);
1359     if (virUUIDParse(uuidstr, def->genid) < 0) {
1360         virReportError(VIR_ERR_INTERNAL_ERROR,
1361                        _("Could not parse UUID from string '%s'"), uuidstr);
1362         return -1;
1363     }
1364     def->genidRequested = true;
1365 
1366     return 0;
1367 }
1368 
1369 
1370 
1371 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1372  * VMX -> Domain XML
1373  */
1374 
1375 virDomainDef *
virVMXParseConfig(virVMXContext * ctx,virDomainXMLOption * xmlopt,virCaps * caps G_GNUC_UNUSED,const char * vmx)1376 virVMXParseConfig(virVMXContext *ctx,
1377                   virDomainXMLOption *xmlopt,
1378                   virCaps *caps G_GNUC_UNUSED,
1379                   const char *vmx)
1380 {
1381     bool success = false;
1382     g_autoptr(virConf) conf = NULL;
1383     char *encoding = NULL;
1384     char *utf8;
1385     virDomainDef *def = NULL;
1386     long long config_version = 0;
1387     long long virtualHW_version = 0;
1388     long long memsize = 0;
1389     long long sched_mem_max = 0;
1390     long long sched_mem_minsize = 0;
1391     long long numvcpus = 0;
1392     char *sched_cpu_affinity = NULL;
1393     char *sched_cpu_shares = NULL;
1394     char *guestOS = NULL;
1395     bool smbios_reflecthost = false;
1396     int controller;
1397     int bus;
1398     int port;
1399     bool present;
1400     int scsi_virtualDev[4] = { -1, -1, -1, -1 };
1401     int unit;
1402     bool hgfs_disabled = true;
1403     long long sharedFolder_maxNum = 0;
1404     struct virVMXConfigScanResults results = { -1 };
1405     long long coresPerSocket = 0;
1406     virCPUDef *cpu = NULL;
1407     char *firmware = NULL;
1408     size_t saved_ndisks = 0;
1409 
1410     if (ctx->parseFileName == NULL) {
1411         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1412                        _("virVMXContext has no parseFileName function set"));
1413         return NULL;
1414     }
1415 
1416     conf = virConfReadString(vmx, VIR_CONF_FLAG_VMX_FORMAT);
1417 
1418     if (conf == NULL)
1419         return NULL;
1420 
1421     /* vmx:.encoding */
1422     if (virVMXGetConfigString(conf, ".encoding", &encoding, true) < 0)
1423         goto cleanup;
1424 
1425     if (encoding == NULL || STRCASEEQ(encoding, "UTF-8")) {
1426         /* nothing */
1427     } else {
1428         virConfFree(conf);
1429         conf = NULL;
1430 
1431         utf8 = virVMXConvertToUTF8(encoding, vmx);
1432 
1433         if (utf8 == NULL)
1434             goto cleanup;
1435 
1436         conf = virConfReadString(utf8, VIR_CONF_FLAG_VMX_FORMAT);
1437 
1438         VIR_FREE(utf8);
1439 
1440         if (conf == NULL)
1441             goto cleanup;
1442     }
1443 
1444     if (virConfWalk(conf, virVMXConfigScanResultsCollector, &results) < 0)
1445         goto cleanup;
1446 
1447     /* Allocate domain def */
1448     if (!(def = virDomainDefNew(xmlopt)))
1449         goto cleanup;
1450 
1451     def->virtType = VIR_DOMAIN_VIRT_VMWARE;
1452     def->id = -1;
1453 
1454     /* vmx:config.version */
1455     if (virVMXGetConfigLong(conf, "config.version", &config_version, 0,
1456                             false) < 0) {
1457         goto cleanup;
1458     }
1459 
1460     if (config_version != 8) {
1461         virReportError(VIR_ERR_INTERNAL_ERROR,
1462                        _("Expecting VMX entry 'config.version' to be 8 but found "
1463                          "%lld"), config_version);
1464         goto cleanup;
1465     }
1466 
1467     /* vmx:virtualHW.version */
1468     if (virVMXGetConfigLong(conf, "virtualHW.version", &virtualHW_version, 0,
1469                             false) < 0) {
1470         goto cleanup;
1471     }
1472 
1473     if (virtualHW_version < 4) {
1474         virReportError(VIR_ERR_INTERNAL_ERROR,
1475                        _("Expecting VMX entry 'virtualHW.version' to be "
1476                          "4 or higher but found %lld"),
1477                        virtualHW_version);
1478         goto cleanup;
1479     } else if (virtualHW_version >= 13) {
1480         def->scsiBusMaxUnit = SCSI_SUPER_WIDE_BUS_MAX_CONT_UNIT;
1481     }
1482 
1483     /* vmx:uuid.bios -> def:uuid */
1484     /* FIXME: Need to handle 'uuid.action = "create"' */
1485     if (virVMXGetConfigUUID(conf, "uuid.bios", def->uuid, true) < 0)
1486         goto cleanup;
1487 
1488     /* vmx:displayName -> def:name */
1489     if (virVMXGetConfigString(conf, "displayName", &def->name, true) < 0)
1490         goto cleanup;
1491 
1492     if (def->name != NULL) {
1493         if (virVMXUnescapeHexPercent(def->name) < 0 ||
1494             virVMXUnescapeHexPipe(def->name) < 0) {
1495             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1496                            _("VMX entry 'name' contains invalid escape sequence"));
1497             goto cleanup;
1498         }
1499     }
1500 
1501     /* vmx:vm.genid + vm.genidX -> def:genid */
1502     if (virVMXParseGenID(conf, def) < 0)
1503         goto cleanup;
1504 
1505     /* vmx:annotation -> def:description */
1506     if (virVMXGetConfigString(conf, "annotation", &def->description,
1507                               true) < 0) {
1508         goto cleanup;
1509     }
1510 
1511     if (def->description != NULL) {
1512         if (virVMXUnescapeHexPipe(def->description) < 0) {
1513             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1514                            _("VMX entry 'annotation' contains invalid escape "
1515                              "sequence"));
1516             goto cleanup;
1517         }
1518     }
1519 
1520     /* vmx:memsize -> def:mem.max_balloon */
1521     if (virVMXGetConfigLong(conf, "memsize", &memsize, 32, true) < 0)
1522         goto cleanup;
1523 
1524     if (memsize <= 0 || memsize % 4 != 0) {
1525         virReportError(VIR_ERR_INTERNAL_ERROR,
1526                        _("Expecting VMX entry 'memsize' to be an unsigned "
1527                          "integer (multiple of 4) but found %lld"), memsize);
1528         goto cleanup;
1529     }
1530 
1531     virDomainDefSetMemoryTotal(def, memsize * 1024); /* Scale from megabytes to kilobytes */
1532 
1533     /* vmx:sched.mem.max -> def:mem.cur_balloon */
1534     if (virVMXGetConfigLong(conf, "sched.mem.max", &sched_mem_max, memsize,
1535                             true) < 0) {
1536         goto cleanup;
1537     }
1538 
1539     if (sched_mem_max < 0)
1540         sched_mem_max = memsize;
1541 
1542     def->mem.cur_balloon = sched_mem_max * 1024; /* Scale from megabytes to kilobytes */
1543 
1544     if (def->mem.cur_balloon > virDomainDefGetMemoryTotal(def))
1545         def->mem.cur_balloon = virDomainDefGetMemoryTotal(def);
1546 
1547     /* vmx:sched.mem.minsize -> def:mem.min_guarantee */
1548     if (virVMXGetConfigLong(conf, "sched.mem.minsize", &sched_mem_minsize, 0,
1549                             true) < 0) {
1550         goto cleanup;
1551     }
1552 
1553     if (sched_mem_minsize < 0)
1554         sched_mem_minsize = 0;
1555 
1556     def->mem.min_guarantee = sched_mem_minsize * 1024; /* Scale from megabytes to kilobytes */
1557 
1558     if (def->mem.min_guarantee > virDomainDefGetMemoryTotal(def))
1559         def->mem.min_guarantee = virDomainDefGetMemoryTotal(def);
1560 
1561     /* vmx:numvcpus -> def:vcpus */
1562     if (virVMXGetConfigLong(conf, "numvcpus", &numvcpus, 1, true) < 0)
1563         goto cleanup;
1564 
1565     if (numvcpus <= 0) {
1566         virReportError(VIR_ERR_INTERNAL_ERROR,
1567                        _("Expecting VMX entry 'numvcpus' to be an unsigned "
1568                          "integer greater than 0 but found %lld"), numvcpus);
1569         goto cleanup;
1570     }
1571 
1572     if (virDomainDefSetVcpusMax(def, numvcpus, xmlopt) < 0)
1573         goto cleanup;
1574 
1575     if (virDomainDefSetVcpus(def, numvcpus) < 0)
1576         goto cleanup;
1577 
1578     /* vmx:cpuid.coresPerSocket -> def:cpu */
1579     if (virVMXGetConfigLong(conf, "cpuid.coresPerSocket", &coresPerSocket, 1,
1580                             true) < 0)
1581         goto cleanup;
1582 
1583     if (coresPerSocket > 1) {
1584         cpu = virCPUDefNew();
1585 
1586         cpu->type = VIR_CPU_TYPE_GUEST;
1587         cpu->mode = VIR_CPU_MODE_CUSTOM;
1588 
1589         cpu->sockets = numvcpus / coresPerSocket;
1590         if (cpu->sockets <= 0) {
1591             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1592                            _("VMX entry 'cpuid.coresPerSocket' smaller than "
1593                              "'numvcpus'"));
1594             goto cleanup;
1595         }
1596         cpu->dies = 1;
1597         cpu->cores = coresPerSocket;
1598         cpu->threads = 1;
1599 
1600         def->cpu = g_steal_pointer(&cpu);
1601     }
1602 
1603     /* vmx:sched.cpu.affinity -> def:cpumask */
1604     /* NOTE: maps to VirtualMachine:config.cpuAffinity.affinitySet */
1605     if (virVMXGetConfigString(conf, "sched.cpu.affinity", &sched_cpu_affinity,
1606                               true) < 0) {
1607         goto cleanup;
1608     }
1609 
1610     if (sched_cpu_affinity != NULL && STRCASENEQ(sched_cpu_affinity, "all")) {
1611         g_auto(GStrv) afflist = NULL;
1612         char **aff;
1613 
1614         def->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN);
1615 
1616         if (!(afflist = g_strsplit(sched_cpu_affinity, ",", 0)))
1617             goto cleanup;
1618 
1619         if (g_strv_length(afflist) < numvcpus) {
1620             virReportError(VIR_ERR_INTERNAL_ERROR,
1621                            _("Expecting VMX entry 'sched.cpu.affinity' to contain "
1622                              "at least as many values as 'numvcpus' (%lld) but "
1623                              "found only %u value(s)"), numvcpus, g_strv_length(afflist));
1624             goto cleanup;
1625         }
1626 
1627         for (aff = afflist; *aff; aff++) {
1628             const char *current = *aff;
1629             unsigned int number;
1630             int rc;
1631 
1632             virSkipSpaces(&current);
1633             rc = virStrToLong_uip(current, (char **) &current, 10, &number);
1634             virSkipSpaces(&current);
1635 
1636             if (rc < 0 || *current != '\0') {
1637                 virReportError(VIR_ERR_INTERNAL_ERROR,
1638                                _("Expecting VMX entry 'sched.cpu.affinity' to be "
1639                                  "a comma separated list of unsigned integers but "
1640                                  "found '%s'"), sched_cpu_affinity);
1641                 goto cleanup;
1642             }
1643 
1644             if (number >= VIR_DOMAIN_CPUMASK_LEN) {
1645                 virReportError(VIR_ERR_INTERNAL_ERROR,
1646                                _("VMX entry 'sched.cpu.affinity' contains a %d, "
1647                                  "this value is too large"), number);
1648                 goto cleanup;
1649             }
1650 
1651             ignore_value(virBitmapSetBit(def->cpumask, number));
1652         }
1653     }
1654 
1655     /* vmx:sched.cpu.shares -> def:cputune.shares */
1656     if (virVMXGetConfigString(conf, "sched.cpu.shares", &sched_cpu_shares,
1657                               true) < 0) {
1658         goto cleanup;
1659     }
1660 
1661     if (sched_cpu_shares != NULL) {
1662         unsigned int vcpus = virDomainDefGetVcpus(def);
1663         /* See https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.SharesInfo.Level.html */
1664         if (STRCASEEQ(sched_cpu_shares, "low")) {
1665             def->cputune.shares = vcpus * 500;
1666         } else if (STRCASEEQ(sched_cpu_shares, "normal")) {
1667             def->cputune.shares = vcpus * 1000;
1668         } else if (STRCASEEQ(sched_cpu_shares, "high")) {
1669             def->cputune.shares = vcpus * 2000;
1670         } else if (virStrToLong_ull(sched_cpu_shares, NULL, 10,
1671                                     &def->cputune.shares) < 0) {
1672             virReportError(VIR_ERR_INTERNAL_ERROR,
1673                            _("Expecting VMX entry 'sched.cpu.shares' to be an "
1674                              "unsigned integer or 'low', 'normal' or 'high' but "
1675                              "found '%s'"), sched_cpu_shares);
1676             goto cleanup;
1677         }
1678         def->cputune.sharesSpecified = true;
1679     }
1680 
1681     /* def:lifecycle */
1682     def->onReboot = VIR_DOMAIN_LIFECYCLE_ACTION_RESTART;
1683     def->onPoweroff = VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY;
1684     def->onCrash = VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY;
1685 
1686     /* def:os */
1687     def->os.type = VIR_DOMAIN_OSTYPE_HVM;
1688 
1689     /* vmx:guestOS -> def:os.arch */
1690     if (virVMXGetConfigString(conf, "guestOS", &guestOS, true) < 0)
1691         goto cleanup;
1692 
1693     if (guestOS != NULL && virStringHasSuffix(guestOS, "-64")) {
1694         def->os.arch = VIR_ARCH_X86_64;
1695     } else {
1696         def->os.arch = VIR_ARCH_I686;
1697     }
1698 
1699     /* vmx:smbios.reflecthost -> def:os.smbios_mode */
1700     if (virVMXGetConfigBoolean(conf, "smbios.reflecthost",
1701                                &smbios_reflecthost, false, true) < 0) {
1702         goto cleanup;
1703     }
1704 
1705     if (smbios_reflecthost)
1706         def->os.smbios_mode = VIR_DOMAIN_SMBIOS_HOST;
1707 
1708     /* def:features */
1709     /* FIXME */
1710 
1711     /* def:clock */
1712     /* FIXME */
1713 
1714     /* def:graphics */
1715     def->graphics = g_new0(virDomainGraphicsDef *, 1);
1716     def->ngraphics = 0;
1717 
1718     if (virVMXParseVNC(conf, &def->graphics[def->ngraphics]) < 0)
1719         goto cleanup;
1720 
1721     if (def->graphics[def->ngraphics] != NULL)
1722         ++def->ngraphics;
1723 
1724     /* def:disks (scsi) */
1725     for (controller = 0; controller < 4; ++controller) {
1726         if (virVMXParseSCSIController(conf, controller, &present,
1727                                       &scsi_virtualDev[controller]) < 0) {
1728             goto cleanup;
1729         }
1730 
1731         if (! present)
1732             continue;
1733 
1734         for (unit = 0; unit < def->scsiBusMaxUnit; unit++) {
1735             g_autoptr(virDomainDiskDef) disk = NULL;
1736 
1737             if (unit == 7) {
1738                 /*
1739                  * SCSI unit 7 is assigned to the SCSI controller and cannot be
1740                  * used for disk devices.
1741                  */
1742                 continue;
1743             }
1744 
1745             if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
1746                                 VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
1747                                 &disk, def) < 0) {
1748                 goto cleanup;
1749             }
1750 
1751             if (!disk &&
1752                 virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1753                                 VIR_DOMAIN_DISK_BUS_SCSI, controller, unit,
1754                                 &disk, def) < 0) {
1755                 goto cleanup;
1756             }
1757 
1758             if (!disk)
1759                 continue;
1760 
1761             VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk);
1762         }
1763     }
1764 
1765     /* add all the SCSI controllers we've seen, up until the last one that is
1766      * currently used by a disk */
1767     if (def->ndisks != 0) {
1768         virDomainDeviceInfo *info = &def->disks[def->ndisks - 1]->info;
1769         for (controller = 0; controller <= info->addr.drive.controller; controller++) {
1770             if (!virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
1771                                            controller, scsi_virtualDev[controller]))
1772                 goto cleanup;
1773         }
1774         saved_ndisks = def->ndisks;
1775     }
1776 
1777     /* def:disks (sata) */
1778     for (controller = 0; controller < 4; ++controller) {
1779         if (virVMXParseSATAController(conf, controller, &present) < 0) {
1780             goto cleanup;
1781         }
1782 
1783         if (! present)
1784             continue;
1785 
1786         for (unit = 0; unit < 30; ++unit) {
1787             g_autoptr(virDomainDiskDef) disk = NULL;
1788 
1789             if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
1790                                 VIR_DOMAIN_DISK_BUS_SATA, controller, unit,
1791                                 &disk, def) < 0) {
1792                 goto cleanup;
1793             }
1794 
1795             if (!disk &&
1796                 virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1797                                  VIR_DOMAIN_DISK_BUS_SATA, controller, unit,
1798                                  &disk, def) < 0) {
1799                 goto cleanup;
1800             }
1801 
1802             if (!disk)
1803                 continue;
1804 
1805             VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk);
1806         }
1807     }
1808 
1809     /* add all the SATA controllers we've seen, up until the last one that is
1810      * currently used by a disk */
1811     if (def->ndisks - saved_ndisks != 0) {
1812         virDomainDeviceInfo *info = &def->disks[def->ndisks - 1]->info;
1813         for (controller = 0; controller <= info->addr.drive.controller; controller++) {
1814             if (!virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_SATA,
1815                                            controller, -1))
1816                 goto cleanup;
1817         }
1818     }
1819 
1820     /* def:disks (ide) */
1821     for (bus = 0; bus < 2; ++bus) {
1822         for (unit = 0; unit < 2; ++unit) {
1823             g_autoptr(virDomainDiskDef) disk = NULL;
1824 
1825             if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_DISK,
1826                                 VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
1827                                 &disk, def) < 0) {
1828                 goto cleanup;
1829             }
1830 
1831             if (!disk &&
1832                 virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_CDROM,
1833                                 VIR_DOMAIN_DISK_BUS_IDE, bus, unit,
1834                                 &disk, def) < 0) {
1835                 goto cleanup;
1836             }
1837 
1838             if (!disk)
1839                 continue;
1840 
1841             VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk);
1842         }
1843     }
1844 
1845     /* def:disks (floppy) */
1846     for (unit = 0; unit < 2; ++unit) {
1847         g_autoptr(virDomainDiskDef) disk = NULL;
1848 
1849         if (virVMXParseDisk(ctx, xmlopt, conf, VIR_DOMAIN_DISK_DEVICE_FLOPPY,
1850                             VIR_DOMAIN_DISK_BUS_FDC, 0, unit,
1851                             &disk, def) < 0) {
1852             goto cleanup;
1853         }
1854 
1855         if (!disk)
1856             continue;
1857 
1858         VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk);
1859     }
1860 
1861     /* def:fss */
1862     if (virVMXGetConfigBoolean(conf, "isolation.tools.hgfs.disable",
1863                                &hgfs_disabled, true, true) < 0) {
1864         goto cleanup;
1865     }
1866 
1867     if (!hgfs_disabled) {
1868         if (virVMXGetConfigLong(conf, "sharedFolder.maxNum", &sharedFolder_maxNum,
1869                                 0, true) < 0) {
1870             goto cleanup;
1871         }
1872 
1873         if (sharedFolder_maxNum > 0) {
1874             int number;
1875 
1876             def->fss = g_new0(virDomainFSDef *, sharedFolder_maxNum);
1877             def->nfss = 0;
1878 
1879             for (number = 0; number < sharedFolder_maxNum; ++number) {
1880                 if (virVMXParseFileSystem(conf, number,
1881                                           &def->fss[def->nfss]) < 0) {
1882                     goto cleanup;
1883                 }
1884 
1885                 if (def->fss[def->nfss] != NULL)
1886                     ++def->nfss;
1887             }
1888         }
1889     }
1890 
1891     /* def:nets */
1892     for (controller = 0; controller <= results.networks_max_index; ++controller) {
1893         virDomainNetDef *net = NULL;
1894         if (virVMXParseEthernet(conf, controller, &net) < 0)
1895             goto cleanup;
1896 
1897         if (!net)
1898             continue;
1899 
1900         VIR_APPEND_ELEMENT(def->nets, def->nnets, net);
1901     }
1902 
1903     /* def:inputs */
1904     /* FIXME */
1905 
1906     /* def:videos */
1907     def->videos = g_new0(virDomainVideoDef *, 1);
1908     def->nvideos = 0;
1909 
1910     if (virVMXParseSVGA(conf, &def->videos[def->nvideos]) < 0)
1911         goto cleanup;
1912 
1913     def->nvideos = 1;
1914 
1915     /* def:sounds */
1916     /* FIXME */
1917 
1918     /* def:hostdevs */
1919     /* FIXME */
1920 
1921     /* def:serials */
1922     def->serials = g_new0(virDomainChrDef *, 4);
1923     def->nserials = 0;
1924 
1925     for (port = 0; port < 4; ++port) {
1926         if (virVMXParseSerial(ctx, conf, port,
1927                               &def->serials[def->nserials]) < 0) {
1928             goto cleanup;
1929         }
1930 
1931         if (def->serials[def->nserials] != NULL)
1932             ++def->nserials;
1933     }
1934 
1935     /* def:parallels */
1936     def->parallels = g_new0(virDomainChrDef *, 3);
1937     def->nparallels = 0;
1938 
1939     for (port = 0; port < 3; ++port) {
1940         if (virVMXParseParallel(ctx, conf, port,
1941                                 &def->parallels[def->nparallels]) < 0) {
1942             goto cleanup;
1943         }
1944 
1945         if (def->parallels[def->nparallels] != NULL)
1946             ++def->nparallels;
1947     }
1948 
1949     /* ctx:datacenterPath -> def:namespaceData */
1950     if (ctx->datacenterPath || ctx->moref) {
1951         struct virVMXDomainDefNamespaceData *nsdata = NULL;
1952 
1953         nsdata = g_new0(struct virVMXDomainDefNamespaceData, 1);
1954 
1955         nsdata->datacenterPath = g_strdup(ctx->datacenterPath);
1956 
1957         nsdata->moref = g_strdup(ctx->moref);
1958 
1959         def->ns = *virDomainXMLOptionGetNamespace(xmlopt);
1960         def->namespaceData = nsdata;
1961     }
1962 
1963     /* vmx:firmware */
1964     if (virVMXGetConfigString(conf, "firmware", &firmware, true) < 0)
1965         goto cleanup;
1966 
1967     if (firmware != NULL) {
1968         if (STREQ(firmware, "efi")) {
1969             def->os.firmware = VIR_DOMAIN_OS_DEF_FIRMWARE_EFI;
1970         } else {
1971             virReportError(VIR_ERR_INTERNAL_ERROR,
1972                            _("VMX entry 'firmware' has unknown value '%s'"),
1973                            firmware);
1974             goto cleanup;
1975         }
1976     }
1977 
1978     if (virDomainDefPostParse(def, VIR_DOMAIN_DEF_PARSE_ABI_UPDATE,
1979                               xmlopt, NULL) < 0)
1980         goto cleanup;
1981 
1982     success = true;
1983 
1984  cleanup:
1985     if (! success) {
1986         virDomainDefFree(def);
1987         def = NULL;
1988     }
1989 
1990     VIR_FREE(encoding);
1991     VIR_FREE(sched_cpu_affinity);
1992     VIR_FREE(sched_cpu_shares);
1993     VIR_FREE(guestOS);
1994     virCPUDefFree(cpu);
1995     VIR_FREE(firmware);
1996 
1997     return def;
1998 }
1999 
2000 
2001 
2002 static int
virVMXParseVNC(virConf * conf,virDomainGraphicsDef ** def)2003 virVMXParseVNC(virConf *conf, virDomainGraphicsDef **def)
2004 {
2005     bool enabled = false;
2006     long long port = 0;
2007     char *listenAddr = NULL;
2008 
2009     if (def == NULL || *def != NULL) {
2010         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2011         return -1;
2012     }
2013 
2014     if (virVMXGetConfigBoolean(conf, "RemoteDisplay.vnc.enabled", &enabled,
2015                                false, true) < 0) {
2016         return -1;
2017     }
2018 
2019     if (! enabled)
2020         return 0;
2021 
2022     *def = g_new0(virDomainGraphicsDef, 1);
2023     (*def)->type = VIR_DOMAIN_GRAPHICS_TYPE_VNC;
2024 
2025     if (virVMXGetConfigLong(conf, "RemoteDisplay.vnc.port", &port, -1,
2026                             true) < 0 ||
2027         virVMXGetConfigString(conf, "RemoteDisplay.vnc.ip",
2028                               &listenAddr, true) < 0 ||
2029         virVMXGetConfigString(conf, "RemoteDisplay.vnc.keymap",
2030                               &(*def)->data.vnc.keymap, true) < 0 ||
2031         virVMXGetConfigString(conf, "RemoteDisplay.vnc.password",
2032                               &(*def)->data.vnc.auth.passwd, true) < 0) {
2033         goto failure;
2034     }
2035 
2036     if (virDomainGraphicsListenAppendAddress(*def, listenAddr) < 0)
2037         goto failure;
2038     VIR_FREE(listenAddr);
2039 
2040     if (port < 0) {
2041         VIR_WARN("VNC is enabled but VMX entry 'RemoteDisplay.vnc.port' "
2042                   "is missing, the VNC port is unknown");
2043 
2044         (*def)->data.vnc.port = 0;
2045         (*def)->data.vnc.autoport = true;
2046     } else {
2047         if (port < 5900 || port > 5964)
2048             VIR_WARN("VNC port %lld it out of [5900..5964] range", port);
2049 
2050         (*def)->data.vnc.port = port;
2051         (*def)->data.vnc.autoport = false;
2052     }
2053 
2054     return 0;
2055 
2056  failure:
2057     VIR_FREE(listenAddr);
2058     virDomainGraphicsDefFree(*def);
2059     *def = NULL;
2060 
2061     return -1;
2062 }
2063 
2064 
2065 
2066 static int
virVMXParseSCSIController(virConf * conf,int controller,bool * present,int * virtualDev)2067 virVMXParseSCSIController(virConf *conf, int controller, bool *present,
2068                           int *virtualDev)
2069 {
2070     int result = -1;
2071     char present_name[32];
2072     char virtualDev_name[32];
2073     char *virtualDev_string = NULL;
2074     char *tmp;
2075 
2076     if (virtualDev == NULL || *virtualDev != -1) {
2077         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2078         return -1;
2079     }
2080 
2081     if (controller < 0 || controller > 3) {
2082         virReportError(VIR_ERR_INTERNAL_ERROR,
2083                        _("SCSI controller index %d out of [0..3] range"),
2084                        controller);
2085         return -1;
2086     }
2087 
2088     g_snprintf(present_name, sizeof(present_name), "scsi%d.present", controller);
2089     g_snprintf(virtualDev_name, sizeof(virtualDev_name), "scsi%d.virtualDev",
2090                controller);
2091 
2092     if (virVMXGetConfigBoolean(conf, present_name, present, false, true) < 0)
2093         goto cleanup;
2094 
2095     if (! *present) {
2096         result = 0;
2097         goto cleanup;
2098     }
2099 
2100     if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev_string,
2101                               true) < 0) {
2102         goto cleanup;
2103     }
2104 
2105     if (virtualDev_string != NULL) {
2106         tmp = virtualDev_string;
2107 
2108         for (; *tmp != '\0'; ++tmp)
2109             *tmp = g_ascii_tolower(*tmp);
2110 
2111         *virtualDev = virVMXControllerModelSCSITypeFromString(virtualDev_string);
2112 
2113         if (*virtualDev == -1 ||
2114             (*virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC &&
2115              *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC &&
2116              *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068 &&
2117              *virtualDev != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI)) {
2118             virReportError(VIR_ERR_INTERNAL_ERROR,
2119                            _("Expecting VMX entry '%s' to be 'buslogic' or 'lsilogic' "
2120                              "or 'lsisas1068' or 'pvscsi' but found '%s'"),
2121                            virtualDev_name, virtualDev_string);
2122             goto cleanup;
2123         }
2124     }
2125 
2126     result = 0;
2127 
2128  cleanup:
2129     VIR_FREE(virtualDev_string);
2130 
2131     return result;
2132 }
2133 
2134 
2135 
2136 static int
virVMXParseSATAController(virConf * conf,int controller,bool * present)2137 virVMXParseSATAController(virConf *conf, int controller, bool *present)
2138 {
2139     char present_name[32];
2140 
2141     if (controller < 0 || controller > 3) {
2142         virReportError(VIR_ERR_INTERNAL_ERROR,
2143                        _("SATA controller index %d out of [0..3] range"),
2144                        controller);
2145         return -1;
2146     }
2147 
2148     g_snprintf(present_name, sizeof(present_name), "sata%d.present", controller);
2149 
2150     if (virVMXGetConfigBoolean(conf, present_name, present, false, true) < 0)
2151         return -1;
2152 
2153     return 0;
2154 }
2155 
2156 
2157 
2158 static int
virVMXParseDisk(virVMXContext * ctx,virDomainXMLOption * xmlopt,virConf * conf,int device,int busType,int controllerOrBus,int unit,virDomainDiskDef ** def,virDomainDef * vmdef)2159 virVMXParseDisk(virVMXContext *ctx, virDomainXMLOption *xmlopt, virConf *conf,
2160                 int device, int busType, int controllerOrBus, int unit,
2161                 virDomainDiskDef **def, virDomainDef *vmdef)
2162 {
2163     /*
2164      *          device = {VIR_DOMAIN_DISK_DEVICE_DISK,
2165      *                    VIR_DOMAIN_DISK_DEVICE_CDROM,
2166      *                    VIR_DOMAIN_DISK_DEVICE_LUN}
2167      *         busType = VIR_DOMAIN_DISK_BUS_SCSI
2168      * controllerOrBus = [0..3] -> controller
2169      *            unit = [0..6,8..15] for virtualHW_version < 13
2170      *            unit = [0..6,8..64] for virtualHW_version >= 13
2171      *
2172      *          device = {VIR_DOMAIN_DISK_DEVICE_DISK,
2173      *                    VIR_DOMAIN_DISK_DEVICE_CDROM,
2174      *                    VIR_DOMAIN_DISK_DEVICE_LUN}
2175      *         busType = VIR_DOMAIN_DISK_BUS_SATA
2176      * controllerOrBus = [0..3] -> controller
2177      *            unit = [0..29]
2178      *
2179      *          device = {VIR_DOMAIN_DISK_DEVICE_DISK,
2180      *                    VIR_DOMAIN_DISK_DEVICE_CDROM,
2181      *                    VIR_DOMAIN_DISK_DEVICE_LUN}
2182      *         busType = VIR_DOMAIN_DISK_BUS_IDE
2183      * controllerOrBus = [0..1] -> bus
2184      *            unit = [0..1]
2185      *
2186      *          device = VIR_DOMAIN_DISK_DEVICE_FLOPPY
2187      *         busType = VIR_DOMAIN_DISK_BUS_FDC
2188      * controllerOrBus = [0]
2189      *            unit = [0..1]
2190      */
2191 
2192     int result = -1;
2193     char *prefix = NULL;
2194 
2195     char present_name[32] = "";
2196     bool present = false;
2197 
2198     char startConnected_name[32] = "";
2199     bool startConnected = false;
2200 
2201     char deviceType_name[32] = "";
2202     char *deviceType = NULL;
2203 
2204     char clientDevice_name[32] = "";
2205     bool clientDevice = false;
2206 
2207     char fileType_name[32] = "";
2208     char *fileType = NULL;
2209 
2210     char fileName_name[32] = "";
2211     char *fileName = NULL;
2212 
2213     char writeThrough_name[32] = "";
2214     bool writeThrough = false;
2215 
2216     char mode_name[32] = "";
2217     char *mode = NULL;
2218 
2219     if (!(*def = virDomainDiskDefNew(xmlopt)))
2220         return -1;
2221 
2222     (*def)->device = device;
2223     (*def)->bus = busType;
2224 
2225     /* def:dst, def:driverName */
2226     if (device == VIR_DOMAIN_DISK_DEVICE_DISK ||
2227         device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
2228         if (busType == VIR_DOMAIN_DISK_BUS_SCSI) {
2229             if (controllerOrBus < 0 || controllerOrBus > 3) {
2230                 virReportError(VIR_ERR_INTERNAL_ERROR,
2231                                _("SCSI controller index %d out of [0..3] range"),
2232                                controllerOrBus);
2233                 goto cleanup;
2234             }
2235 
2236             if (unit < 0 || unit > vmdef->scsiBusMaxUnit || unit == 7) {
2237                 virReportError(VIR_ERR_INTERNAL_ERROR,
2238                                _("SCSI unit index %d out of [0..6,8..%u] range"),
2239                                unit, vmdef->scsiBusMaxUnit);
2240                 goto cleanup;
2241             }
2242 
2243             prefix = g_strdup_printf("scsi%d:%d", controllerOrBus, unit);
2244 
2245             (*def)->dst =
2246                virIndexToDiskName
2247                  (controllerOrBus * 15 + (unit < 7 ? unit : unit - 1), "sd");
2248         } else if (busType == VIR_DOMAIN_DISK_BUS_SATA) {
2249             if (controllerOrBus < 0 || controllerOrBus > 3) {
2250                 virReportError(VIR_ERR_INTERNAL_ERROR,
2251                                _("SATA controller index %d out of [0..3] range"),
2252                                controllerOrBus);
2253                 goto cleanup;
2254             }
2255 
2256             if (unit < 0 || unit >= 30) {
2257                 virReportError(VIR_ERR_INTERNAL_ERROR,
2258                                _("SATA unit index %d out of [0..29] range"),
2259                                unit);
2260                 goto cleanup;
2261             }
2262 
2263             prefix = g_strdup_printf("sata%d:%d", controllerOrBus, unit);
2264 
2265             (*def)->dst = virIndexToDiskName(controllerOrBus * 30 + unit, "sd");
2266         } else if (busType == VIR_DOMAIN_DISK_BUS_IDE) {
2267             if (controllerOrBus < 0 || controllerOrBus > 1) {
2268                 virReportError(VIR_ERR_INTERNAL_ERROR,
2269                                _("IDE bus index %d out of [0..1] range"),
2270                                controllerOrBus);
2271                 goto cleanup;
2272             }
2273 
2274             if (unit < 0 || unit > 1) {
2275                 virReportError(VIR_ERR_INTERNAL_ERROR,
2276                                _("IDE unit index %d out of [0..1] range"), unit);
2277                 goto cleanup;
2278             }
2279 
2280             prefix = g_strdup_printf("ide%d:%d", controllerOrBus, unit);
2281 
2282             (*def)->dst = virIndexToDiskName(controllerOrBus * 2 + unit, "hd");
2283         } else {
2284             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2285                            _("Unsupported bus type '%s' for device type '%s'"),
2286                            virDomainDiskBusTypeToString(busType),
2287                            virDomainDiskDeviceTypeToString(device));
2288             goto cleanup;
2289         }
2290     } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2291         if (busType == VIR_DOMAIN_DISK_BUS_FDC) {
2292             if (controllerOrBus != 0) {
2293                 virReportError(VIR_ERR_INTERNAL_ERROR,
2294                                _("FDC controller index %d out of [0] range"),
2295                                controllerOrBus);
2296                 goto cleanup;
2297             }
2298 
2299             if (unit < 0 || unit > 1) {
2300                 virReportError(VIR_ERR_INTERNAL_ERROR,
2301                                _("FDC unit index %d out of [0..1] range"),
2302                                unit);
2303                 goto cleanup;
2304             }
2305 
2306             prefix = g_strdup_printf("floppy%d", unit);
2307 
2308             (*def)->dst = virIndexToDiskName(unit, "fd");
2309         } else {
2310             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2311                            _("Unsupported bus type '%s' for device type '%s'"),
2312                            virDomainDiskBusTypeToString(busType),
2313                            virDomainDiskDeviceTypeToString(device));
2314             goto cleanup;
2315         }
2316     } else {
2317         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2318                        _("Unsupported device type '%s'"),
2319                        virDomainDiskDeviceTypeToString(device));
2320         goto cleanup;
2321     }
2322 
2323     VMX_BUILD_NAME(present);
2324     VMX_BUILD_NAME(startConnected);
2325     VMX_BUILD_NAME(deviceType);
2326     VMX_BUILD_NAME(clientDevice);
2327     VMX_BUILD_NAME(fileType);
2328     VMX_BUILD_NAME(fileName);
2329     VMX_BUILD_NAME(writeThrough);
2330     VMX_BUILD_NAME(mode);
2331 
2332     /* vmx:present */
2333     if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
2334         goto cleanup;
2335 
2336     /* vmx:startConnected */
2337     if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
2338                                true, true) < 0) {
2339         goto cleanup;
2340     }
2341 
2342     /* FIXME: Need to distinguish between active and inactive domains here */
2343     if (! present/* && ! startConnected*/)
2344         goto ignore;
2345 
2346     /* vmx:deviceType -> def:type */
2347     if (virVMXGetConfigString(conf, deviceType_name, &deviceType, true) < 0)
2348         goto cleanup;
2349 
2350     /* vmx:clientDevice */
2351     if (virVMXGetConfigBoolean(conf, clientDevice_name, &clientDevice, false,
2352                                true) < 0) {
2353         goto cleanup;
2354     }
2355 
2356     /* vmx:mode -> def:transient */
2357     if (virVMXGetConfigString(conf, mode_name, &mode, true) < 0)
2358         goto cleanup;
2359 
2360     if (clientDevice) {
2361         /*
2362          * Just ignore devices in client mode, because I have no clue how to
2363          * handle them (e.g. assign an image) without the VI Client GUI.
2364          */
2365         goto ignore;
2366     }
2367 
2368     /* vmx:fileType -> def:type */
2369     if (virVMXGetConfigString(conf, fileType_name, &fileType, true) < 0)
2370         goto cleanup;
2371 
2372     /* vmx:fileName -> def:src, def:type */
2373     if (virVMXGetConfigString(conf, fileName_name, &fileName, true) < 0)
2374         goto cleanup;
2375 
2376     /* vmx:writeThrough -> def:cachemode */
2377     if (virVMXGetConfigBoolean(conf, writeThrough_name, &writeThrough, false,
2378                                true) < 0) {
2379         goto cleanup;
2380     }
2381 
2382     /* Setup virDomainDiskDef */
2383     if (device == VIR_DOMAIN_DISK_DEVICE_DISK) {
2384         if (fileName == NULL ||
2385             virStringHasCaseSuffix(fileName, ".iso") ||
2386             STREQ(fileName, "emptyBackingString") ||
2387             (deviceType &&
2388              (STRCASEEQ(deviceType, "atapi-cdrom") ||
2389               STRCASEEQ(deviceType, "cdrom-raw") ||
2390               STRCASEEQ(deviceType, "cdrom-image") ||
2391               (STRCASEEQ(deviceType, "scsi-passthru") &&
2392                STRPREFIX(fileName, "/vmfs/devices/cdrom/"))))) {
2393             /*
2394              * This function was called in order to parse a harddisk device,
2395              * but .iso files, 'atapi-cdrom', 'cdrom-raw', 'cdrom-image',
2396              * and 'scsi-passthru' CDROM devices are for CDROM devices only.
2397              * Just ignore it, another call to this function to parse a CDROM
2398              * device may handle it.
2399              */
2400             goto ignore;
2401         } else if (virStringHasCaseSuffix(fileName, ".vmdk")) {
2402             char *tmp = NULL;
2403 
2404             if (deviceType != NULL) {
2405                 if (busType == VIR_DOMAIN_DISK_BUS_SCSI &&
2406                     STRCASENEQ(deviceType, "scsi-hardDisk") &&
2407                     STRCASENEQ(deviceType, "disk")) {
2408                     virReportError(VIR_ERR_INTERNAL_ERROR,
2409                                    _("Expecting VMX entry '%s' to be 'scsi-hardDisk' "
2410                                      "or 'disk' but found '%s'"), deviceType_name,
2411                                    deviceType);
2412                     goto cleanup;
2413                 } else if (busType == VIR_DOMAIN_DISK_BUS_IDE &&
2414                            STRCASENEQ(deviceType, "ata-hardDisk") &&
2415                            STRCASENEQ(deviceType, "disk")) {
2416                     virReportError(VIR_ERR_INTERNAL_ERROR,
2417                                    _("Expecting VMX entry '%s' to be 'ata-hardDisk' "
2418                                      "or 'disk' but found '%s'"), deviceType_name,
2419                                    deviceType);
2420                     goto cleanup;
2421                 }
2422             }
2423 
2424             virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
2425             if (ctx->parseFileName(fileName, ctx->opaque, &tmp, false) < 0)
2426                 goto cleanup;
2427             virDomainDiskSetSource(*def, tmp);
2428             VIR_FREE(tmp);
2429             (*def)->cachemode = writeThrough ? VIR_DOMAIN_DISK_CACHE_WRITETHRU
2430                                              : VIR_DOMAIN_DISK_CACHE_DEFAULT;
2431             if (mode)
2432                 (*def)->transient = STRCASEEQ(mode,
2433                                               "independent-nonpersistent");
2434         } else {
2435             virReportError(VIR_ERR_INTERNAL_ERROR,
2436                            _("Invalid or not yet handled value '%s' "
2437                              "for VMX entry '%s' for device type '%s'"),
2438                            fileName, fileName_name,
2439                            deviceType ? deviceType : "unknown");
2440             goto cleanup;
2441         }
2442     } else if (device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
2443         /* set cdrom to read-only */
2444         (*def)->src->readonly = true;
2445 
2446         if (fileName && virStringHasCaseSuffix(fileName, ".vmdk")) {
2447             /*
2448              * This function was called in order to parse a CDROM device, but
2449              * .vmdk files are for harddisk devices only. Just ignore it,
2450              * another call to this function to parse a harddisk device may
2451              * handle it.
2452              */
2453             goto ignore;
2454         } else if (fileName && virStringHasCaseSuffix(fileName, ".iso")) {
2455             char *tmp = NULL;
2456 
2457             if (deviceType && STRCASENEQ(deviceType, "cdrom-image")) {
2458                 virReportError(VIR_ERR_INTERNAL_ERROR,
2459                                _("Expecting VMX entry '%s' to be 'cdrom-image' "
2460                                  "but found '%s'"), deviceType_name, deviceType);
2461                 goto cleanup;
2462             }
2463 
2464             virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
2465             if (ctx->parseFileName(fileName, ctx->opaque, &tmp, true) < 0)
2466                 goto cleanup;
2467             virDomainDiskSetSource(*def, tmp);
2468             VIR_FREE(tmp);
2469         } else if (deviceType && STRCASEEQ(deviceType, "atapi-cdrom")) {
2470             virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);
2471 
2472             if (fileName && STRCASEEQ(fileName, "auto detect")) {
2473                 virDomainDiskSetSource(*def, NULL);
2474                 (*def)->startupPolicy = VIR_DOMAIN_STARTUP_POLICY_OPTIONAL;
2475             } else {
2476                 virDomainDiskSetSource(*def, fileName);
2477             }
2478         } else if (deviceType && STRCASEEQ(deviceType, "cdrom-raw")) {
2479             /* Raw access CD-ROMs actually are device='lun' */
2480             (*def)->device = VIR_DOMAIN_DISK_DEVICE_LUN;
2481             virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);
2482 
2483             if (fileName && STRCASEEQ(fileName, "auto detect")) {
2484                 virDomainDiskSetSource(*def, NULL);
2485                 (*def)->startupPolicy = VIR_DOMAIN_STARTUP_POLICY_OPTIONAL;
2486             } else {
2487                 virDomainDiskSetSource(*def, fileName);
2488             }
2489         } else if (busType == VIR_DOMAIN_DISK_BUS_SCSI &&
2490                    deviceType && STRCASEEQ(deviceType, "scsi-passthru")) {
2491             if (fileName && STRPREFIX(fileName, "/vmfs/devices/cdrom/")) {
2492                 /* SCSI-passthru CD-ROMs actually are device='lun' */
2493                 (*def)->device = VIR_DOMAIN_DISK_DEVICE_LUN;
2494                 virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);
2495                 virDomainDiskSetSource(*def, fileName);
2496             } else {
2497                 /*
2498                  * This function was called in order to parse a CDROM device,
2499                  * but the filename does not indicate a CDROM device. Just ignore
2500                  * it, another call to this function to parse a harddisk device
2501                  * may handle it.
2502                  */
2503                 goto ignore;
2504             }
2505         } else if (fileName && STREQ(fileName, "emptyBackingString")) {
2506             if (deviceType && STRCASENEQ(deviceType, "cdrom-image")) {
2507                 virReportError(VIR_ERR_INTERNAL_ERROR,
2508                                _("Expecting VMX entry '%s' to be 'cdrom-image' "
2509                                  "but found '%s'"), deviceType_name, deviceType);
2510                 goto cleanup;
2511             }
2512 
2513             virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
2514             virDomainDiskSetSource(*def, NULL);
2515         } else {
2516             virReportError(VIR_ERR_INTERNAL_ERROR,
2517                            _("Invalid or not yet handled value '%s' "
2518                              "for VMX entry '%s' for device type '%s'"),
2519                            NULLSTR(fileName), fileName_name,
2520                            deviceType ? deviceType : "unknown");
2521             goto cleanup;
2522         }
2523     } else if (device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
2524         if (fileType != NULL && STRCASEEQ(fileType, "device")) {
2525             virDomainDiskSetType(*def, VIR_STORAGE_TYPE_BLOCK);
2526             virDomainDiskSetSource(*def, fileName);
2527         } else if (fileType != NULL && STRCASEEQ(fileType, "file")) {
2528             char *tmp = NULL;
2529 
2530             virDomainDiskSetType(*def, VIR_STORAGE_TYPE_FILE);
2531             if (fileName &&
2532                 ctx->parseFileName(fileName, ctx->opaque, &tmp, false) < 0)
2533                 goto cleanup;
2534             virDomainDiskSetSource(*def, tmp);
2535             VIR_FREE(tmp);
2536         } else {
2537             virReportError(VIR_ERR_INTERNAL_ERROR,
2538                            _("Invalid or not yet handled value '%s' "
2539                              "for VMX entry '%s' for device type '%s'"),
2540                            NULLSTR(fileName), fileName_name,
2541                            deviceType ? deviceType : "unknown");
2542             goto cleanup;
2543         }
2544     } else {
2545         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported device type '%s'"),
2546                        virDomainDiskDeviceTypeToString(device));
2547         goto cleanup;
2548     }
2549 
2550     if (virDomainDiskDefAssignAddress(xmlopt, *def, vmdef) < 0) {
2551         virReportError(VIR_ERR_INTERNAL_ERROR,
2552                        _("Could not assign address to disk '%s'"),
2553                        virDomainDiskGetSource(*def));
2554         goto cleanup;
2555     }
2556 
2557     result = 0;
2558 
2559  cleanup:
2560     if (result < 0) {
2561         virDomainDiskDefFree(*def);
2562         *def = NULL;
2563     }
2564 
2565     VIR_FREE(prefix);
2566     VIR_FREE(deviceType);
2567     VIR_FREE(fileType);
2568     VIR_FREE(fileName);
2569     VIR_FREE(mode);
2570 
2571     return result;
2572 
2573  ignore:
2574     virDomainDiskDefFree(*def);
2575     *def = NULL;
2576 
2577     result = 0;
2578 
2579     goto cleanup;
2580 }
2581 
2582 
2583 
2584 static int
virVMXParseFileSystem(virConf * conf,int number,virDomainFSDef ** def)2585 virVMXParseFileSystem(virConf *conf, int number, virDomainFSDef **def)
2586 {
2587     int result = -1;
2588     char prefix[48] = "";
2589 
2590     char present_name[48] = "";
2591     bool present = false;
2592 
2593     char enabled_name[48] = "";
2594     bool enabled = false;
2595 
2596     char hostPath_name[48] = "";
2597     char *hostPath = NULL;
2598 
2599     char guestName_name[48] = "";
2600     char *guestName = NULL;
2601 
2602     char writeAccess_name[48] = "";
2603     bool writeAccess = false;
2604 
2605     if (def == NULL || *def != NULL) {
2606         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2607         return -1;
2608     }
2609 
2610     g_snprintf(prefix, sizeof(prefix), "sharedFolder%d", number);
2611 
2612     VMX_BUILD_NAME(present);
2613     VMX_BUILD_NAME(enabled);
2614     VMX_BUILD_NAME(hostPath);
2615     VMX_BUILD_NAME(guestName);
2616     VMX_BUILD_NAME(writeAccess);
2617 
2618     /* vmx:present */
2619     if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
2620         return -1;
2621 
2622     /* vmx:enabled */
2623     if (virVMXGetConfigBoolean(conf, enabled_name, &enabled, false, true) < 0)
2624         return -1;
2625 
2626     if (!(present && enabled))
2627         return 0;
2628 
2629     if (!(*def = virDomainFSDefNew(NULL)))
2630         return -1;
2631 
2632     (*def)->type = VIR_DOMAIN_FS_TYPE_MOUNT;
2633 
2634     /* vmx:hostPath */
2635     if (virVMXGetConfigString(conf, hostPath_name, &hostPath, false) < 0)
2636         goto cleanup;
2637 
2638     (*def)->src->path = g_steal_pointer(&hostPath);
2639 
2640     /* vmx:guestName */
2641     if (virVMXGetConfigString(conf, guestName_name, &guestName, false) < 0)
2642         goto cleanup;
2643 
2644     (*def)->dst = g_steal_pointer(&guestName);
2645 
2646     /* vmx:writeAccess */
2647     if (virVMXGetConfigBoolean(conf, writeAccess_name, &writeAccess, false,
2648                                true) < 0) {
2649         goto cleanup;
2650     }
2651 
2652     (*def)->readonly = !writeAccess;
2653 
2654     result = 0;
2655 
2656  cleanup:
2657     if (result < 0) {
2658         virDomainFSDefFree(*def);
2659         *def = NULL;
2660     }
2661 
2662     VIR_FREE(hostPath);
2663     VIR_FREE(guestName);
2664 
2665     return result;
2666 }
2667 
2668 
2669 
2670 static int
virVMXParseEthernet(virConf * conf,int controller,virDomainNetDef ** def)2671 virVMXParseEthernet(virConf *conf, int controller, virDomainNetDef **def)
2672 {
2673     int result = -1;
2674     char prefix[48] = "";
2675 
2676     char present_name[48] = "";
2677     bool present = false;
2678 
2679     char startConnected_name[48] = "";
2680     bool startConnected = false;
2681 
2682     char connectionType_name[48] = "";
2683     char *connectionType = NULL;
2684 
2685     char addressType_name[48] = "";
2686     char *addressType = NULL;
2687 
2688     char generatedAddress_name[48] = "";
2689     char *generatedAddress = NULL;
2690 
2691     char checkMACAddress_name[48] = "";
2692     char *checkMACAddress = NULL;
2693 
2694     char address_name[48] = "";
2695     char *address = NULL;
2696 
2697     char virtualDev_name[48] = "";
2698     char *virtualDev = NULL;
2699 
2700     char features_name[48] = "";
2701     long long features = 0;
2702 
2703     char vnet_name[48] = "";
2704     char *vnet = NULL;
2705 
2706     char networkName_name[48] = "";
2707     char *networkName = NULL;
2708 
2709     int netmodel = VIR_DOMAIN_NET_MODEL_UNKNOWN;
2710 
2711     if (def == NULL || *def != NULL) {
2712         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2713         return -1;
2714     }
2715 
2716     g_snprintf(prefix, sizeof(prefix), "ethernet%d", controller);
2717 
2718     VMX_BUILD_NAME(present);
2719     VMX_BUILD_NAME(startConnected);
2720     VMX_BUILD_NAME(connectionType);
2721     VMX_BUILD_NAME(addressType);
2722     VMX_BUILD_NAME(generatedAddress);
2723     VMX_BUILD_NAME(checkMACAddress);
2724     VMX_BUILD_NAME(address);
2725     VMX_BUILD_NAME(virtualDev);
2726     VMX_BUILD_NAME(features);
2727     VMX_BUILD_NAME(networkName);
2728     VMX_BUILD_NAME(vnet);
2729 
2730     /* vmx:present */
2731     if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
2732         return -1;
2733 
2734     /* vmx:startConnected */
2735     if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
2736                                true, true) < 0) {
2737         return -1;
2738     }
2739 
2740     /* FIXME: Need to distinguish between active and inactive domains here */
2741     if (! present/* && ! startConnected*/)
2742         return 0;
2743 
2744     *def = g_new0(virDomainNetDef, 1);
2745 
2746     /* vmx:connectionType -> def:type */
2747     if (virVMXGetConfigString(conf, connectionType_name, &connectionType,
2748                               true) < 0) {
2749         goto cleanup;
2750     }
2751 
2752     /* vmx:addressType, vmx:generatedAddress, vmx:address -> def:mac */
2753     if (virVMXGetConfigString(conf, addressType_name, &addressType,
2754                               true) < 0 ||
2755         virVMXGetConfigString(conf, generatedAddress_name, &generatedAddress,
2756                               true) < 0 ||
2757         virVMXGetConfigString(conf, address_name, &address, true) < 0 ||
2758         virVMXGetConfigString(conf, checkMACAddress_name, &checkMACAddress,
2759                               true) < 0) {
2760         goto cleanup;
2761     }
2762 
2763     if (addressType == NULL || STRCASEEQ(addressType, "generated") ||
2764         STRCASEEQ(addressType, "vpx")) {
2765         if (generatedAddress != NULL) {
2766             if (virMacAddrParse(generatedAddress, &(*def)->mac) < 0) {
2767                 virReportError(VIR_ERR_INTERNAL_ERROR,
2768                                _("Expecting VMX entry '%s' to be MAC address but "
2769                                  "found '%s'"), generatedAddress_name,
2770                                generatedAddress);
2771                 goto cleanup;
2772             }
2773         }
2774         if (addressType != NULL)
2775             (*def)->mac_type = VIR_DOMAIN_NET_MAC_TYPE_GENERATED;
2776     } else if (STRCASEEQ(addressType, "static")) {
2777         if (address != NULL) {
2778             if (virMacAddrParse(address, &(*def)->mac) < 0) {
2779                 virReportError(VIR_ERR_INTERNAL_ERROR,
2780                                _("Expecting VMX entry '%s' to be MAC address but "
2781                                  "found '%s'"), address_name, address);
2782                 goto cleanup;
2783             }
2784         }
2785         (*def)->mac_type = VIR_DOMAIN_NET_MAC_TYPE_STATIC;
2786     } else {
2787         virReportError(VIR_ERR_INTERNAL_ERROR,
2788                        _("Expecting VMX entry '%s' to be 'generated' or 'static' or "
2789                          "'vpx' but found '%s'"), addressType_name, addressType);
2790         goto cleanup;
2791     }
2792 
2793     if (checkMACAddress) {
2794         if (STREQ(checkMACAddress, "true")) {
2795             (*def)->mac_check = VIR_TRISTATE_BOOL_YES;
2796         } else {
2797             (*def)->mac_check = VIR_TRISTATE_BOOL_NO;
2798         }
2799     }
2800 
2801     /* vmx:virtualDev, vmx:features -> def:model */
2802     if (virVMXGetConfigString(conf, virtualDev_name, &virtualDev, true) < 0 ||
2803         virVMXGetConfigLong(conf, features_name, &features, 0, true) < 0) {
2804         goto cleanup;
2805     }
2806 
2807     if (virtualDev != NULL) {
2808         if (STRCASEEQ(virtualDev, "vlance")) {
2809             netmodel = VIR_DOMAIN_NET_MODEL_VLANCE;
2810         } else if (STRCASEEQ(virtualDev, "vmxnet")) {
2811             netmodel = VIR_DOMAIN_NET_MODEL_VMXNET;
2812         } else if (STRCASEEQ(virtualDev, "vmxnet3")) {
2813             netmodel = VIR_DOMAIN_NET_MODEL_VMXNET3;
2814         } else if (STRCASEEQ(virtualDev, "e1000")) {
2815             netmodel = VIR_DOMAIN_NET_MODEL_E1000;
2816         } else if (STRCASEEQ(virtualDev, "e1000e")) {
2817             netmodel = VIR_DOMAIN_NET_MODEL_E1000E;
2818         } else {
2819             virReportError(VIR_ERR_INTERNAL_ERROR,
2820                            _("Expecting VMX entry '%s' to be 'vlance' or 'vmxnet' or "
2821                              "'vmxnet3' or 'e1000' or 'e1000e' but found '%s'"),
2822                            virtualDev_name, virtualDev);
2823             goto cleanup;
2824         }
2825 
2826         if (netmodel == VIR_DOMAIN_NET_MODEL_VMXNET && features == 15)
2827             netmodel = VIR_DOMAIN_NET_MODEL_VMXNET2;
2828     }
2829 
2830     /* vmx:networkName -> def:data.bridge.brname */
2831     if (connectionType == NULL ||
2832         STRCASEEQ(connectionType, "bridged") ||
2833         STRCASEEQ(connectionType, "custom")) {
2834         if (virVMXGetConfigString(conf, networkName_name, &networkName,
2835                                   false) < 0)
2836             goto cleanup;
2837     }
2838 
2839     /* vmx:vnet -> def:data.ifname */
2840     if (connectionType != NULL && STRCASEEQ(connectionType, "custom") &&
2841         virVMXGetConfigString(conf, vnet_name, &vnet, false) < 0) {
2842         goto cleanup;
2843     }
2844 
2845     /* Setup virDomainNetDef */
2846     if (connectionType == NULL || STRCASEEQ(connectionType, "bridged")) {
2847         (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
2848         (*def)->data.bridge.brname = g_steal_pointer(&networkName);
2849     } else if (STRCASEEQ(connectionType, "hostonly")) {
2850         /* FIXME */
2851         virReportError(VIR_ERR_INTERNAL_ERROR,
2852                        _("No yet handled value '%s' for VMX entry '%s'"),
2853                        connectionType, connectionType_name);
2854         goto cleanup;
2855     } else if (STRCASEEQ(connectionType, "nat")) {
2856         (*def)->type = VIR_DOMAIN_NET_TYPE_USER;
2857 
2858     } else if (STRCASEEQ(connectionType, "custom")) {
2859         (*def)->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
2860         (*def)->data.bridge.brname = g_steal_pointer(&networkName);
2861         (*def)->ifname = g_steal_pointer(&vnet);
2862     } else {
2863         virReportError(VIR_ERR_INTERNAL_ERROR,
2864                        _("Invalid value '%s' for VMX entry '%s'"), connectionType,
2865                        connectionType_name);
2866         goto cleanup;
2867     }
2868 
2869     (*def)->model = netmodel;
2870     result = 0;
2871 
2872  cleanup:
2873     if (result < 0) {
2874         virDomainNetDefFree(*def);
2875         *def = NULL;
2876     }
2877 
2878     VIR_FREE(networkName);
2879     VIR_FREE(connectionType);
2880     VIR_FREE(addressType);
2881     VIR_FREE(checkMACAddress);
2882     VIR_FREE(generatedAddress);
2883     VIR_FREE(address);
2884     VIR_FREE(virtualDev);
2885     VIR_FREE(vnet);
2886 
2887     return result;
2888 }
2889 
2890 
2891 
2892 static int
virVMXParseSerial(virVMXContext * ctx,virConf * conf,int port,virDomainChrDef ** def)2893 virVMXParseSerial(virVMXContext *ctx, virConf *conf, int port,
2894                   virDomainChrDef **def)
2895 {
2896     int result = -1;
2897     char prefix[48] = "";
2898 
2899     char present_name[48] = "";
2900     bool present = false;
2901 
2902     char startConnected_name[48] = "";
2903     bool startConnected = false;
2904 
2905     char fileType_name[48] = "";
2906     char *fileType = NULL;
2907 
2908     char fileName_name[48] = "";
2909     char *fileName = NULL;
2910 
2911     char network_endPoint_name[48] = "";
2912     char *network_endPoint = NULL;
2913 
2914     virURI *parsedUri = NULL;
2915 
2916     if (def == NULL || *def != NULL) {
2917         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
2918         return -1;
2919     }
2920 
2921     if (port < 0 || port > 3) {
2922         virReportError(VIR_ERR_INTERNAL_ERROR,
2923                        _("Serial port index %d out of [0..3] range"), port);
2924         return -1;
2925     }
2926 
2927     g_snprintf(prefix, sizeof(prefix), "serial%d", port);
2928 
2929     VMX_BUILD_NAME(present);
2930     VMX_BUILD_NAME(startConnected);
2931     VMX_BUILD_NAME(fileType);
2932     VMX_BUILD_NAME(fileName);
2933     VMX_BUILD_NAME_EXTRA(network_endPoint, "network.endPoint");
2934 
2935     /* vmx:present */
2936     if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
2937         return -1;
2938 
2939     /* vmx:startConnected */
2940     if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
2941                                true, true) < 0) {
2942         return -1;
2943     }
2944 
2945     /* FIXME: Need to distinguish between active and inactive domains here */
2946     if (! present/* && ! startConnected*/)
2947         return 0;
2948 
2949     if (!(*def = virDomainChrDefNew(NULL)))
2950         return -1;
2951 
2952     (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
2953 
2954     /* vmx:fileType -> def:type */
2955     if (virVMXGetConfigString(conf, fileType_name, &fileType, true) < 0)
2956         goto cleanup;
2957 
2958     /* vmx:fileName -> def:data.file.path */
2959     if (virVMXGetConfigString(conf, fileName_name, &fileName, true) < 0)
2960         goto cleanup;
2961 
2962     /* vmx:network.endPoint -> def:data.tcp.listen */
2963     if (virVMXGetConfigString(conf, network_endPoint_name, &network_endPoint,
2964                               true) < 0) {
2965         goto cleanup;
2966     }
2967 
2968     /*
2969      * Setup virDomainChrDef. The default fileType is "device", and vmware
2970      * will sometimes omit this tag when adding a new serial port of this
2971      * type.
2972      */
2973     if (!fileType || STRCASEEQ(fileType, "device")) {
2974         (*def)->target.port = port;
2975         (*def)->source->type = VIR_DOMAIN_CHR_TYPE_DEV;
2976         (*def)->source->data.file.path = g_steal_pointer(&fileName);
2977     } else if (STRCASEEQ(fileType, "file")) {
2978         (*def)->target.port = port;
2979         (*def)->source->type = VIR_DOMAIN_CHR_TYPE_FILE;
2980         if (ctx->parseFileName(fileName,
2981                               ctx->opaque,
2982                               &(*def)->source->data.file.path,
2983                               false) < 0)
2984             goto cleanup;
2985     } else if (STRCASEEQ(fileType, "pipe")) {
2986         /*
2987          * FIXME: Differences between client/server and VM/application pipes
2988          *        not representable in domain XML form
2989          */
2990         (*def)->target.port = port;
2991         (*def)->source->type = VIR_DOMAIN_CHR_TYPE_PIPE;
2992         (*def)->source->data.file.path = g_steal_pointer(&fileName);
2993     } else if (STRCASEEQ(fileType, "network")) {
2994         (*def)->target.port = port;
2995         (*def)->source->type = VIR_DOMAIN_CHR_TYPE_TCP;
2996 
2997         if (!(parsedUri = virURIParse(fileName)))
2998             goto cleanup;
2999 
3000         if (parsedUri->port == 0) {
3001             virReportError(VIR_ERR_INTERNAL_ERROR,
3002                            _("VMX entry '%s' doesn't contain a port part"),
3003                            fileName_name);
3004             goto cleanup;
3005         }
3006 
3007         (*def)->source->data.tcp.host = g_strdup(parsedUri->server);
3008 
3009         (*def)->source->data.tcp.service = g_strdup_printf("%d", parsedUri->port);
3010 
3011         /* See vSphere API documentation about VirtualSerialPortURIBackingInfo */
3012         if (parsedUri->scheme == NULL ||
3013             STRCASEEQ(parsedUri->scheme, "tcp") ||
3014             STRCASEEQ(parsedUri->scheme, "tcp4") ||
3015             STRCASEEQ(parsedUri->scheme, "tcp6")) {
3016             (*def)->source->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW;
3017         } else if (STRCASEEQ(parsedUri->scheme, "telnet")) {
3018             (*def)->source->data.tcp.protocol
3019                 = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET;
3020         } else if (STRCASEEQ(parsedUri->scheme, "telnets")) {
3021             (*def)->source->data.tcp.protocol
3022                 = VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS;
3023         } else if (STRCASEEQ(parsedUri->scheme, "ssl") ||
3024                    STRCASEEQ(parsedUri->scheme, "tcp+ssl") ||
3025                    STRCASEEQ(parsedUri->scheme, "tcp4+ssl") ||
3026                    STRCASEEQ(parsedUri->scheme, "tcp6+ssl")) {
3027             (*def)->source->data.tcp.protocol = VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS;
3028         } else {
3029             virReportError(VIR_ERR_INTERNAL_ERROR,
3030                            _("VMX entry '%s' contains unsupported scheme '%s'"),
3031                            fileName_name, parsedUri->scheme);
3032             goto cleanup;
3033         }
3034 
3035         if (network_endPoint == NULL || STRCASEEQ(network_endPoint, "server")) {
3036             (*def)->source->data.tcp.listen = true;
3037         } else if (STRCASEEQ(network_endPoint, "client")) {
3038             (*def)->source->data.tcp.listen = false;
3039         } else {
3040             virReportError(VIR_ERR_INTERNAL_ERROR,
3041                            _("Expecting VMX entry '%s' to be 'server' or 'client' "
3042                              "but found '%s'"), network_endPoint_name, network_endPoint);
3043             goto cleanup;
3044         }
3045     } else {
3046         virReportError(VIR_ERR_INTERNAL_ERROR,
3047                        _("Expecting VMX entry '%s' to be 'device', 'file' or 'pipe' "
3048                          "or 'network' but found '%s'"), fileType_name, fileType);
3049         goto cleanup;
3050     }
3051 
3052     result = 0;
3053 
3054  cleanup:
3055     if (result < 0) {
3056         virDomainChrDefFree(*def);
3057         *def = NULL;
3058     }
3059 
3060     VIR_FREE(fileType);
3061     VIR_FREE(fileName);
3062     VIR_FREE(network_endPoint);
3063     virURIFree(parsedUri);
3064 
3065     return result;
3066 }
3067 
3068 
3069 
3070 static int
virVMXParseParallel(virVMXContext * ctx,virConf * conf,int port,virDomainChrDef ** def)3071 virVMXParseParallel(virVMXContext *ctx, virConf *conf, int port,
3072                     virDomainChrDef **def)
3073 {
3074     int result = -1;
3075     char prefix[48] = "";
3076 
3077     char present_name[48] = "";
3078     bool present = false;
3079 
3080     char startConnected_name[48] = "";
3081     bool startConnected = false;
3082 
3083     char fileType_name[48] = "";
3084     char *fileType = NULL;
3085 
3086     char fileName_name[48] = "";
3087     char *fileName = NULL;
3088 
3089     if (def == NULL || *def != NULL) {
3090         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
3091         return -1;
3092     }
3093 
3094     if (port < 0 || port > 2) {
3095         virReportError(VIR_ERR_INTERNAL_ERROR,
3096                        _("Parallel port index %d out of [0..2] range"), port);
3097         return -1;
3098     }
3099 
3100     g_snprintf(prefix, sizeof(prefix), "parallel%d", port);
3101 
3102     VMX_BUILD_NAME(present);
3103     VMX_BUILD_NAME(startConnected);
3104     VMX_BUILD_NAME(fileType);
3105     VMX_BUILD_NAME(fileName);
3106 
3107     /* vmx:present */
3108     if (virVMXGetConfigBoolean(conf, present_name, &present, false, true) < 0)
3109         return -1;
3110 
3111     /* vmx:startConnected */
3112     if (virVMXGetConfigBoolean(conf, startConnected_name, &startConnected,
3113                                true, true) < 0) {
3114         return -1;
3115     }
3116 
3117     /* FIXME: Need to distinguish between active and inactive domains here */
3118     if (! present/* && ! startConnected*/)
3119         return 0;
3120 
3121     if (!(*def = virDomainChrDefNew(NULL)))
3122         return -1;
3123 
3124     (*def)->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
3125 
3126     /* vmx:fileType -> def:type */
3127     if (virVMXGetConfigString(conf, fileType_name, &fileType, false) < 0)
3128         goto cleanup;
3129 
3130     /* vmx:fileName -> def:data.file.path */
3131     if (virVMXGetConfigString(conf, fileName_name, &fileName, false) < 0)
3132         goto cleanup;
3133 
3134     /* Setup virDomainChrDef */
3135     if (STRCASEEQ(fileType, "device")) {
3136         (*def)->target.port = port;
3137         (*def)->source->type = VIR_DOMAIN_CHR_TYPE_DEV;
3138         (*def)->source->data.file.path = g_steal_pointer(&fileName);
3139     } else if (STRCASEEQ(fileType, "file")) {
3140         (*def)->target.port = port;
3141         (*def)->source->type = VIR_DOMAIN_CHR_TYPE_FILE;
3142         if (ctx->parseFileName(fileName,
3143                               ctx->opaque,
3144                               &(*def)->source->data.file.path,
3145                               false) < 0)
3146             goto cleanup;
3147     } else {
3148         virReportError(VIR_ERR_INTERNAL_ERROR,
3149                        _("Expecting VMX entry '%s' to be 'device' or 'file' but "
3150                          "found '%s'"), fileType_name, fileType);
3151         goto cleanup;
3152     }
3153 
3154     result = 0;
3155 
3156  cleanup:
3157     if (result < 0) {
3158         virDomainChrDefFree(*def);
3159         *def = NULL;
3160     }
3161 
3162     VIR_FREE(fileType);
3163     VIR_FREE(fileName);
3164 
3165     return result;
3166 }
3167 
3168 
3169 
3170 static int
virVMXParseSVGA(virConf * conf,virDomainVideoDef ** def)3171 virVMXParseSVGA(virConf *conf, virDomainVideoDef **def)
3172 {
3173     int result = -1;
3174     long long svga_vramSize = 0;
3175 
3176     if (def == NULL || *def != NULL) {
3177         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
3178         return -1;
3179     }
3180 
3181     *def = g_new0(virDomainVideoDef, 1);
3182     (*def)->type = VIR_DOMAIN_VIDEO_TYPE_VMVGA;
3183 
3184     /* vmx:vramSize */
3185     if (virVMXGetConfigLong(conf, "svga.vramSize", &svga_vramSize,
3186                             4 * 1024 * 1024, true) < 0) {
3187         goto cleanup;
3188     }
3189 
3190     (*def)->vram = VIR_DIV_UP(svga_vramSize, 1024); /* Scale from bytes to kilobytes */
3191 
3192     result = 0;
3193 
3194  cleanup:
3195     if (result < 0) {
3196         virDomainVideoDefFree(*def);
3197         *def = NULL;
3198     }
3199 
3200     return result;
3201 }
3202 
3203 
3204 
3205 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3206  * Domain XML -> VMX
3207  */
3208 
3209 char *
virVMXFormatConfig(virVMXContext * ctx,virDomainXMLOption * xmlopt,virDomainDef * def,int virtualHW_version)3210 virVMXFormatConfig(virVMXContext *ctx, virDomainXMLOption *xmlopt, virDomainDef *def,
3211                    int virtualHW_version)
3212 {
3213     char *vmx = NULL;
3214     size_t i;
3215     int sched_cpu_affinity_length;
3216     unsigned char zero[VIR_UUID_BUFLEN];
3217     g_auto(virBuffer) buffer = VIR_BUFFER_INITIALIZER;
3218     char *preliminaryDisplayName = NULL;
3219     char *displayName = NULL;
3220     char *annotation = NULL;
3221     unsigned long long max_balloon;
3222     bool scsi_present[4] = { false, false, false, false };
3223     int scsi_virtualDev[4] = { -1, -1, -1, -1 };
3224     bool floppy_present[2] = { false, false };
3225     unsigned int maxvcpus;
3226     bool hasSCSI = false;
3227 
3228     if (ctx->formatFileName == NULL) {
3229         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3230                        _("virVMXContext has no formatFileName function set"));
3231         return NULL;
3232     }
3233 
3234     memset(zero, 0, VIR_UUID_BUFLEN);
3235 
3236     if (def->virtType != VIR_DOMAIN_VIRT_VMWARE) {
3237         virReportError(VIR_ERR_INTERNAL_ERROR,
3238                        _("Expecting virt type to be '%s' but found '%s'"),
3239                        virDomainVirtTypeToString(VIR_DOMAIN_VIRT_VMWARE),
3240                        virDomainVirtTypeToString(def->virtType));
3241         return NULL;
3242     }
3243 
3244     /* vmx:.encoding */
3245     virBufferAddLit(&buffer, ".encoding = \"UTF-8\"\n");
3246 
3247     /* vmx:config.version */
3248     virBufferAddLit(&buffer, "config.version = \"8\"\n");
3249 
3250     /* vmx:virtualHW.version */
3251     virBufferAsprintf(&buffer, "virtualHW.version = \"%d\"\n",
3252                       virtualHW_version);
3253 
3254     /* def:os.arch -> vmx:guestOS */
3255     if (def->os.arch == VIR_ARCH_I686) {
3256         virBufferAddLit(&buffer, "guestOS = \"other\"\n");
3257     } else if (def->os.arch == VIR_ARCH_X86_64) {
3258         virBufferAddLit(&buffer, "guestOS = \"other-64\"\n");
3259     } else {
3260         virReportError(VIR_ERR_INTERNAL_ERROR,
3261                        _("Expecting domain XML attribute 'arch' of entry 'os/type' "
3262                          "to be 'i686' or 'x86_64' but found '%s'"),
3263                        virArchToString(def->os.arch));
3264         goto cleanup;
3265     }
3266 
3267     /* def:os.smbios_mode -> vmx:smbios.reflecthost */
3268     if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_NONE ||
3269         def->os.smbios_mode == VIR_DOMAIN_SMBIOS_EMULATE) {
3270         /* nothing */
3271     } else if (def->os.smbios_mode == VIR_DOMAIN_SMBIOS_HOST) {
3272         virBufferAddLit(&buffer, "smbios.reflecthost = \"true\"\n");
3273     } else {
3274         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3275                        _("Unsupported SMBIOS mode '%s'"),
3276                        virDomainSmbiosModeTypeToString(def->os.smbios_mode));
3277         goto cleanup;
3278     }
3279 
3280     /* def:uuid -> vmx:uuid.action, vmx:uuid.bios */
3281     if (memcmp(def->uuid, zero, VIR_UUID_BUFLEN) == 0) {
3282         virBufferAddLit(&buffer, "uuid.action = \"create\"\n");
3283     } else {
3284         virBufferAsprintf(&buffer, "uuid.bios = \"%02x %02x %02x %02x %02x %02x "
3285                           "%02x %02x-%02x %02x %02x %02x %02x %02x %02x %02x\"\n",
3286                           def->uuid[0], def->uuid[1], def->uuid[2], def->uuid[3],
3287                           def->uuid[4], def->uuid[5], def->uuid[6], def->uuid[7],
3288                           def->uuid[8], def->uuid[9], def->uuid[10], def->uuid[11],
3289                           def->uuid[12], def->uuid[13], def->uuid[14],
3290                           def->uuid[15]);
3291     }
3292 
3293     /* def:name -> vmx:displayName */
3294     preliminaryDisplayName = virVMXEscapeHexPipe(def->name);
3295 
3296     if (preliminaryDisplayName == NULL)
3297         goto cleanup;
3298 
3299     displayName = virVMXEscapeHexPercent(preliminaryDisplayName);
3300 
3301     if (displayName == NULL)
3302         goto cleanup;
3303 
3304     virBufferAsprintf(&buffer, "displayName = \"%s\"\n", displayName);
3305 
3306     /* def:description -> vmx:annotation */
3307     if (def->description != NULL) {
3308         if (!(annotation = virVMXEscapeHexPipe(def->description)))
3309             goto cleanup;
3310 
3311         virBufferAsprintf(&buffer, "annotation = \"%s\"\n", annotation);
3312     }
3313 
3314     /* def:mem.max_balloon -> vmx:memsize */
3315     /* max-memory must be a multiple of 4096 kilobyte */
3316     max_balloon = VIR_DIV_UP(virDomainDefGetMemoryTotal(def), 4096) * 4096;
3317 
3318     virBufferAsprintf(&buffer, "memsize = \"%llu\"\n",
3319                       max_balloon / 1024); /* Scale from kilobytes to megabytes */
3320 
3321     /* def:mem.cur_balloon -> vmx:sched.mem.max */
3322     if (def->mem.cur_balloon < max_balloon) {
3323         virBufferAsprintf(&buffer, "sched.mem.max = \"%llu\"\n",
3324                           VIR_DIV_UP(def->mem.cur_balloon,
3325                                      1024)); /* Scale from kilobytes to megabytes */
3326     }
3327 
3328     /* def:mem.min_guarantee -> vmx:sched.mem.minsize */
3329     if (def->mem.min_guarantee > 0) {
3330         virBufferAsprintf(&buffer, "sched.mem.minsize = \"%llu\"\n",
3331                           VIR_DIV_UP(def->mem.min_guarantee,
3332                                      1024)); /* Scale from kilobytes to megabytes */
3333     }
3334 
3335     /* def:maxvcpus -> vmx:numvcpus */
3336     if (virDomainDefHasVcpusOffline(def)) {
3337         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3338                        _("No support for domain XML entry 'vcpu' attribute "
3339                          "'current'"));
3340         goto cleanup;
3341     }
3342     maxvcpus = virDomainDefGetVcpusMax(def);
3343     if (maxvcpus == 0) {
3344         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3345                        _("Expecting domain XML entry 'vcpu' to be greater "
3346                          "than 0"));
3347         goto cleanup;
3348     }
3349 
3350     virBufferAsprintf(&buffer, "numvcpus = \"%d\"\n", maxvcpus);
3351 
3352     if (def->cpu) {
3353         unsigned int calculated_vcpus;
3354 
3355         if (def->cpu->mode != VIR_CPU_MODE_CUSTOM) {
3356             virReportError(VIR_ERR_INTERNAL_ERROR,
3357                            _("Expecting domain XML CPU mode 'custom' but "
3358                              "found '%s'"),
3359                            virCPUModeTypeToString(def->cpu->mode));
3360             goto cleanup;
3361         }
3362 
3363         if (def->cpu->threads != 1) {
3364             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3365                            _("Only 1 thread per core is supported"));
3366             goto cleanup;
3367         }
3368 
3369         if (def->cpu->dies != 1) {
3370             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
3371                            _("Only 1 die per socket is supported"));
3372             goto cleanup;
3373         }
3374 
3375         calculated_vcpus = def->cpu->sockets * def->cpu->cores;
3376         if (calculated_vcpus != maxvcpus) {
3377             virReportError(VIR_ERR_INTERNAL_ERROR,
3378                            _("Expecting domain XML CPU sockets per core as %d "
3379                              "but found %d"),
3380                            maxvcpus, calculated_vcpus);
3381             goto cleanup;
3382         }
3383 
3384         virBufferAsprintf(&buffer, "cpuid.coresPerSocket = \"%d\"\n", def->cpu->cores);
3385     }
3386 
3387     /* def:cpumask -> vmx:sched.cpu.affinity */
3388     if (def->cpumask && virBitmapSize(def->cpumask) > 0) {
3389         int bit;
3390         virBufferAddLit(&buffer, "sched.cpu.affinity = \"");
3391 
3392         sched_cpu_affinity_length = 0;
3393 
3394         bit = -1;
3395         while ((bit = virBitmapNextSetBit(def->cpumask, bit)) >= 0)
3396             ++sched_cpu_affinity_length;
3397 
3398         if (sched_cpu_affinity_length < maxvcpus) {
3399             virReportError(VIR_ERR_INTERNAL_ERROR,
3400                            _("Expecting domain XML attribute 'cpuset' of entry "
3401                              "'vcpu' to contain at least %d CPU(s)"),
3402                            maxvcpus);
3403             goto cleanup;
3404         }
3405 
3406         bit = -1;
3407         while ((bit = virBitmapNextSetBit(def->cpumask, bit)) >= 0) {
3408             virBufferAsprintf(&buffer, "%d", bit);
3409 
3410             if (sched_cpu_affinity_length > 1)
3411                 virBufferAddChar(&buffer, ',');
3412 
3413             --sched_cpu_affinity_length;
3414         }
3415 
3416         virBufferAddLit(&buffer, "\"\n");
3417     }
3418 
3419     /* def:cputune.shares -> vmx:sched.cpu.shares */
3420     if (def->cputune.sharesSpecified) {
3421         unsigned int vcpus = virDomainDefGetVcpus(def);
3422         /* See https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.SharesInfo.Level.html */
3423         if (def->cputune.shares == vcpus * 500) {
3424             virBufferAddLit(&buffer, "sched.cpu.shares = \"low\"\n");
3425         } else if (def->cputune.shares == vcpus * 1000) {
3426             virBufferAddLit(&buffer, "sched.cpu.shares = \"normal\"\n");
3427         } else if (def->cputune.shares == vcpus * 2000) {
3428             virBufferAddLit(&buffer, "sched.cpu.shares = \"high\"\n");
3429         } else {
3430             virBufferAsprintf(&buffer, "sched.cpu.shares = \"%llu\"\n",
3431                               def->cputune.shares);
3432         }
3433     }
3434 
3435     /* def:graphics */
3436     for (i = 0; i < def->ngraphics; ++i) {
3437         switch (def->graphics[i]->type) {
3438           case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
3439             if (virVMXFormatVNC(def->graphics[i], &buffer) < 0)
3440                 goto cleanup;
3441 
3442             break;
3443 
3444           case VIR_DOMAIN_GRAPHICS_TYPE_SDL:
3445           case VIR_DOMAIN_GRAPHICS_TYPE_RDP:
3446           case VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP:
3447           case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
3448           case VIR_DOMAIN_GRAPHICS_TYPE_EGL_HEADLESS:
3449             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3450                            _("Unsupported graphics type '%s'"),
3451                            virDomainGraphicsTypeToString(def->graphics[i]->type));
3452             goto cleanup;
3453 
3454           case VIR_DOMAIN_GRAPHICS_TYPE_LAST:
3455           default:
3456               virReportEnumRangeError(virDomainGraphicsType, def->graphics[i]->type);
3457               goto cleanup;
3458         }
3459     }
3460 
3461     /* def:disks */
3462     for (i = 0; i < def->ndisks; ++i) {
3463         if (virVMXVerifyDiskAddress(xmlopt, def->disks[i], def) < 0 ||
3464             virVMXHandleLegacySCSIDiskDriverName(def, def->disks[i]) < 0) {
3465             goto cleanup;
3466         }
3467     }
3468 
3469     if (virVMXGatherSCSIControllers(ctx, def, scsi_virtualDev,
3470                                     scsi_present) < 0) {
3471         goto cleanup;
3472     }
3473 
3474     for (i = 0; i < 4; ++i) {
3475         if (scsi_present[i]) {
3476             hasSCSI = true;
3477 
3478             virBufferAsprintf(&buffer, "scsi%zu.present = \"true\"\n", i);
3479 
3480             if (scsi_virtualDev[i] != -1) {
3481                 virBufferAsprintf(&buffer, "scsi%zu.virtualDev = \"%s\"\n", i,
3482                                   virVMXControllerModelSCSITypeToString
3483                                     (scsi_virtualDev[i]));
3484             }
3485         }
3486     }
3487 
3488     for (i = 0; i < def->ndisks; ++i) {
3489         switch (def->disks[i]->device) {
3490           case VIR_DOMAIN_DISK_DEVICE_DISK:
3491           case VIR_DOMAIN_DISK_DEVICE_CDROM:
3492           case VIR_DOMAIN_DISK_DEVICE_LUN:
3493             if (virVMXFormatDisk(ctx, def->disks[i], &buffer) < 0)
3494                 goto cleanup;
3495 
3496             break;
3497 
3498           case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
3499             if (virVMXFormatFloppy(ctx, def->disks[i], &buffer,
3500                                    floppy_present) < 0) {
3501                 goto cleanup;
3502             }
3503 
3504             break;
3505 
3506           case VIR_DOMAIN_DISK_DEVICE_LAST:
3507           default:
3508             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3509                            _("Unsupported disk device type '%s'"),
3510                            virDomainDiskDeviceTypeToString(def->disks[i]->device));
3511             goto cleanup;
3512         }
3513     }
3514 
3515     for (i = 0; i < 2; ++i) {
3516         /* floppy[0..1].present defaults to true, disable it explicitly */
3517         if (! floppy_present[i])
3518             virBufferAsprintf(&buffer, "floppy%zu.present = \"false\"\n", i);
3519     }
3520 
3521     /* def:fss */
3522     if (def->nfss > 0) {
3523         virBufferAddLit(&buffer, "isolation.tools.hgfs.disable = \"false\"\n");
3524         virBufferAsprintf(&buffer, "sharedFolder.maxNum = \"%zu\"\n", def->nfss);
3525     }
3526 
3527     for (i = 0; i < def->nfss; ++i) {
3528         if (virVMXFormatFileSystem(def->fss[i], i, &buffer) < 0)
3529             goto cleanup;
3530     }
3531 
3532     /* def:nets */
3533     for (i = 0; i < def->nnets; ++i) {
3534         if (virVMXFormatEthernet(def->nets[i], i, &buffer, virtualHW_version) < 0)
3535             goto cleanup;
3536     }
3537 
3538     /* def:inputs */
3539     /* FIXME */
3540 
3541     /* def:sounds */
3542     /* FIXME */
3543 
3544     /* def:videos */
3545     if (def->nvideos > 0) {
3546         if (def->nvideos > 1) {
3547             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3548                            _("No support for multiple video devices"));
3549             goto cleanup;
3550         }
3551 
3552         if (virVMXFormatSVGA(def->videos[0], &buffer) < 0)
3553             goto cleanup;
3554     }
3555 
3556     /* def:hostdevs */
3557     /* FIXME */
3558 
3559     /* def:serials */
3560     for (i = 0; i < def->nserials; ++i) {
3561         if (virVMXFormatSerial(ctx, def->serials[i], &buffer) < 0)
3562             goto cleanup;
3563     }
3564 
3565     /* def:parallels */
3566     for (i = 0; i < def->nparallels; ++i) {
3567         if (virVMXFormatParallel(ctx, def->parallels[i], &buffer) < 0)
3568             goto cleanup;
3569     }
3570 
3571     /* vmx:firmware */
3572     if (def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_EFI)
3573         virBufferAddLit(&buffer, "firmware = \"efi\"\n");
3574 
3575     if (virtualHW_version >= 7) {
3576         if (hasSCSI) {
3577             virBufferAddLit(&buffer, "pciBridge0.present = \"true\"\n");
3578 
3579             virBufferAddLit(&buffer, "pciBridge4.present = \"true\"\n");
3580             virBufferAddLit(&buffer, "pciBridge4.virtualDev = \"pcieRootPort\"\n");
3581             virBufferAddLit(&buffer, "pciBridge4.functions = \"8\"\n");
3582 
3583             virBufferAddLit(&buffer, "pciBridge5.present = \"true\"\n");
3584             virBufferAddLit(&buffer, "pciBridge5.virtualDev = \"pcieRootPort\"\n");
3585             virBufferAddLit(&buffer, "pciBridge5.functions = \"8\"\n");
3586 
3587             virBufferAddLit(&buffer, "pciBridge6.present = \"true\"\n");
3588             virBufferAddLit(&buffer, "pciBridge6.virtualDev = \"pcieRootPort\"\n");
3589             virBufferAddLit(&buffer, "pciBridge6.functions = \"8\"\n");
3590 
3591             virBufferAddLit(&buffer, "pciBridge7.present = \"true\"\n");
3592             virBufferAddLit(&buffer, "pciBridge7.virtualDev = \"pcieRootPort\"\n");
3593             virBufferAddLit(&buffer, "pciBridge7.functions = \"8\"\n");
3594         }
3595 
3596         virBufferAddLit(&buffer, "vmci0.present = \"true\"\n");
3597     }
3598 
3599     /* Get final VMX output */
3600     vmx = virBufferContentAndReset(&buffer);
3601 
3602  cleanup:
3603     VIR_FREE(preliminaryDisplayName);
3604     VIR_FREE(displayName);
3605     VIR_FREE(annotation);
3606 
3607     return vmx;
3608 }
3609 
3610 
3611 
3612 static int
virVMXFormatVNC(virDomainGraphicsDef * def,virBuffer * buffer)3613 virVMXFormatVNC(virDomainGraphicsDef *def, virBuffer *buffer)
3614 {
3615     virDomainGraphicsListenDef *glisten;
3616 
3617     if (def->type != VIR_DOMAIN_GRAPHICS_TYPE_VNC) {
3618         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
3619         return -1;
3620     }
3621 
3622     virBufferAddLit(buffer, "RemoteDisplay.vnc.enabled = \"true\"\n");
3623 
3624     if (def->data.vnc.autoport) {
3625         VIR_WARN("VNC autoport is enabled, but the automatically assigned "
3626                   "VNC port cannot be read back");
3627     } else {
3628         if (def->data.vnc.port < 5900 || def->data.vnc.port > 5964) {
3629             VIR_WARN("VNC port %d it out of [5900..5964] range",
3630                      def->data.vnc.port);
3631         }
3632 
3633         virBufferAsprintf(buffer, "RemoteDisplay.vnc.port = \"%d\"\n",
3634                           def->data.vnc.port);
3635     }
3636 
3637     if ((glisten = virDomainGraphicsGetListen(def, 0)) &&
3638         glisten->address) {
3639         virBufferAsprintf(buffer, "RemoteDisplay.vnc.ip = \"%s\"\n",
3640                           glisten->address);
3641     }
3642 
3643     if (def->data.vnc.keymap != NULL) {
3644         virBufferAsprintf(buffer, "RemoteDisplay.vnc.keymap = \"%s\"\n",
3645                           def->data.vnc.keymap);
3646     }
3647 
3648     if (def->data.vnc.auth.passwd != NULL) {
3649         virBufferAsprintf(buffer, "RemoteDisplay.vnc.password = \"%s\"\n",
3650                           def->data.vnc.auth.passwd);
3651     }
3652 
3653     return 0;
3654 }
3655 
3656 static int
virVMXFormatDisk(virVMXContext * ctx,virDomainDiskDef * def,virBuffer * buffer)3657 virVMXFormatDisk(virVMXContext *ctx, virDomainDiskDef *def,
3658                  virBuffer *buffer)
3659 {
3660     int controllerOrBus, unit;
3661     const char *vmxDeviceType = NULL;
3662     char *fileName = NULL;
3663     int type = virDomainDiskGetType(def);
3664 
3665     /* Convert a handful of types to their string values */
3666     const char *busType = virDomainDiskBusTypeToString(def->bus);
3667     const char *deviceType = virDomainDeviceTypeToString(def->device);
3668     const char *diskType = virDomainDeviceTypeToString(type);
3669 
3670     /* If we are dealing with a disk its a .vmdk, otherwise it must be
3671      * an ISO.
3672      */
3673     const char *fileExt = (def->device == VIR_DOMAIN_DISK_DEVICE_DISK) ?
3674                            ".vmdk" : ".iso";
3675 
3676     /* Check that we got a valid device type */
3677     if (def->device != VIR_DOMAIN_DISK_DEVICE_DISK &&
3678         def->device != VIR_DOMAIN_DISK_DEVICE_CDROM &&
3679         def->device != VIR_DOMAIN_DISK_DEVICE_LUN) {
3680         virReportError(VIR_ERR_INTERNAL_ERROR,
3681                        _("Invalid device type supplied: %s"), deviceType);
3682         return -1;
3683     }
3684 
3685     /* We only support type='file' and type='block' */
3686     if (type != VIR_STORAGE_TYPE_FILE &&
3687         type != VIR_STORAGE_TYPE_BLOCK) {
3688         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3689                        _("%s %s '%s' has unsupported type '%s', expecting "
3690                          "'%s' or '%s'"), busType, deviceType, def->dst,
3691                        diskType,
3692                        virStorageTypeToString(VIR_STORAGE_TYPE_FILE),
3693                        virStorageTypeToString(VIR_STORAGE_TYPE_BLOCK));
3694         return -1;
3695     }
3696 
3697     if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
3698         if (virVMXSCSIDiskNameToControllerAndUnit(def->dst, &controllerOrBus,
3699                                                   &unit) < 0) {
3700             return -1;
3701         }
3702     } else if (def->bus == VIR_DOMAIN_DISK_BUS_IDE) {
3703         if (virVMXIDEDiskNameToBusAndUnit(def->dst, &controllerOrBus,
3704                                           &unit) < 0) {
3705             return -1;
3706         }
3707     } else {
3708         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3709                        _("Unsupported bus type '%s' for %s"),
3710                        busType, deviceType);
3711         return -1;
3712     }
3713 
3714     if (def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
3715         type == VIR_STORAGE_TYPE_FILE) {
3716         vmxDeviceType = (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) ?
3717                         "scsi-hardDisk" : "ata-hardDisk";
3718     } else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
3719         if (type == VIR_STORAGE_TYPE_FILE)
3720             vmxDeviceType = "cdrom-image";
3721         else
3722             vmxDeviceType = "atapi-cdrom";
3723     } else if (def->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
3724         const char *src = virDomainDiskGetSource(def);
3725 
3726         if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI &&
3727             src && STRPREFIX(src, "/vmfs/devices/cdrom/"))
3728             vmxDeviceType = "scsi-passthru";
3729         else
3730             vmxDeviceType = "cdrom-raw";
3731     } else {
3732         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3733                        _("%s %s '%s' has an unsupported type '%s'"),
3734                        busType, deviceType, def->dst, diskType);
3735         return -1;
3736     }
3737 
3738     virBufferAsprintf(buffer, "%s%d:%d.present = \"true\"\n",
3739                       busType, controllerOrBus, unit);
3740     virBufferAsprintf(buffer, "%s%d:%d.deviceType = \"%s\"\n",
3741                       busType, controllerOrBus, unit, vmxDeviceType);
3742 
3743     if (type == VIR_STORAGE_TYPE_FILE) {
3744         const char *src = virDomainDiskGetSource(def);
3745 
3746         if (src) {
3747             if (!virStringHasCaseSuffix(src, fileExt)) {
3748                 virReportError(VIR_ERR_INTERNAL_ERROR,
3749                                _("Image file for %s %s '%s' has "
3750                                  "unsupported suffix, expecting '%s'"),
3751                                busType, deviceType, def->dst, fileExt);
3752                 return -1;
3753             }
3754 
3755             fileName = ctx->formatFileName(src, ctx->opaque);
3756         } else if (def->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
3757             fileName = g_strdup("emptyBackingString");
3758         }
3759 
3760         if (fileName == NULL)
3761             return -1;
3762 
3763         virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3764                           busType, controllerOrBus, unit, fileName);
3765 
3766         VIR_FREE(fileName);
3767     } else if (type == VIR_STORAGE_TYPE_BLOCK) {
3768         const char *src = virDomainDiskGetSource(def);
3769 
3770         if (!src &&
3771             def->startupPolicy == VIR_DOMAIN_STARTUP_POLICY_OPTIONAL) {
3772             virBufferAsprintf(buffer, "%s%d:%d.autodetect = \"true\"\n",
3773                               busType, controllerOrBus, unit);
3774             virBufferAsprintf(buffer, "%s%d:%d.fileName = \"auto detect\"\n",
3775                               busType, controllerOrBus, unit);
3776         } else {
3777             virBufferAsprintf(buffer, "%s%d:%d.fileName = \"%s\"\n",
3778                               busType, controllerOrBus, unit, src);
3779         }
3780     }
3781 
3782     if (def->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
3783         if (def->cachemode == VIR_DOMAIN_DISK_CACHE_WRITETHRU) {
3784             virBufferAsprintf(buffer, "%s%d:%d.writeThrough = \"true\"\n",
3785                               busType, controllerOrBus, unit);
3786         } else if (def->cachemode != VIR_DOMAIN_DISK_CACHE_DEFAULT) {
3787             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3788                            _("%s harddisk '%s' has unsupported cache mode '%s'"),
3789                            busType, def->dst,
3790                            virDomainDiskCacheTypeToString(def->cachemode));
3791             return -1;
3792         }
3793     }
3794 
3795     if (def->transient)
3796         virBufferAsprintf(buffer,
3797                           "%s%d:%d.mode = \"independent-nonpersistent\"\n",
3798                           busType, controllerOrBus, unit);
3799 
3800     return 0;
3801 }
3802 
3803 static int
virVMXFormatFloppy(virVMXContext * ctx,virDomainDiskDef * def,virBuffer * buffer,bool floppy_present[2])3804 virVMXFormatFloppy(virVMXContext *ctx, virDomainDiskDef *def,
3805                    virBuffer *buffer, bool floppy_present[2])
3806 {
3807     int unit;
3808     char *fileName = NULL;
3809     int type = virDomainDiskGetType(def);
3810     const char *src = virDomainDiskGetSource(def);
3811 
3812     if (def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
3813         virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid argument"));
3814         return -1;
3815     }
3816 
3817     if (virVMXFloppyDiskNameToUnit(def->dst, &unit) < 0)
3818         return -1;
3819 
3820     floppy_present[unit] = true;
3821 
3822     virBufferAsprintf(buffer, "floppy%d.present = \"true\"\n", unit);
3823 
3824     if (type == VIR_STORAGE_TYPE_FILE) {
3825         virBufferAsprintf(buffer, "floppy%d.fileType = \"file\"\n", unit);
3826 
3827         if (src) {
3828             fileName = ctx->formatFileName(src, ctx->opaque);
3829 
3830             if (fileName == NULL)
3831                 return -1;
3832 
3833             virBufferAsprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3834                               unit, fileName);
3835 
3836             VIR_FREE(fileName);
3837         }
3838     } else if (type == VIR_STORAGE_TYPE_BLOCK) {
3839         virBufferAsprintf(buffer, "floppy%d.fileType = \"device\"\n", unit);
3840 
3841         if (src) {
3842             virBufferAsprintf(buffer, "floppy%d.fileName = \"%s\"\n",
3843                               unit, src);
3844         }
3845     } else {
3846         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3847                        _("Floppy '%s' has unsupported type '%s', expecting '%s' "
3848                          "or '%s'"), def->dst,
3849                        virStorageTypeToString(type),
3850                        virStorageTypeToString(VIR_STORAGE_TYPE_FILE),
3851                        virStorageTypeToString(VIR_STORAGE_TYPE_BLOCK));
3852         return -1;
3853     }
3854 
3855     return 0;
3856 }
3857 
3858 
3859 
3860 static int
virVMXFormatFileSystem(virDomainFSDef * def,int number,virBuffer * buffer)3861 virVMXFormatFileSystem(virDomainFSDef *def, int number, virBuffer *buffer)
3862 {
3863     if (def->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
3864         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
3865                        _("Only '%s' filesystem type is supported"),
3866                        virDomainFSTypeToString(VIR_DOMAIN_FS_TYPE_MOUNT));
3867         return -1;
3868     }
3869 
3870     virBufferAsprintf(buffer, "sharedFolder%d.present = \"true\"\n", number);
3871     virBufferAsprintf(buffer, "sharedFolder%d.enabled = \"true\"\n", number);
3872     virBufferAsprintf(buffer, "sharedFolder%d.readAccess = \"true\"\n", number);
3873     virBufferAsprintf(buffer, "sharedFolder%d.writeAccess = \"%s\"\n", number,
3874                       def->readonly ? "false" : "true");
3875     virBufferAsprintf(buffer, "sharedFolder%d.hostPath = \"%s\"\n", number,
3876                       def->src->path);
3877     virBufferAsprintf(buffer, "sharedFolder%d.guestName = \"%s\"\n", number,
3878                       def->dst);
3879 
3880     return 0;
3881 }
3882 
3883 
3884 
3885 static int
virVMXFormatEthernet(virDomainNetDef * def,int controller,virBuffer * buffer,int virtualHW_version)3886 virVMXFormatEthernet(virDomainNetDef *def, int controller,
3887                      virBuffer *buffer, int virtualHW_version)
3888 {
3889     char mac_string[VIR_MAC_STRING_BUFLEN];
3890     virDomainNetMacType mac_type = VIR_DOMAIN_NET_MAC_TYPE_DEFAULT;
3891     virTristateBool mac_check = VIR_TRISTATE_BOOL_ABSENT;
3892     bool mac_vpx = false;
3893     unsigned int prefix, suffix;
3894 
3895     /*
3896      * Machines older than virtualHW.version = 7 (ESXi 4.0) only support up to 4
3897      * virtual NICs. New machines support up to 10.
3898      */
3899     int controller_limit = 3;
3900     if (virtualHW_version >= 7)
3901         controller_limit = 9;
3902 
3903     if (controller < 0 || controller > controller_limit) {
3904         virReportError(VIR_ERR_INTERNAL_ERROR,
3905                        _("Ethernet controller index %d out of [0..%d] range"),
3906                        controller, controller_limit);
3907         return -1;
3908     }
3909 
3910     virBufferAsprintf(buffer, "ethernet%d.present = \"true\"\n", controller);
3911 
3912     /* def:model -> vmx:virtualDev, vmx:features */
3913     if (def->model) {
3914         if (def->model != VIR_DOMAIN_NET_MODEL_VLANCE &&
3915             def->model != VIR_DOMAIN_NET_MODEL_VMXNET &&
3916             def->model != VIR_DOMAIN_NET_MODEL_VMXNET2 &&
3917             def->model != VIR_DOMAIN_NET_MODEL_VMXNET3 &&
3918             def->model != VIR_DOMAIN_NET_MODEL_E1000 &&
3919             def->model != VIR_DOMAIN_NET_MODEL_E1000E) {
3920             virReportError(VIR_ERR_INTERNAL_ERROR,
3921                            _("Expecting domain XML entry 'devices/interface/model' "
3922                              "to be 'vlance' or 'vmxnet' or 'vmxnet2' or 'vmxnet3' "
3923                              "or 'e1000' or 'e1000e' but found '%s'"),
3924                             virDomainNetModelTypeToString(def->model));
3925             return -1;
3926         }
3927 
3928         if (def->model == VIR_DOMAIN_NET_MODEL_VMXNET2) {
3929             virBufferAsprintf(buffer, "ethernet%d.virtualDev = \"vmxnet\"\n",
3930                               controller);
3931             virBufferAsprintf(buffer, "ethernet%d.features = \"15\"\n",
3932                               controller);
3933         } else {
3934             virBufferAsprintf(buffer, "ethernet%d.virtualDev = \"%s\"\n",
3935                               controller,
3936                               virDomainNetModelTypeToString(def->model));
3937         }
3938     }
3939 
3940     /* def:type, def:ifname -> vmx:connectionType */
3941     switch (def->type) {
3942       case VIR_DOMAIN_NET_TYPE_BRIDGE:
3943         virBufferAsprintf(buffer, "ethernet%d.networkName = \"%s\"\n",
3944                           controller, def->data.bridge.brname);
3945 
3946         if (def->ifname != NULL) {
3947             virBufferAsprintf(buffer, "ethernet%d.connectionType = \"custom\"\n",
3948                               controller);
3949             virBufferAsprintf(buffer, "ethernet%d.vnet = \"%s\"\n",
3950                               controller, def->ifname);
3951         } else {
3952             virBufferAsprintf(buffer, "ethernet%d.connectionType = \"bridged\"\n",
3953                               controller);
3954         }
3955 
3956         break;
3957 
3958       case VIR_DOMAIN_NET_TYPE_USER:
3959         virBufferAsprintf(buffer, "ethernet%d.connectionType = \"nat\"\n",
3960                           controller);
3961         break;
3962 
3963       case VIR_DOMAIN_NET_TYPE_ETHERNET:
3964       case VIR_DOMAIN_NET_TYPE_VHOSTUSER:
3965       case VIR_DOMAIN_NET_TYPE_SERVER:
3966       case VIR_DOMAIN_NET_TYPE_CLIENT:
3967       case VIR_DOMAIN_NET_TYPE_MCAST:
3968       case VIR_DOMAIN_NET_TYPE_NETWORK:
3969       case VIR_DOMAIN_NET_TYPE_INTERNAL:
3970       case VIR_DOMAIN_NET_TYPE_DIRECT:
3971       case VIR_DOMAIN_NET_TYPE_HOSTDEV:
3972       case VIR_DOMAIN_NET_TYPE_UDP:
3973       case VIR_DOMAIN_NET_TYPE_VDPA:
3974         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("Unsupported net type '%s'"),
3975                        virDomainNetTypeToString(def->type));
3976         return -1;
3977 
3978       case VIR_DOMAIN_NET_TYPE_LAST:
3979       default:
3980           virReportEnumRangeError(virDomainNetType, def->type);
3981           return -1;
3982     }
3983 
3984     /* def:mac -> vmx:addressType, vmx:(generated)Address, vmx:checkMACAddress */
3985     virMacAddrFormat(&def->mac, mac_string);
3986 
3987     prefix = (def->mac.addr[0] << 16) | (def->mac.addr[1] << 8) | def->mac.addr[2];
3988     suffix = (def->mac.addr[3] << 16) | (def->mac.addr[4] << 8) | def->mac.addr[5];
3989 
3990     /*
3991      * Historically we've not stored all the MAC related properties
3992      * explicitly in the XML, so we must figure out some defaults
3993      * based on the address ranges.
3994      */
3995     if (prefix == 0x000c29) {
3996         mac_type = VIR_DOMAIN_NET_MAC_TYPE_GENERATED;
3997     } else if (prefix == 0x005056 && suffix <= 0x3fffff) {
3998         mac_type = VIR_DOMAIN_NET_MAC_TYPE_STATIC;
3999     } else if (prefix == 0x005056 && suffix >= 0x800000 && suffix <= 0xbfffff) {
4000         mac_type = VIR_DOMAIN_NET_MAC_TYPE_GENERATED;
4001         mac_vpx = true;
4002     } else {
4003         mac_type = VIR_DOMAIN_NET_MAC_TYPE_STATIC;
4004         mac_check = VIR_TRISTATE_BOOL_NO;
4005     }
4006 
4007     /* If explicit MAC type is set, ignore the above defaults */
4008     if (def->mac_type != VIR_DOMAIN_NET_MAC_TYPE_DEFAULT) {
4009         mac_type = def->mac_type;
4010         if (mac_type == VIR_DOMAIN_NET_MAC_TYPE_GENERATED)
4011             mac_check = VIR_TRISTATE_BOOL_ABSENT;
4012     }
4013 
4014     if (def->mac_check != VIR_TRISTATE_BOOL_ABSENT)
4015         mac_check = def->mac_check;
4016 
4017     if (mac_type == VIR_DOMAIN_NET_MAC_TYPE_GENERATED) {
4018         virBufferAsprintf(buffer, "ethernet%d.addressType = \"%s\"\n",
4019                           controller, mac_vpx ? "vpx" : "generated");
4020         virBufferAsprintf(buffer, "ethernet%d.generatedAddress = \"%s\"\n",
4021                           controller, mac_string);
4022         if (!mac_vpx)
4023             virBufferAsprintf(buffer, "ethernet%d.generatedAddressOffset = \"0\"\n",
4024                               controller);
4025     } else {
4026         virBufferAsprintf(buffer, "ethernet%d.addressType = \"static\"\n",
4027                           controller);
4028         virBufferAsprintf(buffer, "ethernet%d.address = \"%s\"\n",
4029                           controller, mac_string);
4030     }
4031     if (mac_check != VIR_TRISTATE_BOOL_ABSENT)
4032         virBufferAsprintf(buffer, "ethernet%d.checkMACAddress = \"%s\"\n",
4033                           controller,
4034                           mac_check == VIR_TRISTATE_BOOL_YES ? "true" : "false");
4035 
4036     return 0;
4037 }
4038 
4039 
4040 
4041 static int
virVMXFormatSerial(virVMXContext * ctx,virDomainChrDef * def,virBuffer * buffer)4042 virVMXFormatSerial(virVMXContext *ctx, virDomainChrDef *def,
4043                    virBuffer *buffer)
4044 {
4045     char *fileName = NULL;
4046     const char *protocol;
4047 
4048     if (def->target.port < 0 || def->target.port > 3) {
4049         virReportError(VIR_ERR_INTERNAL_ERROR,
4050                        _("Serial port index %d out of [0..3] range"),
4051                        def->target.port);
4052         return -1;
4053     }
4054 
4055     virBufferAsprintf(buffer, "serial%d.present = \"true\"\n", def->target.port);
4056 
4057     /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
4058     switch (def->source->type) {
4059       case VIR_DOMAIN_CHR_TYPE_DEV:
4060         virBufferAsprintf(buffer, "serial%d.fileType = \"device\"\n",
4061                           def->target.port);
4062         virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
4063                           def->target.port, def->source->data.file.path);
4064         break;
4065 
4066       case VIR_DOMAIN_CHR_TYPE_FILE:
4067         virBufferAsprintf(buffer, "serial%d.fileType = \"file\"\n",
4068                           def->target.port);
4069 
4070         fileName = ctx->formatFileName(def->source->data.file.path, ctx->opaque);
4071 
4072         if (fileName == NULL)
4073             return -1;
4074 
4075         virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
4076                           def->target.port, fileName);
4077 
4078         VIR_FREE(fileName);
4079         break;
4080 
4081       case VIR_DOMAIN_CHR_TYPE_PIPE:
4082         virBufferAsprintf(buffer, "serial%d.fileType = \"pipe\"\n",
4083                           def->target.port);
4084         /* FIXME: Based on VI Client GUI default */
4085         virBufferAsprintf(buffer, "serial%d.pipe.endPoint = \"client\"\n",
4086                           def->target.port);
4087         /* FIXME: Based on VI Client GUI default */
4088         virBufferAsprintf(buffer, "serial%d.tryNoRxLoss = \"false\"\n",
4089                           def->target.port);
4090         virBufferAsprintf(buffer, "serial%d.fileName = \"%s\"\n",
4091                           def->target.port, def->source->data.file.path);
4092         break;
4093 
4094       case VIR_DOMAIN_CHR_TYPE_TCP:
4095         switch (def->source->data.tcp.protocol) {
4096           case VIR_DOMAIN_CHR_TCP_PROTOCOL_RAW:
4097             protocol = "tcp";
4098             break;
4099 
4100           case VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNET:
4101             protocol = "telnet";
4102             break;
4103 
4104           case VIR_DOMAIN_CHR_TCP_PROTOCOL_TELNETS:
4105             protocol = "telnets";
4106             break;
4107 
4108           case VIR_DOMAIN_CHR_TCP_PROTOCOL_TLS:
4109             protocol = "ssl";
4110             break;
4111 
4112           default:
4113             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4114                            _("Unsupported character device TCP protocol '%s'"),
4115                            virDomainChrTcpProtocolTypeToString(
4116                                def->source->data.tcp.protocol));
4117             return -1;
4118         }
4119 
4120         virBufferAsprintf(buffer, "serial%d.fileType = \"network\"\n",
4121                           def->target.port);
4122         virBufferAsprintf(buffer, "serial%d.fileName = \"%s://%s:%s\"\n",
4123                           def->target.port, protocol, def->source->data.tcp.host,
4124                           def->source->data.tcp.service);
4125         virBufferAsprintf(buffer, "serial%d.network.endPoint = \"%s\"\n",
4126                           def->target.port,
4127                           def->source->data.tcp.listen ? "server" : "client");
4128         break;
4129 
4130       default:
4131         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4132                        _("Unsupported character device type '%s'"),
4133                        virDomainChrTypeToString(def->source->type));
4134         return -1;
4135     }
4136 
4137     /* vmx:yieldOnMsrRead */
4138     /* FIXME: Based on VI Client GUI default */
4139     virBufferAsprintf(buffer, "serial%d.yieldOnMsrRead = \"true\"\n",
4140                       def->target.port);
4141 
4142     return 0;
4143 }
4144 
4145 
4146 
4147 static int
virVMXFormatParallel(virVMXContext * ctx,virDomainChrDef * def,virBuffer * buffer)4148 virVMXFormatParallel(virVMXContext *ctx, virDomainChrDef *def,
4149                      virBuffer *buffer)
4150 {
4151     char *fileName = NULL;
4152 
4153     if (def->target.port < 0 || def->target.port > 2) {
4154         virReportError(VIR_ERR_INTERNAL_ERROR,
4155                        _("Parallel port index %d out of [0..2] range"),
4156                        def->target.port);
4157         return -1;
4158     }
4159 
4160     virBufferAsprintf(buffer, "parallel%d.present = \"true\"\n",
4161                       def->target.port);
4162 
4163     /* def:type -> vmx:fileType and def:data.file.path -> vmx:fileName */
4164     switch (def->source->type) {
4165       case VIR_DOMAIN_CHR_TYPE_DEV:
4166         virBufferAsprintf(buffer, "parallel%d.fileType = \"device\"\n",
4167                           def->target.port);
4168         virBufferAsprintf(buffer, "parallel%d.fileName = \"%s\"\n",
4169                           def->target.port, def->source->data.file.path);
4170         break;
4171 
4172       case VIR_DOMAIN_CHR_TYPE_FILE:
4173         virBufferAsprintf(buffer, "parallel%d.fileType = \"file\"\n",
4174                           def->target.port);
4175 
4176         fileName = ctx->formatFileName(def->source->data.file.path, ctx->opaque);
4177 
4178         if (fileName == NULL)
4179             return -1;
4180 
4181         virBufferAsprintf(buffer, "parallel%d.fileName = \"%s\"\n",
4182                           def->target.port, fileName);
4183 
4184         VIR_FREE(fileName);
4185         break;
4186 
4187       default:
4188         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4189                        _("Unsupported character device type '%s'"),
4190                        virDomainChrTypeToString(def->source->type));
4191         return -1;
4192     }
4193 
4194     return 0;
4195 }
4196 
4197 
4198 
4199 static int
virVMXFormatSVGA(virDomainVideoDef * def,virBuffer * buffer)4200 virVMXFormatSVGA(virDomainVideoDef *def, virBuffer *buffer)
4201 {
4202     unsigned long long vram;
4203 
4204     if (def->type != VIR_DOMAIN_VIDEO_TYPE_VMVGA) {
4205         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
4206                        _("Unsupported video device type '%s'"),
4207                        virDomainVideoTypeToString(def->type));
4208         return -1;
4209     }
4210 
4211     /*
4212      * For Windows guests the VRAM size should be a multiple of 64 kilobyte.
4213      * See https://kb.vmware.com/kb/1003 and https://kb.vmware.com/kb/1001558
4214      */
4215     vram = VIR_DIV_UP(def->vram, 64) * 64;
4216 
4217     if (def->heads > 1) {
4218         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
4219                        _("Multi-head video devices are unsupported"));
4220         return -1;
4221     }
4222 
4223     virBufferAsprintf(buffer, "svga.vramSize = \"%lld\"\n",
4224                       vram * 1024); /* kilobyte to byte */
4225 
4226     return 0;
4227 }
4228