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(¤t);
1633 rc = virStrToLong_uip(current, (char **) ¤t, 10, &number);
1634 virSkipSpaces(¤t);
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