1 /*
2 * Copyright (C) 2014, Taowei Luo (uaedante@gmail.com)
3 * Copyright (C) 2010-2016 Red Hat, Inc.
4 * Copyright (C) 2008-2009 Sun Microsystems, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #include <unistd.h>
24 #include <fcntl.h>
25
26 #include "internal.h"
27 #include "datatypes.h"
28 #include "virdomainobjlist.h"
29 #include "domain_event.h"
30 #include "virlog.h"
31 #include "viralloc.h"
32 #include "virhostmem.h"
33 #include "virstring.h"
34 #include "virfile.h"
35 #include "virtime.h"
36 #include "virkeycode.h"
37 #include "snapshot_conf.h"
38 #include "vbox_snapshot_conf.h"
39 #include "virfdstream.h"
40 #include "virutil.h"
41 #include "configmake.h"
42
43 #include "vbox_common.h"
44 #include "vbox_uniformed_api.h"
45 #include "vbox_get_driver.h"
46
47 /* Common codes for vbox driver. With the definitions in vbox_common.h,
48 * it treats vbox structs as a void*. Though vboxUniformedAPI
49 * it call vbox functions. This file is a high level implement about
50 * the vbox driver.
51 */
52
53 #define VIR_FROM_THIS VIR_FROM_VBOX
54
55 VIR_LOG_INIT("vbox.vbox_common");
56
57 /* global vbox API, used for all common codes. */
58 static vboxUniformedAPI gVBoxAPI;
59
60 static virClass *vboxDriverClass;
61 static virMutex vbox_driver_lock = VIR_MUTEX_INITIALIZER;
62 static struct _vboxDriver *vbox_driver;
63 static struct _vboxDriver *vboxDriverObjNew(void);
64 static __thread bool vboxDriverDisposed;
65
66 static int
vboxDomainDevicesDefPostParse(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)67 vboxDomainDevicesDefPostParse(virDomainDeviceDef *dev G_GNUC_UNUSED,
68 const virDomainDef *def G_GNUC_UNUSED,
69 unsigned int parseFlags G_GNUC_UNUSED,
70 void *opaque G_GNUC_UNUSED,
71 void *parseOpaque G_GNUC_UNUSED)
72 {
73 if (dev->type == VIR_DOMAIN_DEVICE_VIDEO &&
74 dev->data.video->type == VIR_DOMAIN_VIDEO_TYPE_DEFAULT) {
75 dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_VBOX;
76 }
77
78 return 0;
79 }
80
81 static virDomainDefParserConfig vboxDomainDefParserConfig = {
82 .macPrefix = { 0x08, 0x00, 0x27 },
83 .features = VIR_DOMAIN_DEF_FEATURE_NAME_SLASH,
84 .devicesPostParseCallback = vboxDomainDevicesDefPostParse,
85 };
86
87 static virCaps *
vboxCapsInit(void)88 vboxCapsInit(void)
89 {
90 g_autoptr(virCaps) caps = NULL;
91 virCapsGuest *guest = NULL;
92
93 if ((caps = virCapabilitiesNew(virArchFromHost(),
94 false, false)) == NULL)
95 return NULL;
96
97 if (!(caps->host.numa = virCapabilitiesHostNUMANewHost()))
98 return NULL;
99
100 if (virCapabilitiesInitCaches(caps) < 0)
101 return NULL;
102
103 guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM,
104 caps->host.arch, NULL, NULL, 0, NULL);
105
106 virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_VBOX,
107 NULL, NULL, 0, NULL);
108
109 return g_steal_pointer(&caps);
110 }
111
112 static void
vboxDriverDispose(void * obj)113 vboxDriverDispose(void *obj)
114 {
115 struct _vboxDriver *driver = obj;
116
117 vboxDriverDisposed = true;
118 virObjectUnref(driver->caps);
119 virObjectUnref(driver->xmlopt);
120 }
121
122 static int
vboxDriverOnceInit(void)123 vboxDriverOnceInit(void)
124 {
125 if (!VIR_CLASS_NEW(vboxDriver, virClassForObjectLockable()))
126 return -1;
127
128 return 0;
129 }
130
131 VIR_ONCE_GLOBAL_INIT(vboxDriver);
132
133 static struct _vboxDriver *
vboxDriverObjNew(void)134 vboxDriverObjNew(void)
135 {
136 struct _vboxDriver *driver;
137
138 if (vboxDriverInitialize() < 0)
139 return NULL;
140
141 if (!(driver = virObjectLockableNew(vboxDriverClass)))
142 return NULL;
143
144 if (!(driver->caps = vboxCapsInit()) ||
145 !(driver->xmlopt = virDomainXMLOptionNew(&vboxDomainDefParserConfig,
146 NULL, NULL, NULL, NULL)))
147 goto cleanup;
148
149 return driver;
150
151 cleanup:
152 virObjectUnref(driver);
153 return NULL;
154 }
155
156 static int
vboxExtractVersion(void)157 vboxExtractVersion(void)
158 {
159 int ret = -1;
160 PRUnichar *versionUtf16 = NULL;
161 char *vboxVersion = NULL;
162 nsresult rc;
163
164 if (vbox_driver->version > 0)
165 return 0;
166
167 rc = gVBoxAPI.UIVirtualBox.GetVersion(vbox_driver->vboxObj, &versionUtf16);
168 if (NS_FAILED(rc))
169 goto failed;
170
171 gVBoxAPI.UPFN.Utf16ToUtf8(vbox_driver->pFuncs, versionUtf16, &vboxVersion);
172
173 if (virParseVersionString(vboxVersion, &vbox_driver->version, false) >= 0)
174 ret = 0;
175
176 gVBoxAPI.UPFN.Utf8Free(vbox_driver->pFuncs, vboxVersion);
177 gVBoxAPI.UPFN.ComUnallocMem(vbox_driver->pFuncs, versionUtf16);
178 vboxVersion = NULL;
179 versionUtf16 = NULL;
180
181 failed:
182 if (ret != 0)
183 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
184 _("Could not extract VirtualBox version"));
185
186 return ret;
187 }
188
189 static int
vboxSdkInitialize(void)190 vboxSdkInitialize(void)
191 {
192 /* vbox API was already initialized by first connection */
193 if (vbox_driver->connectionCount > 0)
194 return 0;
195
196 if (gVBoxAPI.UPFN.Initialize(vbox_driver) != 0)
197 return -1;
198
199 if (vbox_driver->vboxObj == NULL) {
200 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
201 _("IVirtualBox object is null"));
202 return -1;
203 }
204
205 if (vbox_driver->vboxSession == NULL) {
206 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
207 _("ISession object is null"));
208 return -1;
209 }
210
211 return 0;
212 }
213
214 static void
vboxSdkUninitialize(void)215 vboxSdkUninitialize(void)
216 {
217 /* do not uninitialize, when there are still connection using it */
218 if (vbox_driver->connectionCount > 0)
219 return;
220
221 gVBoxAPI.UPFN.Uninitialize(vbox_driver);
222 }
223
224 static struct _vboxDriver *
vboxGetDriverConnection(void)225 vboxGetDriverConnection(void)
226 {
227 virMutexLock(&vbox_driver_lock);
228
229 if (vbox_driver) {
230 virObjectRef(vbox_driver);
231 } else {
232 vbox_driver = vboxDriverObjNew();
233
234 if (!vbox_driver) {
235 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
236 _("Failed to create vbox driver object."));
237
238 virMutexUnlock(&vbox_driver_lock);
239
240 return NULL;
241 }
242 }
243
244 if (vboxSdkInitialize() < 0 || vboxExtractVersion() < 0) {
245 gVBoxAPI.UPFN.Uninitialize(vbox_driver);
246 /* make sure to clear the pointer when last reference was released */
247 vboxDriverDisposed = false;
248 virObjectUnref(vbox_driver);
249 if (vboxDriverDisposed)
250 vbox_driver = NULL;
251
252 virMutexUnlock(&vbox_driver_lock);
253
254 return NULL;
255 }
256
257 vbox_driver->connectionCount++;
258
259 virMutexUnlock(&vbox_driver_lock);
260
261 return vbox_driver;
262 }
263
264 static void
vboxDestroyDriverConnection(void)265 vboxDestroyDriverConnection(void)
266 {
267 virMutexLock(&vbox_driver_lock);
268
269 if (!vbox_driver)
270 goto cleanup;
271
272 vbox_driver->connectionCount--;
273
274 vboxSdkUninitialize();
275
276 vboxDriverDisposed = false;
277 virObjectUnref(vbox_driver);
278 if (vboxDriverDisposed)
279 vbox_driver = NULL;
280
281 cleanup:
282 virMutexUnlock(&vbox_driver_lock);
283 }
284
openSessionForMachine(struct _vboxDriver * data,const unsigned char * dom_uuid,vboxIID * iid,IMachine ** machine)285 static int openSessionForMachine(struct _vboxDriver *data, const unsigned char *dom_uuid,
286 vboxIID *iid, IMachine **machine)
287 {
288 VBOX_IID_INITIALIZE(iid);
289 vboxIIDFromUUID(iid, dom_uuid);
290
291 /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */
292 if (NS_FAILED(gVBoxAPI.UIVirtualBox.GetMachine(data->vboxObj, iid, machine))) {
293 virReportError(VIR_ERR_NO_DOMAIN, "%s",
294 _("no domain with matching uuid"));
295 return -1;
296 }
297
298 return 0;
299 }
300
301
302 /**
303 * function to generate the name for medium,
304 * for e.g: hda, sda, etc
305 *
306 * @returns null terminated string with device name or NULL
307 * for failures
308 * @param storageBus Input storage bus type
309 * @param devicePort Input port number
310 * @param deviceSlot Input slot number
311 * @param sdCount Running total of disk devices with "sd" prefix
312 */
313 static char *
vboxGenerateMediumName(PRUint32 storageBus,PRInt32 devicePort,PRInt32 deviceSlot,size_t sdCount)314 vboxGenerateMediumName(PRUint32 storageBus,
315 PRInt32 devicePort,
316 PRInt32 deviceSlot,
317 size_t sdCount)
318 {
319 const char *prefix = NULL;
320 char *name = NULL;
321 int total = 0;
322
323 switch ((enum StorageBus) storageBus) {
324 case StorageBus_IDE:
325 prefix = "hd";
326 total = devicePort * 2 + deviceSlot;
327
328 break;
329 case StorageBus_SATA:
330 case StorageBus_SCSI:
331 case StorageBus_SAS:
332 prefix = "sd";
333 total = sdCount;
334
335 break;
336 case StorageBus_Floppy:
337 total = deviceSlot;
338 prefix = "fd";
339
340 break;
341 case StorageBus_Null:
342
343 return NULL;
344 }
345
346 name = virIndexToDiskName(total, prefix);
347
348 return name;
349 }
350
351
352 static int
vboxSetStorageController(virDomainControllerDef * controller,struct _vboxDriver * data,IMachine * machine)353 vboxSetStorageController(virDomainControllerDef *controller,
354 struct _vboxDriver *data,
355 IMachine *machine)
356 {
357 PRUnichar *controllerName = NULL;
358 PRInt32 vboxModel = StorageControllerType_Null;
359 PRInt32 vboxBusType = StorageBus_Null;
360 IStorageController *vboxController = NULL;
361 nsresult rc = 0;
362 char *debugName = NULL;
363 int ret = -1;
364
365 /* libvirt controller type => vbox bus type */
366 switch ((virDomainControllerType) controller->type) {
367 case VIR_DOMAIN_CONTROLLER_TYPE_FDC:
368 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_FLOPPY_NAME, &controllerName);
369 vboxBusType = StorageBus_Floppy;
370
371 break;
372 case VIR_DOMAIN_CONTROLLER_TYPE_IDE:
373 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_IDE_NAME, &controllerName);
374 vboxBusType = StorageBus_IDE;
375
376 break;
377 case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
378 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_SCSI_NAME, &controllerName);
379 vboxBusType = StorageBus_SCSI;
380
381 break;
382 case VIR_DOMAIN_CONTROLLER_TYPE_SATA:
383 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_SATA_NAME, &controllerName);
384 vboxBusType = StorageBus_SATA;
385
386 break;
387 case VIR_DOMAIN_CONTROLLER_TYPE_VIRTIO_SERIAL:
388 case VIR_DOMAIN_CONTROLLER_TYPE_CCID:
389 case VIR_DOMAIN_CONTROLLER_TYPE_USB:
390 case VIR_DOMAIN_CONTROLLER_TYPE_PCI:
391 case VIR_DOMAIN_CONTROLLER_TYPE_XENBUS:
392 case VIR_DOMAIN_CONTROLLER_TYPE_ISA:
393 case VIR_DOMAIN_CONTROLLER_TYPE_LAST:
394 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
395 _("The vbox driver does not support %s controller type"),
396 virDomainControllerTypeToString(controller->type));
397 return -1;
398 }
399
400 /* libvirt scsi model => vbox scsi model */
401 if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) {
402 switch ((virDomainControllerModelSCSI) controller->model) {
403 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
404 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO:
405 vboxModel = StorageControllerType_LsiLogic;
406
407 break;
408 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC:
409 vboxModel = StorageControllerType_BusLogic;
410
411 break;
412 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068:
413 /* in vbox, lsisas has a dedicated SAS bus type with no model */
414 VBOX_UTF16_FREE(controllerName);
415 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_SAS_NAME, &controllerName);
416 vboxBusType = StorageBus_SAS;
417
418 break;
419 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI:
420 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
421 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
422 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL:
423 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL:
424 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
425 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_NCR53C90:
426 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DC390:
427 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AM53C974:
428 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
429 _("The vbox driver does not support %s SCSI "
430 "controller model"),
431 virDomainControllerModelSCSITypeToString(controller->model));
432 goto cleanup;
433 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT:
434 case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST:
435 virReportError(VIR_ERR_INTERNAL_ERROR,
436 _("Unexpected SCSI controller model %d"),
437 controller->model);
438 goto cleanup;
439 }
440 /* libvirt ide model => vbox ide model */
441 } else if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_IDE) {
442 switch ((virDomainControllerModelIDE) controller->model) {
443 case VIR_DOMAIN_CONTROLLER_MODEL_IDE_PIIX3:
444 vboxModel = StorageControllerType_PIIX3;
445
446 break;
447 case VIR_DOMAIN_CONTROLLER_MODEL_IDE_PIIX4:
448 vboxModel = StorageControllerType_PIIX4;
449
450 break;
451 case VIR_DOMAIN_CONTROLLER_MODEL_IDE_ICH6:
452 vboxModel = StorageControllerType_ICH6;
453
454 break;
455 case VIR_DOMAIN_CONTROLLER_MODEL_IDE_LAST:
456 case VIR_DOMAIN_CONTROLLER_MODEL_IDE_DEFAULT:
457 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
458 _("Unexpected IDE controller model %d"),
459 controller->model);
460 goto cleanup;
461 }
462 }
463
464 VBOX_UTF16_TO_UTF8(controllerName, &debugName);
465 VIR_DEBUG("Adding VBOX storage controller (name: %s, busType: %d)",
466 debugName, vboxBusType);
467
468 rc = gVBoxAPI.UIMachine.AddStorageController(machine, controllerName,
469 vboxBusType, &vboxController);
470
471 if (NS_FAILED(rc)) {
472 virReportError(VIR_ERR_INTERNAL_ERROR,
473 _("Failed to add storage controller "
474 "(name: %s, busType: %d), rc=%08x"),
475 debugName, vboxBusType, rc);
476 goto cleanup;
477 }
478
479 /* only IDE or SCSI controller have model choices */
480 if (vboxModel != StorageControllerType_Null) {
481 rc = gVBoxAPI.UIStorageController.SetControllerType(vboxController,
482 vboxModel);
483 if (NS_FAILED(rc)) {
484 virReportError(VIR_ERR_INTERNAL_ERROR,
485 _("Failed to change storage controller model, "
486 "rc=%08x"), rc);
487 goto cleanup;
488 }
489 }
490
491 ret = 0;
492
493 cleanup:
494 VBOX_UTF16_FREE(controllerName);
495 VBOX_UTF8_FREE(debugName);
496 VBOX_RELEASE(vboxController);
497
498 return ret;
499 }
500
501
502 static int
vboxAttachStorageControllers(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)503 vboxAttachStorageControllers(virDomainDef *def,
504 struct _vboxDriver *data,
505 IMachine *machine)
506 {
507 size_t i;
508 for (i = 0; i < def->ncontrollers; i++) {
509 if (vboxSetStorageController(def->controllers[i], data, machine) < 0)
510 return -1;
511 }
512
513 return 0;
514 }
515
516
517 static int
vboxConnectURIProbe(char ** uri)518 vboxConnectURIProbe(char **uri)
519 {
520 *uri = g_strdup(geteuid() ? "vbox:///session" : "vbox:///system");
521 return 1;
522 }
523
524
525 static virDrvOpenStatus
vboxConnectOpen(virConnectPtr conn,virConnectAuthPtr auth G_GNUC_UNUSED,virConf * conf G_GNUC_UNUSED,unsigned int flags)526 vboxConnectOpen(virConnectPtr conn,
527 virConnectAuthPtr auth G_GNUC_UNUSED,
528 virConf *conf G_GNUC_UNUSED,
529 unsigned int flags)
530 {
531 struct _vboxDriver *driver = NULL;
532 uid_t uid = geteuid();
533
534 virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
535
536 if (!virConnectValidateURIPath(conn->uri->path, "vbox", uid == 0))
537 return VIR_DRV_OPEN_ERROR;
538
539 if (!(driver = vboxGetDriverConnection()))
540 return VIR_DRV_OPEN_ERROR;
541
542 conn->privateData = virObjectRef(driver);
543
544 VIR_DEBUG("in vboxOpen");
545
546 return VIR_DRV_OPEN_SUCCESS;
547 }
548
vboxConnectClose(virConnectPtr conn)549 static int vboxConnectClose(virConnectPtr conn)
550 {
551 VIR_DEBUG("%s: in vboxClose", conn->driver->name);
552
553 virObjectUnref(conn->privateData);
554 vboxDestroyDriverConnection();
555
556 return 0;
557 }
558
559 static int
vboxDomainSave(virDomainPtr dom,const char * path G_GNUC_UNUSED)560 vboxDomainSave(virDomainPtr dom, const char *path G_GNUC_UNUSED)
561 {
562 struct _vboxDriver *data = dom->conn->privateData;
563 IConsole *console = NULL;
564 vboxIID iid;
565 IMachine *machine = NULL;
566 IProgress *progress = NULL;
567 resultCodeUnion resultCode;
568 nsresult rc;
569 int ret = -1;
570
571 if (!data->vboxObj)
572 return ret;
573
574 /* VirtualBox currently doesn't support saving to a file
575 * at a location other then the machine folder and thus
576 * setting path to G_GNUC_UNUSED for now, will change
577 * this behaviour once get the VirtualBox API in right
578 * shape to do this
579 */
580
581 /* Open a Session for the machine */
582 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
583 goto cleanup;
584
585 rc = gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
586 if (NS_FAILED(rc))
587 goto cleanup;
588
589 rc = gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
590 if (NS_FAILED(rc) || !console)
591 goto freeSession;
592
593 rc = gVBoxAPI.UIConsole.SaveState(console, &progress);
594 if (!progress)
595 goto freeSession;
596
597 gVBoxAPI.UIProgress.WaitForCompletion(progress, -1);
598 gVBoxAPI.UIProgress.GetResultCode(progress, &resultCode);
599 if (RC_SUCCEEDED(resultCode))
600 ret = 0;
601
602 freeSession:
603 gVBoxAPI.UISession.Close(data->vboxSession);
604
605 cleanup:
606 DEBUGIID("UUID of machine being saved:", &iid);
607 VBOX_RELEASE(machine);
608 VBOX_RELEASE(console);
609 VBOX_RELEASE(progress);
610 vboxIIDUnalloc(&iid);
611 return ret;
612 }
613
vboxConnectGetVersion(virConnectPtr conn,unsigned long * version)614 static int vboxConnectGetVersion(virConnectPtr conn, unsigned long *version)
615 {
616 struct _vboxDriver *data = conn->privateData;
617 VIR_DEBUG("%s: in vboxGetVersion", conn->driver->name);
618
619 virObjectLock(data);
620 *version = data->version;
621 virObjectUnlock(data);
622
623 return 0;
624 }
625
vboxConnectGetHostname(virConnectPtr conn G_GNUC_UNUSED)626 static char *vboxConnectGetHostname(virConnectPtr conn G_GNUC_UNUSED)
627 {
628 return virGetHostname();
629 }
630
vboxConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)631 static int vboxConnectIsSecure(virConnectPtr conn G_GNUC_UNUSED)
632 {
633 /* Driver is using local, non-network based transport */
634 return 1;
635 }
636
vboxConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)637 static int vboxConnectIsEncrypted(virConnectPtr conn G_GNUC_UNUSED)
638 {
639 /* No encryption is needed, or used on the local transport */
640 return 0;
641 }
642
vboxConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)643 static int vboxConnectIsAlive(virConnectPtr conn G_GNUC_UNUSED)
644 {
645 return 1;
646 }
647
648 static int
vboxConnectGetMaxVcpus(virConnectPtr conn,const char * type G_GNUC_UNUSED)649 vboxConnectGetMaxVcpus(virConnectPtr conn, const char *type G_GNUC_UNUSED)
650 {
651 struct _vboxDriver *data = conn->privateData;
652 ISystemProperties *systemProperties = NULL;
653 PRUint32 maxCPUCount = 0;
654 int ret = -1;
655
656 if (!data->vboxObj)
657 return ret;
658
659 /* VirtualBox Supports only hvm and thus the type passed to it
660 * has no meaning, setting it to G_GNUC_UNUSED
661 */
662
663 gVBoxAPI.UIVirtualBox.GetSystemProperties(data->vboxObj, &systemProperties);
664 if (!systemProperties)
665 goto cleanup;
666 gVBoxAPI.UISystemProperties.GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
667
668 if (maxCPUCount > 0)
669 ret = maxCPUCount;
670
671 cleanup:
672 VBOX_RELEASE(systemProperties);
673 return ret;
674 }
675
vboxConnectGetCapabilities(virConnectPtr conn)676 static char *vboxConnectGetCapabilities(virConnectPtr conn)
677 {
678 struct _vboxDriver *data = conn->privateData;
679 char *ret = NULL;
680
681 if (!data->vboxObj)
682 return ret;
683
684 virObjectLock(data);
685 ret = virCapabilitiesFormatXML(data->caps);
686 virObjectUnlock(data);
687
688 return ret;
689 }
690
vboxConnectListDomains(virConnectPtr conn,int * ids,int nids)691 static int vboxConnectListDomains(virConnectPtr conn, int *ids, int nids)
692 {
693 struct _vboxDriver *data = conn->privateData;
694 vboxArray machines = VBOX_ARRAY_INITIALIZER;
695 PRUint32 state;
696 nsresult rc;
697 size_t i, j;
698 int ret = -1;
699
700 if (!data->vboxObj)
701 return ret;
702
703 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj, ARRAY_GET_MACHINES);
704 if (NS_FAILED(rc)) {
705 virReportError(VIR_ERR_INTERNAL_ERROR,
706 _("Could not get list of Domains, rc=%08x"),
707 (unsigned)rc);
708 goto cleanup;
709 }
710
711 ret = 0;
712 for (i = 0, j = 0; (i < machines.count) && (j < nids); ++i) {
713 IMachine *machine = machines.items[i];
714
715 if (machine) {
716 PRBool isAccessible = PR_FALSE;
717 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
718 if (isAccessible) {
719 gVBoxAPI.UIMachine.GetState(machine, &state);
720 if (gVBoxAPI.machineStateChecker.Online(state)) {
721 ret++;
722 ids[j++] = i + 1;
723 }
724 }
725 }
726 }
727
728 cleanup:
729 gVBoxAPI.UArray.vboxArrayRelease(&machines);
730 return ret;
731 }
732
vboxConnectNumOfDomains(virConnectPtr conn)733 static int vboxConnectNumOfDomains(virConnectPtr conn)
734 {
735 struct _vboxDriver *data = conn->privateData;
736 vboxArray machines = VBOX_ARRAY_INITIALIZER;
737 PRUint32 state;
738 nsresult rc;
739 size_t i;
740 int ret = -1;
741
742 if (!data->vboxObj)
743 return ret;
744
745 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj, ARRAY_GET_MACHINES);
746 if (NS_FAILED(rc)) {
747 virReportError(VIR_ERR_INTERNAL_ERROR,
748 _("Could not get number of Domains, rc=%08x"), (unsigned)rc);
749 goto cleanup;
750 }
751
752 ret = 0;
753 for (i = 0; i < machines.count; ++i) {
754 IMachine *machine = machines.items[i];
755
756 if (machine) {
757 PRBool isAccessible = PR_FALSE;
758 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
759 if (isAccessible) {
760 gVBoxAPI.UIMachine.GetState(machine, &state);
761 if (gVBoxAPI.machineStateChecker.Online(state))
762 ret++;
763 }
764 }
765 }
766
767 cleanup:
768 gVBoxAPI.UArray.vboxArrayRelease(&machines);
769 return ret;
770 }
771
vboxDomainLookupByID(virConnectPtr conn,int id)772 static virDomainPtr vboxDomainLookupByID(virConnectPtr conn, int id)
773 {
774 struct _vboxDriver *data = conn->privateData;
775 vboxArray machines = VBOX_ARRAY_INITIALIZER;
776 IMachine *machine;
777 PRBool isAccessible = PR_FALSE;
778 PRUnichar *machineNameUtf16 = NULL;
779 char *machineNameUtf8 = NULL;
780 vboxIID iid;
781 unsigned char uuid[VIR_UUID_BUFLEN];
782 PRUint32 state;
783 nsresult rc;
784 virDomainPtr ret = NULL;
785
786 if (!data->vboxObj)
787 return ret;
788
789 VBOX_IID_INITIALIZE(&iid);
790 /* Internal vbox IDs start from 0, the public libvirt ID
791 * starts from 1, so refuse id == 0, and adjust the rest */
792 if (id == 0) {
793 virReportError(VIR_ERR_NO_DOMAIN,
794 _("no domain with matching id %d"), id);
795 return NULL;
796 }
797 id = id - 1;
798
799 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj, ARRAY_GET_MACHINES);
800 if (NS_FAILED(rc)) {
801 virReportError(VIR_ERR_INTERNAL_ERROR,
802 _("Could not get list of machines, rc=%08x"), (unsigned)rc);
803 return NULL;
804 }
805
806 if (id >= machines.count)
807 goto cleanup;
808
809 machine = machines.items[id];
810
811 if (!machine)
812 goto cleanup;
813
814 isAccessible = PR_FALSE;
815 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
816 if (!isAccessible)
817 goto cleanup;
818
819 gVBoxAPI.UIMachine.GetState(machine, &state);
820 if (!gVBoxAPI.machineStateChecker.Online(state))
821 goto cleanup;
822
823 gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16);
824 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
825
826 gVBoxAPI.UIMachine.GetId(machine, &iid);
827 vboxIIDToUUID(&iid, uuid);
828 vboxIIDUnalloc(&iid);
829
830 /* get a new domain pointer from virGetDomain, if it fails
831 * then no need to assign the id, else assign the id, cause
832 * it is -1 by default. rest is taken care by virGetDomain
833 * itself, so need not worry.
834 */
835
836 ret = virGetDomain(conn, machineNameUtf8, uuid, id + 1);
837
838 /* Cleanup all the XPCOM allocated stuff here */
839 VBOX_UTF8_FREE(machineNameUtf8);
840 VBOX_UTF16_FREE(machineNameUtf16);
841
842 cleanup:
843 gVBoxAPI.UArray.vboxArrayRelease(&machines);
844 return ret;
845 }
846
vboxDomainLookupByUUID(virConnectPtr conn,const unsigned char * uuid)847 virDomainPtr vboxDomainLookupByUUID(virConnectPtr conn,
848 const unsigned char *uuid)
849 {
850 struct _vboxDriver *data = conn->privateData;
851 vboxArray machines = VBOX_ARRAY_INITIALIZER;
852 vboxIID iid;
853 char *machineNameUtf8 = NULL;
854 PRUnichar *machineNameUtf16 = NULL;
855 unsigned char iid_as_uuid[VIR_UUID_BUFLEN];
856 size_t i;
857 bool matched = false;
858 nsresult rc;
859 virDomainPtr ret = NULL;
860
861 if (!data->vboxObj)
862 return ret;
863
864 VBOX_IID_INITIALIZE(&iid);
865 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj, ARRAY_GET_MACHINES);
866 if (NS_FAILED(rc)) {
867 virReportError(VIR_ERR_INTERNAL_ERROR,
868 _("Could not get list of machines, rc=%08x"), (unsigned)rc);
869 return NULL;
870 }
871
872 for (i = 0; i < machines.count; ++i) {
873 IMachine *machine = machines.items[i];
874 PRBool isAccessible = PR_FALSE;
875
876 if (!machine)
877 continue;
878
879 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
880 if (!isAccessible)
881 continue;
882
883 rc = gVBoxAPI.UIMachine.GetId(machine, &iid);
884 if (NS_FAILED(rc))
885 continue;
886 vboxIIDToUUID(&iid, iid_as_uuid);
887 vboxIIDUnalloc(&iid);
888
889 if (memcmp(uuid, iid_as_uuid, VIR_UUID_BUFLEN) == 0) {
890 PRUint32 state;
891 int id = -1;
892
893
894 matched = true;
895
896 gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16);
897 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
898
899 gVBoxAPI.UIMachine.GetState(machine, &state);
900
901 if (gVBoxAPI.machineStateChecker.Online(state))
902 id = i + 1;
903
904 ret = virGetDomain(conn, machineNameUtf8, iid_as_uuid, id);
905 }
906
907 if (matched)
908 break;
909 }
910
911 /* Do the cleanup and take care you dont leak any memory */
912 VBOX_UTF8_FREE(machineNameUtf8);
913 VBOX_COM_UNALLOC_MEM(machineNameUtf16);
914 gVBoxAPI.UArray.vboxArrayRelease(&machines);
915
916 return ret;
917 }
918
919 static virDomainPtr
vboxDomainLookupByName(virConnectPtr conn,const char * name)920 vboxDomainLookupByName(virConnectPtr conn, const char *name)
921 {
922 struct _vboxDriver *data = conn->privateData;
923 vboxArray machines = VBOX_ARRAY_INITIALIZER;
924 vboxIID iid;
925 char *machineNameUtf8 = NULL;
926 PRUnichar *machineNameUtf16 = NULL;
927 unsigned char uuid[VIR_UUID_BUFLEN];
928 size_t i;
929 bool matched = false;
930 nsresult rc;
931 virDomainPtr ret = NULL;
932
933 if (!data->vboxObj)
934 return ret;
935
936 VBOX_IID_INITIALIZE(&iid);
937 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj, ARRAY_GET_MACHINES);
938 if (NS_FAILED(rc)) {
939 virReportError(VIR_ERR_INTERNAL_ERROR,
940 _("Could not get list of machines, rc=%08x"), (unsigned)rc);
941 return NULL;
942 }
943
944 for (i = 0; i < machines.count; ++i) {
945 IMachine *machine = machines.items[i];
946 PRBool isAccessible = PR_FALSE;
947
948 if (!machine)
949 continue;
950
951 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
952 if (!isAccessible)
953 continue;
954
955 gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16);
956 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
957
958 if (STREQ(name, machineNameUtf8)) {
959 PRUint32 state;
960 int id = -1;
961
962 matched = true;
963
964 gVBoxAPI.UIMachine.GetId(machine, &iid);
965 vboxIIDToUUID(&iid, uuid);
966 vboxIIDUnalloc(&iid);
967
968 gVBoxAPI.UIMachine.GetState(machine, &state);
969
970 if (gVBoxAPI.machineStateChecker.Online(state))
971 id = i + 1;
972
973 ret = virGetDomain(conn, machineNameUtf8, uuid, id);
974 }
975
976 VBOX_UTF8_FREE(machineNameUtf8);
977 VBOX_COM_UNALLOC_MEM(machineNameUtf16);
978 if (matched)
979 break;
980 }
981
982 gVBoxAPI.UArray.vboxArrayRelease(&machines);
983
984 return ret;
985 }
986
987 static void
vboxSetBootDeviceOrder(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)988 vboxSetBootDeviceOrder(virDomainDef *def, struct _vboxDriver *data,
989 IMachine *machine)
990 {
991 ISystemProperties *systemProperties = NULL;
992 PRUint32 maxBootPosition = 0;
993 size_t i = 0;
994
995 VIR_DEBUG("def->os.type %s", virDomainOSTypeToString(def->os.type));
996 VIR_DEBUG("def->os.arch %s", virArchToString(def->os.arch));
997 VIR_DEBUG("def->os.machine %s", def->os.machine);
998 VIR_DEBUG("def->os.nBootDevs %zu", def->os.nBootDevs);
999 VIR_DEBUG("def->os.bootDevs[0] %d", def->os.bootDevs[0]);
1000 VIR_DEBUG("def->os.bootDevs[1] %d", def->os.bootDevs[1]);
1001 VIR_DEBUG("def->os.bootDevs[2] %d", def->os.bootDevs[2]);
1002 VIR_DEBUG("def->os.bootDevs[3] %d", def->os.bootDevs[3]);
1003 VIR_DEBUG("def->os.init %s", def->os.init);
1004 VIR_DEBUG("def->os.kernel %s", def->os.kernel);
1005 VIR_DEBUG("def->os.initrd %s", def->os.initrd);
1006 VIR_DEBUG("def->os.cmdline %s", def->os.cmdline);
1007 VIR_DEBUG("def->os.root %s", def->os.root);
1008 if (def->os.loader) {
1009 VIR_DEBUG("def->os.loader->path %s", def->os.loader->path);
1010 VIR_DEBUG("def->os.loader->readonly %d", def->os.loader->readonly);
1011 VIR_DEBUG("def->os.loader->type %d", def->os.loader->type);
1012 VIR_DEBUG("def->os.loader->nvram %s", def->os.loader->nvram);
1013 }
1014 VIR_DEBUG("def->os.bootloader %s", def->os.bootloader);
1015 VIR_DEBUG("def->os.bootloaderArgs %s", def->os.bootloaderArgs);
1016
1017 gVBoxAPI.UIVirtualBox.GetSystemProperties(data->vboxObj, &systemProperties);
1018 if (systemProperties) {
1019 gVBoxAPI.UISystemProperties.GetMaxBootPosition(systemProperties,
1020 &maxBootPosition);
1021 VBOX_RELEASE(systemProperties);
1022 }
1023
1024 /* Clear the defaults first */
1025 for (i = 0; i < maxBootPosition; i++)
1026 gVBoxAPI.UIMachine.SetBootOrder(machine, i+1, DeviceType_Null);
1027
1028 for (i = 0; (i < def->os.nBootDevs) && (i < maxBootPosition); i++) {
1029 PRUint32 device = DeviceType_Null;
1030
1031 if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) {
1032 device = DeviceType_Floppy;
1033 } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) {
1034 device = DeviceType_DVD;
1035 } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_DISK) {
1036 device = DeviceType_HardDisk;
1037 } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_NET) {
1038 device = DeviceType_Network;
1039 }
1040 gVBoxAPI.UIMachine.SetBootOrder(machine, i+1, device);
1041 }
1042 }
1043
1044 static int
vboxAttachDrives(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)1045 vboxAttachDrives(virDomainDef *def, struct _vboxDriver *data, IMachine *machine)
1046 {
1047 size_t i;
1048 int type, ret = 0;
1049 const char *src = NULL;
1050 nsresult rc = 0;
1051 virDomainDiskDef *disk = NULL;
1052 virDomainControllerDef *cont;
1053 PRUnichar *storageCtlName = NULL;
1054 char *controllerName = NULL;
1055 IMedium *medium = NULL;
1056 PRUnichar *mediumFileUtf16 = NULL;
1057 PRUint32 devicePort, deviceSlot, deviceType, accessMode;
1058 vboxIID mediumUUID;
1059
1060 VBOX_IID_INITIALIZE(&mediumUUID);
1061
1062 for (i = 0; i < def->ndisks; i++) {
1063 disk = def->disks[i];
1064 src = virDomainDiskGetSource(disk);
1065 type = virDomainDiskGetType(disk);
1066 deviceType = DeviceType_Null;
1067 accessMode = AccessMode_ReadOnly;
1068 devicePort = disk->info.addr.drive.unit;
1069 deviceSlot = disk->info.addr.drive.bus;
1070
1071 if (type != VIR_STORAGE_TYPE_FILE) {
1072 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1073 _("Unsupported storage type %s, the only supported "
1074 "type is %s"),
1075 virStorageTypeToString(type),
1076 virStorageTypeToString(VIR_STORAGE_TYPE_FILE));
1077 ret = -1;
1078 goto cleanup;
1079 }
1080
1081 switch ((virDomainDiskDevice) disk->device) {
1082 case VIR_DOMAIN_DISK_DEVICE_DISK:
1083 if (!src) {
1084 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1085 _("Missing disk source file path"));
1086 ret = -1;
1087 goto cleanup;
1088 }
1089
1090 deviceType = DeviceType_HardDisk;
1091 accessMode = AccessMode_ReadWrite;
1092
1093 break;
1094
1095 case VIR_DOMAIN_DISK_DEVICE_CDROM:
1096 deviceType = DeviceType_DVD;
1097 accessMode = AccessMode_ReadOnly;
1098
1099 break;
1100 case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
1101 deviceType = DeviceType_Floppy;
1102 accessMode = AccessMode_ReadWrite;
1103
1104 break;
1105 case VIR_DOMAIN_DISK_DEVICE_LUN:
1106 case VIR_DOMAIN_DISK_DEVICE_LAST:
1107 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1108 _("The vbox driver does not support %s disk device"),
1109 virDomainDiskDeviceTypeToString(disk->device));
1110 ret = -1;
1111 goto cleanup;
1112 }
1113
1114 switch ((virDomainDiskBus) disk->bus) {
1115 case VIR_DOMAIN_DISK_BUS_IDE:
1116 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_IDE_NAME, &storageCtlName);
1117 devicePort = def->disks[i]->info.addr.drive.bus;
1118 deviceSlot = def->disks[i]->info.addr.drive.unit;
1119
1120 break;
1121 case VIR_DOMAIN_DISK_BUS_SATA:
1122 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_SATA_NAME, &storageCtlName);
1123
1124 break;
1125 case VIR_DOMAIN_DISK_BUS_SCSI:
1126 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_SCSI_NAME, &storageCtlName);
1127
1128 cont = virDomainDeviceFindSCSIController(def, &disk->info.addr.drive);
1129 if (cont && cont->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068) {
1130 VBOX_UTF16_FREE(storageCtlName);
1131 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_SAS_NAME, &storageCtlName);
1132 }
1133
1134 break;
1135 case VIR_DOMAIN_DISK_BUS_FDC:
1136 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_FLOPPY_NAME, &storageCtlName);
1137 devicePort = 0;
1138 deviceSlot = disk->info.addr.drive.unit;
1139
1140 break;
1141 case VIR_DOMAIN_DISK_BUS_VIRTIO:
1142 case VIR_DOMAIN_DISK_BUS_XEN:
1143 case VIR_DOMAIN_DISK_BUS_USB:
1144 case VIR_DOMAIN_DISK_BUS_UML:
1145 case VIR_DOMAIN_DISK_BUS_SD:
1146 case VIR_DOMAIN_DISK_BUS_NONE:
1147 case VIR_DOMAIN_DISK_BUS_LAST:
1148 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1149 _("The vbox driver does not support %s bus type"),
1150 virDomainDiskBusTypeToString(disk->bus));
1151 ret = -1;
1152 goto cleanup;
1153 }
1154
1155 /* If disk source is specified, lookup IMedium - removable drives don't
1156 * have either.
1157 */
1158 if (src) {
1159 VBOX_UTF8_TO_UTF16(src, &mediumFileUtf16);
1160 VIR_DEBUG("Looking up medium %s, type: %d, mode: %d", src,
1161 deviceType, accessMode);
1162
1163 rc = gVBoxAPI.UIVirtualBox.FindHardDisk(data->vboxObj, mediumFileUtf16,
1164 deviceType, accessMode, &medium);
1165
1166 /* The following is not needed for vbox 4.2+ but older versions have
1167 * distinct find and open operations where the former looks in vbox
1168 * media registry while the latter at storage location. In 4.2+, the
1169 * OpenMedium call takes care of both cases internally
1170 */
1171 if (!medium) {
1172 rc = gVBoxAPI.UIVirtualBox.OpenMedium(data->vboxObj,
1173 mediumFileUtf16,
1174 deviceType, accessMode,
1175 &medium);
1176 }
1177
1178 if (!medium) {
1179 virReportError(VIR_ERR_INTERNAL_ERROR,
1180 _("Failed to open the following disk/dvd/floppy "
1181 "to the machine: %s, rc=%08x"), src, rc);
1182 ret = -1;
1183 goto cleanup;
1184 }
1185
1186 rc = gVBoxAPI.UIMedium.GetId(medium, &mediumUUID);
1187 if (NS_FAILED(rc)) {
1188 virReportError(VIR_ERR_INTERNAL_ERROR,
1189 _("Can't get the UUID of the file to be attached "
1190 "as harddisk/dvd/floppy: %s, rc=%08x"),
1191 src, rc);
1192 ret = -1;
1193 goto cleanup;
1194 }
1195 }
1196
1197 if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
1198 if (disk->src->readonly) {
1199 gVBoxAPI.UIMedium.SetType(medium, MediumType_Immutable);
1200 VIR_DEBUG("Setting hard disk to immutable");
1201 } else {
1202 gVBoxAPI.UIMedium.SetType(medium, MediumType_Normal);
1203 VIR_DEBUG("Setting hard disk type to normal");
1204 }
1205 }
1206
1207 VBOX_UTF16_TO_UTF8(storageCtlName, &controllerName);
1208 VIR_DEBUG("Attaching disk(%zu), controller: %s, port: %d, slot: %d, "
1209 "type: %d, medium: %s", i, controllerName, devicePort,
1210 deviceSlot, deviceType, medium == NULL ? "empty" : src);
1211 VBOX_UTF8_FREE(controllerName);
1212
1213 /* Attach the harddisk/dvd/Floppy to the storage controller,
1214 * medium == NULL is ok here
1215 */
1216 rc = gVBoxAPI.UIMachine.AttachDevice(machine,
1217 storageCtlName,
1218 devicePort,
1219 deviceSlot,
1220 deviceType,
1221 medium);
1222
1223 if (NS_FAILED(rc)) {
1224 virReportError(VIR_ERR_INTERNAL_ERROR,
1225 _("Could not attach the file as "
1226 "harddisk/dvd/floppy: %s, rc=%08x"), src, rc);
1227 ret = -1;
1228 goto cleanup;
1229 } else {
1230 DEBUGIID("Attached HDD/DVD/Floppy with UUID", &mediumUUID);
1231 }
1232
1233 cleanup:
1234 VBOX_MEDIUM_RELEASE(medium);
1235 vboxIIDUnalloc(&mediumUUID);
1236 VBOX_UTF16_FREE(mediumFileUtf16);
1237 VBOX_UTF16_FREE(storageCtlName);
1238
1239 if (ret < 0)
1240 break;
1241 }
1242
1243 return ret;
1244 }
1245
1246 static void
vboxAttachSound(virDomainDef * def,IMachine * machine)1247 vboxAttachSound(virDomainDef *def, IMachine *machine)
1248 {
1249 nsresult rc;
1250 IAudioAdapter *audioAdapter = NULL;
1251
1252 /* Check if def->nsounds is one as VirtualBox currently supports
1253 * only one sound card
1254 */
1255 if (def->nsounds != 1)
1256 return;
1257
1258 gVBoxAPI.UIMachine.GetAudioAdapter(machine, &audioAdapter);
1259 if (!audioAdapter)
1260 return;
1261
1262 rc = gVBoxAPI.UIAudioAdapter.SetEnabled(audioAdapter, 1);
1263 if (NS_FAILED(rc))
1264 goto cleanup;
1265
1266 if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_SB16) {
1267 gVBoxAPI.UIAudioAdapter.SetAudioController(audioAdapter,
1268 AudioControllerType_SB16);
1269 } else if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_AC97) {
1270 gVBoxAPI.UIAudioAdapter.SetAudioController(audioAdapter,
1271 AudioControllerType_AC97);
1272 }
1273
1274 cleanup:
1275 VBOX_RELEASE(audioAdapter);
1276 }
1277
1278 static int
vboxAttachNetwork(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)1279 vboxAttachNetwork(virDomainDef *def, struct _vboxDriver *data, IMachine *machine)
1280 {
1281 ISystemProperties *systemProperties = NULL;
1282 PRUint32 chipsetType = ChipsetType_Null;
1283 PRUint32 networkAdapterCount = 0;
1284 size_t i = 0;
1285
1286 if (gVBoxAPI.chipsetType)
1287 gVBoxAPI.UIMachine.GetChipsetType(machine, &chipsetType);
1288
1289 gVBoxAPI.UIVirtualBox.GetSystemProperties(data->vboxObj, &systemProperties);
1290 if (systemProperties) {
1291 gVBoxAPI.UISystemProperties.GetMaxNetworkAdapters(systemProperties, chipsetType,
1292 &networkAdapterCount);
1293 VBOX_RELEASE(systemProperties);
1294 }
1295
1296 VIR_DEBUG("Number of Network Cards to be connected: %zu", def->nnets);
1297 VIR_DEBUG("Number of Network Cards available: %d", networkAdapterCount);
1298
1299 for (i = 0; (i < def->nnets) && (i < networkAdapterCount); i++) {
1300 INetworkAdapter *adapter = NULL;
1301 PRUint32 adapterType = NetworkAdapterType_Null;
1302 char macaddr[VIR_MAC_STRING_BUFLEN] = {0};
1303 char macaddrvbox[VIR_MAC_STRING_BUFLEN - 5] = {0};
1304 PRUnichar *MACAddress = NULL;
1305
1306 virMacAddrFormat(&def->nets[i]->mac, macaddr);
1307 g_snprintf(macaddrvbox, VIR_MAC_STRING_BUFLEN - 5,
1308 "%02X%02X%02X%02X%02X%02X",
1309 def->nets[i]->mac.addr[0],
1310 def->nets[i]->mac.addr[1],
1311 def->nets[i]->mac.addr[2],
1312 def->nets[i]->mac.addr[3],
1313 def->nets[i]->mac.addr[4],
1314 def->nets[i]->mac.addr[5]);
1315 macaddrvbox[VIR_MAC_STRING_BUFLEN - 6] = '\0';
1316
1317 VIR_DEBUG("NIC(%zu): Type: %d", i, def->nets[i]->type);
1318 VIR_DEBUG("NIC(%zu): Model: %s", i, virDomainNetModelTypeToString(def->nets[i]->model));
1319 VIR_DEBUG("NIC(%zu): Mac: %s", i, macaddr);
1320 VIR_DEBUG("NIC(%zu): ifname: %s", i, def->nets[i]->ifname);
1321 if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
1322 VIR_DEBUG("NIC(%zu): name: %s", i, def->nets[i]->data.network.name);
1323 } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
1324 VIR_DEBUG("NIC(%zu): name: %s", i, def->nets[i]->data.internal.name);
1325 } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
1326 VIR_DEBUG("NIC(%zu): NAT.", i);
1327 } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
1328 VIR_DEBUG("NIC(%zu): brname: %s", i, def->nets[i]->data.bridge.brname);
1329 VIR_DEBUG("NIC(%zu): script: %s", i, def->nets[i]->script);
1330 if (def->nets[i]->guestIP.nips == 1) {
1331 char *ipStr = virSocketAddrFormat(&def->nets[i]->guestIP.ips[0]->address);
1332 VIR_DEBUG("NIC(%zu): ipaddr: %s", i, ipStr);
1333 VIR_FREE(ipStr);
1334 } else if (def->nets[i]->guestIP.nips > 1) {
1335 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1336 _("Driver does not support setting multiple IP addresses"));
1337 return -1;
1338 }
1339 }
1340
1341 gVBoxAPI.UIMachine.GetNetworkAdapter(machine, i, &adapter);
1342 if (!adapter)
1343 continue;
1344
1345 gVBoxAPI.UINetworkAdapter.SetEnabled(adapter, 1);
1346
1347 if (def->nets[i]->model) {
1348 if (def->nets[i]->model == VIR_DOMAIN_NET_MODEL_AM79C970A) {
1349 adapterType = NetworkAdapterType_Am79C970A;
1350 } else if (def->nets[i]->model == VIR_DOMAIN_NET_MODEL_AM79C973) {
1351 adapterType = NetworkAdapterType_Am79C973;
1352 } else if (def->nets[i]->model == VIR_DOMAIN_NET_MODEL_82540EM) {
1353 adapterType = NetworkAdapterType_I82540EM;
1354 } else if (def->nets[i]->model == VIR_DOMAIN_NET_MODEL_82545EM) {
1355 adapterType = NetworkAdapterType_I82545EM;
1356 } else if (def->nets[i]->model == VIR_DOMAIN_NET_MODEL_82543GC) {
1357 adapterType = NetworkAdapterType_I82543GC;
1358 } else if (gVBoxAPI.APIVersion >= 3000051 &&
1359 def->nets[i]->model == VIR_DOMAIN_NET_MODEL_VIRTIO) {
1360 /* Only vbox 3.1 and later support NetworkAdapterType_Virto */
1361 adapterType = NetworkAdapterType_Virtio;
1362 }
1363 } else {
1364 adapterType = NetworkAdapterType_Am79C973;
1365 }
1366
1367 gVBoxAPI.UINetworkAdapter.SetAdapterType(adapter, adapterType);
1368
1369 if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
1370 PRUnichar *hostInterface = NULL;
1371 /* Bridged Network */
1372
1373 gVBoxAPI.UINetworkAdapter.AttachToBridgedInterface(adapter);
1374
1375 if (def->nets[i]->data.bridge.brname) {
1376 VBOX_UTF8_TO_UTF16(def->nets[i]->data.bridge.brname,
1377 &hostInterface);
1378 gVBoxAPI.UINetworkAdapter.SetBridgedInterface(adapter, hostInterface);
1379 VBOX_UTF16_FREE(hostInterface);
1380 }
1381 } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
1382 PRUnichar *internalNetwork = NULL;
1383 /* Internal Network */
1384
1385 gVBoxAPI.UINetworkAdapter.AttachToInternalNetwork(adapter);
1386
1387 if (def->nets[i]->data.internal.name) {
1388 VBOX_UTF8_TO_UTF16(def->nets[i]->data.internal.name,
1389 &internalNetwork);
1390 gVBoxAPI.UINetworkAdapter.SetInternalNetwork(adapter, internalNetwork);
1391 VBOX_UTF16_FREE(internalNetwork);
1392 }
1393 } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
1394 PRUnichar *hostInterface = NULL;
1395 /* Host Only Networking (currently only vboxnet0 available
1396 * on *nix and mac, on windows you can create and configure
1397 * as many as you want)
1398 */
1399 gVBoxAPI.UINetworkAdapter.AttachToHostOnlyInterface(adapter);
1400
1401 if (def->nets[i]->data.network.name) {
1402 VBOX_UTF8_TO_UTF16(def->nets[i]->data.network.name,
1403 &hostInterface);
1404 gVBoxAPI.UINetworkAdapter.SetHostOnlyInterface(adapter, hostInterface);
1405 VBOX_UTF16_FREE(hostInterface);
1406 }
1407 } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
1408 /* NAT */
1409 gVBoxAPI.UINetworkAdapter.AttachToNAT(adapter);
1410 } else {
1411 /* else always default to NAT if we don't understand
1412 * what option is been passed to us
1413 */
1414 gVBoxAPI.UINetworkAdapter.AttachToNAT(adapter);
1415 }
1416
1417 VBOX_UTF8_TO_UTF16(macaddrvbox, &MACAddress);
1418 gVBoxAPI.UINetworkAdapter.SetMACAddress(adapter, MACAddress);
1419 VBOX_UTF16_FREE(MACAddress);
1420 }
1421 return 0;
1422 }
1423
1424 static void
vboxAttachSerial(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)1425 vboxAttachSerial(virDomainDef *def, struct _vboxDriver *data, IMachine *machine)
1426 {
1427 ISystemProperties *systemProperties = NULL;
1428 PRUint32 serialPortCount = 0;
1429 size_t i = 0;
1430
1431 gVBoxAPI.UIVirtualBox.GetSystemProperties(data->vboxObj, &systemProperties);
1432 if (systemProperties) {
1433 gVBoxAPI.UISystemProperties.GetSerialPortCount(systemProperties,
1434 &serialPortCount);
1435 VBOX_RELEASE(systemProperties);
1436 }
1437
1438 VIR_DEBUG("Number of Serial Ports to be connected: %zu", def->nserials);
1439 VIR_DEBUG("Number of Serial Ports available: %d", serialPortCount);
1440
1441 for (i = 0; (i < def->nserials) && (i < serialPortCount); i++) {
1442 ISerialPort *serialPort = NULL;
1443 PRUnichar *pathUtf16 = NULL;
1444
1445 VIR_DEBUG("SerialPort(%zu): Type: %d", i, def->serials[i]->source->type);
1446 VIR_DEBUG("SerialPort(%zu): target.port: %d", i,
1447 def->serials[i]->target.port);
1448
1449 gVBoxAPI.UIMachine.GetSerialPort(machine, i, &serialPort);
1450 if (!serialPort)
1451 continue;
1452
1453 gVBoxAPI.UISerialPort.SetEnabled(serialPort, 1);
1454
1455 if (def->serials[i]->source->data.file.path) {
1456 VBOX_UTF8_TO_UTF16(def->serials[i]->source->data.file.path,
1457 &pathUtf16);
1458 gVBoxAPI.UISerialPort.SetPath(serialPort, pathUtf16);
1459 }
1460
1461 /* For now hard code the serial ports to COM1 and COM2,
1462 * COM1 (Base Addr: 0x3F8 (decimal: 1016), IRQ: 4)
1463 * COM2 (Base Addr: 0x2F8 (decimal: 760), IRQ: 3)
1464 * TODO: make this more flexible
1465 */
1466 /* TODO: to improve the libvirt XMl handling so
1467 * that def->serials[i]->target.port shows real port
1468 * and not always start at 0
1469 */
1470 if (def->serials[i]->target.port == 0) {
1471 gVBoxAPI.UISerialPort.SetIRQ(serialPort, 4);
1472 gVBoxAPI.UISerialPort.SetIOBase(serialPort, 1016);
1473 VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
1474 i, 4, 1016, def->serials[i]->source->data.file.path);
1475 } else if (def->serials[i]->target.port == 1) {
1476 gVBoxAPI.UISerialPort.SetIRQ(serialPort, 3);
1477 gVBoxAPI.UISerialPort.SetIOBase(serialPort, 760);
1478 VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
1479 i, 3, 760, def->serials[i]->source->data.file.path);
1480 }
1481
1482 if (def->serials[i]->source->type == VIR_DOMAIN_CHR_TYPE_DEV) {
1483 gVBoxAPI.UISerialPort.SetHostMode(serialPort, PortMode_HostDevice);
1484 } else if (def->serials[i]->source->type == VIR_DOMAIN_CHR_TYPE_PIPE) {
1485 gVBoxAPI.UISerialPort.SetHostMode(serialPort, PortMode_HostPipe);
1486 } else if (gVBoxAPI.APIVersion >= 2002051 &&
1487 def->serials[i]->source->type == VIR_DOMAIN_CHR_TYPE_FILE) {
1488 /* PortMode RawFile is used for vbox 3.0 or later */
1489 gVBoxAPI.UISerialPort.SetHostMode(serialPort, PortMode_RawFile);
1490 } else {
1491 gVBoxAPI.UISerialPort.SetHostMode(serialPort,
1492 PortMode_Disconnected);
1493 }
1494
1495 VBOX_RELEASE(serialPort);
1496 VBOX_UTF16_FREE(pathUtf16);
1497 }
1498 }
1499
1500 static void
vboxAttachParallel(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)1501 vboxAttachParallel(virDomainDef *def, struct _vboxDriver *data, IMachine *machine)
1502 {
1503 ISystemProperties *systemProperties = NULL;
1504 PRUint32 parallelPortCount = 0;
1505 size_t i = 0;
1506
1507 gVBoxAPI.UIVirtualBox.GetSystemProperties(data->vboxObj, &systemProperties);
1508 if (systemProperties) {
1509 gVBoxAPI.UISystemProperties.GetParallelPortCount(systemProperties,
1510 ¶llelPortCount);
1511 VBOX_RELEASE(systemProperties);
1512 }
1513
1514 VIR_DEBUG("Number of Parallel Ports to be connected: %zu", def->nparallels);
1515 VIR_DEBUG("Number of Parallel Ports available: %d", parallelPortCount);
1516 for (i = 0; (i < def->nparallels) && (i < parallelPortCount); i++) {
1517 IParallelPort *parallelPort = NULL;
1518 PRUnichar *pathUtf16 = NULL;
1519
1520 VIR_DEBUG("ParallelPort(%zu): Type: %d", i, def->parallels[i]->source->type);
1521 VIR_DEBUG("ParallelPort(%zu): target.port: %d", i,
1522 def->parallels[i]->target.port);
1523
1524 gVBoxAPI.UIMachine.GetParallelPort(machine, i, ¶llelPort);
1525 if (!parallelPort)
1526 continue;
1527
1528 VBOX_UTF8_TO_UTF16(def->parallels[i]->source->data.file.path, &pathUtf16);
1529
1530 /* For now hard code the parallel ports to
1531 * LPT1 (Base Addr: 0x378 (decimal: 888), IRQ: 7)
1532 * LPT2 (Base Addr: 0x278 (decimal: 632), IRQ: 5)
1533 * TODO: make this more flexible
1534 */
1535 if ((def->parallels[i]->source->type == VIR_DOMAIN_CHR_TYPE_DEV) ||
1536 (def->parallels[i]->source->type == VIR_DOMAIN_CHR_TYPE_PTY) ||
1537 (def->parallels[i]->source->type == VIR_DOMAIN_CHR_TYPE_FILE) ||
1538 (def->parallels[i]->source->type == VIR_DOMAIN_CHR_TYPE_PIPE)) {
1539 gVBoxAPI.UIParallelPort.SetPath(parallelPort, pathUtf16);
1540 if (i == 0) {
1541 gVBoxAPI.UIParallelPort.SetIRQ(parallelPort, 7);
1542 gVBoxAPI.UIParallelPort.SetIOBase(parallelPort, 888);
1543 VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
1544 i, 7, 888, def->parallels[i]->source->data.file.path);
1545 } else if (i == 1) {
1546 gVBoxAPI.UIParallelPort.SetIRQ(parallelPort, 5);
1547 gVBoxAPI.UIParallelPort.SetIOBase(parallelPort, 632);
1548 VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
1549 i, 5, 632, def->parallels[i]->source->data.file.path);
1550 }
1551 }
1552
1553 /* like serial port, parallel port can't be enabled unless
1554 * correct IRQ and IOBase values are specified.
1555 */
1556 gVBoxAPI.UIParallelPort.SetEnabled(parallelPort, 1);
1557
1558 VBOX_RELEASE(parallelPort);
1559 VBOX_UTF16_FREE(pathUtf16);
1560 }
1561 }
1562
1563 static void
vboxAttachVideo(virDomainDef * def,IMachine * machine)1564 vboxAttachVideo(virDomainDef *def, IMachine *machine)
1565 {
1566 if ((def->nvideos == 1) &&
1567 (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_VBOX)) {
1568 gVBoxAPI.UIMachine.SetVRAMSize(machine,
1569 VIR_DIV_UP(def->videos[0]->vram, 1024));
1570 gVBoxAPI.UIMachine.SetMonitorCount(machine, def->videos[0]->heads);
1571 if (def->videos[0]->accel) {
1572 if (def->videos[0]->accel->accel3d) {
1573 gVBoxAPI.UIMachine.SetAccelerate3DEnabled(machine,
1574 def->videos[0]->accel->accel3d == VIR_TRISTATE_BOOL_YES);
1575 }
1576 if (def->videos[0]->accel->accel2d) {
1577 gVBoxAPI.UIMachine.SetAccelerate2DVideoEnabled(machine,
1578 def->videos[0]->accel->accel2d == VIR_TRISTATE_BOOL_YES);
1579 }
1580 } else {
1581 gVBoxAPI.UIMachine.SetAccelerate3DEnabled(machine, 0);
1582 gVBoxAPI.UIMachine.SetAccelerate2DVideoEnabled(machine, 0);
1583 }
1584 }
1585 }
1586
1587 static void
vboxAttachDisplay(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)1588 vboxAttachDisplay(virDomainDef *def, struct _vboxDriver *data, IMachine *machine)
1589 {
1590 int vrdpPresent = 0;
1591 int sdlPresent = 0;
1592 int guiPresent = 0;
1593 char *guiDisplay = NULL;
1594 char *sdlDisplay = NULL;
1595 size_t i = 0;
1596 virDomainGraphicsListenDef *glisten;
1597
1598 for (i = 0; i < def->ngraphics; i++) {
1599 IVRDEServer *VRDEServer = NULL;
1600
1601 if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) &&
1602 (vrdpPresent == 0)) {
1603
1604 vrdpPresent = 1;
1605 gVBoxAPI.UIMachine.GetVRDEServer(machine, &VRDEServer);
1606 if (VRDEServer) {
1607 gVBoxAPI.UIVRDEServer.SetEnabled(VRDEServer, PR_TRUE);
1608 VIR_DEBUG("VRDP Support turned ON.");
1609
1610 gVBoxAPI.UIVRDEServer.SetPorts(data, VRDEServer, def->graphics[i]);
1611
1612 if (def->graphics[i]->data.rdp.replaceUser) {
1613 gVBoxAPI.UIVRDEServer.SetReuseSingleConnection(VRDEServer,
1614 PR_TRUE);
1615 VIR_DEBUG("VRDP set to reuse single connection");
1616 }
1617
1618 if (def->graphics[i]->data.rdp.multiUser) {
1619 gVBoxAPI.UIVRDEServer.SetAllowMultiConnection(VRDEServer,
1620 PR_TRUE);
1621 VIR_DEBUG("VRDP set to allow multiple connection");
1622 }
1623
1624 if ((glisten = virDomainGraphicsGetListen(def->graphics[i], 0)) &&
1625 glisten->address) {
1626 PRUnichar *netAddressUtf16 = NULL;
1627
1628 VBOX_UTF8_TO_UTF16(glisten->address, &netAddressUtf16);
1629 gVBoxAPI.UIVRDEServer.SetNetAddress(data, VRDEServer,
1630 netAddressUtf16);
1631 VIR_DEBUG("VRDP listen address is set to: %s",
1632 glisten->address);
1633
1634 VBOX_UTF16_FREE(netAddressUtf16);
1635 }
1636
1637 VBOX_RELEASE(VRDEServer);
1638 }
1639 }
1640
1641 if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) &&
1642 (guiPresent == 0)) {
1643 guiPresent = 1;
1644 guiDisplay = g_strdup(def->graphics[i]->data.desktop.display);
1645 }
1646
1647 if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) &&
1648 (sdlPresent == 0)) {
1649 sdlPresent = 1;
1650 sdlDisplay = g_strdup(def->graphics[i]->data.sdl.display);
1651 }
1652 }
1653
1654 if ((vrdpPresent == 1) && (guiPresent == 0) && (sdlPresent == 0)) {
1655 /* store extradata key that frontend is set to vrdp */
1656 PRUnichar *keyTypeUtf16 = NULL;
1657 PRUnichar *valueTypeUtf16 = NULL;
1658
1659 VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
1660 VBOX_UTF8_TO_UTF16("vrdp", &valueTypeUtf16);
1661
1662 gVBoxAPI.UIMachine.SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
1663
1664 VBOX_UTF16_FREE(keyTypeUtf16);
1665 VBOX_UTF16_FREE(valueTypeUtf16);
1666
1667 } else if ((guiPresent == 0) && (sdlPresent == 1)) {
1668 /* store extradata key that frontend is set to sdl */
1669 PRUnichar *keyTypeUtf16 = NULL;
1670 PRUnichar *valueTypeUtf16 = NULL;
1671 PRUnichar *keyDislpayUtf16 = NULL;
1672 PRUnichar *valueDisplayUtf16 = NULL;
1673
1674 VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
1675 VBOX_UTF8_TO_UTF16("sdl", &valueTypeUtf16);
1676
1677 gVBoxAPI.UIMachine.SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
1678
1679 VBOX_UTF16_FREE(keyTypeUtf16);
1680 VBOX_UTF16_FREE(valueTypeUtf16);
1681
1682 if (sdlDisplay) {
1683 VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
1684 VBOX_UTF8_TO_UTF16(sdlDisplay, &valueDisplayUtf16);
1685
1686 gVBoxAPI.UIMachine.SetExtraData(machine, keyDislpayUtf16,
1687 valueDisplayUtf16);
1688
1689 VBOX_UTF16_FREE(keyDislpayUtf16);
1690 VBOX_UTF16_FREE(valueDisplayUtf16);
1691 }
1692
1693 } else {
1694 /* if all are set then default is gui, with vrdp turned on */
1695 PRUnichar *keyTypeUtf16 = NULL;
1696 PRUnichar *valueTypeUtf16 = NULL;
1697 PRUnichar *keyDislpayUtf16 = NULL;
1698 PRUnichar *valueDisplayUtf16 = NULL;
1699
1700 VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
1701 VBOX_UTF8_TO_UTF16("gui", &valueTypeUtf16);
1702
1703 gVBoxAPI.UIMachine.SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
1704
1705 VBOX_UTF16_FREE(keyTypeUtf16);
1706 VBOX_UTF16_FREE(valueTypeUtf16);
1707
1708 if (guiDisplay) {
1709 VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
1710 VBOX_UTF8_TO_UTF16(guiDisplay, &valueDisplayUtf16);
1711
1712 gVBoxAPI.UIMachine.SetExtraData(machine, keyDislpayUtf16,
1713 valueDisplayUtf16);
1714
1715 VBOX_UTF16_FREE(keyDislpayUtf16);
1716 VBOX_UTF16_FREE(valueDisplayUtf16);
1717 }
1718 }
1719
1720 VIR_FREE(guiDisplay);
1721 VIR_FREE(sdlDisplay);
1722 }
1723
1724 static void
vboxAttachUSB(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)1725 vboxAttachUSB(virDomainDef *def, struct _vboxDriver *data, IMachine *machine)
1726 {
1727 IUSBCommon *USBCommon = NULL;
1728 size_t i = 0;
1729 bool isUSB = false;
1730 nsresult rc;
1731
1732 if (def->nhostdevs == 0)
1733 return;
1734
1735 /* Loop through the devices first and see if you
1736 * have a USB Device, only if you have one then
1737 * start the USB controller else just proceed as
1738 * usual
1739 */
1740 for (i = 0; i < def->nhostdevs; i++) {
1741 if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
1742 continue;
1743
1744 if (def->hostdevs[i]->source.subsys.type !=
1745 VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
1746 continue;
1747
1748 if (!def->hostdevs[i]->source.subsys.u.usb.vendor &&
1749 !def->hostdevs[i]->source.subsys.u.usb.product)
1750 continue;
1751
1752 VIR_DEBUG("USB Device detected, VendorId:0x%x, ProductId:0x%x",
1753 def->hostdevs[i]->source.subsys.u.usb.vendor,
1754 def->hostdevs[i]->source.subsys.u.usb.product);
1755 isUSB = true;
1756 break;
1757 }
1758
1759 if (!isUSB)
1760 return;
1761
1762 /* First Start the USB Controller and then loop
1763 * to attach USB Devices to it
1764 */
1765 rc = gVBoxAPI.UIMachine.GetUSBCommon(machine, &USBCommon);
1766 if (NS_FAILED(rc) || !USBCommon)
1767 return;
1768 gVBoxAPI.UIUSBCommon.Enable(USBCommon);
1769
1770 for (i = 0; i < def->nhostdevs; i++) {
1771 char *filtername = NULL;
1772 PRUnichar *filternameUtf16 = NULL;
1773 IUSBDeviceFilter *filter = NULL;
1774 PRUnichar *vendorIdUtf16 = NULL;
1775 char vendorId[40] = {0};
1776 PRUnichar *productIdUtf16 = NULL;
1777 char productId[40] = {0};
1778
1779 if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
1780 continue;
1781
1782 if (def->hostdevs[i]->source.subsys.type !=
1783 VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
1784 continue;
1785
1786 /* Zero pad for nice alignment when fewer than 9999
1787 * devices.
1788 */
1789 filtername = g_strdup_printf("filter%04zu", i);
1790 VBOX_UTF8_TO_UTF16(filtername, &filternameUtf16);
1791 VIR_FREE(filtername);
1792 gVBoxAPI.UIUSBCommon.CreateDeviceFilter(USBCommon,
1793 filternameUtf16,
1794 &filter);
1795 VBOX_UTF16_FREE(filternameUtf16);
1796
1797 if (!filter)
1798 continue;
1799
1800 if (!def->hostdevs[i]->source.subsys.u.usb.vendor &&
1801 !def->hostdevs[i]->source.subsys.u.usb.product)
1802 continue;
1803
1804 if (def->hostdevs[i]->source.subsys.u.usb.vendor) {
1805 g_snprintf(vendorId, sizeof(vendorId), "%x",
1806 def->hostdevs[i]->source.subsys.u.usb.vendor);
1807 VBOX_UTF8_TO_UTF16(vendorId, &vendorIdUtf16);
1808 gVBoxAPI.UIUSBDeviceFilter.SetVendorId(filter, vendorIdUtf16);
1809 VBOX_UTF16_FREE(vendorIdUtf16);
1810 }
1811 if (def->hostdevs[i]->source.subsys.u.usb.product) {
1812 g_snprintf(productId, sizeof(productId), "%x",
1813 def->hostdevs[i]->source.subsys.u.usb.product);
1814 VBOX_UTF8_TO_UTF16(productId, &productIdUtf16);
1815 gVBoxAPI.UIUSBDeviceFilter.SetProductId(filter,
1816 productIdUtf16);
1817 VBOX_UTF16_FREE(productIdUtf16);
1818 }
1819 gVBoxAPI.UIUSBDeviceFilter.SetActive(filter, 1);
1820 gVBoxAPI.UIUSBCommon.InsertDeviceFilter(USBCommon, i, filter);
1821 VBOX_RELEASE(filter);
1822 }
1823
1824 VBOX_RELEASE(USBCommon);
1825 }
1826
1827 static void
vboxAttachSharedFolder(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)1828 vboxAttachSharedFolder(virDomainDef *def, struct _vboxDriver *data, IMachine *machine)
1829 {
1830 size_t i;
1831 PRUnichar *nameUtf16;
1832 PRUnichar *hostPathUtf16;
1833 PRBool writable;
1834
1835 if (def->nfss == 0)
1836 return;
1837
1838 for (i = 0; i < def->nfss; i++) {
1839 if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
1840 continue;
1841
1842 VBOX_UTF8_TO_UTF16(def->fss[i]->dst, &nameUtf16);
1843 VBOX_UTF8_TO_UTF16(def->fss[i]->src->path, &hostPathUtf16);
1844 writable = !def->fss[i]->readonly;
1845
1846 gVBoxAPI.UIMachine.CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
1847 writable, PR_FALSE);
1848
1849 VBOX_UTF16_FREE(nameUtf16);
1850 VBOX_UTF16_FREE(hostPathUtf16);
1851 }
1852 }
1853
1854 static virDomainPtr
vboxDomainDefineXMLFlags(virConnectPtr conn,const char * xml,unsigned int flags)1855 vboxDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
1856 {
1857 struct _vboxDriver *data = conn->privateData;
1858 IMachine *machine = NULL;
1859 IBIOSSettings *bios = NULL;
1860 vboxIID mchiid;
1861 virDomainDef *def = NULL;
1862 nsresult rc;
1863 char uuidstr[VIR_UUID_STRING_BUFLEN];
1864 virDomainPtr ret = NULL;
1865 unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
1866 bool machineReady = false;
1867
1868
1869 virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);
1870
1871 if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
1872 parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
1873
1874 if (!data->vboxObj)
1875 return ret;
1876
1877 if (!(def = virDomainDefParseString(xml, data->xmlopt,
1878 NULL, parse_flags)))
1879 return ret;
1880
1881 VBOX_IID_INITIALIZE(&mchiid);
1882 virUUIDFormat(def->uuid, uuidstr);
1883
1884 rc = gVBoxAPI.UIVirtualBox.CreateMachine(data, def, &machine, uuidstr);
1885
1886 if (NS_FAILED(rc)) {
1887 virReportError(VIR_ERR_INTERNAL_ERROR,
1888 _("could not define a domain, rc=%08x"), (unsigned)rc);
1889 goto cleanup;
1890 }
1891
1892 rc = gVBoxAPI.UIMachine.SetMemorySize(machine,
1893 VIR_DIV_UP(def->mem.cur_balloon, 1024));
1894 if (NS_FAILED(rc)) {
1895 virReportError(VIR_ERR_INTERNAL_ERROR,
1896 _("could not set the memory size of the domain to: %llu Kb, "
1897 "rc=%08x"),
1898 def->mem.cur_balloon, (unsigned)rc);
1899 }
1900
1901 if (virDomainDefHasVcpusOffline(def)) {
1902 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
1903 _("current vcpu count must equal maximum"));
1904 }
1905 rc = gVBoxAPI.UIMachine.SetCPUCount(machine, virDomainDefGetVcpusMax(def));
1906 if (NS_FAILED(rc)) {
1907 virReportError(VIR_ERR_INTERNAL_ERROR,
1908 _("could not set the number of virtual CPUs to: %u, rc=%08x"),
1909 virDomainDefGetVcpusMax(def), (unsigned)rc);
1910 }
1911
1912 rc = gVBoxAPI.UIMachine.SetCPUProperty(machine, CPUPropertyType_PAE,
1913 def->features[VIR_DOMAIN_FEATURE_PAE] ==
1914 VIR_TRISTATE_SWITCH_ON);
1915 if (NS_FAILED(rc)) {
1916 virReportError(VIR_ERR_INTERNAL_ERROR,
1917 _("could not change PAE status to: %s, rc=%08x"),
1918 (def->features[VIR_DOMAIN_FEATURE_PAE] == VIR_TRISTATE_SWITCH_ON)
1919 ? _("Enabled") : _("Disabled"), (unsigned)rc);
1920 }
1921
1922 gVBoxAPI.UIMachine.GetBIOSSettings(machine, &bios);
1923 if (bios) {
1924 rc = gVBoxAPI.UIBIOSSettings.SetACPIEnabled(bios,
1925 def->features[VIR_DOMAIN_FEATURE_ACPI] ==
1926 VIR_TRISTATE_SWITCH_ON);
1927 if (NS_FAILED(rc)) {
1928 virReportError(VIR_ERR_INTERNAL_ERROR,
1929 _("could not change ACPI status to: %s, rc=%08x"),
1930 (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_TRISTATE_SWITCH_ON)
1931 ? _("Enabled") : _("Disabled"), (unsigned)rc);
1932 }
1933 rc = gVBoxAPI.UIBIOSSettings.SetIOAPICEnabled(bios,
1934 def->features[VIR_DOMAIN_FEATURE_APIC] ==
1935 VIR_TRISTATE_SWITCH_ON);
1936 if (NS_FAILED(rc)) {
1937 virReportError(VIR_ERR_INTERNAL_ERROR,
1938 _("could not change APIC status to: %s, rc=%08x"),
1939 (def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_TRISTATE_SWITCH_ON)
1940 ? _("Enabled") : _("Disabled"), (unsigned)rc);
1941 }
1942 VBOX_RELEASE(bios);
1943 }
1944
1945 /* Register the machine before attaching other devices to it */
1946 rc = gVBoxAPI.UIVirtualBox.RegisterMachine(data->vboxObj, machine);
1947 if (NS_FAILED(rc)) {
1948 virReportError(VIR_ERR_INTERNAL_ERROR,
1949 _("could not define a domain, rc=%08x"), (unsigned)rc);
1950 goto cleanup;
1951 }
1952
1953 /* Get the uuid of the machine, currently it is immutable
1954 * object so open a session to it and get it back, so that
1955 * you can make changes to the machine setting
1956 */
1957 gVBoxAPI.UIMachine.GetId(machine, &mchiid);
1958 gVBoxAPI.UISession.Open(data, &mchiid, machine);
1959 gVBoxAPI.UISession.GetMachine(data->vboxSession, &machine);
1960
1961 vboxSetBootDeviceOrder(def, data, machine);
1962 if (vboxAttachStorageControllers(def, data, machine) < 0)
1963 goto cleanup;
1964 if (vboxAttachDrives(def, data, machine) < 0)
1965 goto cleanup;
1966 vboxAttachSound(def, machine);
1967 if (vboxAttachNetwork(def, data, machine) < 0)
1968 goto cleanup;
1969 vboxAttachSerial(def, data, machine);
1970 vboxAttachParallel(def, data, machine);
1971 vboxAttachVideo(def, machine);
1972 vboxAttachDisplay(def, data, machine);
1973 vboxAttachUSB(def, data, machine);
1974 vboxAttachSharedFolder(def, data, machine);
1975
1976 machineReady = true;
1977
1978 cleanup:
1979 /* if machine wasn't even created, cleanup is trivial */
1980 if (!machine) {
1981 vboxIIDUnalloc(&mchiid);
1982 virDomainDefFree(def);
1983
1984 return ret;
1985 }
1986
1987 /* Save the machine settings made till now, even when jumped here on error,
1988 * as otherwise unregister won't cleanup properly. For example, it won't
1989 * close media that were partially attached. The VBOX SDK docs say that
1990 * unregister implicitly calls saveSettings but evidently it's not so...
1991 */
1992 rc = gVBoxAPI.UIMachine.SaveSettings(machine);
1993 if (NS_FAILED(rc)) {
1994 virReportError(VIR_ERR_INTERNAL_ERROR,
1995 _("Failed to save VM settings, rc=%08x"), rc);
1996 machineReady = false;
1997 }
1998
1999 gVBoxAPI.UISession.Close(data->vboxSession);
2000
2001 if (machineReady) {
2002 ret = virGetDomain(conn, def->name, def->uuid, -1);
2003 } else {
2004 /* Unregister incompletely configured VM to not leave garbage behind */
2005 rc = gVBoxAPI.unregisterMachine(data, &mchiid, &machine);
2006
2007 if (NS_SUCCEEDED(rc))
2008 gVBoxAPI.deleteConfig(machine);
2009 else
2010 VIR_WARN("Could not cleanup partially created VM after failure, "
2011 "rc=%08x", rc);
2012 }
2013
2014 VBOX_RELEASE(machine);
2015 vboxIIDUnalloc(&mchiid);
2016 virDomainDefFree(def);
2017
2018 return ret;
2019 }
2020
2021 static virDomainPtr
vboxDomainDefineXML(virConnectPtr conn,const char * xml)2022 vboxDomainDefineXML(virConnectPtr conn, const char *xml)
2023 {
2024 return vboxDomainDefineXMLFlags(conn, xml, 0);
2025 }
2026
vboxDomainUndefineFlags(virDomainPtr dom,unsigned int flags)2027 static int vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags)
2028 {
2029 struct _vboxDriver *data = dom->conn->privateData;
2030 IMachine *machine = NULL;
2031 vboxIID iid;
2032 nsresult rc;
2033 int ret = -1;
2034
2035 if (!data->vboxObj)
2036 return ret;
2037
2038 gVBoxAPI.UIID.vboxIIDInitialize(&iid);
2039 /* No managed save, so we explicitly reject
2040 * VIR_DOMAIN_UNDEFINE_MANAGED_SAVE. No snapshot metadata for
2041 * VBox, so we can trivially ignore that flag. */
2042 virCheckFlags(VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
2043 vboxIIDFromUUID(&iid, dom->uuid);
2044 rc = gVBoxAPI.unregisterMachine(data, &iid, &machine);
2045
2046 DEBUGIID("UUID of machine being undefined", &iid);
2047
2048 if (NS_SUCCEEDED(rc)) {
2049 gVBoxAPI.deleteConfig(machine);
2050 ret = 0;
2051 } else {
2052 virReportError(VIR_ERR_INTERNAL_ERROR,
2053 _("could not delete the domain, rc=%08x"), (unsigned)rc);
2054 }
2055
2056 vboxIIDUnalloc(&iid);
2057 VBOX_RELEASE(machine);
2058
2059 return ret;
2060 }
2061
vboxDomainUndefine(virDomainPtr dom)2062 static int vboxDomainUndefine(virDomainPtr dom)
2063 {
2064 return vboxDomainUndefineFlags(dom, 0);
2065 }
2066
2067 static int
vboxStartMachine(virDomainPtr dom,int maxDomID,IMachine * machine,vboxIID * iid)2068 vboxStartMachine(virDomainPtr dom, int maxDomID, IMachine *machine, vboxIID *iid)
2069 {
2070 struct _vboxDriver *data = dom->conn->privateData;
2071 int vrdpPresent = 0;
2072 int sdlPresent = 0;
2073 int guiPresent = 0;
2074 char *guiDisplay = NULL;
2075 char *sdlDisplay = NULL;
2076 PRUnichar *keyTypeUtf16 = NULL;
2077 PRUnichar *valueTypeUtf16 = NULL;
2078 char *valueTypeUtf8 = NULL;
2079 PRUnichar *keyDislpayUtf16 = NULL;
2080 PRUnichar *valueDisplayUtf16 = NULL;
2081 char *valueDisplayUtf8 = NULL;
2082 IProgress *progress = NULL;
2083 PRUnichar *env = NULL;
2084 PRUnichar *sessionType = NULL;
2085 nsresult rc;
2086 int ret = -1;
2087
2088 if (!data->vboxObj)
2089 return -1;
2090
2091 VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
2092 gVBoxAPI.UIMachine.GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16);
2093 VBOX_UTF16_FREE(keyTypeUtf16);
2094
2095 if (valueTypeUtf16) {
2096 VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
2097 VBOX_UTF16_FREE(valueTypeUtf16);
2098
2099 if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
2100
2101 VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
2102 gVBoxAPI.UIMachine.GetExtraData(machine, keyDislpayUtf16,
2103 &valueDisplayUtf16);
2104 VBOX_UTF16_FREE(keyDislpayUtf16);
2105
2106 if (valueDisplayUtf16) {
2107 VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
2108 VBOX_UTF16_FREE(valueDisplayUtf16);
2109
2110 if (strlen(valueDisplayUtf8) == 0)
2111 VBOX_UTF8_FREE(valueDisplayUtf8);
2112 }
2113
2114 if (STREQ(valueTypeUtf8, "sdl")) {
2115 sdlPresent = 1;
2116 sdlDisplay = g_strdup(valueDisplayUtf8);
2117 }
2118
2119 if (STREQ(valueTypeUtf8, "gui")) {
2120 guiPresent = 1;
2121 guiDisplay = g_strdup(valueDisplayUtf8);
2122 }
2123 }
2124
2125 if (STREQ(valueTypeUtf8, "vrdp"))
2126 vrdpPresent = 1;
2127
2128 if (!vrdpPresent && !sdlPresent && !guiPresent) {
2129 /* if nothing is selected it means either the machine xml
2130 * file is really old or some values are missing so fallback
2131 */
2132 guiPresent = 1;
2133 }
2134
2135 VBOX_UTF8_FREE(valueTypeUtf8);
2136
2137 } else {
2138 guiPresent = 1;
2139 }
2140 VBOX_UTF8_FREE(valueDisplayUtf8);
2141
2142 if (guiPresent) {
2143 if (guiDisplay) {
2144 char *displayutf8;
2145 displayutf8 = g_strdup_printf("DISPLAY=%s", guiDisplay);
2146 VBOX_UTF8_TO_UTF16(displayutf8, &env);
2147 VIR_FREE(displayutf8);
2148 VIR_FREE(guiDisplay);
2149 }
2150
2151 VBOX_UTF8_TO_UTF16("gui", &sessionType);
2152 }
2153
2154 if (sdlPresent) {
2155 if (sdlDisplay) {
2156 char *displayutf8;
2157 displayutf8 = g_strdup_printf("DISPLAY=%s", sdlDisplay);
2158 VBOX_UTF8_TO_UTF16(displayutf8, &env);
2159 VIR_FREE(displayutf8);
2160 VIR_FREE(sdlDisplay);
2161 }
2162
2163 VBOX_UTF8_TO_UTF16("sdl", &sessionType);
2164 }
2165
2166 if (vrdpPresent)
2167 VBOX_UTF8_TO_UTF16("vrdp", &sessionType);
2168
2169 rc = gVBoxAPI.UIMachine.LaunchVMProcess(data, machine, iid,
2170 sessionType, env,
2171 &progress);
2172
2173 if (NS_FAILED(rc)) {
2174 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2175 _("OpenRemoteSession/LaunchVMProcess failed, domain can't be started"));
2176 goto cleanup;
2177 } else {
2178 PRBool completed = 0;
2179 resultCodeUnion resultCode;
2180
2181 gVBoxAPI.UIProgress.WaitForCompletion(progress, -1);
2182 rc = gVBoxAPI.UIProgress.GetCompleted(progress, &completed);
2183 if (NS_FAILED(rc)) {
2184 /* error */
2185 goto cleanup;
2186 }
2187 gVBoxAPI.UIProgress.GetResultCode(progress, &resultCode);
2188 if (RC_FAILED(resultCode)) {
2189 /* error */
2190 goto cleanup;
2191 } else {
2192 /* all ok set the domid */
2193 dom->id = maxDomID + 1;
2194 }
2195 }
2196
2197 ret = 0;
2198
2199 cleanup:
2200 VBOX_RELEASE(progress);
2201
2202 gVBoxAPI.UISession.Close(data->vboxSession);
2203
2204 VBOX_UTF16_FREE(env);
2205 VBOX_UTF16_FREE(sessionType);
2206
2207 return ret;
2208 }
2209
vboxDomainCreateWithFlags(virDomainPtr dom,unsigned int flags)2210 static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
2211 {
2212 struct _vboxDriver *data = dom->conn->privateData;
2213 vboxArray machines = VBOX_ARRAY_INITIALIZER;
2214 unsigned char uuid[VIR_UUID_BUFLEN] = {0};
2215 nsresult rc;
2216 size_t i = 0;
2217 int ret = -1;
2218
2219 if (!data->vboxObj)
2220 return -1;
2221
2222 virCheckFlags(0, -1);
2223
2224 if (!dom->name) {
2225 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
2226 _("Error while reading the domain name"));
2227 return -1;
2228 }
2229
2230 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj, ARRAY_GET_MACHINES);
2231 if (NS_FAILED(rc)) {
2232 virReportError(VIR_ERR_INTERNAL_ERROR,
2233 _("Could not get list of machines, rc=%08x"), (unsigned)rc);
2234 return -1;
2235 }
2236
2237 for (i = 0; i < machines.count; ++i) {
2238 IMachine *machine = machines.items[i];
2239 PRBool isAccessible = PR_FALSE;
2240
2241 if (!machine)
2242 continue;
2243
2244 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
2245 if (isAccessible) {
2246 vboxIID iid;
2247
2248 VBOX_IID_INITIALIZE(&iid);
2249
2250 rc = gVBoxAPI.UIMachine.GetId(machine, &iid);
2251 if (NS_FAILED(rc))
2252 continue;
2253 vboxIIDToUUID(&iid, uuid);
2254
2255 if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
2256 PRUint32 state;
2257 gVBoxAPI.UIMachine.GetState(machine, &state);
2258
2259 if (gVBoxAPI.machineStateChecker.NotStart(state)) {
2260 ret = vboxStartMachine(dom, i, machine, &iid);
2261 } else {
2262 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2263 _("machine is not in "
2264 "poweroff|saved|aborted state, so "
2265 "couldn't start it"));
2266 ret = -1;
2267 }
2268 }
2269 vboxIIDUnalloc(&iid);
2270 if (ret != -1)
2271 break;
2272 }
2273 }
2274
2275 /* Do the cleanup and take care you dont leak any memory */
2276 gVBoxAPI.UArray.vboxArrayRelease(&machines);
2277
2278 return ret;
2279 }
2280
vboxDomainCreate(virDomainPtr dom)2281 static int vboxDomainCreate(virDomainPtr dom)
2282 {
2283 return vboxDomainCreateWithFlags(dom, 0);
2284 }
2285
vboxDomainCreateXML(virConnectPtr conn,const char * xml,unsigned int flags)2286 static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml,
2287 unsigned int flags)
2288 {
2289 /* VirtualBox currently doesn't have support for running
2290 * virtual machines without actually defining them and thus
2291 * for time being just define new machine and start it.
2292 *
2293 * TODO: After the appropriate API's are added in VirtualBox
2294 * change this behaviour to the expected one.
2295 */
2296
2297 virDomainPtr dom;
2298
2299 virCheckFlags(0, NULL);
2300
2301 dom = vboxDomainDefineXML(conn, xml);
2302 if (dom == NULL)
2303 return NULL;
2304
2305 if (vboxDomainCreate(dom) < 0) {
2306 vboxDomainUndefineFlags(dom, 0);
2307 virObjectUnref(dom);
2308 return NULL;
2309 }
2310
2311 return dom;
2312 }
2313
vboxDomainIsActive(virDomainPtr dom)2314 static int vboxDomainIsActive(virDomainPtr dom)
2315 {
2316 struct _vboxDriver *data = dom->conn->privateData;
2317 vboxArray machines = VBOX_ARRAY_INITIALIZER;
2318 vboxIID iid;
2319 char *machineNameUtf8 = NULL;
2320 PRUnichar *machineNameUtf16 = NULL;
2321 unsigned char uuid[VIR_UUID_BUFLEN];
2322 size_t i;
2323 bool matched = false;
2324 nsresult rc;
2325 int ret = -1;
2326
2327 if (!data->vboxObj)
2328 return ret;
2329
2330 VBOX_IID_INITIALIZE(&iid);
2331 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj, ARRAY_GET_MACHINES);
2332 if (NS_FAILED(rc)) {
2333 virReportError(VIR_ERR_INTERNAL_ERROR,
2334 _("Could not get list of machines, rc=%08x"), (unsigned)rc);
2335 return ret;
2336 }
2337
2338 for (i = 0; i < machines.count; ++i) {
2339 IMachine *machine = machines.items[i];
2340 PRBool isAccessible = PR_FALSE;
2341
2342 if (!machine)
2343 continue;
2344
2345 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
2346 if (!isAccessible)
2347 continue;
2348
2349 gVBoxAPI.UIMachine.GetId(machine, &iid);
2350 if (NS_FAILED(rc))
2351 continue;
2352 vboxIIDToUUID(&iid, uuid);
2353 vboxIIDUnalloc(&iid);
2354
2355 if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
2356
2357 PRUint32 state;
2358
2359 matched = true;
2360
2361 gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16);
2362 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
2363
2364 gVBoxAPI.UIMachine.GetState(machine, &state);
2365
2366 if (gVBoxAPI.machineStateChecker.Online(state))
2367 ret = 1;
2368 else
2369 ret = 0;
2370 }
2371
2372 if (matched)
2373 break;
2374 }
2375
2376 /* Do the cleanup and take care you dont leak any memory */
2377 VBOX_UTF8_FREE(machineNameUtf8);
2378 VBOX_COM_UNALLOC_MEM(machineNameUtf16);
2379 gVBoxAPI.UArray.vboxArrayRelease(&machines);
2380
2381 return ret;
2382 }
2383
vboxDomainIsPersistent(virDomainPtr dom)2384 static int vboxDomainIsPersistent(virDomainPtr dom)
2385 {
2386 /* All domains are persistent. However, we do want to check for
2387 * existence. */
2388 struct _vboxDriver *data = dom->conn->privateData;
2389 vboxIID iid;
2390 IMachine *machine = NULL;
2391 int ret = -1;
2392
2393 if (!data->vboxObj)
2394 return ret;
2395
2396 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
2397 goto cleanup;
2398
2399 ret = 1;
2400
2401 cleanup:
2402 VBOX_RELEASE(machine);
2403 vboxIIDUnalloc(&iid);
2404 return ret;
2405 }
2406
vboxDomainIsUpdated(virDomainPtr dom)2407 static int vboxDomainIsUpdated(virDomainPtr dom)
2408 {
2409 /* VBox domains never have a persistent state that differs from
2410 * current state. However, we do want to check for existence. */
2411 struct _vboxDriver *data = dom->conn->privateData;
2412 vboxIID iid;
2413 IMachine *machine = NULL;
2414 int ret = -1;
2415
2416 if (!data->vboxObj)
2417 return ret;
2418
2419 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
2420 goto cleanup;
2421
2422 ret = 0;
2423
2424 cleanup:
2425 VBOX_RELEASE(machine);
2426 vboxIIDUnalloc(&iid);
2427 return ret;
2428 }
2429
vboxDomainSuspend(virDomainPtr dom)2430 static int vboxDomainSuspend(virDomainPtr dom)
2431 {
2432 struct _vboxDriver *data = dom->conn->privateData;
2433 IMachine *machine = NULL;
2434 vboxIID iid;
2435 IConsole *console = NULL;
2436 PRBool isAccessible = PR_FALSE;
2437 PRUint32 state;
2438 int ret = -1;
2439
2440 if (!data->vboxObj)
2441 return ret;
2442
2443 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
2444 goto cleanup;
2445
2446 if (!machine)
2447 goto cleanup;
2448
2449 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
2450 if (!isAccessible)
2451 goto cleanup;
2452
2453 gVBoxAPI.UIMachine.GetState(machine, &state);
2454
2455 if (gVBoxAPI.machineStateChecker.Running(state)) {
2456 /* set state pause */
2457 gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
2458 gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
2459 if (console) {
2460 gVBoxAPI.UIConsole.Pause(console);
2461 VBOX_RELEASE(console);
2462 ret = 0;
2463 } else {
2464 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2465 _("error while suspending the domain"));
2466 goto cleanup;
2467 }
2468 gVBoxAPI.UISession.Close(data->vboxSession);
2469 } else {
2470 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2471 _("machine not in running state to suspend it"));
2472 goto cleanup;
2473 }
2474
2475 cleanup:
2476 VBOX_RELEASE(machine);
2477 vboxIIDUnalloc(&iid);
2478 return ret;
2479 }
2480
vboxDomainResume(virDomainPtr dom)2481 static int vboxDomainResume(virDomainPtr dom)
2482 {
2483 struct _vboxDriver *data = dom->conn->privateData;
2484 IMachine *machine = NULL;
2485 vboxIID iid;
2486 IConsole *console = NULL;
2487 PRUint32 state;
2488 PRBool isAccessible = PR_FALSE;
2489 int ret = -1;
2490
2491 if (!data->vboxObj)
2492 return ret;
2493
2494 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
2495 goto cleanup;
2496
2497 if (!machine)
2498 goto cleanup;
2499
2500 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
2501 if (!isAccessible)
2502 goto cleanup;
2503
2504 gVBoxAPI.UIMachine.GetState(machine, &state);
2505
2506 if (gVBoxAPI.machineStateChecker.Paused(state)) {
2507 /* resume the machine here */
2508 gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
2509 gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
2510 if (console) {
2511 gVBoxAPI.UIConsole.Resume(console);
2512 VBOX_RELEASE(console);
2513 ret = 0;
2514 } else {
2515 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2516 _("error while resuming the domain"));
2517 goto cleanup;
2518 }
2519 gVBoxAPI.UISession.Close(data->vboxSession);
2520 } else {
2521 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2522 _("machine not paused, so can't resume it"));
2523 goto cleanup;
2524 }
2525
2526 cleanup:
2527 VBOX_RELEASE(machine);
2528 vboxIIDUnalloc(&iid);
2529 return ret;
2530 }
2531
vboxDomainShutdownFlags(virDomainPtr dom,unsigned int flags)2532 static int vboxDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
2533 {
2534 struct _vboxDriver *data = dom->conn->privateData;
2535 IMachine *machine = NULL;
2536 vboxIID iid;
2537 IConsole *console = NULL;
2538 PRUint32 state;
2539 PRBool isAccessible = PR_FALSE;
2540 int ret = -1;
2541
2542 if (!data->vboxObj)
2543 return ret;
2544
2545 virCheckFlags(0, -1);
2546
2547 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
2548 goto cleanup;
2549
2550 if (!machine)
2551 goto cleanup;
2552
2553 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
2554 if (!isAccessible)
2555 goto cleanup;
2556
2557 gVBoxAPI.UIMachine.GetState(machine, &state);
2558
2559 if (gVBoxAPI.machineStateChecker.Paused(state)) {
2560 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2561 _("machine paused, so can't power it down"));
2562 goto cleanup;
2563 } else if (gVBoxAPI.machineStateChecker.PoweredOff(state)) {
2564 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2565 _("machine already powered down"));
2566 goto cleanup;
2567 }
2568
2569 gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
2570 gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
2571 if (console) {
2572 gVBoxAPI.UIConsole.PowerButton(console);
2573 VBOX_RELEASE(console);
2574 ret = 0;
2575 }
2576 gVBoxAPI.UISession.Close(data->vboxSession);
2577
2578 cleanup:
2579 VBOX_RELEASE(machine);
2580 vboxIIDUnalloc(&iid);
2581 return ret;
2582 }
2583
vboxDomainShutdown(virDomainPtr dom)2584 static int vboxDomainShutdown(virDomainPtr dom)
2585 {
2586 return vboxDomainShutdownFlags(dom, 0);
2587 }
2588
vboxDomainReboot(virDomainPtr dom,unsigned int flags)2589 static int vboxDomainReboot(virDomainPtr dom, unsigned int flags)
2590 {
2591 struct _vboxDriver *data = dom->conn->privateData;
2592 IMachine *machine = NULL;
2593 vboxIID iid;
2594 IConsole *console = NULL;
2595 PRUint32 state;
2596 PRBool isAccessible = PR_FALSE;
2597 int ret = -1;
2598
2599 if (!data->vboxObj)
2600 return ret;
2601
2602 virCheckFlags(0, -1);
2603
2604 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
2605 goto cleanup;
2606
2607 if (!machine)
2608 goto cleanup;
2609
2610 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
2611 if (!isAccessible)
2612 goto cleanup;
2613
2614 gVBoxAPI.UIMachine.GetState(machine, &state);
2615
2616 if (gVBoxAPI.machineStateChecker.Running(state)) {
2617 gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
2618 gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
2619 if (console) {
2620 gVBoxAPI.UIConsole.Reset(console);
2621 VBOX_RELEASE(console);
2622 ret = 0;
2623 }
2624 gVBoxAPI.UISession.Close(data->vboxSession);
2625 } else {
2626 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2627 _("machine not running, so can't reboot it"));
2628 goto cleanup;
2629 }
2630
2631 cleanup:
2632 VBOX_RELEASE(machine);
2633 vboxIIDUnalloc(&iid);
2634 return ret;
2635 }
2636
vboxDomainDestroyFlags(virDomainPtr dom,unsigned int flags)2637 static int vboxDomainDestroyFlags(virDomainPtr dom, unsigned int flags)
2638 {
2639 struct _vboxDriver *data = dom->conn->privateData;
2640 IMachine *machine = NULL;
2641 vboxIID iid;
2642 IConsole *console = NULL;
2643 PRUint32 state;
2644 PRBool isAccessible = PR_FALSE;
2645 int ret = -1;
2646
2647 if (!data->vboxObj)
2648 return ret;
2649
2650 virCheckFlags(0, -1);
2651
2652 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
2653 goto cleanup;
2654
2655 if (!machine)
2656 goto cleanup;
2657
2658 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
2659 if (!isAccessible)
2660 goto cleanup;
2661
2662 gVBoxAPI.UIMachine.GetState(machine, &state);
2663
2664 if (gVBoxAPI.machineStateChecker.PoweredOff(state)) {
2665 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2666 _("machine already powered down"));
2667 goto cleanup;
2668 }
2669
2670 gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
2671 gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
2672 if (console) {
2673 gVBoxAPI.UIConsole.PowerDown(console);
2674 VBOX_RELEASE(console);
2675 dom->id = -1;
2676 ret = 0;
2677 }
2678 gVBoxAPI.UISession.Close(data->vboxSession);
2679
2680 cleanup:
2681 VBOX_RELEASE(machine);
2682 vboxIIDUnalloc(&iid);
2683 return ret;
2684 }
2685
vboxDomainDestroy(virDomainPtr dom)2686 static int vboxDomainDestroy(virDomainPtr dom)
2687 {
2688 return vboxDomainDestroyFlags(dom, 0);
2689 }
2690
vboxDomainGetOSType(virDomainPtr dom G_GNUC_UNUSED)2691 static char *vboxDomainGetOSType(virDomainPtr dom G_GNUC_UNUSED)
2692 {
2693 /* Returning "hvm" always as suggested on list, cause
2694 * this functions seems to be badly named and it
2695 * is supposed to pass the ABI name and not the domain
2696 * operating system driver as I had imagined ;)
2697 */
2698
2699 return g_strdup("hvm");
2700 }
2701
vboxDomainSetMemory(virDomainPtr dom,unsigned long memory)2702 static int vboxDomainSetMemory(virDomainPtr dom, unsigned long memory)
2703 {
2704 struct _vboxDriver *data = dom->conn->privateData;
2705 IMachine *machine = NULL;
2706 vboxIID iid;
2707 PRUint32 state;
2708 PRBool isAccessible = PR_FALSE;
2709 nsresult rc;
2710 int ret = -1;
2711
2712 if (!data->vboxObj)
2713 return ret;
2714
2715 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
2716 goto cleanup;
2717
2718 if (!machine)
2719 goto cleanup;
2720
2721 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
2722 if (!isAccessible)
2723 goto cleanup;
2724
2725 gVBoxAPI.UIMachine.GetState(machine, &state);
2726
2727 if (!gVBoxAPI.machineStateChecker.PoweredOff(state)) {
2728 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
2729 _("memory size can't be changed unless domain is powered down"));
2730 goto cleanup;
2731 }
2732
2733 rc = gVBoxAPI.UISession.Open(data, &iid, machine);
2734 if (NS_FAILED(rc))
2735 goto cleanup;
2736
2737 rc = gVBoxAPI.UISession.GetMachine(data->vboxSession, &machine);
2738 if (NS_SUCCEEDED(rc) && machine) {
2739
2740 rc = gVBoxAPI.UIMachine.SetMemorySize(machine,
2741 VIR_DIV_UP(memory, 1024));
2742 if (NS_SUCCEEDED(rc)) {
2743 gVBoxAPI.UIMachine.SaveSettings(machine);
2744 ret = 0;
2745 } else {
2746 virReportError(VIR_ERR_INTERNAL_ERROR,
2747 _("could not set the memory size of the "
2748 "domain to: %lu Kb, rc=%08x"),
2749 memory, (unsigned)rc);
2750 }
2751 }
2752 gVBoxAPI.UISession.Close(data->vboxSession);
2753
2754 cleanup:
2755 VBOX_RELEASE(machine);
2756 vboxIIDUnalloc(&iid);
2757 return ret;
2758 }
2759
vboxDomainGetInfo(virDomainPtr dom,virDomainInfoPtr info)2760 static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
2761 {
2762 struct _vboxDriver *data = dom->conn->privateData;
2763 vboxArray machines = VBOX_ARRAY_INITIALIZER;
2764 char *machineName = NULL;
2765 PRUnichar *machineNameUtf16 = NULL;
2766 nsresult rc;
2767 size_t i = 0;
2768 int ret = -1;
2769
2770 if (!data->vboxObj)
2771 return -1;
2772
2773 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj, ARRAY_GET_MACHINES);
2774 if (NS_FAILED(rc)) {
2775 virReportError(VIR_ERR_INTERNAL_ERROR,
2776 _("Could not get list of machines, rc=%08x"), (unsigned)rc);
2777 return -1;
2778 }
2779
2780 info->nrVirtCpu = 0;
2781 for (i = 0; i < machines.count; ++i) {
2782 IMachine *machine = machines.items[i];
2783 PRBool isAccessible = PR_FALSE;
2784
2785 if (!machine)
2786 continue;
2787
2788 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
2789 if (!isAccessible)
2790 continue;
2791
2792 gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16);
2793 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
2794
2795 if (STREQ(dom->name, machineName)) {
2796 /* Get the Machine State (also match it with
2797 * virDomainState). Get the Machine memory and
2798 * for time being set max_balloon and cur_balloon to same
2799 * Also since there is no direct way of checking
2800 * the cputime required (one condition being the
2801 * VM is remote), return zero for cputime. Get the
2802 * number of CPU.
2803 */
2804 PRUint32 CPUCount = 0;
2805 PRUint32 memorySize = 0;
2806 PRUint32 state;
2807 PRUint32 maxMemorySize = 4 * 1024;
2808 ISystemProperties *systemProperties = NULL;
2809
2810 gVBoxAPI.UIVirtualBox.GetSystemProperties(data->vboxObj, &systemProperties);
2811 if (systemProperties) {
2812 gVBoxAPI.UISystemProperties.GetMaxGuestRAM(systemProperties, &maxMemorySize);
2813 VBOX_RELEASE(systemProperties);
2814 systemProperties = NULL;
2815 }
2816
2817 gVBoxAPI.UIMachine.GetCPUCount(machine, &CPUCount);
2818 gVBoxAPI.UIMachine.GetMemorySize(machine, &memorySize);
2819 gVBoxAPI.UIMachine.GetState(machine, &state);
2820
2821 info->cpuTime = 0;
2822 info->nrVirtCpu = CPUCount;
2823 info->memory = memorySize * 1024;
2824 info->maxMem = maxMemorySize * 1024;
2825 info->state = gVBoxAPI.vboxConvertState(state);
2826
2827 ret = 0;
2828 }
2829
2830 VBOX_UTF8_FREE(machineName);
2831 VBOX_COM_UNALLOC_MEM(machineNameUtf16);
2832 if (info->nrVirtCpu)
2833 break;
2834
2835 }
2836
2837 gVBoxAPI.UArray.vboxArrayRelease(&machines);
2838
2839 return ret;
2840 }
2841
vboxDomainGetState(virDomainPtr dom,int * state,int * reason,unsigned int flags)2842 static int vboxDomainGetState(virDomainPtr dom, int *state,
2843 int *reason, unsigned int flags)
2844 {
2845 struct _vboxDriver *data = dom->conn->privateData;
2846 vboxIID domiid;
2847 IMachine *machine = NULL;
2848 PRUint32 mstate;
2849 int ret = -1;
2850
2851 if (!data->vboxObj)
2852 return ret;
2853
2854 virCheckFlags(0, -1);
2855
2856 if (openSessionForMachine(data, dom->uuid, &domiid, &machine) < 0)
2857 goto cleanup;
2858
2859 gVBoxAPI.UIMachine.GetState(machine, &mstate);
2860
2861 *state = gVBoxAPI.vboxConvertState(mstate);
2862
2863 if (reason)
2864 *reason = 0;
2865
2866 ret = 0;
2867
2868 cleanup:
2869 vboxIIDUnalloc(&domiid);
2870 return ret;
2871 }
2872
vboxDomainSetVcpusFlags(virDomainPtr dom,unsigned int nvcpus,unsigned int flags)2873 static int vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
2874 unsigned int flags)
2875 {
2876 struct _vboxDriver *data = dom->conn->privateData;
2877 IMachine *machine = NULL;
2878 vboxIID iid;
2879 PRUint32 CPUCount = nvcpus;
2880 nsresult rc;
2881 int ret = -1;
2882
2883 if (!data->vboxObj)
2884 return ret;
2885
2886 if (flags != VIR_DOMAIN_AFFECT_LIVE) {
2887 virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2888 return -1;
2889 }
2890
2891 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
2892 return -1;
2893
2894 rc = gVBoxAPI.UISession.Open(data, &iid, machine);
2895 if (NS_SUCCEEDED(rc)) {
2896 gVBoxAPI.UISession.GetMachine(data->vboxSession, &machine);
2897 if (machine) {
2898 rc = gVBoxAPI.UIMachine.SetCPUCount(machine, CPUCount);
2899 if (NS_SUCCEEDED(rc)) {
2900 gVBoxAPI.UIMachine.SaveSettings(machine);
2901 ret = 0;
2902 } else {
2903 virReportError(VIR_ERR_INTERNAL_ERROR,
2904 _("could not set the number of cpus of the domain "
2905 "to: %u, rc=%08x"),
2906 CPUCount, (unsigned)rc);
2907 }
2908 VBOX_RELEASE(machine);
2909 } else {
2910 virReportError(VIR_ERR_NO_DOMAIN,
2911 _("no domain with matching id %d"), dom->id);
2912 }
2913 } else {
2914 virReportError(VIR_ERR_NO_DOMAIN,
2915 _("can't open session to the domain with id %d"), dom->id);
2916 }
2917 gVBoxAPI.UISession.Close(data->vboxSession);
2918
2919 vboxIIDUnalloc(&iid);
2920 return ret;
2921 }
2922
vboxDomainSetVcpus(virDomainPtr dom,unsigned int nvcpus)2923 static int vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
2924 {
2925 return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2926 }
2927
vboxDomainGetVcpusFlags(virDomainPtr dom,unsigned int flags)2928 static int vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
2929 {
2930 struct _vboxDriver *data = dom->conn->privateData;
2931 ISystemProperties *systemProperties = NULL;
2932 PRUint32 maxCPUCount = 0;
2933 int ret = -1;
2934
2935 if (!data->vboxObj)
2936 return ret;
2937
2938 if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
2939 virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2940 return -1;
2941 }
2942
2943 /* Currently every domain supports the same number of max cpus
2944 * as that supported by vbox and thus take it directly from
2945 * the systemproperties.
2946 */
2947
2948 gVBoxAPI.UIVirtualBox.GetSystemProperties(data->vboxObj, &systemProperties);
2949 if (systemProperties) {
2950 gVBoxAPI.UISystemProperties.GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
2951 VBOX_RELEASE(systemProperties);
2952 }
2953
2954 if (maxCPUCount > 0)
2955 ret = maxCPUCount;
2956
2957 return ret;
2958 }
2959
vboxDomainGetMaxVcpus(virDomainPtr dom)2960 static int vboxDomainGetMaxVcpus(virDomainPtr dom)
2961 {
2962 return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
2963 VIR_DOMAIN_VCPU_MAXIMUM));
2964 }
2965
2966 static void
vboxHostDeviceGetXMLDesc(struct _vboxDriver * data,virDomainDef * def,IMachine * machine)2967 vboxHostDeviceGetXMLDesc(struct _vboxDriver *data, virDomainDef *def, IMachine *machine)
2968 {
2969 IUSBCommon *USBCommon = NULL;
2970 PRBool enabled = PR_FALSE;
2971 vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER;
2972 size_t i;
2973 PRUint32 USBFilterCount = 0;
2974
2975 def->nhostdevs = 0;
2976
2977 gVBoxAPI.UIMachine.GetUSBCommon(machine, &USBCommon);
2978 if (!USBCommon)
2979 return;
2980
2981 gVBoxAPI.UIUSBCommon.GetEnabled(USBCommon, &enabled);
2982 if (!enabled)
2983 goto release_controller;
2984
2985 gVBoxAPI.UArray.vboxArrayGet(&deviceFilters, USBCommon,
2986 gVBoxAPI.UArray.handleUSBGetDeviceFilters(USBCommon));
2987
2988 if (deviceFilters.count == 0)
2989 goto release_filters;
2990
2991 /* check if the filters are active and then only
2992 * alloc mem and set def->nhostdevs
2993 */
2994
2995 for (i = 0; i < deviceFilters.count; i++) {
2996 PRBool active = PR_FALSE;
2997 IUSBDeviceFilter *deviceFilter = deviceFilters.items[i];
2998
2999 gVBoxAPI.UIUSBDeviceFilter.GetActive(deviceFilter, &active);
3000 if (active)
3001 def->nhostdevs++;
3002 }
3003
3004 if (def->nhostdevs == 0)
3005 goto release_filters;
3006
3007 /* Alloc mem needed for the filters now */
3008 def->hostdevs = g_new0(virDomainHostdevDef *, def->nhostdevs);
3009
3010 for (i = 0; i < def->nhostdevs; i++) {
3011 def->hostdevs[i] = virDomainHostdevDefNew();
3012 if (!def->hostdevs[i])
3013 goto release_hostdevs;
3014 }
3015
3016 for (i = 0; i < deviceFilters.count; i++) {
3017 PRBool active = PR_FALSE;
3018 IUSBDeviceFilter *deviceFilter = deviceFilters.items[i];
3019 PRUnichar *vendorIdUtf16 = NULL;
3020 char *vendorIdUtf8 = NULL;
3021 unsigned vendorId = 0;
3022 PRUnichar *productIdUtf16 = NULL;
3023 char *productIdUtf8 = NULL;
3024 unsigned productId = 0;
3025 char *endptr = NULL;
3026
3027 gVBoxAPI.UIUSBDeviceFilter.GetActive(deviceFilter, &active);
3028 if (!active)
3029 continue;
3030
3031 def->hostdevs[USBFilterCount]->mode =
3032 VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
3033 def->hostdevs[USBFilterCount]->source.subsys.type =
3034 VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
3035
3036 gVBoxAPI.UIUSBDeviceFilter.GetVendorId(deviceFilter, &vendorIdUtf16);
3037 gVBoxAPI.UIUSBDeviceFilter.GetProductId(deviceFilter, &productIdUtf16);
3038
3039 VBOX_UTF16_TO_UTF8(vendorIdUtf16, &vendorIdUtf8);
3040 VBOX_UTF16_TO_UTF8(productIdUtf16, &productIdUtf8);
3041
3042 ignore_value(virStrToLong_ui(vendorIdUtf8, &endptr, 16, &vendorId));
3043 ignore_value(virStrToLong_ui(productIdUtf8, &endptr, 16, &productId));
3044
3045 def->hostdevs[USBFilterCount]->source.subsys.u.usb.vendor = vendorId;
3046 def->hostdevs[USBFilterCount]->source.subsys.u.usb.product = productId;
3047
3048 VBOX_UTF16_FREE(vendorIdUtf16);
3049 VBOX_UTF8_FREE(vendorIdUtf8);
3050
3051 VBOX_UTF16_FREE(productIdUtf16);
3052 VBOX_UTF8_FREE(productIdUtf8);
3053
3054 USBFilterCount++;
3055 }
3056
3057 release_filters:
3058 gVBoxAPI.UArray.vboxArrayRelease(&deviceFilters);
3059 release_controller:
3060 VBOX_RELEASE(USBCommon);
3061 return;
3062
3063 release_hostdevs:
3064 for (i = 0; i < def->nhostdevs; i++)
3065 virDomainHostdevDefFree(def->hostdevs[i]);
3066 VIR_FREE(def->hostdevs);
3067
3068 goto release_filters;
3069 }
3070
3071
3072 static int
vboxDumpStorageControllers(virDomainDef * def,IMachine * machine)3073 vboxDumpStorageControllers(virDomainDef *def, IMachine *machine)
3074 {
3075 vboxArray storageControllers = VBOX_ARRAY_INITIALIZER;
3076 size_t i = 0;
3077 int ret = -1;
3078
3079 gVBoxAPI.UArray.vboxArrayGet(&storageControllers, machine,
3080 gVBoxAPI.UArray.handleMachineGetStorageControllers(machine));
3081
3082 for (i = 0; i < storageControllers.count; i++) {
3083 IStorageController *controller = storageControllers.items[i];
3084 PRUint32 storageBus = StorageBus_Null;
3085 PRUint32 controllerType = StorageControllerType_Null;
3086 virDomainControllerType type = VIR_DOMAIN_CONTROLLER_TYPE_LAST;
3087 int model = -1;
3088
3089 if (!controller)
3090 continue;
3091
3092 gVBoxAPI.UIStorageController.GetBus(controller, &storageBus);
3093 gVBoxAPI.UIStorageController.GetControllerType(controller,
3094 &controllerType);
3095
3096 /* vbox controller model => libvirt controller model */
3097 switch ((enum StorageControllerType) controllerType) {
3098 case StorageControllerType_PIIX3:
3099 model = VIR_DOMAIN_CONTROLLER_MODEL_IDE_PIIX3;
3100
3101 break;
3102 case StorageControllerType_PIIX4:
3103 model = VIR_DOMAIN_CONTROLLER_MODEL_IDE_PIIX4;
3104
3105 break;
3106 case StorageControllerType_ICH6:
3107 model = VIR_DOMAIN_CONTROLLER_MODEL_IDE_ICH6;
3108
3109 break;
3110 case StorageControllerType_BusLogic:
3111 model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC;
3112
3113 break;
3114 case StorageControllerType_LsiLogic:
3115 model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC;
3116
3117 break;
3118 case StorageControllerType_LsiLogicSas:
3119 model = VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068;
3120
3121 break;
3122 case StorageControllerType_IntelAhci:
3123 case StorageControllerType_I82078:
3124 case StorageControllerType_Null:
3125 break;
3126 }
3127
3128 /* vbox controller bus => libvirt controller type */
3129 switch ((enum StorageBus) storageBus) {
3130 case StorageBus_IDE:
3131 type = VIR_DOMAIN_CONTROLLER_TYPE_IDE;
3132
3133 break;
3134 case StorageBus_SCSI:
3135 case StorageBus_SAS:
3136 type = VIR_DOMAIN_CONTROLLER_TYPE_SCSI;
3137
3138 break;
3139 case StorageBus_SATA:
3140 type = VIR_DOMAIN_CONTROLLER_TYPE_SATA;
3141
3142 break;
3143 case StorageBus_Floppy:
3144 type = VIR_DOMAIN_CONTROLLER_TYPE_FDC;
3145
3146 break;
3147 case StorageBus_Null:
3148 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3149 _("Unsupported null storage bus"));
3150
3151 goto cleanup;
3152 }
3153
3154 if (type != VIR_DOMAIN_CONTROLLER_TYPE_LAST) {
3155 virDomainControllerDef *cont;
3156
3157 cont = virDomainDefAddController(def, type, -1, model);
3158 if (!cont) {
3159 virReportError(VIR_ERR_INTERNAL_ERROR,
3160 _("Failed to add %s controller type definition"),
3161 virDomainControllerTypeToString(type));
3162 goto cleanup;
3163 }
3164 }
3165 }
3166
3167 ret = 0;
3168
3169 cleanup:
3170 gVBoxAPI.UArray.vboxArrayRelease(&storageControllers);
3171
3172 return ret;
3173 }
3174
3175
3176 static int
vboxDumpDisks(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)3177 vboxDumpDisks(virDomainDef *def, struct _vboxDriver *data, IMachine *machine)
3178 {
3179 vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
3180 int ret = -1;
3181 IMediumAttachment *mediumAttachment = NULL;
3182 IMedium *medium = NULL;
3183 IStorageController *controller = NULL;
3184 PRUnichar *controllerName = NULL, *mediumLocUtf16 = NULL;
3185 PRUint32 deviceType, storageBus;
3186 PRInt32 devicePort, deviceSlot;
3187 PRBool readOnly;
3188 nsresult rc;
3189 virDomainDiskDef *disk = NULL;
3190 virDomainControllerDef *ctrl = NULL;
3191 char *mediumLocUtf8 = NULL;
3192 size_t sdCount = 0, i, j;
3193
3194 def->ndisks = 0;
3195 gVBoxAPI.UArray.vboxArrayGet(&mediumAttachments, machine,
3196 gVBoxAPI.UArray.handleMachineGetMediumAttachments(machine));
3197
3198 /* get the number of attachments */
3199 for (i = 0; i < mediumAttachments.count; i++) {
3200 mediumAttachment = mediumAttachments.items[i];
3201 if (!mediumAttachment)
3202 continue;
3203
3204 rc = gVBoxAPI.UIMediumAttachment.GetMedium(mediumAttachment, &medium);
3205 if (NS_FAILED(rc)) {
3206 virReportError(VIR_ERR_INTERNAL_ERROR,
3207 _("Could not get IMedium, rc=%08x"), rc);
3208 goto cleanup;
3209 }
3210
3211 def->ndisks++;
3212 VBOX_RELEASE(medium);
3213 }
3214
3215 /* Allocate mem, if fails return error */
3216 def->disks = g_new0(virDomainDiskDef *, def->ndisks);
3217
3218 for (i = 0; i < def->ndisks; i++) {
3219 disk = virDomainDiskDefNew(NULL);
3220 if (!disk)
3221 goto cleanup;
3222
3223 def->disks[i] = disk;
3224 }
3225
3226 /* get the attachment details here */
3227 for (i = 0; i < mediumAttachments.count; i++) {
3228 mediumAttachment = mediumAttachments.items[i];
3229 controller = NULL;
3230 controllerName = NULL;
3231 deviceType = DeviceType_Null;
3232 storageBus = StorageBus_Null;
3233 readOnly = PR_FALSE;
3234 medium = NULL;
3235 mediumLocUtf16 = NULL;
3236 mediumLocUtf8 = NULL;
3237 devicePort = 0;
3238 deviceSlot = 0;
3239 disk = def->disks[i];
3240
3241 if (!mediumAttachment)
3242 continue;
3243
3244 rc = gVBoxAPI.UIMediumAttachment.GetMedium(mediumAttachment, &medium);
3245 if (NS_FAILED(rc)) {
3246 virReportError(VIR_ERR_INTERNAL_ERROR,
3247 _("Could not get IMedium, rc=%08x"), rc);
3248 goto cleanup;
3249 }
3250
3251 rc = gVBoxAPI.UIMediumAttachment.GetController(mediumAttachment,
3252 &controllerName);
3253 if (NS_FAILED(rc)) {
3254 virReportError(VIR_ERR_INTERNAL_ERROR,
3255 _("Failed to get storage controller name, rc=%08x"),
3256 rc);
3257 goto cleanup;
3258 }
3259
3260 rc = gVBoxAPI.UIMachine.GetStorageControllerByName(machine,
3261 controllerName,
3262 &controller);
3263 if (NS_FAILED(rc)) {
3264 virReportError(VIR_ERR_INTERNAL_ERROR,
3265 _("Could not get storage controller by name, rc=%08x"),
3266 rc);
3267 goto cleanup;
3268 }
3269
3270 rc = gVBoxAPI.UIMediumAttachment.GetType(mediumAttachment, &deviceType);
3271 if (NS_FAILED(rc)) {
3272 virReportError(VIR_ERR_INTERNAL_ERROR,
3273 _("Could not get device type, rc=%08x"), rc);
3274 goto cleanup;
3275 }
3276 rc = gVBoxAPI.UIMediumAttachment.GetPort(mediumAttachment, &devicePort);
3277 if (NS_FAILED(rc)) {
3278 virReportError(VIR_ERR_INTERNAL_ERROR,
3279 _("Could not get device port, rc=%08x"), rc);
3280 goto cleanup;
3281 }
3282 rc = gVBoxAPI.UIMediumAttachment.GetDevice(mediumAttachment, &deviceSlot);
3283 if (NS_FAILED(rc)) {
3284 virReportError(VIR_ERR_INTERNAL_ERROR,
3285 _("Could not get device slot, rc=%08x"), rc);
3286 goto cleanup;
3287 }
3288 rc = gVBoxAPI.UIStorageController.GetBus(controller, &storageBus);
3289 if (NS_FAILED(rc)) {
3290 virReportError(VIR_ERR_INTERNAL_ERROR,
3291 _("Could not get storage controller bus, rc=%08x"),
3292 rc);
3293 goto cleanup;
3294 }
3295
3296 if (medium) {
3297 rc = gVBoxAPI.UIMedium.GetLocation(medium, &mediumLocUtf16);
3298 if (NS_FAILED(rc)) {
3299 virReportError(VIR_ERR_INTERNAL_ERROR,
3300 _("Could not get medium storage location, rc=%08x"),
3301 rc);
3302 goto cleanup;
3303 }
3304
3305 VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
3306
3307 virDomainDiskSetSource(disk, mediumLocUtf8);
3308
3309 rc = gVBoxAPI.UIMedium.GetReadOnly(medium, &readOnly);
3310 if (NS_FAILED(rc)) {
3311 virReportError(VIR_ERR_INTERNAL_ERROR,
3312 _("Could not get read only state, rc=%08x"), rc);
3313 goto cleanup;
3314 }
3315 }
3316
3317 disk->dst = vboxGenerateMediumName(storageBus, devicePort, deviceSlot,
3318 sdCount);
3319
3320 if (!disk->dst) {
3321 virReportError(VIR_ERR_INTERNAL_ERROR,
3322 _("Could not generate medium name for the disk "
3323 "at: port:%d, slot:%d"), devicePort, deviceSlot);
3324 goto cleanup;
3325 }
3326
3327 disk->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE;
3328 disk->info.addr.drive.bus = 0;
3329 disk->info.addr.drive.unit = devicePort;
3330
3331 switch ((enum StorageBus) storageBus) {
3332 case StorageBus_IDE:
3333 disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
3334 disk->info.addr.drive.bus = devicePort; /* primary, secondary */
3335 disk->info.addr.drive.unit = deviceSlot; /* master, slave */
3336
3337 break;
3338 case StorageBus_SATA:
3339 disk->bus = VIR_DOMAIN_DISK_BUS_SATA;
3340 sdCount++;
3341
3342 break;
3343 case StorageBus_SCSI:
3344 case StorageBus_SAS:
3345 disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
3346 sdCount++;
3347
3348 /* In vbox, if there's a disk attached to SAS controller, there will
3349 * be libvirt SCSI controller present with model "lsi1068", and we
3350 * need to find its index
3351 */
3352 for (j = 0; j < def->ncontrollers; j++) {
3353 ctrl = def->controllers[j];
3354
3355 if (ctrl->type != VIR_DOMAIN_CONTROLLER_TYPE_SCSI)
3356 continue;
3357
3358 if (storageBus == StorageBus_SAS &&
3359 ctrl->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068) {
3360 disk->info.addr.drive.controller = ctrl->idx;
3361 break;
3362 }
3363
3364 if (storageBus == StorageBus_SCSI &&
3365 ctrl->model != VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068) {
3366 disk->info.addr.drive.controller = ctrl->idx;
3367 break;
3368 }
3369 }
3370
3371 break;
3372 case StorageBus_Floppy:
3373 disk->bus = VIR_DOMAIN_DISK_BUS_FDC;
3374
3375 break;
3376 case StorageBus_Null:
3377 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3378 _("Unsupported null storage bus"));
3379 goto cleanup;
3380 }
3381
3382 switch ((enum DeviceType) deviceType) {
3383 case DeviceType_HardDisk:
3384 disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
3385
3386 break;
3387 case DeviceType_Floppy:
3388 disk->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
3389
3390 break;
3391 case DeviceType_DVD:
3392 disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
3393
3394 break;
3395 case DeviceType_Network:
3396 case DeviceType_USB:
3397 case DeviceType_SharedFolder:
3398 case DeviceType_Null:
3399 virReportError(VIR_ERR_INTERNAL_ERROR,
3400 _("Unsupported vbox device type: %d"), deviceType);
3401 goto cleanup;
3402 }
3403
3404 if (readOnly == PR_TRUE)
3405 disk->src->readonly = true;
3406
3407 virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
3408
3409 VBOX_UTF16_FREE(controllerName);
3410 VBOX_UTF8_FREE(mediumLocUtf8);
3411 VBOX_UTF16_FREE(mediumLocUtf16);
3412 VBOX_RELEASE(medium);
3413 VBOX_RELEASE(controller);
3414 }
3415
3416 ret = 0;
3417
3418 cleanup:
3419 gVBoxAPI.UArray.vboxArrayRelease(&mediumAttachments);
3420
3421 if (ret < 0) {
3422 VBOX_UTF16_FREE(controllerName);
3423 VBOX_UTF8_FREE(mediumLocUtf8);
3424 VBOX_UTF16_FREE(mediumLocUtf16);
3425 VBOX_RELEASE(medium);
3426 VBOX_RELEASE(controller);
3427 }
3428
3429 return ret;
3430 }
3431
3432 static int
vboxDumpVideo(virDomainDef * def,struct _vboxDriver * data G_GNUC_UNUSED,IMachine * machine)3433 vboxDumpVideo(virDomainDef *def, struct _vboxDriver *data G_GNUC_UNUSED,
3434 IMachine *machine)
3435 {
3436 /* dump video options vram/2d/3d/directx/etc. */
3437 /* the default is: vram is 8MB, One monitor, 3dAccel Off */
3438 PRUint32 VRAMSize = 8;
3439 PRUint32 monitorCount = 1;
3440 PRBool accelerate3DEnabled = PR_FALSE;
3441 PRBool accelerate2DEnabled = PR_FALSE;
3442
3443 /* Currently supports only one graphics card */
3444 def->videos = g_new0(virDomainVideoDef *, 1);
3445 def->nvideos = 1;
3446
3447 def->videos[0] = g_new0(virDomainVideoDef, 1);
3448
3449 gVBoxAPI.UIMachine.GetVRAMSize(machine, &VRAMSize);
3450 gVBoxAPI.UIMachine.GetMonitorCount(machine, &monitorCount);
3451 gVBoxAPI.UIMachine.GetAccelerate3DEnabled(machine, &accelerate3DEnabled);
3452 gVBoxAPI.UIMachine.GetAccelerate2DVideoEnabled(machine, &accelerate2DEnabled);
3453
3454 def->videos[0]->type = VIR_DOMAIN_VIDEO_TYPE_VBOX;
3455 def->videos[0]->vram = VRAMSize * 1024;
3456 def->videos[0]->heads = monitorCount;
3457 def->videos[0]->accel = g_new0(virDomainVideoAccelDef, 1);
3458 def->videos[0]->accel->accel3d = accelerate3DEnabled ?
3459 VIR_TRISTATE_BOOL_YES : VIR_TRISTATE_BOOL_NO;
3460 def->videos[0]->accel->accel2d = accelerate2DEnabled ?
3461 VIR_TRISTATE_BOOL_YES : VIR_TRISTATE_BOOL_NO;
3462
3463 return 0;
3464 }
3465
3466 static int
vboxDumpDisplay(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)3467 vboxDumpDisplay(virDomainDef *def, struct _vboxDriver *data, IMachine *machine)
3468 {
3469 /* dump display options vrdp/gui/sdl */
3470 PRUnichar *keyUtf16 = NULL;
3471 PRUnichar *valueTypeUtf16 = NULL;
3472 char *valueTypeUtf8 = NULL;
3473 char *netAddressUtf8 = NULL;
3474 IVRDEServer *VRDEServer = NULL;
3475 PRBool VRDxEnabled = PR_FALSE;
3476 virDomainGraphicsDef *graphics = NULL;
3477 int ret = -1;
3478
3479 def->ngraphics = 0;
3480
3481 VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyUtf16);
3482 gVBoxAPI.UIMachine.GetExtraData(machine, keyUtf16, &valueTypeUtf16);
3483 VBOX_UTF16_FREE(keyUtf16);
3484
3485 if (valueTypeUtf16) {
3486 VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
3487 VBOX_UTF16_FREE(valueTypeUtf16);
3488 }
3489
3490 if (STREQ_NULLABLE(valueTypeUtf8, "sdl") ||
3491 STREQ_NULLABLE(valueTypeUtf8, "gui")) {
3492 PRUnichar *valueDisplayUtf16 = NULL;
3493 char *valueDisplayUtf8 = NULL;
3494
3495 graphics = g_new0(virDomainGraphicsDef, 1);
3496
3497 VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyUtf16);
3498 gVBoxAPI.UIMachine.GetExtraData(machine, keyUtf16, &valueDisplayUtf16);
3499 VBOX_UTF16_FREE(keyUtf16);
3500
3501 if (valueDisplayUtf16) {
3502 VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
3503 VBOX_UTF16_FREE(valueDisplayUtf16);
3504
3505 if (STREQ(valueDisplayUtf8, ""))
3506 VBOX_UTF8_FREE(valueDisplayUtf8);
3507 }
3508
3509 if (STREQ_NULLABLE(valueTypeUtf8, "sdl")) {
3510 graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
3511 graphics->data.sdl.display = g_steal_pointer(&valueDisplayUtf8);
3512 }
3513
3514 if (STREQ_NULLABLE(valueTypeUtf8, "gui")) {
3515 graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
3516 graphics->data.desktop.display = g_steal_pointer(&valueDisplayUtf8);
3517 }
3518 VBOX_UTF8_FREE(valueDisplayUtf8);
3519 } else if (STRNEQ_NULLABLE(valueTypeUtf8, "vrdp")) {
3520 graphics = g_new0(virDomainGraphicsDef, 1);
3521
3522 graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
3523 graphics->data.desktop.display = g_strdup(getenv("DISPLAY"));
3524 }
3525
3526 if (graphics)
3527 VIR_APPEND_ELEMENT(def->graphics, def->ngraphics, graphics);
3528
3529 gVBoxAPI.UIMachine.GetVRDEServer(machine, &VRDEServer);
3530 if (VRDEServer)
3531 gVBoxAPI.UIVRDEServer.GetEnabled(VRDEServer, &VRDxEnabled);
3532
3533 if (VRDxEnabled) {
3534 PRUnichar *netAddressUtf16 = NULL;
3535 PRBool allowMultiConnection = PR_FALSE;
3536 PRBool reuseSingleConnection = PR_FALSE;
3537
3538 graphics = g_new0(virDomainGraphicsDef, 1);
3539
3540 gVBoxAPI.UIVRDEServer.GetPorts(data, VRDEServer, machine, graphics);
3541
3542 graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;
3543
3544 gVBoxAPI.UIVRDEServer.GetNetAddress(data, VRDEServer, &netAddressUtf16);
3545 if (netAddressUtf16) {
3546 VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8);
3547 VBOX_UTF16_FREE(netAddressUtf16);
3548 }
3549
3550 if (netAddressUtf8 && STREQ(netAddressUtf8, ""))
3551 VBOX_UTF8_FREE(netAddressUtf8);
3552
3553 if (virDomainGraphicsListenAppendAddress(graphics, netAddressUtf8) < 0)
3554 goto cleanup;
3555
3556 gVBoxAPI.UIVRDEServer.GetAllowMultiConnection(VRDEServer, &allowMultiConnection);
3557 if (allowMultiConnection)
3558 graphics->data.rdp.multiUser = true;
3559
3560 gVBoxAPI.UIVRDEServer.GetReuseSingleConnection(VRDEServer, &reuseSingleConnection);
3561 if (reuseSingleConnection)
3562 graphics->data.rdp.replaceUser = true;
3563
3564 VIR_APPEND_ELEMENT(def->graphics, def->ngraphics, graphics);
3565 }
3566
3567 ret = 0;
3568
3569 cleanup:
3570 VBOX_RELEASE(VRDEServer);
3571 VBOX_UTF8_FREE(valueTypeUtf8);
3572 VBOX_UTF8_FREE(netAddressUtf8);
3573 virDomainGraphicsDefFree(graphics);
3574 return ret;
3575 }
3576
3577 static int
vboxDumpSharedFolders(virDomainDef * def,struct _vboxDriver * data,IMachine * machine)3578 vboxDumpSharedFolders(virDomainDef *def, struct _vboxDriver *data, IMachine *machine)
3579 {
3580 vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER;
3581 size_t i = 0;
3582 int ret = -1;
3583
3584 def->nfss = 0;
3585
3586 gVBoxAPI.UArray.vboxArrayGet(&sharedFolders, machine,
3587 gVBoxAPI.UArray.handleMachineGetSharedFolders(machine));
3588
3589 if (sharedFolders.count == 0) {
3590 ret = 0;
3591 goto cleanup;
3592 }
3593
3594 def->fss = g_new0(virDomainFSDef *, sharedFolders.count);
3595
3596 for (i = 0; i < sharedFolders.count; i++) {
3597 ISharedFolder *sharedFolder = sharedFolders.items[i];
3598 PRUnichar *nameUtf16 = NULL;
3599 char *name = NULL;
3600 PRUnichar *hostPathUtf16 = NULL;
3601 char *hostPath = NULL;
3602 PRBool writable = PR_FALSE;
3603
3604 if (!(def->fss[i] = virDomainFSDefNew(data->xmlopt)))
3605 goto cleanup;
3606
3607 def->fss[i]->type = VIR_DOMAIN_FS_TYPE_MOUNT;
3608
3609 gVBoxAPI.UISharedFolder.GetHostPath(sharedFolder, &hostPathUtf16);
3610 VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath);
3611 def->fss[i]->src->path = g_strdup(hostPath);
3612 VBOX_UTF8_FREE(hostPath);
3613 VBOX_UTF16_FREE(hostPathUtf16);
3614
3615 gVBoxAPI.UISharedFolder.GetName(sharedFolder, &nameUtf16);
3616 VBOX_UTF16_TO_UTF8(nameUtf16, &name);
3617 def->fss[i]->dst = g_strdup(name);
3618 VBOX_UTF8_FREE(name);
3619 VBOX_UTF16_FREE(nameUtf16);
3620
3621 gVBoxAPI.UISharedFolder.GetWritable(sharedFolder, &writable);
3622 def->fss[i]->readonly = !writable;
3623
3624 ++def->nfss;
3625 }
3626
3627 ret = 0;
3628
3629 cleanup:
3630 gVBoxAPI.UArray.vboxArrayRelease(&sharedFolders);
3631 return ret;
3632 }
3633
3634 static virDomainNetDef *
vboxDumpNetwork(struct _vboxDriver * data,INetworkAdapter * adapter)3635 vboxDumpNetwork(struct _vboxDriver *data, INetworkAdapter *adapter)
3636 {
3637 PRUint32 attachmentType = NetworkAttachmentType_Null;
3638 PRUint32 adapterType = NetworkAdapterType_Null;
3639 PRUnichar *utf16 = NULL;
3640 char *utf8 = NULL;
3641 virDomainNetDef *net = NULL;
3642
3643 if (!(net = virDomainNetDefNew(data->xmlopt)))
3644 return NULL;
3645
3646 gVBoxAPI.UINetworkAdapter.GetAttachmentType(adapter, &attachmentType);
3647
3648 switch (attachmentType) {
3649 case NetworkAttachmentType_NAT:
3650 net->type = VIR_DOMAIN_NET_TYPE_USER;
3651 break;
3652
3653 case NetworkAttachmentType_Bridged:
3654 net->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
3655
3656 gVBoxAPI.UINetworkAdapter.GetBridgedInterface(adapter, &utf16);
3657
3658 VBOX_UTF16_TO_UTF8(utf16, &utf8);
3659 net->data.bridge.brname = g_steal_pointer(&utf8);
3660 VBOX_UTF16_FREE(utf16);
3661 break;
3662
3663 case NetworkAttachmentType_Internal:
3664 net->type = VIR_DOMAIN_NET_TYPE_INTERNAL;
3665
3666 gVBoxAPI.UINetworkAdapter.GetInternalNetwork(adapter, &utf16);
3667
3668 VBOX_UTF16_TO_UTF8(utf16, &utf8);
3669 net->data.internal.name = g_steal_pointer(&utf8);
3670 VBOX_UTF16_FREE(utf16);
3671 break;
3672
3673 case NetworkAttachmentType_HostOnly:
3674 net->type = VIR_DOMAIN_NET_TYPE_NETWORK;
3675
3676 gVBoxAPI.UINetworkAdapter.GetHostOnlyInterface(adapter, &utf16);
3677
3678 VBOX_UTF16_TO_UTF8(utf16, &utf8);
3679 net->data.network.name = g_steal_pointer(&utf8);
3680 VBOX_UTF16_FREE(utf16);
3681 break;
3682
3683 default:
3684 /* default to user type i.e. NAT in VirtualBox if this
3685 * dump is ever used to create a machine.
3686 */
3687 net->type = VIR_DOMAIN_NET_TYPE_USER;
3688 }
3689
3690 gVBoxAPI.UINetworkAdapter.GetAdapterType(adapter, &adapterType);
3691 switch (adapterType) {
3692 case NetworkAdapterType_Am79C970A:
3693 net->model = VIR_DOMAIN_NET_MODEL_AM79C970A;
3694 break;
3695 case NetworkAdapterType_Am79C973:
3696 net->model = VIR_DOMAIN_NET_MODEL_AM79C973;
3697 break;
3698 case NetworkAdapterType_I82540EM:
3699 net->model = VIR_DOMAIN_NET_MODEL_82540EM;
3700 break;
3701 case NetworkAdapterType_I82545EM:
3702 net->model = VIR_DOMAIN_NET_MODEL_82545EM;
3703 break;
3704 case NetworkAdapterType_I82543GC:
3705 net->model = VIR_DOMAIN_NET_MODEL_82543GC;
3706 break;
3707 case NetworkAdapterType_Virtio:
3708 /* Only vbox 3.1 and later support NetworkAdapterType_Virto */
3709 if (gVBoxAPI.APIVersion >= 3000051)
3710 net->model = VIR_DOMAIN_NET_MODEL_VIRTIO;
3711 break;
3712 }
3713
3714 gVBoxAPI.UINetworkAdapter.GetMACAddress(adapter, &utf16);
3715 VBOX_UTF16_TO_UTF8(utf16, &utf8);
3716 VBOX_UTF16_FREE(utf16);
3717
3718 if (virMacAddrParseHex(utf8, &net->mac) < 0) {
3719 VBOX_UTF8_FREE(utf8);
3720 goto error;
3721 }
3722
3723 VBOX_UTF8_FREE(utf8);
3724 return net;
3725
3726 error:
3727 virDomainNetDefFree(net);
3728 return NULL;
3729 }
3730
3731 static int
vboxDumpNetworks(virDomainDef * def,struct _vboxDriver * data,IMachine * machine,PRUint32 networkAdapterCount)3732 vboxDumpNetworks(virDomainDef *def, struct _vboxDriver *data, IMachine *machine, PRUint32 networkAdapterCount)
3733 {
3734 size_t i = 0;
3735
3736 for (i = 0; i < networkAdapterCount; i++) {
3737 INetworkAdapter *adapter = NULL;
3738 virDomainNetDef *net = NULL;
3739 PRBool enabled = PR_FALSE;
3740
3741 gVBoxAPI.UIMachine.GetNetworkAdapter(machine, i, &adapter);
3742 if (adapter)
3743 gVBoxAPI.UINetworkAdapter.GetEnabled(adapter, &enabled);
3744
3745 if (enabled) {
3746 net = vboxDumpNetwork(data, adapter);
3747 VIR_APPEND_ELEMENT(def->nets, def->nnets, net);
3748 }
3749
3750 VBOX_RELEASE(adapter);
3751 }
3752
3753 return 0;
3754 }
3755
3756 static void
vboxDumpAudio(virDomainDef * def,struct _vboxDriver * data G_GNUC_UNUSED,IMachine * machine)3757 vboxDumpAudio(virDomainDef *def, struct _vboxDriver *data G_GNUC_UNUSED,
3758 IMachine *machine)
3759 {
3760 /* dump sound card if active */
3761
3762 /* Set def->nsounds to one as VirtualBox currently supports
3763 * only one sound card
3764 */
3765 IAudioAdapter *audioAdapter = NULL;
3766
3767 gVBoxAPI.UIMachine.GetAudioAdapter(machine, &audioAdapter);
3768 if (audioAdapter) {
3769 PRBool enabled = PR_FALSE;
3770
3771 gVBoxAPI.UIAudioAdapter.GetEnabled(audioAdapter, &enabled);
3772 if (enabled) {
3773 PRUint32 audioController = AudioControllerType_AC97;
3774
3775 def->nsounds = 1;
3776 def->sounds = g_new0(virDomainSoundDef *, 1);
3777 def->sounds[0] = g_new0(virDomainSoundDef, 1);
3778
3779 gVBoxAPI.UIAudioAdapter.GetAudioController(audioAdapter, &audioController);
3780 if (audioController == AudioControllerType_SB16) {
3781 def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_SB16;
3782 } else if (audioController == AudioControllerType_AC97) {
3783 def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_AC97;
3784 }
3785 }
3786 VBOX_RELEASE(audioAdapter);
3787 }
3788 }
3789
3790 static int
vboxDumpSerial(virDomainDef * def,struct _vboxDriver * data,IMachine * machine,PRUint32 serialPortCount)3791 vboxDumpSerial(virDomainDef *def, struct _vboxDriver *data, IMachine *machine, PRUint32 serialPortCount)
3792 {
3793 PRUint32 serialPortIncCount = 0;
3794 size_t i = 0;
3795 /* dump serial port if active */
3796 def->nserials = 0;
3797 /* Get which serial ports are enabled/active */
3798 for (i = 0; i < serialPortCount; i++) {
3799 ISerialPort *serialPort = NULL;
3800
3801 gVBoxAPI.UIMachine.GetSerialPort(machine, i, &serialPort);
3802 if (serialPort) {
3803 PRBool enabled = PR_FALSE;
3804
3805 gVBoxAPI.UISerialPort.GetEnabled(serialPort, &enabled);
3806 if (enabled)
3807 def->nserials++;
3808
3809 VBOX_RELEASE(serialPort);
3810 }
3811 }
3812
3813 /* Allocate memory for the serial ports which are enabled */
3814 if (def->nserials > 0) {
3815 def->serials = g_new0(virDomainChrDef *, def->nserials);
3816
3817 for (i = 0; i < def->nserials; i++) {
3818 def->serials[i] = virDomainChrDefNew(NULL);
3819 if (!def->serials[i])
3820 return -1;
3821 }
3822 }
3823
3824 /* Now get the details about the serial ports here */
3825 for (i = 0;
3826 serialPortIncCount < def->nserials && i < serialPortCount;
3827 i++) {
3828 ISerialPort *serialPort = NULL;
3829
3830 gVBoxAPI.UIMachine.GetSerialPort(machine, i, &serialPort);
3831 if (serialPort) {
3832 PRBool enabled = PR_FALSE;
3833
3834 gVBoxAPI.UISerialPort.GetEnabled(serialPort, &enabled);
3835 if (enabled) {
3836 PRUint32 hostMode = PortMode_Disconnected;
3837 PRUint32 IOBase = 0;
3838 PRUint32 IRQ = 0;
3839 PRUnichar *pathUtf16 = NULL;
3840 char *path = NULL;
3841
3842 gVBoxAPI.UISerialPort.GetHostMode(serialPort, &hostMode);
3843 if (hostMode == PortMode_HostPipe) {
3844 def->serials[serialPortIncCount]->source->type = VIR_DOMAIN_CHR_TYPE_PIPE;
3845 } else if (hostMode == PortMode_HostDevice) {
3846 def->serials[serialPortIncCount]->source->type = VIR_DOMAIN_CHR_TYPE_DEV;
3847 } else if (gVBoxAPI.APIVersion >= 2002051 &&
3848 hostMode == PortMode_RawFile) {
3849 /* PortMode RawFile is used for vbox 3.0 or later */
3850 def->serials[serialPortIncCount]->source->type = VIR_DOMAIN_CHR_TYPE_FILE;
3851 } else {
3852 def->serials[serialPortIncCount]->source->type = VIR_DOMAIN_CHR_TYPE_NULL;
3853 }
3854
3855 def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
3856
3857 gVBoxAPI.UISerialPort.GetIRQ(serialPort, &IRQ);
3858 gVBoxAPI.UISerialPort.GetIOBase(serialPort, &IOBase);
3859 if ((IRQ == 4) && (IOBase == 1016)) {
3860 def->serials[serialPortIncCount]->target.port = 0;
3861 } else if ((IRQ == 3) && (IOBase == 760)) {
3862 def->serials[serialPortIncCount]->target.port = 1;
3863 }
3864
3865 gVBoxAPI.UISerialPort.GetPath(serialPort, &pathUtf16);
3866
3867 if (pathUtf16) {
3868 VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3869 def->serials[serialPortIncCount]->source->data.file.path = g_strdup(path);
3870 }
3871
3872 serialPortIncCount++;
3873
3874 VBOX_UTF16_FREE(pathUtf16);
3875 VBOX_UTF8_FREE(path);
3876 }
3877
3878 VBOX_RELEASE(serialPort);
3879 }
3880 }
3881 return 0;
3882 }
3883
3884 static int
vboxDumpParallel(virDomainDef * def,struct _vboxDriver * data,IMachine * machine,PRUint32 parallelPortCount)3885 vboxDumpParallel(virDomainDef *def, struct _vboxDriver *data, IMachine *machine, PRUint32 parallelPortCount)
3886 {
3887 PRUint32 parallelPortIncCount = 0;
3888 size_t i = 0;
3889 /* dump parallel ports if active */
3890 def->nparallels = 0;
3891 /* Get which parallel ports are enabled/active */
3892 for (i = 0; i < parallelPortCount; i++) {
3893 IParallelPort *parallelPort = NULL;
3894
3895 gVBoxAPI.UIMachine.GetParallelPort(machine, i, ¶llelPort);
3896 if (parallelPort) {
3897 PRBool enabled = PR_FALSE;
3898
3899 gVBoxAPI.UIParallelPort.GetEnabled(parallelPort, &enabled);
3900 if (enabled)
3901 def->nparallels++;
3902
3903 VBOX_RELEASE(parallelPort);
3904 }
3905 }
3906
3907 /* Allocate memory for the parallel ports which are enabled */
3908 if (def->nparallels > 0) {
3909 def->parallels = g_new0(virDomainChrDef *, def->nparallels);
3910
3911 for (i = 0; i < def->nparallels; i++) {
3912 def->parallels[i] = virDomainChrDefNew(NULL);
3913 if (!def->parallels[i])
3914 return -1;
3915 }
3916 }
3917
3918 /* Now get the details about the parallel ports here */
3919 for (i = 0;
3920 parallelPortIncCount < def->nparallels &&
3921 i < parallelPortCount;
3922 i++) {
3923 IParallelPort *parallelPort = NULL;
3924
3925 gVBoxAPI.UIMachine.GetParallelPort(machine, i, ¶llelPort);
3926 if (parallelPort) {
3927 PRBool enabled = PR_FALSE;
3928
3929 gVBoxAPI.UIParallelPort.GetEnabled(parallelPort, &enabled);
3930 if (enabled) {
3931 PRUint32 IOBase = 0;
3932 PRUint32 IRQ = 0;
3933 PRUnichar *pathUtf16 = NULL;
3934 char *path = NULL;
3935
3936 gVBoxAPI.UIParallelPort.GetIRQ(parallelPort, &IRQ);
3937 gVBoxAPI.UIParallelPort.GetIOBase(parallelPort, &IOBase);
3938 if ((IRQ == 7) && (IOBase == 888)) {
3939 def->parallels[parallelPortIncCount]->target.port = 0;
3940 } else if ((IRQ == 5) && (IOBase == 632)) {
3941 def->parallels[parallelPortIncCount]->target.port = 1;
3942 }
3943
3944 def->parallels[parallelPortIncCount]->source->type = VIR_DOMAIN_CHR_TYPE_FILE;
3945 def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
3946
3947 gVBoxAPI.UIParallelPort.GetPath(parallelPort, &pathUtf16);
3948
3949 VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3950 def->parallels[parallelPortIncCount]->source->data.file.path = g_strdup(path);
3951
3952 parallelPortIncCount++;
3953
3954 VBOX_UTF16_FREE(pathUtf16);
3955 VBOX_UTF8_FREE(path);
3956 }
3957
3958 VBOX_RELEASE(parallelPort);
3959 }
3960 }
3961 return 0;
3962 }
3963
vboxDomainGetXMLDesc(virDomainPtr dom,unsigned int flags)3964 static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
3965 {
3966 struct _vboxDriver *data = dom->conn->privateData;
3967 virDomainDef *def = NULL;
3968 IMachine *machine = NULL;
3969 vboxIID iid;
3970 PRBool accessible = PR_FALSE;
3971 size_t i = 0;
3972 PRBool PAEEnabled = PR_FALSE;
3973 PRBool ACPIEnabled = PR_FALSE;
3974 PRBool IOAPICEnabled = PR_FALSE;
3975 PRUint32 CPUCount = 0;
3976 PRUint32 memorySize = 0;
3977 PRUint32 networkAdapterCount = 0;
3978 PRUint32 maxMemorySize = 4 * 1024;
3979 PRUint32 maxBootPosition = 0;
3980 PRUint32 serialPortCount = 0;
3981 PRUint32 parallelPortCount = 0;
3982 IBIOSSettings *bios = NULL;
3983 PRUint32 chipsetType = ChipsetType_Null;
3984 ISystemProperties *systemProperties = NULL;
3985 char *ret = NULL;
3986
3987 if (!data->vboxObj)
3988 return ret;
3989
3990 virCheckFlags(VIR_DOMAIN_XML_COMMON_FLAGS, NULL);
3991
3992 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
3993 goto cleanup;
3994
3995 if (!(def = virDomainDefNew(data->xmlopt)))
3996 goto cleanup;
3997
3998 gVBoxAPI.UIMachine.GetAccessible(machine, &accessible);
3999 if (!accessible)
4000 goto cleanup;
4001
4002 def->virtType = VIR_DOMAIN_VIRT_VBOX;
4003 def->id = dom->id;
4004 memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
4005 def->name = g_strdup(dom->name);
4006
4007 gVBoxAPI.UIMachine.GetMemorySize(machine, &memorySize);
4008 def->mem.cur_balloon = memorySize * 1024;
4009
4010 if (gVBoxAPI.chipsetType)
4011 gVBoxAPI.UIMachine.GetChipsetType(machine, &chipsetType);
4012
4013 gVBoxAPI.UIVirtualBox.GetSystemProperties(data->vboxObj, &systemProperties);
4014 if (systemProperties) {
4015 gVBoxAPI.UISystemProperties.GetMaxGuestRAM(systemProperties, &maxMemorySize);
4016 gVBoxAPI.UISystemProperties.GetMaxBootPosition(systemProperties, &maxBootPosition);
4017 gVBoxAPI.UISystemProperties.GetMaxNetworkAdapters(systemProperties, chipsetType, &networkAdapterCount);
4018 gVBoxAPI.UISystemProperties.GetSerialPortCount(systemProperties, &serialPortCount);
4019 gVBoxAPI.UISystemProperties.GetParallelPortCount(systemProperties, ¶llelPortCount);
4020 VBOX_RELEASE(systemProperties);
4021 systemProperties = NULL;
4022 }
4023 /* Currently setting memory and maxMemory as same, cause
4024 * the notation here seems to be inconsistent while
4025 * reading and while dumping xml
4026 */
4027 /* def->mem.max_balloon = maxMemorySize * 1024; */
4028 virDomainDefSetMemoryTotal(def, memorySize * 1024);
4029
4030 gVBoxAPI.UIMachine.GetCPUCount(machine, &CPUCount);
4031 if (virDomainDefSetVcpusMax(def, CPUCount, data->xmlopt) < 0)
4032 goto cleanup;
4033
4034 if (virDomainDefSetVcpus(def, CPUCount) < 0)
4035 goto cleanup;
4036
4037 /* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */
4038
4039 def->os.type = VIR_DOMAIN_OSTYPE_HVM;
4040 def->os.arch = virArchFromHost();
4041
4042 def->os.nBootDevs = 0;
4043 for (i = 0; (i < VIR_DOMAIN_BOOT_LAST) && (i < maxBootPosition); i++) {
4044 PRUint32 device = DeviceType_Null;
4045
4046 gVBoxAPI.UIMachine.GetBootOrder(machine, i+1, &device);
4047
4048 if (device == DeviceType_Floppy) {
4049 def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
4050 def->os.nBootDevs++;
4051 } else if (device == DeviceType_DVD) {
4052 def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
4053 def->os.nBootDevs++;
4054 } else if (device == DeviceType_HardDisk) {
4055 def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
4056 def->os.nBootDevs++;
4057 } else if (device == DeviceType_Network) {
4058 def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
4059 def->os.nBootDevs++;
4060 } else if (device == DeviceType_USB) {
4061 /* Not supported by libvirt yet */
4062 } else if (device == DeviceType_SharedFolder) {
4063 /* Not supported by libvirt yet */
4064 /* Can VirtualBox really boot from a shared folder? */
4065 }
4066 }
4067
4068 gVBoxAPI.UIMachine.GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled);
4069 if (PAEEnabled)
4070 def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
4071
4072 gVBoxAPI.UIMachine.GetBIOSSettings(machine, &bios);
4073 if (bios) {
4074 gVBoxAPI.UIBIOSSettings.GetACPIEnabled(bios, &ACPIEnabled);
4075 if (ACPIEnabled)
4076 def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON;
4077
4078 gVBoxAPI.UIBIOSSettings.GetIOAPICEnabled(bios, &IOAPICEnabled);
4079 if (IOAPICEnabled)
4080 def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_TRISTATE_SWITCH_ON;
4081
4082 VBOX_RELEASE(bios);
4083 }
4084
4085 /* Currently VirtualBox always uses locatime
4086 * so locatime is always true here */
4087 def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
4088
4089 if (vboxDumpVideo(def, data, machine) < 0)
4090 goto cleanup;
4091 if (vboxDumpDisplay(def, data, machine) < 0)
4092 goto cleanup;
4093 if (vboxDumpStorageControllers(def, machine) < 0)
4094 goto cleanup;
4095 if (vboxDumpDisks(def, data, machine) < 0)
4096 goto cleanup;
4097
4098 if (vboxDumpSharedFolders(def, data, machine) < 0)
4099 goto cleanup;
4100 if (vboxDumpNetworks(def, data, machine, networkAdapterCount) < 0)
4101 goto cleanup;
4102 vboxDumpAudio(def, data, machine);
4103
4104 if (vboxDumpSerial(def, data, machine, serialPortCount) < 0)
4105 goto cleanup;
4106 if (vboxDumpParallel(def, data, machine, parallelPortCount) < 0)
4107 goto cleanup;
4108
4109 /* dump USB devices/filters if active */
4110 vboxHostDeviceGetXMLDesc(data, def, machine);
4111
4112 ret = virDomainDefFormat(def, data->xmlopt,
4113 virDomainDefFormatConvertXMLFlags(flags));
4114
4115 cleanup:
4116 VBOX_RELEASE(machine);
4117 vboxIIDUnalloc(&iid);
4118 virDomainDefFree(def);
4119 return ret;
4120 }
4121
vboxConnectListDefinedDomains(virConnectPtr conn,char ** const names,int maxnames)4122 static int vboxConnectListDefinedDomains(virConnectPtr conn,
4123 char ** const names, int maxnames)
4124 {
4125 struct _vboxDriver *data = conn->privateData;
4126 vboxArray machines = VBOX_ARRAY_INITIALIZER;
4127 char *machineName = NULL;
4128 PRUnichar *machineNameUtf16 = NULL;
4129 PRUint32 state;
4130 nsresult rc;
4131 size_t i, j;
4132 int ret = -1;
4133
4134 if (!data->vboxObj)
4135 return ret;
4136
4137 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj,
4138 ARRAY_GET_MACHINES);
4139 if (NS_FAILED(rc)) {
4140 virReportError(VIR_ERR_INTERNAL_ERROR,
4141 _("Could not get list of Defined Domains, rc=%08x"),
4142 (unsigned)rc);
4143 goto cleanup;
4144 }
4145
4146 memset(names, 0, sizeof(names[i]) * maxnames);
4147
4148 ret = 0;
4149 for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) {
4150 PRBool isAccessible = PR_FALSE;
4151 IMachine *machine = machines.items[i];
4152
4153 if (!machine)
4154 continue;
4155
4156 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
4157 if (!isAccessible)
4158 continue;
4159
4160 gVBoxAPI.UIMachine.GetState(machine, &state);
4161 if (!gVBoxAPI.machineStateChecker.Inactive(state))
4162 continue;
4163
4164 gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16);
4165 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
4166 names[j] = g_strdup(machineName);
4167 VBOX_UTF16_FREE(machineNameUtf16);
4168 VBOX_UTF8_FREE(machineName);
4169 j++;
4170 ret++;
4171 }
4172
4173 cleanup:
4174 gVBoxAPI.UArray.vboxArrayRelease(&machines);
4175 return ret;
4176 }
4177
vboxConnectNumOfDefinedDomains(virConnectPtr conn)4178 static int vboxConnectNumOfDefinedDomains(virConnectPtr conn)
4179 {
4180 struct _vboxDriver *data = conn->privateData;
4181 vboxArray machines = VBOX_ARRAY_INITIALIZER;
4182 PRUint32 state;
4183 nsresult rc;
4184 size_t i;
4185 int ret = -1;
4186
4187 if (!data->vboxObj)
4188 return ret;
4189
4190 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj,
4191 ARRAY_GET_MACHINES);
4192 if (NS_FAILED(rc)) {
4193 virReportError(VIR_ERR_INTERNAL_ERROR,
4194 _("Could not get number of Defined Domains, rc=%08x"),
4195 (unsigned)rc);
4196 goto cleanup;
4197 }
4198
4199 ret = 0;
4200 for (i = 0; i < machines.count; ++i) {
4201 PRBool isAccessible = PR_FALSE;
4202 IMachine *machine = machines.items[i];
4203
4204 if (!machine)
4205 continue;
4206
4207 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
4208 if (!isAccessible)
4209 continue;
4210
4211 gVBoxAPI.UIMachine.GetState(machine, &state);
4212 if (gVBoxAPI.machineStateChecker.Inactive(state))
4213 ret++;
4214 }
4215
4216 cleanup:
4217 gVBoxAPI.UArray.vboxArrayRelease(&machines);
4218 return ret;
4219 }
4220
vboxDomainAttachDeviceImpl(virDomainPtr dom,const char * xml,int mediaChangeOnly G_GNUC_UNUSED)4221 static int vboxDomainAttachDeviceImpl(virDomainPtr dom,
4222 const char *xml,
4223 int mediaChangeOnly G_GNUC_UNUSED)
4224 {
4225 struct _vboxDriver *data = dom->conn->privateData;
4226 IMachine *machine = NULL;
4227 vboxIID iid;
4228 PRUint32 state;
4229 virDomainDef *def = NULL;
4230 virDomainDeviceDef *dev = NULL;
4231 nsresult rc;
4232 int ret = -1;
4233
4234 if (!data->vboxObj)
4235 return ret;
4236
4237 VBOX_IID_INITIALIZE(&iid);
4238 if (!(def = virDomainDefNew(data->xmlopt)))
4239 return ret;
4240
4241 def->os.type = VIR_DOMAIN_OSTYPE_HVM;
4242
4243 dev = virDomainDeviceDefParse(xml, def, data->xmlopt, NULL,
4244 VIR_DOMAIN_DEF_PARSE_INACTIVE);
4245 if (dev == NULL)
4246 goto cleanup;
4247
4248 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
4249 goto cleanup;
4250
4251 if (!machine)
4252 goto cleanup;
4253
4254 gVBoxAPI.UIMachine.GetState(machine, &state);
4255
4256 if (gVBoxAPI.machineStateChecker.Running(state) ||
4257 gVBoxAPI.machineStateChecker.Paused(state)) {
4258 rc = gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
4259 } else {
4260 rc = gVBoxAPI.UISession.Open(data, &iid, machine);
4261 }
4262
4263 if (NS_FAILED(rc))
4264 goto cleanup;
4265
4266 rc = gVBoxAPI.UISession.GetMachine(data->vboxSession, &machine);
4267
4268 if (NS_SUCCEEDED(rc) && machine) {
4269 /* ret = -VIR_ERR_ARGUMENT_UNSUPPORTED means the current device don't support hotplug. */
4270 ret = -VIR_ERR_ARGUMENT_UNSUPPORTED;
4271 if (dev->type == VIR_DOMAIN_DEVICE_FS &&
4272 dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) {
4273 PRUnichar *nameUtf16;
4274 PRUnichar *hostPathUtf16;
4275 PRBool writable;
4276
4277 VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16);
4278 VBOX_UTF8_TO_UTF16(dev->data.fs->src->path, &hostPathUtf16);
4279 writable = !dev->data.fs->readonly;
4280
4281 rc = gVBoxAPI.UIMachine.CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
4282 writable, PR_FALSE);
4283
4284 if (NS_FAILED(rc)) {
4285 virReportError(VIR_ERR_INTERNAL_ERROR,
4286 _("could not attach shared folder '%s', rc=%08x"),
4287 dev->data.fs->dst, (unsigned)rc);
4288 ret = -1;
4289 } else {
4290 ret = 0;
4291 }
4292
4293 VBOX_UTF16_FREE(nameUtf16);
4294 VBOX_UTF16_FREE(hostPathUtf16);
4295 }
4296 gVBoxAPI.UIMachine.SaveSettings(machine);
4297 VBOX_RELEASE(machine);
4298
4299 if (ret == -VIR_ERR_ARGUMENT_UNSUPPORTED) {
4300 virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, _("Unsupported device type %d"), dev->type);
4301 ret = -1;
4302 }
4303 }
4304 gVBoxAPI.UISession.Close(data->vboxSession);
4305
4306 cleanup:
4307 vboxIIDUnalloc(&iid);
4308 virDomainDefFree(def);
4309 virDomainDeviceDefFree(dev);
4310 return ret;
4311 }
4312
vboxDomainAttachDevice(virDomainPtr dom,const char * xml)4313 static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml)
4314 {
4315 return vboxDomainAttachDeviceImpl(dom, xml, 0);
4316 }
4317
vboxDomainAttachDeviceFlags(virDomainPtr dom,const char * xml,unsigned int flags)4318 static int vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
4319 unsigned int flags)
4320 {
4321 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE, -1);
4322
4323 return vboxDomainAttachDeviceImpl(dom, xml, 0);
4324 }
4325
vboxDomainUpdateDeviceFlags(virDomainPtr dom,const char * xml,unsigned int flags)4326 static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
4327 unsigned int flags)
4328 {
4329 virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
4330 VIR_DOMAIN_AFFECT_LIVE |
4331 VIR_DOMAIN_AFFECT_CONFIG, -1);
4332
4333 if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
4334 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
4335 _("cannot modify the persistent configuration of a domain"));
4336 return -1;
4337 }
4338
4339 return vboxDomainAttachDeviceImpl(dom, xml, 1);
4340 }
4341
vboxDomainDetachDevice(virDomainPtr dom,const char * xml)4342 static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml)
4343 {
4344 struct _vboxDriver *data = dom->conn->privateData;
4345 IMachine *machine = NULL;
4346 vboxIID iid;
4347 PRUint32 state;
4348 virDomainDef *def = NULL;
4349 virDomainDeviceDef *dev = NULL;
4350 nsresult rc;
4351 int ret = -1;
4352
4353 if (!data->vboxObj)
4354 return ret;
4355
4356 VBOX_IID_INITIALIZE(&iid);
4357 if (!(def = virDomainDefNew(data->xmlopt)))
4358 return ret;
4359
4360 def->os.type = VIR_DOMAIN_OSTYPE_HVM;
4361
4362 dev = virDomainDeviceDefParse(xml, def, data->xmlopt, NULL,
4363 VIR_DOMAIN_DEF_PARSE_INACTIVE |
4364 VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
4365 if (dev == NULL)
4366 goto cleanup;
4367
4368 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
4369 goto cleanup;
4370
4371 if (!machine)
4372 goto cleanup;
4373
4374 gVBoxAPI.UIMachine.GetState(machine, &state);
4375
4376 if (gVBoxAPI.machineStateChecker.Running(state) ||
4377 gVBoxAPI.machineStateChecker.Paused(state)) {
4378 rc = gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
4379 } else {
4380 rc = gVBoxAPI.UISession.Open(data, &iid, machine);
4381 }
4382
4383 if (NS_FAILED(rc))
4384 goto cleanup;
4385
4386 rc = gVBoxAPI.UISession.GetMachine(data->vboxSession, &machine);
4387 if (NS_SUCCEEDED(rc) && machine) {
4388 /* ret = -VIR_ERR_ARGUMENT_UNSUPPORTED means the current device don't support hotplug. */
4389 ret = -VIR_ERR_ARGUMENT_UNSUPPORTED;
4390 if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
4391 if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
4392 if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
4393 }
4394 }
4395 } else if (dev->type == VIR_DOMAIN_DEVICE_FS &&
4396 dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) {
4397 PRUnichar *nameUtf16;
4398
4399 VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16);
4400
4401 rc = gVBoxAPI.UIMachine.RemoveSharedFolder(machine, nameUtf16);
4402
4403 if (NS_FAILED(rc)) {
4404 virReportError(VIR_ERR_INTERNAL_ERROR,
4405 _("could not detach shared folder '%s', rc=%08x"),
4406 dev->data.fs->dst, (unsigned)rc);
4407 } else {
4408 ret = 0;
4409 }
4410
4411 VBOX_UTF16_FREE(nameUtf16);
4412 }
4413 gVBoxAPI.UIMachine.SaveSettings(machine);
4414 VBOX_RELEASE(machine);
4415
4416 if (ret == -VIR_ERR_ARGUMENT_UNSUPPORTED) {
4417 virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, _("Unsupported device type %d"), dev->type);
4418 ret = -1;
4419 }
4420 }
4421 gVBoxAPI.UISession.Close(data->vboxSession);
4422
4423 cleanup:
4424 vboxIIDUnalloc(&iid);
4425 virDomainDefFree(def);
4426 virDomainDeviceDefFree(dev);
4427 return ret;
4428 }
4429
vboxDomainDetachDeviceFlags(virDomainPtr dom,const char * xml,unsigned int flags)4430 static int vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
4431 unsigned int flags)
4432 {
4433 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE, -1);
4434
4435 return vboxDomainDetachDevice(dom, xml);
4436 }
4437
vboxCloseDisksRecursively(virDomainPtr dom,char * location)4438 static int vboxCloseDisksRecursively(virDomainPtr dom, char *location)
4439 {
4440 struct _vboxDriver *data = dom->conn->privateData;
4441 nsresult rc;
4442 size_t i = 0;
4443 PRUnichar *locationUtf = NULL;
4444 IMedium *medium = NULL;
4445 IMedium **children = NULL;
4446 PRUint32 childrenSize = 0;
4447 int ret = -1;
4448
4449 if (!data->vboxObj)
4450 return ret;
4451
4452 if (!gVBoxAPI.vboxSnapshotRedefine)
4453 VIR_WARN("This function may not work in current version");
4454
4455 VBOX_UTF8_TO_UTF16(location, &locationUtf);
4456 rc = gVBoxAPI.UIVirtualBox.OpenMedium(data->vboxObj,
4457 locationUtf,
4458 DeviceType_HardDisk,
4459 AccessMode_ReadWrite,
4460 &medium);
4461 if (NS_FAILED(rc)) {
4462 virReportError(VIR_ERR_INTERNAL_ERROR,
4463 _("Unable to open HardDisk, rc=%08x"),
4464 (unsigned)rc);
4465 goto cleanup;
4466 }
4467 rc = gVBoxAPI.UIMedium.GetChildren(medium, &childrenSize, &children);
4468 if (NS_FAILED(rc)) {
4469 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4470 _("Unable to get disk children"));
4471 goto cleanup;
4472 }
4473 for (i = 0; i < childrenSize; i++) {
4474 IMedium *childMedium = children[i];
4475 if (childMedium) {
4476 PRUnichar *childLocationUtf = NULL;
4477 char *childLocation = NULL;
4478 rc = gVBoxAPI.UIMedium.GetLocation(childMedium, &childLocationUtf);
4479 if (NS_FAILED(rc)) {
4480 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4481 _("Unable to get childMedium location"));
4482 goto cleanup;
4483 }
4484 VBOX_UTF16_TO_UTF8(childLocationUtf, &childLocation);
4485 VBOX_UTF16_FREE(childLocationUtf);
4486 if (vboxCloseDisksRecursively(dom, childLocation) < 0) {
4487 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4488 _("Unable to close disk children"));
4489 goto cleanup;
4490 }
4491 VIR_FREE(childLocation);
4492 }
4493 }
4494 rc = gVBoxAPI.UIMedium.Close(medium);
4495 if (NS_FAILED(rc)) {
4496 virReportError(VIR_ERR_INTERNAL_ERROR,
4497 _("Unable to close HardDisk, rc=%08x"),
4498 (unsigned)rc);
4499 goto cleanup;
4500 }
4501
4502 ret = 0;
4503 cleanup:
4504 VBOX_UTF16_FREE(locationUtf);
4505 return ret;
4506 }
4507
4508 static int
vboxSnapshotRedefine(virDomainPtr dom,virDomainSnapshotDef * def,bool isCurrent)4509 vboxSnapshotRedefine(virDomainPtr dom,
4510 virDomainSnapshotDef *def,
4511 bool isCurrent)
4512 {
4513 /*
4514 * If your snapshot has a parent,
4515 * it will only be redefined if you have already
4516 * redefined the parent.
4517 *
4518 * The general algorithm of this function is below :
4519 * First of all, we are going to create our vboxSnapshotXmlMachinePtr struct from
4520 * the machine settings path.
4521 * Then, if the machine current snapshot xml file is saved in the machine location,
4522 * it means that this snapshot was previously modified by us and has fake disks.
4523 * Fake disks are added when the flag VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT was not set
4524 * yet, in order to not corrupt read-only disks. The first thing to do is to remove those
4525 * disks and restore the read-write disks, if any, in the vboxSnapshotXmlMachinePtr struct.
4526 * We also delete the current snapshot xml file.
4527 *
4528 * After that, we are going to register the snapshot read-only disks that we want to redefine,
4529 * if they are not in the media registry struct.
4530 *
4531 * The next step is to unregister the machine and close all disks.
4532 *
4533 * Then, we check if the flag VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE has already been set.
4534 * If this flag was set, we just add read-write disks to the media registry
4535 * struct. Otherwise, we save the snapshot xml file into the machine location in order
4536 * to recover the read-write disks during the next redefine and we create differential disks
4537 * from the snapshot read-only disks and add them to the media registry struct.
4538 *
4539 * Finally, we register the machine with the new virtualbox description file.
4540 */
4541 struct _vboxDriver *data = dom->conn->privateData;
4542 vboxIID domiid;
4543 IMachine *machine = NULL;
4544 nsresult rc;
4545 PRUnichar *settingsFilePath = NULL;
4546 char *settingsFilePath_Utf8 = NULL;
4547 virVBoxSnapshotConfMachine *snapshotMachineDesc = NULL;
4548 char *currentSnapshotXmlFilePath = NULL;
4549 PRUnichar *machineNameUtf16 = NULL;
4550 char *machineName = NULL;
4551 g_auto(GStrv) realReadWriteDisksPath = NULL;
4552 int realReadWriteDisksPathSize = 0;
4553 g_auto(GStrv) realReadOnlyDisksPath = NULL;
4554 int realReadOnlyDisksPathSize = 0;
4555 virVBoxSnapshotConfSnapshot *newSnapshotPtr = NULL;
4556 unsigned char snapshotUuid[VIR_UUID_BUFLEN];
4557 virVBoxSnapshotConfHardDisk **hardDiskToOpen = NULL;
4558 size_t hardDiskToOpenSize = 0;
4559 virVBoxSnapshotConfHardDisk *newHardDisk = NULL;
4560 g_auto(GStrv) searchResultTab = NULL;
4561 ssize_t resultSize = 0;
4562 int it = 0;
4563 int jt = 0;
4564 PRUint32 aMediaSize = 0;
4565 IMedium **aMedia = NULL;
4566 char *machineLocationPath = NULL;
4567 char *nameTmpUse = NULL;
4568 bool snapshotFileExists = false;
4569 bool needToChangeStorageController = false;
4570 char uuidtmp[VIR_UUID_STRING_BUFLEN];
4571 int ret = -1;
4572
4573 if (!data->vboxObj)
4574 return ret;
4575
4576 if (!gVBoxAPI.vboxSnapshotRedefine)
4577 VIR_WARN("This function may not work in current version");
4578
4579 if (openSessionForMachine(data, dom->uuid, &domiid, &machine) < 0)
4580 goto cleanup;
4581
4582 rc = gVBoxAPI.UIMachine.SaveSettings(machine);
4583 /* It may failed when the machine is not mutable. */
4584 rc = gVBoxAPI.UIMachine.GetSettingsFilePath(machine, &settingsFilePath);
4585 if (NS_FAILED(rc)) {
4586 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4587 _("cannot get settings file path"));
4588 goto cleanup;
4589 }
4590 VBOX_UTF16_TO_UTF8(settingsFilePath, &settingsFilePath_Utf8);
4591
4592 /* Getting the machine name to retrieve the machine location path. */
4593 rc = gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16);
4594 if (NS_FAILED(rc)) {
4595 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4596 _("cannot get machine name"));
4597 goto cleanup;
4598 }
4599 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
4600
4601 nameTmpUse = g_strdup_printf("%s.vbox", machineName);
4602 machineLocationPath = virStringReplace(settingsFilePath_Utf8, nameTmpUse, "");
4603 if (machineLocationPath == NULL) {
4604 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4605 _("Unable to get the machine location path"));
4606 goto cleanup;
4607 }
4608
4609 /* We create the xml struct with the settings file path. */
4610 snapshotMachineDesc = virVBoxSnapshotConfLoadVboxFile(settingsFilePath_Utf8, machineLocationPath);
4611 if (snapshotMachineDesc == NULL) {
4612 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4613 _("cannot create a vboxSnapshotXmlPtr"));
4614 goto cleanup;
4615 }
4616 if (snapshotMachineDesc->currentSnapshot != NULL) {
4617 currentSnapshotXmlFilePath = g_strdup_printf("%s%s.xml",
4618 machineLocationPath, snapshotMachineDesc->currentSnapshot);
4619 snapshotFileExists = virFileExists(currentSnapshotXmlFilePath);
4620 }
4621
4622 if (snapshotFileExists) {
4623 /*
4624 * We have created fake disks, so we have to remove them and replace them with
4625 * the read-write disks if there are any. The fake disks will be closed during
4626 * the machine unregistration.
4627 */
4628 if (virVBoxSnapshotConfRemoveFakeDisks(snapshotMachineDesc) < 0) {
4629 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4630 _("Unable to remove Fake Disks"));
4631 goto cleanup;
4632 }
4633 realReadWriteDisksPathSize = virVBoxSnapshotConfGetRWDisksPathsFromLibvirtXML(currentSnapshotXmlFilePath,
4634 &realReadWriteDisksPath);
4635 realReadOnlyDisksPathSize = virVBoxSnapshotConfGetRODisksPathsFromLibvirtXML(currentSnapshotXmlFilePath,
4636 &realReadOnlyDisksPath);
4637 /* The read-only disk number is necessarily greater or equal to the
4638 * read-write disk number */
4639 if (realReadOnlyDisksPathSize < realReadWriteDisksPathSize) {
4640 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4641 _("The read only disk number must be greater or equal to the "
4642 " read write disk number"));
4643 goto cleanup;
4644 }
4645 for (it = 0; it < realReadWriteDisksPathSize; it++) {
4646 virVBoxSnapshotConfHardDisk *readWriteDisk = NULL;
4647 PRUnichar *locationUtf = NULL;
4648 IMedium *readWriteMedium = NULL;
4649 char *uuid = NULL;
4650 PRUnichar *formatUtf = NULL;
4651 char *format = NULL;
4652 const char *parentUuid = NULL;
4653 vboxIID iid;
4654
4655 VBOX_IID_INITIALIZE(&iid);
4656 VBOX_UTF8_TO_UTF16(realReadWriteDisksPath[it], &locationUtf);
4657 rc = gVBoxAPI.UIVirtualBox.OpenMedium(data->vboxObj,
4658 locationUtf,
4659 DeviceType_HardDisk,
4660 AccessMode_ReadWrite,
4661 &readWriteMedium);
4662 if (NS_FAILED(rc)) {
4663 virReportError(VIR_ERR_INTERNAL_ERROR,
4664 _("Unable to open HardDisk, rc=%08x"),
4665 (unsigned)rc);
4666 VBOX_UTF16_FREE(locationUtf);
4667 goto cleanup;
4668 }
4669 VBOX_UTF16_FREE(locationUtf);
4670
4671 rc = gVBoxAPI.UIMedium.GetId(readWriteMedium, &iid);
4672 if (NS_FAILED(rc)) {
4673 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4674 _("Unable to get the read write medium id"));
4675 goto cleanup;
4676 }
4677 gVBoxAPI.UIID.vboxIIDToUtf8(data, &iid, &uuid);
4678 vboxIIDUnalloc(&iid);
4679
4680 rc = gVBoxAPI.UIMedium.GetFormat(readWriteMedium, &formatUtf);
4681 if (NS_FAILED(rc)) {
4682 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4683 _("Unable to get the read write medium format"));
4684 goto cleanup;
4685 }
4686 VBOX_UTF16_TO_UTF8(formatUtf, &format);
4687 VBOX_UTF16_FREE(formatUtf);
4688
4689 readWriteDisk = g_new0(virVBoxSnapshotConfHardDisk, 1);
4690
4691 readWriteDisk->format = format;
4692 readWriteDisk->uuid = uuid;
4693 readWriteDisk->location = realReadWriteDisksPath[it];
4694 /*
4695 * We get the current snapshot's read-only disk uuid in order to add the
4696 * read-write disk to the media registry as its child. The read-only disk
4697 * is already in the media registry because it is the fake disk's parent.
4698 */
4699 parentUuid = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc,
4700 realReadOnlyDisksPath[it]);
4701 if (parentUuid == NULL) {
4702 VIR_FREE(readWriteDisk);
4703 goto cleanup;
4704 }
4705
4706 if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(readWriteDisk,
4707 snapshotMachineDesc->mediaRegistry,
4708 parentUuid) < 0) {
4709 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4710 _("Unable to add hard disk to media Registry"));
4711 VIR_FREE(readWriteDisk);
4712 goto cleanup;
4713 }
4714 rc = gVBoxAPI.UIMedium.Close(readWriteMedium);
4715 if (NS_FAILED(rc)) {
4716 virReportError(VIR_ERR_INTERNAL_ERROR,
4717 _("Unable to close HardDisk, rc=%08x"),
4718 (unsigned)rc);
4719 goto cleanup;
4720 }
4721 }
4722 /*
4723 * Now we have done this swap, we remove the snapshot xml file from the
4724 * current machine location.
4725 */
4726 if (unlink(currentSnapshotXmlFilePath) < 0) {
4727 virReportSystemError(errno,
4728 _("Unable to delete file %s"), currentSnapshotXmlFilePath);
4729 goto cleanup;
4730 }
4731 }
4732 /*
4733 * Before unregistering the machine, while all disks are still open, ensure that all
4734 * read-only disks are in the redefined snapshot's media registry (the disks need to
4735 * be open to query their uuid).
4736 */
4737 for (it = 0; it < def->parent.dom->ndisks; it++) {
4738 int diskInMediaRegistry = 0;
4739 IMedium *readOnlyMedium = NULL;
4740 PRUnichar *locationUtf = NULL;
4741 char *uuid = NULL;
4742 PRUnichar *formatUtf = NULL;
4743 char *format = NULL;
4744 char *parentUuid = NULL;
4745 virVBoxSnapshotConfHardDisk *readOnlyDisk = NULL;
4746 vboxIID iid, parentiid;
4747 IMedium *parentReadOnlyMedium = NULL;
4748
4749 VBOX_IID_INITIALIZE(&iid);
4750 VBOX_IID_INITIALIZE(&parentiid);
4751 diskInMediaRegistry = virVBoxSnapshotConfDiskIsInMediaRegistry(snapshotMachineDesc,
4752 def->parent.dom->disks[it]->src->path);
4753 if (diskInMediaRegistry == -1) {
4754 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4755 _("Unable to know if disk is in media registry"));
4756 goto cleanup;
4757 }
4758 if (diskInMediaRegistry == 1) /* Nothing to do. */
4759 continue;
4760 /* The read only disk is not in the media registry */
4761
4762 VBOX_UTF8_TO_UTF16(def->parent.dom->disks[it]->src->path, &locationUtf);
4763 rc = gVBoxAPI.UIVirtualBox.OpenMedium(data->vboxObj,
4764 locationUtf,
4765 DeviceType_HardDisk,
4766 AccessMode_ReadWrite,
4767 &readOnlyMedium);
4768 if (NS_FAILED(rc)) {
4769 virReportError(VIR_ERR_INTERNAL_ERROR,
4770 _("Unable to open HardDisk, rc=%08x"),
4771 (unsigned)rc);
4772 VBOX_UTF16_FREE(locationUtf);
4773 goto cleanup;
4774 }
4775 VBOX_UTF16_FREE(locationUtf);
4776
4777 rc = gVBoxAPI.UIMedium.GetId(readOnlyMedium, &iid);
4778 if (NS_FAILED(rc)) {
4779 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4780 _("Unable to get hard disk id"));
4781 goto cleanup;
4782 }
4783 gVBoxAPI.UIID.vboxIIDToUtf8(data, &iid, &uuid);
4784 vboxIIDUnalloc(&iid);
4785
4786 rc = gVBoxAPI.UIMedium.GetFormat(readOnlyMedium, &formatUtf);
4787 if (NS_FAILED(rc)) {
4788 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4789 _("Unable to get hard disk format"));
4790 VIR_FREE(uuid);
4791 goto cleanup;
4792 }
4793 VBOX_UTF16_TO_UTF8(formatUtf, &format);
4794 VBOX_UTF16_FREE(formatUtf);
4795
4796 /* This disk is already in the media registry */
4797 rc = gVBoxAPI.UIMedium.GetParent(readOnlyMedium, &parentReadOnlyMedium);
4798 if (NS_FAILED(rc)) {
4799 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4800 _("Unable to get parent hard disk"));
4801 VIR_FREE(uuid);
4802 goto cleanup;
4803 }
4804
4805 rc = gVBoxAPI.UIMedium.GetId(parentReadOnlyMedium, &parentiid);
4806 if (NS_FAILED(rc)) {
4807 virReportError(VIR_ERR_INTERNAL_ERROR,
4808 _("Unable to get hard disk id, rc=%08x"),
4809 (unsigned)rc);
4810 VIR_FREE(uuid);
4811 goto cleanup;
4812 }
4813 gVBoxAPI.UIID.vboxIIDToUtf8(data, &parentiid, &parentUuid);
4814 vboxIIDUnalloc(&parentiid);
4815
4816 rc = gVBoxAPI.UIMedium.Close(readOnlyMedium);
4817 if (NS_FAILED(rc)) {
4818 virReportError(VIR_ERR_INTERNAL_ERROR,
4819 _("Unable to close HardDisk, rc=%08x"),
4820 (unsigned)rc);
4821 VIR_FREE(uuid);
4822 VIR_FREE(parentUuid);
4823 goto cleanup;
4824 }
4825
4826 readOnlyDisk = g_new0(virVBoxSnapshotConfHardDisk, 1);
4827
4828 readOnlyDisk->format = format;
4829 readOnlyDisk->uuid = uuid;
4830 readOnlyDisk->location = g_strdup(def->parent.dom->disks[it]->src->path);
4831
4832 if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(readOnlyDisk, snapshotMachineDesc->mediaRegistry,
4833 parentUuid) < 0) {
4834 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4835 _("Unable to add hard disk to media registry"));
4836 VIR_FREE(readOnlyDisk);
4837 goto cleanup;
4838 }
4839 }
4840
4841 /* Now, we can unregister the machine */
4842 rc = gVBoxAPI.UIMachine.Unregister(machine,
4843 CleanupMode_DetachAllReturnHardDisksOnly,
4844 &aMediaSize,
4845 &aMedia);
4846 if (NS_FAILED(rc)) {
4847 virReportError(VIR_ERR_INTERNAL_ERROR,
4848 _("Unable to unregister machine, rc=%08x"),
4849 (unsigned)rc);
4850 goto cleanup;
4851 }
4852 VBOX_RELEASE(machine);
4853
4854 /*
4855 * Unregister the machine, and then close all disks returned by the unregister method.
4856 * Some close operations will fail because some disks that need to be closed will not
4857 * be returned by virtualbox. We will close them just after. We have to use this
4858 * solution because it is the only way to delete fake disks.
4859 */
4860 for (it = 0; it < aMediaSize; it++) {
4861 IMedium *medium = aMedia[it];
4862 if (medium) {
4863 PRUnichar *locationUtf16 = NULL;
4864 char *locationUtf8 = NULL;
4865 rc = gVBoxAPI.UIMedium.GetLocation(medium, &locationUtf16);
4866 if (NS_FAILED(rc)) {
4867 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4868 _("Unable to get medium location"));
4869 goto cleanup;
4870 }
4871 VBOX_UTF16_TO_UTF8(locationUtf16, &locationUtf8);
4872 VBOX_UTF16_FREE(locationUtf16);
4873 if (strstr(locationUtf8, "fake") != NULL) {
4874 /* we delete the fake disk because we don't need it anymore */
4875 IProgress *progress = NULL;
4876 resultCodeUnion resultCode;
4877 rc = gVBoxAPI.UIMedium.DeleteStorage(medium, &progress);
4878 if (NS_FAILED(rc)) {
4879 virReportError(VIR_ERR_INTERNAL_ERROR,
4880 _("Unable to delete medium, rc=%08x"),
4881 (unsigned)rc);
4882 VIR_FREE(locationUtf8);
4883 goto cleanup;
4884 }
4885 gVBoxAPI.UIProgress.WaitForCompletion(progress, -1);
4886 gVBoxAPI.UIProgress.GetResultCode(progress, &resultCode);
4887 if (RC_FAILED(resultCode)) {
4888 virReportError(VIR_ERR_INTERNAL_ERROR,
4889 _("Error while closing medium, rc=%08x"),
4890 resultCode.uResultCode);
4891 VIR_FREE(locationUtf8);
4892 goto cleanup;
4893 }
4894 VBOX_RELEASE(progress);
4895 } else {
4896 /*
4897 * This a comment from vboxmanage code in the handleUnregisterVM
4898 * function in VBoxManageMisc.cpp :
4899 * Note that the IMachine::Unregister method will return the medium
4900 * reference in a sane order, which means that closing will normally
4901 * succeed, unless there is still another machine which uses the
4902 * medium. No harm done if we ignore the error.
4903 */
4904 ignore_value(gVBoxAPI.UIMedium.Close(medium));
4905 }
4906 VBOX_UTF8_FREE(locationUtf8);
4907 }
4908 }
4909 /* Close all disks that failed to close normally. */
4910 for (it = 0; it < snapshotMachineDesc->mediaRegistry->ndisks; it++) {
4911 if (vboxCloseDisksRecursively(dom, snapshotMachineDesc->mediaRegistry->disks[it]->location) < 0) {
4912 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4913 _("Unable to close recursively all disks"));
4914 goto cleanup;
4915 }
4916 }
4917 /* Here, all disks are closed or deleted */
4918
4919 /* We are now going to create and fill the Snapshot xml struct */
4920 newSnapshotPtr = g_new0(virVBoxSnapshotConfSnapshot, 1);
4921
4922 if (virUUIDGenerate(snapshotUuid) < 0)
4923 goto cleanup;
4924
4925 virUUIDFormat(snapshotUuid, uuidtmp);
4926 newSnapshotPtr->uuid = g_strdup(uuidtmp);
4927
4928 VIR_DEBUG("New snapshot UUID: %s", newSnapshotPtr->uuid);
4929 newSnapshotPtr->name = g_strdup(def->parent.name);
4930
4931 newSnapshotPtr->timeStamp = virTimeStringThen(def->parent.creationTime * 1000);
4932
4933 newSnapshotPtr->description = g_strdup(def->parent.description);
4934
4935 newSnapshotPtr->hardware = g_strdup(snapshotMachineDesc->hardware);
4936
4937 newSnapshotPtr->storageController = g_strdup(snapshotMachineDesc->storageController);
4938
4939 /* We get the parent disk uuid from the parent disk location
4940 * to correctly fill the storage controller. */
4941 for (it = 0; it < def->parent.dom->ndisks; it++) {
4942 char *location = NULL;
4943 const char *uuidReplacing = NULL;
4944 char *tmp = NULL;
4945
4946 location = def->parent.dom->disks[it]->src->path;
4947 if (!location)
4948 goto cleanup;
4949 /* Replacing the uuid */
4950 uuidReplacing = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc, location);
4951 if (uuidReplacing == NULL)
4952 goto cleanup;
4953
4954 resultSize = virStringSearch(newSnapshotPtr->storageController,
4955 VBOX_UUID_REGEX,
4956 it + 1,
4957 &searchResultTab);
4958 if (resultSize != it + 1)
4959 goto cleanup;
4960
4961 tmp = virStringReplace(newSnapshotPtr->storageController,
4962 searchResultTab[it],
4963 uuidReplacing);
4964 g_strfreev(searchResultTab);
4965 searchResultTab = NULL;
4966 VIR_FREE(newSnapshotPtr->storageController);
4967 if (!tmp)
4968 goto cleanup;
4969 newSnapshotPtr->storageController = g_strdup(tmp);
4970
4971 VIR_FREE(tmp);
4972 }
4973 if (virVBoxSnapshotConfAddSnapshotToXmlMachine(newSnapshotPtr, snapshotMachineDesc, def->parent.parent_name) < 0) {
4974 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4975 _("Unable to add the snapshot to the machine description"));
4976 goto cleanup;
4977 }
4978 /*
4979 * We change the current snapshot only if there is no current snapshot or if the
4980 * snapshotFile exists, otherwise, it means that the correct current snapshot is
4981 * already set.
4982 */
4983
4984 if (snapshotMachineDesc->currentSnapshot == NULL || snapshotFileExists) {
4985 snapshotMachineDesc->currentSnapshot = newSnapshotPtr->uuid;
4986 needToChangeStorageController = true;
4987 }
4988
4989 /*
4990 * Open the snapshot's read-write disk's full ancestry to allow opening the
4991 * read-write disk itself.
4992 */
4993 for (it = 0; it < def->parent.dom->ndisks; it++) {
4994 char *location = NULL;
4995
4996 location = def->parent.dom->disks[it]->src->path;
4997 if (!location)
4998 goto cleanup;
4999
5000 hardDiskToOpenSize = virVBoxSnapshotConfDiskListToOpen(snapshotMachineDesc,
5001 &hardDiskToOpen, location);
5002 for (jt = hardDiskToOpenSize -1; jt >= 0; jt--) {
5003 IMedium *medium = NULL;
5004 PRUnichar *locationUtf16 = NULL;
5005 VBOX_UTF8_TO_UTF16(hardDiskToOpen[jt]->location, &locationUtf16);
5006
5007 rc = gVBoxAPI.UIVirtualBox.OpenMedium(data->vboxObj,
5008 locationUtf16,
5009 DeviceType_HardDisk,
5010 AccessMode_ReadWrite,
5011 &medium);
5012 VBOX_UTF16_FREE(locationUtf16);
5013 if (NS_FAILED(rc)) {
5014 virReportError(VIR_ERR_INTERNAL_ERROR,
5015 _("Unable to open HardDisk, rc=%08x"),
5016 (unsigned)rc);
5017 goto cleanup;
5018 }
5019 }
5020 }
5021 if (isCurrent || !needToChangeStorageController) {
5022 /* We don't create a differential hard disk because either the current snapshot
5023 * has already been defined or the snapshot to redefine is the current snapshot.
5024 * If the snapshot to redefine is the current snapshot, we add read-write disks in
5025 * the machine storage controllers.
5026 */
5027 for (it = 0; it < def->ndisks; it++) {
5028 IMedium *medium = NULL;
5029 PRUnichar *locationUtf16 = NULL;
5030 virVBoxSnapshotConfHardDisk *disk = NULL;
5031 PRUnichar *formatUtf16 = NULL;
5032 char *format = NULL;
5033 char *uuid = NULL;
5034 IMedium *parentDisk = NULL;
5035 char *parentUuid = NULL;
5036 vboxIID iid, parentiid;
5037
5038 VBOX_IID_INITIALIZE(&iid);
5039 VBOX_IID_INITIALIZE(&parentiid);
5040 VBOX_UTF8_TO_UTF16(def->disks[it].src->path, &locationUtf16);
5041 rc = gVBoxAPI.UIVirtualBox.OpenMedium(data->vboxObj,
5042 locationUtf16,
5043 DeviceType_HardDisk,
5044 AccessMode_ReadWrite,
5045 &medium);
5046 if (NS_FAILED(rc)) {
5047 virReportError(VIR_ERR_INTERNAL_ERROR,
5048 _("Unable to open HardDisk, rc=%08x"),
5049 (unsigned)rc);
5050 goto cleanup;
5051 }
5052 VBOX_UTF16_FREE(locationUtf16);
5053
5054 disk = g_new0(virVBoxSnapshotConfHardDisk, 1);
5055
5056 rc = gVBoxAPI.UIMedium.GetFormat(medium, &formatUtf16);
5057 if (NS_FAILED(rc)) {
5058 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5059 _("Unable to get disk format"));
5060 VIR_FREE(disk);
5061 goto cleanup;
5062 }
5063
5064 VBOX_UTF16_TO_UTF8(formatUtf16, &format);
5065 disk->format = format;
5066 VBOX_UTF16_FREE(formatUtf16);
5067
5068 disk->location = g_strdup(def->disks[it].src->path);
5069
5070 rc = gVBoxAPI.UIMedium.GetId(medium, &iid);
5071 if (NS_FAILED(rc)) {
5072 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5073 _("Unable to get disk uuid"));
5074 VIR_FREE(disk);
5075 goto cleanup;
5076 }
5077 gVBoxAPI.UIID.vboxIIDToUtf8(data, &iid, &uuid);
5078 disk->uuid = uuid;
5079 vboxIIDUnalloc(&iid);
5080
5081 rc = gVBoxAPI.UIMedium.GetParent(medium, &parentDisk);
5082 if (NS_FAILED(rc)) {
5083 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5084 _("Unable to get disk parent"));
5085 VIR_FREE(disk);
5086 goto cleanup;
5087 }
5088
5089 gVBoxAPI.UIMedium.GetId(parentDisk, &parentiid);
5090 gVBoxAPI.UIID.vboxIIDToUtf8(data, &parentiid, &parentUuid);
5091 vboxIIDUnalloc(&parentiid);
5092 if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk,
5093 snapshotMachineDesc->mediaRegistry,
5094 parentUuid) < 0) {
5095 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5096 _("Unable to add hard disk to the media registry"));
5097 VIR_FREE(disk);
5098 goto cleanup;
5099 }
5100
5101 if (needToChangeStorageController) {
5102 /* We need to append this disk in the storage controller */
5103 char *tmp = NULL;
5104 resultSize = virStringSearch(snapshotMachineDesc->storageController,
5105 VBOX_UUID_REGEX,
5106 it + 1,
5107 &searchResultTab);
5108 if (resultSize != it + 1) {
5109 virReportError(VIR_ERR_INTERNAL_ERROR,
5110 _("Unable to find UUID %s"), searchResultTab[it]);
5111 goto cleanup;
5112 }
5113
5114 tmp = virStringReplace(snapshotMachineDesc->storageController,
5115 searchResultTab[it],
5116 disk->uuid);
5117 VIR_FREE(snapshotMachineDesc->storageController);
5118 if (!tmp)
5119 goto cleanup;
5120 snapshotMachineDesc->storageController = g_strdup(tmp);
5121
5122 VIR_FREE(tmp);
5123 }
5124 /* Close disk */
5125 rc = gVBoxAPI.UIMedium.Close(medium);
5126 if (NS_FAILED(rc)) {
5127 virReportError(VIR_ERR_INTERNAL_ERROR,
5128 _("Unable to close HardDisk, rc=%08x"),
5129 (unsigned)rc);
5130 goto cleanup;
5131 }
5132 }
5133 } else {
5134 char *snapshotContent;
5135 /* Create a "fake" disk to avoid corrupting children snapshot disks. */
5136 for (it = 0; it < def->parent.dom->ndisks; it++) {
5137 IMedium *medium = NULL;
5138 PRUnichar *locationUtf16 = NULL;
5139 char *parentUuid = NULL;
5140 IMedium *newMedium = NULL;
5141 PRUnichar *formatUtf16 = NULL;
5142 PRUnichar *newLocation = NULL;
5143 char *newLocationUtf8 = NULL;
5144 resultCodeUnion resultCode;
5145 char *uuid = NULL;
5146 char *format = NULL;
5147 char *tmp = NULL;
5148 vboxIID iid, parentiid;
5149 IProgress *progress = NULL;
5150 PRUint32 tab[1];
5151
5152 VBOX_IID_INITIALIZE(&iid);
5153 VBOX_IID_INITIALIZE(&parentiid);
5154 VBOX_UTF8_TO_UTF16(def->parent.dom->disks[it]->src->path, &locationUtf16);
5155 rc = gVBoxAPI.UIVirtualBox.OpenMedium(data->vboxObj,
5156 locationUtf16,
5157 DeviceType_HardDisk,
5158 AccessMode_ReadWrite,
5159 &medium);
5160 if (NS_FAILED(rc)) {
5161 virReportError(VIR_ERR_INTERNAL_ERROR,
5162 _("Unable to open HardDisk, rc=%08x"),
5163 (unsigned)rc);
5164 VBOX_UTF16_FREE(locationUtf16);
5165 goto cleanup;
5166 }
5167 VBOX_UTF16_FREE(locationUtf16);
5168
5169 rc = gVBoxAPI.UIMedium.GetId(medium, &parentiid);
5170 if (NS_FAILED(rc)) {
5171 virReportError(VIR_ERR_INTERNAL_ERROR,
5172 _("Unable to get hardDisk Id, rc=%08x"),
5173 (unsigned)rc);
5174 goto cleanup;
5175 }
5176 gVBoxAPI.UIID.vboxIIDToUtf8(data, &parentiid, &parentUuid);
5177 vboxIIDUnalloc(&parentiid);
5178 VBOX_UTF8_TO_UTF16("VDI", &formatUtf16);
5179
5180 newLocationUtf8 = g_strdup_printf("%sfakedisk-%d.vdi",
5181 machineLocationPath, it);
5182 VBOX_UTF8_TO_UTF16(newLocationUtf8, &newLocation);
5183 rc = gVBoxAPI.UIVirtualBox.CreateHardDisk(data->vboxObj,
5184 formatUtf16,
5185 newLocation,
5186 &newMedium);
5187 VBOX_UTF16_FREE(newLocation);
5188 VBOX_UTF16_FREE(formatUtf16);
5189 if (NS_FAILED(rc)) {
5190 virReportError(VIR_ERR_INTERNAL_ERROR,
5191 _("Unable to create HardDisk, rc=%08x"),
5192 (unsigned)rc);
5193 goto cleanup;
5194 }
5195
5196 tab[0] = MediumVariant_Diff;
5197 gVBoxAPI.UIMedium.CreateDiffStorage(medium, newMedium, 1, tab, &progress);
5198
5199 gVBoxAPI.UIProgress.WaitForCompletion(progress, -1);
5200 gVBoxAPI.UIProgress.GetResultCode(progress, &resultCode);
5201 if (RC_FAILED(resultCode)) {
5202 virReportError(VIR_ERR_INTERNAL_ERROR,
5203 _("Error while creating diff storage, rc=%08x"),
5204 resultCode.uResultCode);
5205 goto cleanup;
5206 }
5207 VBOX_RELEASE(progress);
5208 /*
5209 * The differential newHardDisk is created, we add it to the
5210 * media registry and the machine storage controllers.
5211 */
5212
5213 newHardDisk = g_new0(virVBoxSnapshotConfHardDisk, 1);
5214
5215 rc = gVBoxAPI.UIMedium.GetId(newMedium, &iid);
5216 if (NS_FAILED(rc)) {
5217 virReportError(VIR_ERR_INTERNAL_ERROR,
5218 _("Unable to get medium uuid, rc=%08x"),
5219 (unsigned)rc);
5220 goto cleanup;
5221 }
5222 gVBoxAPI.UIID.vboxIIDToUtf8(data, &iid, &uuid);
5223 newHardDisk->uuid = uuid;
5224 vboxIIDUnalloc(&iid);
5225
5226 newHardDisk->location = g_strdup(newLocationUtf8);
5227
5228 rc = gVBoxAPI.UIMedium.GetFormat(newMedium, &formatUtf16);
5229 VBOX_UTF16_TO_UTF8(formatUtf16, &format);
5230 newHardDisk->format = format;
5231 VBOX_UTF16_FREE(formatUtf16);
5232
5233 if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(newHardDisk,
5234 snapshotMachineDesc->mediaRegistry,
5235 parentUuid) < 0) {
5236 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5237 _("Unable to add hard disk to the media registry"));
5238 goto cleanup;
5239 }
5240 newHardDisk = NULL; /* Consumed by above */
5241 /* Adding the fake disk to the machine storage controllers */
5242
5243 resultSize = virStringSearch(snapshotMachineDesc->storageController,
5244 VBOX_UUID_REGEX,
5245 it + 1,
5246 &searchResultTab);
5247 if (resultSize != it + 1) {
5248 virReportError(VIR_ERR_INTERNAL_ERROR,
5249 _("Unable to find UUID %s"), searchResultTab[it]);
5250 goto cleanup;
5251 }
5252
5253 tmp = virStringReplace(snapshotMachineDesc->storageController,
5254 searchResultTab[it],
5255 uuid);
5256 VIR_FREE(snapshotMachineDesc->storageController);
5257 if (!tmp)
5258 goto cleanup;
5259 snapshotMachineDesc->storageController = g_strdup(tmp);
5260
5261 VIR_FREE(tmp);
5262 /* Closing the "fake" disk */
5263 rc = gVBoxAPI.UIMedium.Close(newMedium);
5264 if (NS_FAILED(rc)) {
5265 virReportError(VIR_ERR_INTERNAL_ERROR,
5266 _("Unable to close the new medium, rc=%08x"),
5267 (unsigned)rc);
5268 goto cleanup;
5269 }
5270 }
5271 /*
5272 * We save the snapshot xml file to retrieve the real read-write disk during the
5273 * next define. This file is saved as "'machineLocation'/snapshot-'uuid'.xml"
5274 */
5275 VIR_FREE(currentSnapshotXmlFilePath);
5276 currentSnapshotXmlFilePath = g_strdup_printf("%s%s.xml",
5277 machineLocationPath, snapshotMachineDesc->currentSnapshot);
5278 snapshotContent = virDomainSnapshotDefFormat(NULL, def,
5279 data->xmlopt,
5280 VIR_DOMAIN_SNAPSHOT_FORMAT_SECURE);
5281 if (snapshotContent == NULL) {
5282 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5283 _("Unable to get snapshot content"));
5284 goto cleanup;
5285 }
5286 if (virFileWriteStr(currentSnapshotXmlFilePath, snapshotContent, 0644) < 0) {
5287 virReportSystemError(errno, "%s",
5288 _("Unable to save new snapshot xml file"));
5289 goto cleanup;
5290 }
5291 VIR_FREE(snapshotContent);
5292 }
5293 /*
5294 * All the snapshot structure manipulation is done, we close the disks we have
5295 * previously opened.
5296 */
5297 for (it = 0; it < def->parent.dom->ndisks; it++) {
5298 char *location = def->parent.dom->disks[it]->src->path;
5299 if (!location)
5300 goto cleanup;
5301
5302 hardDiskToOpenSize = virVBoxSnapshotConfDiskListToOpen(snapshotMachineDesc,
5303 &hardDiskToOpen, location);
5304 for (jt = 0; jt < hardDiskToOpenSize; jt++) {
5305 IMedium *medium = NULL;
5306 PRUnichar *locationUtf16 = NULL;
5307 VBOX_UTF8_TO_UTF16(hardDiskToOpen[jt]->location, &locationUtf16);
5308 rc = gVBoxAPI.UIVirtualBox.OpenMedium(data->vboxObj,
5309 locationUtf16,
5310 DeviceType_HardDisk,
5311 AccessMode_ReadWrite,
5312 &medium);
5313 if (NS_FAILED(rc)) {
5314 virReportError(VIR_ERR_INTERNAL_ERROR,
5315 _("Unable to open HardDisk, rc=%08x"),
5316 (unsigned)rc);
5317 goto cleanup;
5318 }
5319 rc = gVBoxAPI.UIMedium.Close(medium);
5320 if (NS_FAILED(rc)) {
5321 virReportError(VIR_ERR_INTERNAL_ERROR,
5322 _("Unable to close HardDisk, rc=%08x"),
5323 (unsigned)rc);
5324 goto cleanup;
5325 }
5326 VBOX_UTF16_FREE(locationUtf16);
5327 }
5328 }
5329
5330 /* Now, we rewrite the 'machineName'.vbox file to redefine the machine. */
5331 if (virVBoxSnapshotConfSaveVboxFile(snapshotMachineDesc, settingsFilePath_Utf8) < 0) {
5332 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5333 _("Unable to serialize the machine description"));
5334 goto cleanup;
5335 }
5336 rc = gVBoxAPI.UIVirtualBox.OpenMachine(data->vboxObj,
5337 settingsFilePath,
5338 &machine);
5339 if (NS_FAILED(rc)) {
5340 virReportError(VIR_ERR_INTERNAL_ERROR,
5341 _("Unable to open Machine, rc=%08x"),
5342 (unsigned)rc);
5343 goto cleanup;
5344 }
5345
5346 rc = gVBoxAPI.UIVirtualBox.RegisterMachine(data->vboxObj, machine);
5347 if (NS_FAILED(rc)) {
5348 virReportError(VIR_ERR_INTERNAL_ERROR,
5349 _("Unable to register Machine, rc=%08x"),
5350 (unsigned)rc);
5351 goto cleanup;
5352 }
5353
5354 ret = 0;
5355 cleanup:
5356 VBOX_RELEASE(machine);
5357 VBOX_UTF16_FREE(settingsFilePath);
5358 VBOX_UTF8_FREE(settingsFilePath_Utf8);
5359 VIR_FREE(snapshotMachineDesc);
5360 VIR_FREE(currentSnapshotXmlFilePath);
5361 VBOX_UTF16_FREE(machineNameUtf16);
5362 VBOX_UTF8_FREE(machineName);
5363 virVboxSnapshotConfHardDiskFree(newHardDisk);
5364 VIR_FREE(hardDiskToOpen);
5365 VIR_FREE(newSnapshotPtr);
5366 VIR_FREE(machineLocationPath);
5367 VIR_FREE(nameTmpUse);
5368 return ret;
5369 }
5370
5371 static virDomainSnapshotPtr
vboxDomainSnapshotCreateXML(virDomainPtr dom,const char * xmlDesc,unsigned int flags)5372 vboxDomainSnapshotCreateXML(virDomainPtr dom,
5373 const char *xmlDesc,
5374 unsigned int flags)
5375 {
5376 struct _vboxDriver *data = dom->conn->privateData;
5377 vboxIID domiid;
5378 IMachine *machine = NULL;
5379 IConsole *console = NULL;
5380 IProgress *progress = NULL;
5381 ISnapshot *snapshot = NULL;
5382 PRUnichar *name = NULL;
5383 PRUnichar *description = NULL;
5384 PRUint32 state;
5385 nsresult rc;
5386 resultCodeUnion result;
5387 virDomainSnapshotPtr ret = NULL;
5388 unsigned int parse_flags = (VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
5389 VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE);
5390 g_autoptr(virDomainSnapshotDef) def = NULL;
5391
5392 if (!data->vboxObj)
5393 return ret;
5394
5395 VBOX_IID_INITIALIZE(&domiid);
5396 /* VBox has no snapshot metadata, so this flag is trivial. */
5397 virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
5398 VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
5399 VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
5400 VIR_DOMAIN_SNAPSHOT_CREATE_VALIDATE, NULL);
5401
5402 if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_VALIDATE)
5403 parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_VALIDATE;
5404
5405 if (!(def = virDomainSnapshotDefParseString(xmlDesc,
5406 data->xmlopt, NULL, NULL,
5407 parse_flags)))
5408 goto cleanup;
5409
5410
5411 if (openSessionForMachine(data, dom->uuid, &domiid, &machine) < 0)
5412 goto cleanup;
5413
5414 if (gVBoxAPI.vboxSnapshotRedefine) {
5415 PRBool isCurrent = flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT;
5416 if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
5417 if (vboxSnapshotRedefine(dom, def, isCurrent) < 0)
5418 goto cleanup;
5419 ret = virGetDomainSnapshot(dom, def->parent.name);
5420 goto cleanup;
5421 }
5422 }
5423
5424 rc = gVBoxAPI.UIMachine.GetState(machine, &state);
5425 if (NS_FAILED(rc)) {
5426 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5427 _("could not get domain state"));
5428 goto cleanup;
5429 }
5430
5431 if (gVBoxAPI.machineStateChecker.Online(state)) {
5432 rc = gVBoxAPI.UISession.OpenExisting(data, &domiid, machine);
5433 } else {
5434 rc = gVBoxAPI.UISession.Open(data, &domiid, machine);
5435 }
5436
5437 if (NS_SUCCEEDED(rc))
5438 rc = gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
5439 if (NS_FAILED(rc)) {
5440 virReportError(VIR_ERR_INTERNAL_ERROR,
5441 _("could not open VirtualBox session with domain %s"),
5442 dom->name);
5443 goto cleanup;
5444 }
5445
5446 VBOX_UTF8_TO_UTF16(def->parent.name, &name);
5447
5448 if (def->parent.description) {
5449 VBOX_UTF8_TO_UTF16(def->parent.description, &description);
5450 }
5451
5452 rc = gVBoxAPI.UIConsole.TakeSnapshot(console, name, description, &progress);
5453 if (NS_FAILED(rc) || !progress) {
5454 virReportError(VIR_ERR_INTERNAL_ERROR,
5455 _("could not take snapshot of domain %s"), dom->name);
5456 goto cleanup;
5457 }
5458
5459 gVBoxAPI.UIProgress.WaitForCompletion(progress, -1);
5460 gVBoxAPI.UIProgress.GetResultCode(progress, &result);
5461 if (RC_FAILED(result)) {
5462 virReportError(VIR_ERR_INTERNAL_ERROR,
5463 _("could not take snapshot of domain %s"), dom->name);
5464 goto cleanup;
5465 }
5466
5467 rc = gVBoxAPI.UIMachine.GetCurrentSnapshot(machine, &snapshot);
5468 if (NS_FAILED(rc)) {
5469 virReportError(VIR_ERR_INTERNAL_ERROR,
5470 _("could not get current snapshot of domain %s"),
5471 dom->name);
5472 goto cleanup;
5473 }
5474
5475 ret = virGetDomainSnapshot(dom, def->parent.name);
5476
5477 cleanup:
5478 VBOX_RELEASE(progress);
5479 VBOX_UTF16_FREE(description);
5480 VBOX_UTF16_FREE(name);
5481 VBOX_RELEASE(console);
5482 gVBoxAPI.UISession.Close(data->vboxSession);
5483 VBOX_RELEASE(machine);
5484 vboxIIDUnalloc(&domiid);
5485 return ret;
5486 }
5487
5488 static int
vboxDomainSnapshotGetAll(virDomainPtr dom,IMachine * machine,ISnapshot *** snapshots)5489 vboxDomainSnapshotGetAll(virDomainPtr dom,
5490 IMachine *machine,
5491 ISnapshot ***snapshots)
5492 {
5493 vboxIID empty;
5494 ISnapshot **list = NULL;
5495 PRUint32 count;
5496 nsresult rc;
5497 unsigned int next;
5498 unsigned int top;
5499
5500 VBOX_IID_INITIALIZE(&empty);
5501 rc = gVBoxAPI.UIMachine.GetSnapshotCount(machine, &count);
5502 if (NS_FAILED(rc)) {
5503 virReportError(VIR_ERR_INTERNAL_ERROR,
5504 _("could not get snapshot count for domain %s"),
5505 dom->name);
5506 goto error;
5507 }
5508
5509 if (count == 0)
5510 goto out;
5511
5512 list = g_new0(ISnapshot *, count);
5513
5514 rc = gVBoxAPI.UIMachine.FindSnapshot(machine, &empty, list);
5515 if (NS_FAILED(rc) || !list[0]) {
5516 virReportError(VIR_ERR_INTERNAL_ERROR,
5517 _("could not get root snapshot for domain %s"),
5518 dom->name);
5519 goto error;
5520 }
5521
5522 /* BFS walk through snapshot tree */
5523 top = 1;
5524 for (next = 0; next < count; next++) {
5525 vboxArray children = VBOX_ARRAY_INITIALIZER;
5526 size_t i;
5527
5528 if (!list[next]) {
5529 virReportError(VIR_ERR_INTERNAL_ERROR,
5530 _("unexpected number of snapshots < %u"), count);
5531 goto error;
5532 }
5533
5534 rc = gVBoxAPI.UArray.vboxArrayGet(&children, list[next],
5535 gVBoxAPI.UArray.handleSnapshotGetChildren(list[next]));
5536 if (NS_FAILED(rc)) {
5537 virReportError(VIR_ERR_INTERNAL_ERROR,
5538 "%s", _("could not get children snapshots"));
5539 goto error;
5540 }
5541 for (i = 0; i < children.count; i++) {
5542 ISnapshot *child = children.items[i];
5543 if (!child)
5544 continue;
5545 if (top == count) {
5546 virReportError(VIR_ERR_INTERNAL_ERROR,
5547 _("unexpected number of snapshots > %u"), count);
5548 gVBoxAPI.UArray.vboxArrayRelease(&children);
5549 goto error;
5550 }
5551 VBOX_ADDREF(child);
5552 list[top++] = child;
5553 }
5554 gVBoxAPI.UArray.vboxArrayRelease(&children);
5555 }
5556
5557 out:
5558 *snapshots = list;
5559 return count;
5560
5561 error:
5562 if (list) {
5563 for (next = 0; next < count; next++)
5564 VBOX_RELEASE(list[next]);
5565 }
5566 VIR_FREE(list);
5567
5568 return -1;
5569 }
5570
5571 static ISnapshot *
vboxDomainSnapshotGet(struct _vboxDriver * data,virDomainPtr dom,IMachine * machine,const char * name)5572 vboxDomainSnapshotGet(struct _vboxDriver *data,
5573 virDomainPtr dom,
5574 IMachine *machine,
5575 const char *name)
5576 {
5577 ISnapshot **snapshots = NULL;
5578 ISnapshot *snapshot = NULL;
5579 nsresult rc;
5580 ssize_t i, count = 0;
5581
5582 if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
5583 return NULL;
5584
5585 for (i = 0; i < count; i++) {
5586 PRUnichar *nameUtf16;
5587 char *nameUtf8;
5588
5589 rc = gVBoxAPI.UISnapshot.GetName(snapshots[i], &nameUtf16);
5590 if (NS_FAILED(rc) || !nameUtf16) {
5591 virReportError(VIR_ERR_INTERNAL_ERROR,
5592 "%s", _("could not get snapshot name"));
5593 goto cleanup;
5594 }
5595 VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
5596 VBOX_UTF16_FREE(nameUtf16);
5597 if (STREQ(name, nameUtf8))
5598 snapshot = snapshots[i];
5599 VBOX_UTF8_FREE(nameUtf8);
5600
5601 if (snapshot)
5602 break;
5603 }
5604
5605 if (!snapshot) {
5606 virReportError(VIR_ERR_OPERATION_INVALID,
5607 _("domain %s has no snapshots with name %s"),
5608 dom->name, name);
5609 goto cleanup;
5610 }
5611
5612 cleanup:
5613 for (i = 0; i < count; i++) {
5614 if (snapshots[i] != snapshot)
5615 VBOX_RELEASE(snapshots[i]);
5616 }
5617 VIR_FREE(snapshots);
5618 return snapshot;
5619 }
5620
5621 static int
vboxSnapshotGetReadWriteDisks(virDomainSnapshotDef * def,virDomainSnapshotPtr snapshot)5622 vboxSnapshotGetReadWriteDisks(virDomainSnapshotDef *def,
5623 virDomainSnapshotPtr snapshot)
5624 {
5625 virDomainPtr dom = snapshot->domain;
5626 struct _vboxDriver *data = dom->conn->privateData;
5627 vboxIID domiid;
5628 IMachine *machine = NULL;
5629 ISnapshot *snap = NULL;
5630 IMachine *snapMachine = NULL;
5631 vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
5632 size_t diskCount = 0, sdCount = 0;
5633 nsresult rc;
5634 vboxIID snapIid;
5635 char *snapshotUuidStr = NULL;
5636 size_t i = 0;
5637 int ret = -1;
5638
5639 if (!data->vboxObj)
5640 return ret;
5641
5642 if (!gVBoxAPI.vboxSnapshotRedefine)
5643 VIR_WARN("This function may not work in current version");
5644
5645 VBOX_IID_INITIALIZE(&snapIid);
5646 if (openSessionForMachine(data, dom->uuid, &domiid, &machine) < 0)
5647 goto cleanup;
5648
5649 if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
5650 goto cleanup;
5651
5652 rc = gVBoxAPI.UISnapshot.GetId(snap, &snapIid);
5653 if (NS_FAILED(rc)) {
5654 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5655 _("Could not get snapshot id"));
5656 goto cleanup;
5657 }
5658
5659 gVBoxAPI.UIID.vboxIIDToUtf8(data, &snapIid, &snapshotUuidStr);
5660 vboxIIDUnalloc(&snapIid);
5661 rc = gVBoxAPI.UISnapshot.GetMachine(snap, &snapMachine);
5662 if (NS_FAILED(rc)) {
5663 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5664 _("could not get machine"));
5665 goto cleanup;
5666 }
5667 def->ndisks = 0;
5668 rc = gVBoxAPI.UArray.vboxArrayGet(&mediumAttachments, snapMachine,
5669 gVBoxAPI.UArray.handleMachineGetMediumAttachments(snapMachine));
5670 if (NS_FAILED(rc)) {
5671 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5672 _("no medium attachments"));
5673 goto cleanup;
5674 }
5675 /* get the number of attachments */
5676 for (i = 0; i < mediumAttachments.count; i++) {
5677 IMediumAttachment *imediumattach = mediumAttachments.items[i];
5678 if (imediumattach) {
5679 IMedium *medium = NULL;
5680
5681 rc = gVBoxAPI.UIMediumAttachment.GetMedium(imediumattach, &medium);
5682 if (NS_FAILED(rc)) {
5683 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5684 _("cannot get medium"));
5685 goto cleanup;
5686 }
5687 if (medium) {
5688 def->ndisks++;
5689 VBOX_RELEASE(medium);
5690 }
5691 }
5692 }
5693 /* Allocate mem, if fails return error */
5694 def->disks = g_new0(virDomainSnapshotDiskDef, def->ndisks);
5695 for (i = 0; i < def->ndisks; i++) {
5696 def->disks[i].src = g_new0(virStorageSource, 1);
5697 }
5698
5699 /* get the attachment details here */
5700 for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks; i++) {
5701 IStorageController *storageController = NULL;
5702 PRUnichar *storageControllerName = NULL;
5703 PRUint32 deviceType = DeviceType_Null;
5704 PRUint32 storageBus = StorageBus_Null;
5705 IMedium *disk = NULL;
5706 PRUnichar *childLocUtf16 = NULL;
5707 char *childLocUtf8 = NULL;
5708 PRInt32 devicePort = 0;
5709 PRInt32 deviceSlot = 0;
5710 vboxArray children = VBOX_ARRAY_INITIALIZER;
5711 vboxArray snapshotIids = VBOX_ARRAY_INITIALIZER;
5712 IMediumAttachment *imediumattach = mediumAttachments.items[i];
5713 void *handle;
5714 size_t j = 0;
5715 size_t k = 0;
5716
5717 if (!imediumattach)
5718 continue;
5719
5720 rc = gVBoxAPI.UIMediumAttachment.GetController(imediumattach,
5721 &storageControllerName);
5722 if (NS_FAILED(rc)) {
5723 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5724 _("Cannot get storage controller name"));
5725 goto cleanup;
5726 }
5727
5728 rc = gVBoxAPI.UIMachine.GetStorageControllerByName(machine,
5729 storageControllerName,
5730 &storageController);
5731 VBOX_UTF16_FREE(storageControllerName);
5732 if (NS_FAILED(rc)) {
5733 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5734 _("Cannot get storage controller by name"));
5735 goto cleanup;
5736 }
5737
5738 rc = gVBoxAPI.UIStorageController.GetBus(storageController, &storageBus);
5739 if (NS_FAILED(rc)) {
5740 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5741 _("Cannot get storage controller bus"));
5742 VBOX_RELEASE(storageController);
5743 goto cleanup;
5744 }
5745
5746 rc = gVBoxAPI.UIMediumAttachment.GetType(imediumattach, &deviceType);
5747 if (NS_FAILED(rc)) {
5748 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5749 _("Cannot get medium attachment type"));
5750 VBOX_RELEASE(storageController);
5751 goto cleanup;
5752 }
5753 rc = gVBoxAPI.UIMediumAttachment.GetPort(imediumattach, &devicePort);
5754 if (NS_FAILED(rc)) {
5755 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5756 _("Cannot get medium attachment port"));
5757 VBOX_RELEASE(storageController);
5758 goto cleanup;
5759 }
5760 rc = gVBoxAPI.UIMediumAttachment.GetDevice(imediumattach, &deviceSlot);
5761 if (NS_FAILED(rc)) {
5762 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5763 _("Cannot get medium attachment slot"));
5764 VBOX_RELEASE(storageController);
5765 goto cleanup;
5766 }
5767
5768 rc = gVBoxAPI.UIMediumAttachment.GetMedium(imediumattach, &disk);
5769 if (NS_FAILED(rc)) {
5770 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5771 _("Cannot get medium"));
5772 VBOX_RELEASE(storageController);
5773 goto cleanup;
5774 }
5775
5776 /* skip empty removable disk */
5777 if (!disk) {
5778 /* removable disks with empty (ejected) media won't be displayed
5779 * in XML, but we need to update "sdCount" so that device names match
5780 * in domain dumpxml and snapshot dumpxml
5781 */
5782 if (storageBus == StorageBus_SATA || storageBus == StorageBus_SCSI ||
5783 storageBus == StorageBus_SAS)
5784 sdCount++;
5785
5786 VBOX_RELEASE(storageController);
5787 continue;
5788 }
5789
5790 handle = gVBoxAPI.UArray.handleMediumGetChildren(disk);
5791 rc = gVBoxAPI.UArray.vboxArrayGet(&children, disk, handle);
5792 if (NS_FAILED(rc)) {
5793 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5794 _("cannot get children disk"));
5795 goto cleanup;
5796 }
5797 handle = gVBoxAPI.UArray.handleMediumGetSnapshotIds(disk);
5798 rc = gVBoxAPI.UArray.vboxArrayGetWithIIDArg(&snapshotIids, disk,
5799 handle, &domiid);
5800 if (NS_FAILED(rc)) {
5801 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5802 _("cannot get snapshot ids"));
5803 goto cleanup;
5804 }
5805 for (j = 0; j < children.count; ++j) {
5806 IMedium *child = children.items[j];
5807 for (k = 0; k < snapshotIids.count; ++k) {
5808 PRUnichar *diskSnapId = snapshotIids.items[k];
5809 char *diskSnapIdStr = NULL;
5810 VBOX_UTF16_TO_UTF8(diskSnapId, &diskSnapIdStr);
5811 if (STREQ(diskSnapIdStr, snapshotUuidStr)) {
5812 rc = gVBoxAPI.UIMedium.GetLocation(child, &childLocUtf16);
5813 if (NS_FAILED(rc)) {
5814 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5815 _("cannot get disk location"));
5816 VBOX_RELEASE(storageController);
5817 VBOX_RELEASE(disk);
5818 VBOX_RELEASE(child);
5819 goto cleanup;
5820 }
5821 VBOX_UTF16_TO_UTF8(childLocUtf16, &childLocUtf8);
5822 VBOX_UTF16_FREE(childLocUtf16);
5823 def->disks[diskCount].src->path = g_strdup(childLocUtf8);
5824 VBOX_UTF8_FREE(childLocUtf8);
5825
5826 def->disks[diskCount].src->type = VIR_STORAGE_TYPE_FILE;
5827 def->disks[diskCount].name = vboxGenerateMediumName(storageBus,
5828 devicePort,
5829 deviceSlot,
5830 sdCount);
5831 }
5832 VBOX_UTF8_FREE(diskSnapIdStr);
5833 }
5834 }
5835 VBOX_RELEASE(storageController);
5836 VBOX_RELEASE(disk);
5837 diskCount++;
5838
5839 if (storageBus == StorageBus_SATA || storageBus == StorageBus_SCSI ||
5840 storageBus == StorageBus_SAS)
5841 sdCount++;
5842
5843 }
5844 gVBoxAPI.UArray.vboxArrayRelease(&mediumAttachments);
5845
5846 ret = 0;
5847
5848 cleanup:
5849 VBOX_RELEASE(snap);
5850
5851 return ret;
5852 }
5853
5854 static int
vboxSnapshotGetReadOnlyDisks(virDomainSnapshotDef * def,virDomainSnapshotPtr snapshot)5855 vboxSnapshotGetReadOnlyDisks(virDomainSnapshotDef *def,
5856 virDomainSnapshotPtr snapshot)
5857 {
5858 virDomainPtr dom = snapshot->domain;
5859 struct _vboxDriver *data = dom->conn->privateData;
5860 vboxIID domiid;
5861 ISnapshot *snap = NULL;
5862 IMachine *machine = NULL;
5863 IMachine *snapMachine = NULL;
5864 IStorageController *storageController = NULL;
5865 IMedium *disk = NULL;
5866 nsresult rc;
5867 vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
5868 size_t i = 0, diskCount = 0, sdCount = 0;
5869 int ret = -1;
5870 virDomainDef *defdom = def->parent.dom;
5871
5872 if (!data->vboxObj)
5873 return ret;
5874
5875 if (!gVBoxAPI.vboxSnapshotRedefine)
5876 VIR_WARN("This function may not work in current version");
5877
5878 if (openSessionForMachine(data, dom->uuid, &domiid, &machine) < 0)
5879 goto cleanup;
5880
5881 if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
5882 goto cleanup;
5883
5884 rc = gVBoxAPI.UISnapshot.GetMachine(snap, &snapMachine);
5885 if (NS_FAILED(rc)) {
5886 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5887 _("cannot get machine"));
5888 goto cleanup;
5889 }
5890 /*
5891 * Get READ ONLY disks
5892 * In the snapshot metadata, these are the disks written inside the <domain> node
5893 */
5894 rc = gVBoxAPI.UArray.vboxArrayGet(&mediumAttachments, snapMachine,
5895 gVBoxAPI.UArray.handleMachineGetMediumAttachments(snapMachine));
5896 if (NS_FAILED(rc)) {
5897 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5898 _("cannot get medium attachments"));
5899 goto cleanup;
5900 }
5901 /* get the number of attachments */
5902 for (i = 0; i < mediumAttachments.count; i++) {
5903 IMediumAttachment *imediumattach = mediumAttachments.items[i];
5904 if (imediumattach) {
5905 IMedium *medium = NULL;
5906
5907 rc = gVBoxAPI.UIMediumAttachment.GetMedium(imediumattach, &medium);
5908 if (NS_FAILED(rc)) {
5909 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5910 _("cannot get medium"));
5911 goto cleanup;
5912 }
5913 if (medium) {
5914 defdom->ndisks++;
5915 VBOX_RELEASE(medium);
5916 }
5917 }
5918 }
5919
5920 /* Allocate mem, if fails return error */
5921 defdom->disks = g_new0(virDomainDiskDef *, defdom->ndisks);
5922
5923 for (i = 0; i < defdom->ndisks; i++) {
5924 virDomainDiskDef *diskDef = virDomainDiskDefNew(NULL);
5925 if (!diskDef)
5926 goto cleanup;
5927 defdom->disks[i] = diskDef;
5928 }
5929
5930 /* get the attachment details here */
5931 for (i = 0; i < mediumAttachments.count && diskCount < defdom->ndisks; i++) {
5932 PRUnichar *storageControllerName = NULL;
5933 PRUint32 deviceType = DeviceType_Null;
5934 PRUint32 storageBus = StorageBus_Null;
5935 PRBool readOnly = PR_FALSE;
5936 PRUnichar *mediumLocUtf16 = NULL;
5937 char *mediumLocUtf8 = NULL;
5938 PRInt32 devicePort = 0;
5939 PRInt32 deviceSlot = 0;
5940 IMediumAttachment *imediumattach = mediumAttachments.items[i];
5941 if (!imediumattach)
5942 continue;
5943 rc = gVBoxAPI.UIMediumAttachment.GetController(imediumattach, &storageControllerName);
5944 if (NS_FAILED(rc)) {
5945 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5946 _("Cannot get storage controller name"));
5947 goto cleanup;
5948 }
5949 if (!storageControllerName)
5950 continue;
5951 rc = gVBoxAPI.UIMachine.GetStorageControllerByName(machine,
5952 storageControllerName,
5953 &storageController);
5954 VBOX_UTF16_FREE(storageControllerName);
5955 if (NS_FAILED(rc)) {
5956 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5957 _("Cannot get storage controller"));
5958 goto cleanup;
5959 }
5960 if (!storageController)
5961 continue;
5962 rc = gVBoxAPI.UIStorageController.GetBus(storageController, &storageBus);
5963 if (NS_FAILED(rc)) {
5964 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5965 _("Cannot get storage controller bus"));
5966 goto cleanup;
5967 }
5968 rc = gVBoxAPI.UIMediumAttachment.GetPort(imediumattach, &devicePort);
5969 if (NS_FAILED(rc)) {
5970 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5971 _("Cannot get medium attachment port"));
5972 goto cleanup;
5973 }
5974 rc = gVBoxAPI.UIMediumAttachment.GetDevice(imediumattach, &deviceSlot);
5975 if (NS_FAILED(rc)) {
5976 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5977 _("Cannot get device slot"));
5978 goto cleanup;
5979 }
5980
5981 rc = gVBoxAPI.UIMediumAttachment.GetMedium(imediumattach, &disk);
5982 if (NS_FAILED(rc)) {
5983 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
5984 _("Cannot get medium"));
5985 goto cleanup;
5986 }
5987
5988 /* skip empty removable disk */
5989 if (!disk) {
5990 /* removable disks with empty (ejected) media won't be displayed
5991 * in XML, but we need to update "sdCount" so that device names match
5992 * in domain dumpxml and snapshot dumpxml
5993 */
5994 if (storageBus == StorageBus_SATA || storageBus == StorageBus_SCSI ||
5995 storageBus == StorageBus_SAS)
5996 sdCount++;
5997
5998 VBOX_RELEASE(storageController);
5999 continue;
6000 }
6001
6002 rc = gVBoxAPI.UIMedium.GetLocation(disk, &mediumLocUtf16);
6003 if (NS_FAILED(rc)) {
6004 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6005 _("Cannot get disk location"));
6006 goto cleanup;
6007 }
6008 VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
6009 VBOX_UTF16_FREE(mediumLocUtf16);
6010 defdom->disks[diskCount]->src->path = g_strdup(mediumLocUtf8);
6011
6012 VBOX_UTF8_FREE(mediumLocUtf8);
6013 rc = gVBoxAPI.UIMedium.GetReadOnly(disk, &readOnly);
6014 if (NS_FAILED(rc)) {
6015 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6016 _("Cannot get read only attribute"));
6017 goto cleanup;
6018 }
6019
6020 defdom->disks[diskCount]->dst = vboxGenerateMediumName(storageBus,
6021 devicePort,
6022 deviceSlot,
6023 sdCount);
6024 if (!defdom->disks[diskCount]->dst) {
6025 virReportError(VIR_ERR_INTERNAL_ERROR,
6026 _("Could not generate medium name for the disk "
6027 "at: port:%d, slot:%d"), devicePort, deviceSlot);
6028 ret = -1;
6029 goto cleanup;
6030 }
6031
6032 if (storageBus == StorageBus_IDE) {
6033 defdom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE;
6034 } else if (storageBus == StorageBus_SATA) {
6035 sdCount++;
6036 defdom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA;
6037 } else if (storageBus == StorageBus_SCSI ||
6038 storageBus == StorageBus_SAS) {
6039 sdCount++;
6040 defdom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI;
6041 } else if (storageBus == StorageBus_Floppy) {
6042 defdom->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC;
6043 }
6044
6045 rc = gVBoxAPI.UIMediumAttachment.GetType(imediumattach, &deviceType);
6046 if (NS_FAILED(rc)) {
6047 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6048 _("cannot get medium attachment type"));
6049 goto cleanup;
6050 }
6051 if (deviceType == DeviceType_HardDisk)
6052 defdom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
6053 else if (deviceType == DeviceType_Floppy)
6054 defdom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
6055 else if (deviceType == DeviceType_DVD)
6056 defdom->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
6057
6058 if (readOnly == PR_TRUE)
6059 defdom->disks[diskCount]->src->readonly = true;
6060 defdom->disks[diskCount]->src->type = VIR_STORAGE_TYPE_FILE;
6061
6062 diskCount++;
6063 }
6064
6065 ret = 0;
6066
6067 cleanup:
6068 VBOX_RELEASE(disk);
6069 VBOX_RELEASE(storageController);
6070 gVBoxAPI.UArray.vboxArrayRelease(&mediumAttachments);
6071 VBOX_RELEASE(snap);
6072
6073 return ret;
6074 }
6075
vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,unsigned int flags)6076 static char *vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
6077 unsigned int flags)
6078 {
6079 virDomainPtr dom = snapshot->domain;
6080 struct _vboxDriver *data = dom->conn->privateData;
6081 vboxIID domiid;
6082 IMachine *machine = NULL;
6083 ISnapshot *snap = NULL;
6084 ISnapshot *parent = NULL;
6085 nsresult rc;
6086 PRUnichar *str16;
6087 char *str8;
6088 PRInt64 timestamp;
6089 PRBool online = PR_FALSE;
6090 char uuidstr[VIR_UUID_STRING_BUFLEN];
6091 char *ret = NULL;
6092 virDomainDef *defdom;
6093 g_autoptr(virDomainSnapshotDef) def = NULL;
6094
6095 if (!data->vboxObj)
6096 return ret;
6097
6098 virCheckFlags(0, NULL);
6099
6100 if (openSessionForMachine(data, dom->uuid, &domiid, &machine) < 0)
6101 goto cleanup;
6102
6103 if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
6104 goto cleanup;
6105
6106 if (!(def = virDomainSnapshotDefNew()) ||
6107 !(def->parent.dom = virDomainDefNew(data->xmlopt)))
6108 goto cleanup;
6109 defdom = def->parent.dom;
6110 def->parent.name = g_strdup(snapshot->name);
6111
6112 if (gVBoxAPI.vboxSnapshotRedefine) {
6113 /* Register def->dom properties for them to be saved inside the snapshot XMl
6114 * Otherwise, there is a problem while parsing the xml
6115 */
6116 PRUint32 memorySize = 0;
6117 PRUint32 CPUCount = 0;
6118
6119 defdom->virtType = VIR_DOMAIN_VIRT_VBOX;
6120 defdom->id = dom->id;
6121 memcpy(defdom->uuid, dom->uuid, VIR_UUID_BUFLEN);
6122 defdom->name = g_strdup(dom->name);
6123 gVBoxAPI.UIMachine.GetMemorySize(machine, &memorySize);
6124 defdom->mem.cur_balloon = memorySize * 1024;
6125 /* Currently setting memory and maxMemory as same, cause
6126 * the notation here seems to be inconsistent while
6127 * reading and while dumping xml
6128 */
6129 virDomainDefSetMemoryTotal(defdom, memorySize * 1024);
6130 defdom->os.type = VIR_DOMAIN_OSTYPE_HVM;
6131 defdom->os.arch = virArchFromHost();
6132 gVBoxAPI.UIMachine.GetCPUCount(machine, &CPUCount);
6133 if (virDomainDefSetVcpusMax(defdom, CPUCount, data->xmlopt) < 0)
6134 goto cleanup;
6135
6136 if (virDomainDefSetVcpus(defdom, CPUCount) < 0)
6137 goto cleanup;
6138
6139 if (vboxSnapshotGetReadWriteDisks(def, snapshot) < 0)
6140 VIR_DEBUG("Could not get read write disks for snapshot");
6141
6142 if (vboxSnapshotGetReadOnlyDisks(def, snapshot) < 0)
6143 VIR_DEBUG("Could not get Readonly disks for snapshot");
6144 }
6145
6146 rc = gVBoxAPI.UISnapshot.GetDescription(snap, &str16);
6147 if (NS_FAILED(rc)) {
6148 virReportError(VIR_ERR_INTERNAL_ERROR,
6149 _("could not get description of snapshot %s"),
6150 snapshot->name);
6151 goto cleanup;
6152 }
6153 if (str16) {
6154 VBOX_UTF16_TO_UTF8(str16, &str8);
6155 VBOX_UTF16_FREE(str16);
6156 def->parent.description = g_strdup(str8);
6157 VBOX_UTF8_FREE(str8);
6158 }
6159
6160 rc = gVBoxAPI.UISnapshot.GetTimeStamp(snap, ×tamp);
6161 if (NS_FAILED(rc)) {
6162 virReportError(VIR_ERR_INTERNAL_ERROR,
6163 _("could not get creation time of snapshot %s"),
6164 snapshot->name);
6165 goto cleanup;
6166 }
6167 /* timestamp is in milliseconds while creationTime in seconds */
6168 def->parent.creationTime = timestamp / 1000;
6169
6170 rc = gVBoxAPI.UISnapshot.GetParent(snap, &parent);
6171 if (NS_FAILED(rc)) {
6172 virReportError(VIR_ERR_INTERNAL_ERROR,
6173 _("could not get parent of snapshot %s"),
6174 snapshot->name);
6175 goto cleanup;
6176 }
6177 if (parent) {
6178 rc = gVBoxAPI.UISnapshot.GetName(parent, &str16);
6179 if (NS_FAILED(rc) || !str16) {
6180 virReportError(VIR_ERR_INTERNAL_ERROR,
6181 _("could not get name of parent of snapshot %s"),
6182 snapshot->name);
6183 goto cleanup;
6184 }
6185 VBOX_UTF16_TO_UTF8(str16, &str8);
6186 VBOX_UTF16_FREE(str16);
6187 def->parent.parent_name = g_strdup(str8);
6188 VBOX_UTF8_FREE(str8);
6189 }
6190
6191 rc = gVBoxAPI.UISnapshot.GetOnline(snap, &online);
6192 if (NS_FAILED(rc)) {
6193 virReportError(VIR_ERR_INTERNAL_ERROR,
6194 _("could not get online state of snapshot %s"),
6195 snapshot->name);
6196 goto cleanup;
6197 }
6198 if (online)
6199 def->state = VIR_DOMAIN_SNAPSHOT_RUNNING;
6200 else
6201 def->state = VIR_DOMAIN_SNAPSHOT_SHUTOFF;
6202
6203 virUUIDFormat(dom->uuid, uuidstr);
6204 memcpy(defdom->uuid, dom->uuid, VIR_UUID_BUFLEN);
6205 ret = virDomainSnapshotDefFormat(uuidstr, def, data->xmlopt, 0);
6206
6207 cleanup:
6208 VBOX_RELEASE(parent);
6209 VBOX_RELEASE(snap);
6210 VBOX_RELEASE(machine);
6211 vboxIIDUnalloc(&domiid);
6212 return ret;
6213 }
6214
vboxDomainSnapshotNum(virDomainPtr dom,unsigned int flags)6215 static int vboxDomainSnapshotNum(virDomainPtr dom, unsigned int flags)
6216 {
6217 struct _vboxDriver *data = dom->conn->privateData;
6218 vboxIID iid;
6219 IMachine *machine = NULL;
6220 nsresult rc;
6221 PRUint32 snapshotCount;
6222 int ret = -1;
6223
6224 if (!data->vboxObj)
6225 return ret;
6226
6227 virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
6228 VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6229
6230 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
6231 goto cleanup;
6232
6233 /* VBox snapshots do not require libvirt to maintain any metadata. */
6234 if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
6235 ret = 0;
6236 goto cleanup;
6237 }
6238
6239 rc = gVBoxAPI.UIMachine.GetSnapshotCount(machine, &snapshotCount);
6240 if (NS_FAILED(rc)) {
6241 virReportError(VIR_ERR_INTERNAL_ERROR,
6242 _("could not get snapshot count for domain %s"),
6243 dom->name);
6244 goto cleanup;
6245 }
6246
6247 /* VBox has at most one root snapshot. */
6248 if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS))
6249 ret = 1;
6250 else
6251 ret = snapshotCount;
6252
6253 cleanup:
6254 VBOX_RELEASE(machine);
6255 vboxIIDUnalloc(&iid);
6256 return ret;
6257 }
6258
vboxDomainSnapshotListNames(virDomainPtr dom,char ** names,int nameslen,unsigned int flags)6259 static int vboxDomainSnapshotListNames(virDomainPtr dom, char **names,
6260 int nameslen, unsigned int flags)
6261 {
6262 struct _vboxDriver *data = dom->conn->privateData;
6263 vboxIID iid;
6264 IMachine *machine = NULL;
6265 nsresult rc;
6266 ISnapshot **snapshots = NULL;
6267 ssize_t i, count = 0;
6268 int ret = -1;
6269
6270 if (!data->vboxObj)
6271 return ret;
6272
6273 virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
6274 VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6275
6276 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
6277 goto cleanup;
6278
6279 if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
6280 ret = 0;
6281 goto cleanup;
6282 }
6283
6284 if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) {
6285 vboxIID empty;
6286
6287 VBOX_IID_INITIALIZE(&empty);
6288 snapshots = g_new0(ISnapshot *, 1);
6289 rc = gVBoxAPI.UIMachine.FindSnapshot(machine, &empty, snapshots);
6290 if (NS_FAILED(rc) || !snapshots[0]) {
6291 virReportError(VIR_ERR_INTERNAL_ERROR,
6292 _("could not get root snapshot for domain %s"),
6293 dom->name);
6294 goto cleanup;
6295 }
6296 count = 1;
6297 } else {
6298 if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
6299 goto cleanup;
6300 }
6301
6302 for (i = 0; i < nameslen; i++) {
6303 PRUnichar *nameUtf16;
6304 char *name;
6305
6306 if (i >= count)
6307 break;
6308
6309 rc = gVBoxAPI.UISnapshot.GetName(snapshots[i], &nameUtf16);
6310 if (NS_FAILED(rc) || !nameUtf16) {
6311 virReportError(VIR_ERR_INTERNAL_ERROR,
6312 "%s", _("could not get snapshot name"));
6313 goto cleanup;
6314 }
6315 VBOX_UTF16_TO_UTF8(nameUtf16, &name);
6316 VBOX_UTF16_FREE(nameUtf16);
6317 names[i] = g_strdup(name);
6318 VBOX_UTF8_FREE(name);
6319 }
6320
6321 if (count <= nameslen)
6322 ret = count;
6323 else
6324 ret = nameslen;
6325
6326 cleanup:
6327 for (i = 0; i < count; i++)
6328 VBOX_RELEASE(snapshots[i]);
6329 VIR_FREE(snapshots);
6330 VBOX_RELEASE(machine);
6331 vboxIIDUnalloc(&iid);
6332 return ret;
6333 }
6334
6335 static virDomainSnapshotPtr
vboxDomainSnapshotLookupByName(virDomainPtr dom,const char * name,unsigned int flags)6336 vboxDomainSnapshotLookupByName(virDomainPtr dom, const char *name,
6337 unsigned int flags)
6338 {
6339 struct _vboxDriver *data = dom->conn->privateData;
6340 vboxIID iid;
6341 IMachine *machine = NULL;
6342 ISnapshot *snapshot = NULL;
6343 virDomainSnapshotPtr ret = NULL;
6344
6345 if (!data->vboxObj)
6346 return ret;
6347
6348 virCheckFlags(0, NULL);
6349
6350 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
6351 goto cleanup;
6352
6353 if (!(snapshot = vboxDomainSnapshotGet(data, dom, machine, name)))
6354 goto cleanup;
6355
6356 ret = virGetDomainSnapshot(dom, name);
6357
6358 cleanup:
6359 VBOX_RELEASE(snapshot);
6360 VBOX_RELEASE(machine);
6361 vboxIIDUnalloc(&iid);
6362 return ret;
6363 }
6364
vboxDomainHasCurrentSnapshot(virDomainPtr dom,unsigned int flags)6365 static int vboxDomainHasCurrentSnapshot(virDomainPtr dom,
6366 unsigned int flags)
6367 {
6368 struct _vboxDriver *data = dom->conn->privateData;
6369 vboxIID iid;
6370 IMachine *machine = NULL;
6371 ISnapshot *snapshot = NULL;
6372 nsresult rc;
6373 int ret = -1;
6374
6375 if (!data->vboxObj)
6376 return ret;
6377
6378 virCheckFlags(0, -1);
6379
6380 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
6381 goto cleanup;
6382
6383 rc = gVBoxAPI.UIMachine.GetCurrentSnapshot(machine, &snapshot);
6384 if (NS_FAILED(rc)) {
6385 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6386 _("could not get current snapshot"));
6387 goto cleanup;
6388 }
6389
6390 if (snapshot)
6391 ret = 1;
6392 else
6393 ret = 0;
6394
6395 cleanup:
6396 VBOX_RELEASE(machine);
6397 vboxIIDUnalloc(&iid);
6398 return ret;
6399 }
6400
6401 static virDomainSnapshotPtr
vboxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,unsigned int flags)6402 vboxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
6403 unsigned int flags)
6404 {
6405 virDomainPtr dom = snapshot->domain;
6406 struct _vboxDriver *data = dom->conn->privateData;
6407 vboxIID iid;
6408 IMachine *machine = NULL;
6409 ISnapshot *snap = NULL;
6410 ISnapshot *parent = NULL;
6411 PRUnichar *nameUtf16 = NULL;
6412 char *name = NULL;
6413 nsresult rc;
6414 virDomainSnapshotPtr ret = NULL;
6415
6416 if (!data->vboxObj)
6417 return ret;
6418
6419 virCheckFlags(0, NULL);
6420
6421 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
6422 goto cleanup;
6423
6424 if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
6425 goto cleanup;
6426
6427 rc = gVBoxAPI.UISnapshot.GetParent(snap, &parent);
6428 if (NS_FAILED(rc)) {
6429 virReportError(VIR_ERR_INTERNAL_ERROR,
6430 _("could not get parent of snapshot %s"),
6431 snapshot->name);
6432 goto cleanup;
6433 }
6434 if (!parent) {
6435 virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
6436 _("snapshot '%s' does not have a parent"),
6437 snapshot->name);
6438 goto cleanup;
6439 }
6440
6441 rc = gVBoxAPI.UISnapshot.GetName(parent, &nameUtf16);
6442 if (NS_FAILED(rc) || !nameUtf16) {
6443 virReportError(VIR_ERR_INTERNAL_ERROR,
6444 _("could not get name of parent of snapshot %s"),
6445 snapshot->name);
6446 goto cleanup;
6447 }
6448 VBOX_UTF16_TO_UTF8(nameUtf16, &name);
6449
6450 ret = virGetDomainSnapshot(dom, name);
6451
6452 cleanup:
6453 VBOX_UTF8_FREE(name);
6454 VBOX_UTF16_FREE(nameUtf16);
6455 VBOX_RELEASE(snap);
6456 VBOX_RELEASE(parent);
6457 VBOX_RELEASE(machine);
6458 vboxIIDUnalloc(&iid);
6459 return ret;
6460 }
6461
6462 static virDomainSnapshotPtr
vboxDomainSnapshotCurrent(virDomainPtr dom,unsigned int flags)6463 vboxDomainSnapshotCurrent(virDomainPtr dom, unsigned int flags)
6464 {
6465 struct _vboxDriver *data = dom->conn->privateData;
6466 vboxIID iid;
6467 IMachine *machine = NULL;
6468 ISnapshot *snapshot = NULL;
6469 PRUnichar *nameUtf16 = NULL;
6470 char *name = NULL;
6471 nsresult rc;
6472 virDomainSnapshotPtr ret = NULL;
6473
6474 if (!data->vboxObj)
6475 return ret;
6476
6477 virCheckFlags(0, NULL);
6478
6479 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
6480 goto cleanup;
6481
6482 rc = gVBoxAPI.UIMachine.GetCurrentSnapshot(machine, &snapshot);
6483 if (NS_FAILED(rc)) {
6484 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6485 _("could not get current snapshot"));
6486 goto cleanup;
6487 }
6488
6489 if (!snapshot) {
6490 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6491 _("domain has no snapshots"));
6492 goto cleanup;
6493 }
6494
6495 rc = gVBoxAPI.UISnapshot.GetName(snapshot, &nameUtf16);
6496 if (NS_FAILED(rc) || !nameUtf16) {
6497 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6498 _("could not get current snapshot name"));
6499 goto cleanup;
6500 }
6501
6502 VBOX_UTF16_TO_UTF8(nameUtf16, &name);
6503
6504 ret = virGetDomainSnapshot(dom, name);
6505
6506 cleanup:
6507 VBOX_UTF8_FREE(name);
6508 VBOX_UTF16_FREE(nameUtf16);
6509 VBOX_RELEASE(snapshot);
6510 VBOX_RELEASE(machine);
6511 vboxIIDUnalloc(&iid);
6512 return ret;
6513 }
6514
vboxDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,unsigned int flags)6515 static int vboxDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
6516 unsigned int flags)
6517 {
6518 virDomainPtr dom = snapshot->domain;
6519 struct _vboxDriver *data = dom->conn->privateData;
6520 vboxIID iid;
6521 IMachine *machine = NULL;
6522 ISnapshot *snap = NULL;
6523 ISnapshot *current = NULL;
6524 PRUnichar *nameUtf16 = NULL;
6525 char *name = NULL;
6526 nsresult rc;
6527 int ret = -1;
6528
6529 if (!data->vboxObj)
6530 return ret;
6531
6532 virCheckFlags(0, -1);
6533
6534 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
6535 goto cleanup;
6536
6537 if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
6538 goto cleanup;
6539
6540 rc = gVBoxAPI.UIMachine.GetCurrentSnapshot(machine, ¤t);
6541 if (NS_FAILED(rc)) {
6542 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6543 _("could not get current snapshot"));
6544 goto cleanup;
6545 }
6546 if (!current) {
6547 ret = 0;
6548 goto cleanup;
6549 }
6550
6551 rc = gVBoxAPI.UISnapshot.GetName(current, &nameUtf16);
6552 if (NS_FAILED(rc) || !nameUtf16) {
6553 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6554 _("could not get current snapshot name"));
6555 goto cleanup;
6556 }
6557
6558 VBOX_UTF16_TO_UTF8(nameUtf16, &name);
6559
6560 ret = STREQ(snapshot->name, name);
6561
6562 cleanup:
6563 VBOX_UTF8_FREE(name);
6564 VBOX_UTF16_FREE(nameUtf16);
6565 VBOX_RELEASE(snap);
6566 VBOX_RELEASE(current);
6567 VBOX_RELEASE(machine);
6568 vboxIIDUnalloc(&iid);
6569 return ret;
6570 }
6571
vboxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,unsigned int flags)6572 static int vboxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
6573 unsigned int flags)
6574 {
6575 virDomainPtr dom = snapshot->domain;
6576 struct _vboxDriver *data = dom->conn->privateData;
6577 vboxIID iid;
6578 IMachine *machine = NULL;
6579 ISnapshot *snap = NULL;
6580 int ret = -1;
6581
6582 if (!data->vboxObj)
6583 return ret;
6584
6585 virCheckFlags(0, -1);
6586
6587 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
6588 goto cleanup;
6589
6590 /* Check that snapshot exists. If so, there is no metadata. */
6591 if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
6592 goto cleanup;
6593
6594 ret = 0;
6595
6596 cleanup:
6597 VBOX_RELEASE(snap);
6598 VBOX_RELEASE(machine);
6599 vboxIIDUnalloc(&iid);
6600 return ret;
6601 }
6602
vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,unsigned int flags)6603 static int vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
6604 unsigned int flags)
6605 {
6606 virDomainPtr dom = snapshot->domain;
6607 struct _vboxDriver *data = dom->conn->privateData;
6608 vboxIID domiid;
6609 IMachine *machine = NULL;
6610 ISnapshot *newSnapshot = NULL;
6611 ISnapshot *prevSnapshot = NULL;
6612 PRBool online = PR_FALSE;
6613 PRUint32 state;
6614 nsresult rc;
6615 int ret = -1;
6616
6617 if (!data->vboxObj)
6618 return ret;
6619
6620 virCheckFlags(0, -1);
6621
6622 if (openSessionForMachine(data, dom->uuid, &domiid, &machine) < 0)
6623 goto cleanup;
6624
6625 newSnapshot = vboxDomainSnapshotGet(data, dom, machine, snapshot->name);
6626 if (!newSnapshot)
6627 goto cleanup;
6628
6629 rc = gVBoxAPI.UISnapshot.GetOnline(newSnapshot, &online);
6630 if (NS_FAILED(rc)) {
6631 virReportError(VIR_ERR_INTERNAL_ERROR,
6632 _("could not get online state of snapshot %s"),
6633 snapshot->name);
6634 goto cleanup;
6635 }
6636
6637 rc = gVBoxAPI.UIMachine.GetCurrentSnapshot(machine, &prevSnapshot);
6638 if (NS_FAILED(rc)) {
6639 virReportError(VIR_ERR_INTERNAL_ERROR,
6640 _("could not get current snapshot of domain %s"),
6641 dom->name);
6642 goto cleanup;
6643 }
6644
6645 rc = gVBoxAPI.UIMachine.GetState(machine, &state);
6646 if (NS_FAILED(rc)) {
6647 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6648 _("could not get domain state"));
6649 goto cleanup;
6650 }
6651
6652 if (gVBoxAPI.machineStateChecker.Online(state)) {
6653 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6654 _("cannot revert snapshot of running domain"));
6655 goto cleanup;
6656 }
6657
6658 if (gVBoxAPI.snapshotRestore(dom, machine, newSnapshot))
6659 goto cleanup;
6660
6661 if (online) {
6662 ret = vboxDomainCreate(dom);
6663 if (!ret)
6664 gVBoxAPI.snapshotRestore(dom, machine, prevSnapshot);
6665 } else {
6666 ret = 0;
6667 }
6668
6669 cleanup:
6670 VBOX_RELEASE(prevSnapshot);
6671 VBOX_RELEASE(newSnapshot);
6672 vboxIIDUnalloc(&domiid);
6673 return ret;
6674 }
6675
6676 static int
vboxDomainSnapshotDeleteSingle(struct _vboxDriver * data,IConsole * console,ISnapshot * snapshot)6677 vboxDomainSnapshotDeleteSingle(struct _vboxDriver *data,
6678 IConsole *console,
6679 ISnapshot *snapshot)
6680 {
6681 IProgress *progress = NULL;
6682 vboxIID iid;
6683 int ret = -1;
6684 nsresult rc;
6685 resultCodeUnion result;
6686
6687 VBOX_IID_INITIALIZE(&iid);
6688 rc = gVBoxAPI.UISnapshot.GetId(snapshot, &iid);
6689 if (NS_FAILED(rc)) {
6690 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6691 _("could not get snapshot UUID"));
6692 goto cleanup;
6693 }
6694
6695 rc = gVBoxAPI.UIConsole.DeleteSnapshot(console, &iid, &progress);
6696 if (NS_FAILED(rc) || !progress) {
6697 if (rc == VBOX_E_INVALID_VM_STATE) {
6698 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6699 _("cannot delete domain snapshot for running domain"));
6700 } else {
6701 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6702 _("could not delete snapshot"));
6703 }
6704 goto cleanup;
6705 }
6706
6707 gVBoxAPI.UIProgress.WaitForCompletion(progress, -1);
6708 gVBoxAPI.UIProgress.GetResultCode(progress, &result);
6709 if (RC_FAILED(result)) {
6710 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6711 _("could not delete snapshot"));
6712 goto cleanup;
6713 }
6714
6715 ret = 0;
6716
6717 cleanup:
6718 VBOX_RELEASE(progress);
6719 vboxIIDUnalloc(&iid);
6720 return ret;
6721 }
6722
6723 static int
vboxDomainSnapshotDeleteTree(struct _vboxDriver * data,IConsole * console,ISnapshot * snapshot)6724 vboxDomainSnapshotDeleteTree(struct _vboxDriver *data,
6725 IConsole *console,
6726 ISnapshot *snapshot)
6727 {
6728 vboxArray children = VBOX_ARRAY_INITIALIZER;
6729 int ret = -1;
6730 nsresult rc;
6731 size_t i;
6732
6733 rc = gVBoxAPI.UArray.vboxArrayGet(&children, snapshot,
6734 gVBoxAPI.UArray.handleSnapshotGetChildren(snapshot));
6735 if (NS_FAILED(rc)) {
6736 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6737 _("could not get children snapshots"));
6738 goto cleanup;
6739 }
6740
6741 for (i = 0; i < children.count; i++) {
6742 if (vboxDomainSnapshotDeleteTree(data, console, children.items[i]))
6743 goto cleanup;
6744 }
6745
6746 ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot);
6747
6748 cleanup:
6749 gVBoxAPI.UArray.vboxArrayRelease(&children);
6750 return ret;
6751 }
6752
6753 static int
vboxDomainSnapshotDeleteMetadataOnly(virDomainSnapshotPtr snapshot)6754 vboxDomainSnapshotDeleteMetadataOnly(virDomainSnapshotPtr snapshot)
6755 {
6756 /*
6757 * This function will remove the node in the vbox xml corresponding to the snapshot.
6758 * It is usually called by vboxDomainSnapshotDelete() with the flag
6759 * VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY.
6760 * If you want to use it anywhere else, be careful, if the snapshot you want to delete
6761 * has children, the result is not granted, they will probably will be deleted in the
6762 * xml, but you may have a problem with hard drives.
6763 *
6764 * If the snapshot which is being deleted is the current one, we will set the current
6765 * snapshot of the machine to the parent of this snapshot. Before writing the modified
6766 * xml file, we undefine the machine from vbox. After writing the file, we redefine
6767 * the machine with the new file.
6768 */
6769
6770 virDomainPtr dom = snapshot->domain;
6771 struct _vboxDriver *data = dom->conn->privateData;
6772 virDomainSnapshotDef *def = NULL;
6773 char *defXml = NULL;
6774 vboxIID domiid;
6775 nsresult rc;
6776 IMachine *machine = NULL;
6777 PRUnichar *settingsFilePathUtf16 = NULL;
6778 char *settingsFilepath = NULL;
6779 virVBoxSnapshotConfMachine *snapshotMachineDesc = NULL;
6780 int isCurrent = -1;
6781 g_auto(GStrv) searchResultTab = NULL;
6782 ssize_t resultSize = 0;
6783 int it = 0;
6784 PRUnichar *machineNameUtf16 = NULL;
6785 char *machineName = NULL;
6786 char *nameTmpUse = NULL;
6787 char *machineLocationPath = NULL;
6788 PRUint32 aMediaSize = 0;
6789 IMedium **aMedia = NULL;
6790 int ret = -1;
6791
6792 if (!data->vboxObj)
6793 return ret;
6794
6795 VBOX_IID_INITIALIZE(&domiid);
6796 if (!gVBoxAPI.vboxSnapshotRedefine)
6797 VIR_WARN("This function may not work in current version");
6798
6799 defXml = vboxDomainSnapshotGetXMLDesc(snapshot, 0);
6800 if (!defXml) {
6801 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6802 _("Unable to get XML Desc of snapshot"));
6803 goto cleanup;
6804 }
6805 def = virDomainSnapshotDefParseString(defXml,
6806 data->xmlopt, NULL, NULL,
6807 VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
6808 VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE);
6809 if (!def) {
6810 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6811 _("Unable to get a virDomainSnapshotDef *"));
6812 goto cleanup;
6813 }
6814
6815 if (openSessionForMachine(data, dom->uuid, &domiid, &machine) < 0)
6816 goto cleanup;
6817 rc = gVBoxAPI.UIMachine.GetSettingsFilePath(machine, &settingsFilePathUtf16);
6818 if (NS_FAILED(rc)) {
6819 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6820 _("cannot get settings file path"));
6821 goto cleanup;
6822 }
6823 VBOX_UTF16_TO_UTF8(settingsFilePathUtf16, &settingsFilepath);
6824
6825 /* Getting the machine name to retrieve the machine location path. */
6826 rc = gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16);
6827 if (NS_FAILED(rc)) {
6828 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6829 _("cannot get machine name"));
6830 goto cleanup;
6831 }
6832 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
6833 nameTmpUse = g_strdup_printf("%s.vbox", machineName);
6834 machineLocationPath = virStringReplace(settingsFilepath, nameTmpUse, "");
6835 if (machineLocationPath == NULL) {
6836 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6837 _("Unable to get the machine location path"));
6838 goto cleanup;
6839 }
6840 snapshotMachineDesc = virVBoxSnapshotConfLoadVboxFile(settingsFilepath, machineLocationPath);
6841 if (!snapshotMachineDesc) {
6842 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6843 _("cannot create a vboxSnapshotXmlPtr"));
6844 goto cleanup;
6845 }
6846
6847 isCurrent = virVBoxSnapshotConfIsCurrentSnapshot(snapshotMachineDesc, def->parent.name);
6848 if (isCurrent < 0) {
6849 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6850 _("Unable to know if the snapshot is the current snapshot"));
6851 goto cleanup;
6852 }
6853 if (isCurrent) {
6854 /*
6855 * If the snapshot is the current snapshot, it means that the machine has read-write
6856 * disks. The first thing to do is to manipulate VirtualBox API to create
6857 * differential read-write disks if the parent snapshot is not null.
6858 */
6859 if (def->parent.parent_name != NULL) {
6860 for (it = 0; it < def->parent.dom->ndisks; it++) {
6861 virVBoxSnapshotConfHardDisk *readOnly = NULL;
6862 IMedium *medium = NULL;
6863 PRUnichar *locationUtf16 = NULL;
6864 char *parentUuid = NULL;
6865 IMedium *newMedium = NULL;
6866 PRUnichar *formatUtf16 = NULL;
6867 PRUnichar *newLocation = NULL;
6868 char *newLocationUtf8 = NULL;
6869 IProgress *progress = NULL;
6870 virVBoxSnapshotConfHardDisk *disk = NULL;
6871 char *uuid = NULL;
6872 char *format = NULL;
6873 char *tmp = NULL;
6874 vboxIID iid, parentiid;
6875 resultCodeUnion resultCode;
6876 PRUint32 tab[1];
6877
6878 VBOX_IID_INITIALIZE(&iid);
6879 VBOX_IID_INITIALIZE(&parentiid);
6880 readOnly = virVBoxSnapshotConfHardDiskPtrByLocation(snapshotMachineDesc,
6881 def->parent.dom->disks[it]->src->path);
6882 if (!readOnly) {
6883 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6884 _("Cannot get hard disk by location"));
6885 goto cleanup;
6886 }
6887 if (readOnly->parent == NULL) {
6888 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6889 _("The read only disk has no parent"));
6890 goto cleanup;
6891 }
6892
6893 VBOX_UTF8_TO_UTF16(readOnly->parent->location, &locationUtf16);
6894 rc = gVBoxAPI.UIVirtualBox.OpenMedium(data->vboxObj,
6895 locationUtf16,
6896 DeviceType_HardDisk,
6897 AccessMode_ReadWrite,
6898 &medium);
6899 if (NS_FAILED(rc)) {
6900 virReportError(VIR_ERR_INTERNAL_ERROR,
6901 _("Unable to open HardDisk, rc=%08x"),
6902 (unsigned)rc);
6903 goto cleanup;
6904 }
6905
6906 rc = gVBoxAPI.UIMedium.GetId(medium, &parentiid);
6907 if (NS_FAILED(rc)) {
6908 virReportError(VIR_ERR_INTERNAL_ERROR,
6909 _("Unable to get hardDisk Id, rc=%08x"),
6910 (unsigned)rc);
6911 goto cleanup;
6912 }
6913 gVBoxAPI.UIID.vboxIIDToUtf8(data, &parentiid, &parentUuid);
6914 vboxIIDUnalloc(&parentiid);
6915 VBOX_UTF16_FREE(locationUtf16);
6916 VBOX_UTF8_TO_UTF16("VDI", &formatUtf16);
6917
6918 newLocationUtf8 = g_strdup_printf("%sfakedisk-%s-%d.vdi",
6919 machineLocationPath, def->parent.parent_name, it);
6920 VBOX_UTF8_TO_UTF16(newLocationUtf8, &newLocation);
6921 rc = gVBoxAPI.UIVirtualBox.CreateHardDisk(data->vboxObj,
6922 formatUtf16,
6923 newLocation,
6924 &newMedium);
6925 if (NS_FAILED(rc)) {
6926 virReportError(VIR_ERR_INTERNAL_ERROR,
6927 _("Unable to create HardDisk, rc=%08x"),
6928 (unsigned)rc);
6929 goto cleanup;
6930 }
6931 VBOX_UTF16_FREE(formatUtf16);
6932 VBOX_UTF16_FREE(newLocation);
6933
6934 tab[0] = MediumVariant_Diff;
6935 gVBoxAPI.UIMedium.CreateDiffStorage(medium, newMedium, 1, tab, &progress);
6936
6937 gVBoxAPI.UIProgress.WaitForCompletion(progress, -1);
6938 gVBoxAPI.UIProgress.GetResultCode(progress, &resultCode);
6939 if (RC_FAILED(resultCode)) {
6940 virReportError(VIR_ERR_INTERNAL_ERROR,
6941 _("Error while creating diff storage, rc=%08x"),
6942 resultCode.uResultCode);
6943 goto cleanup;
6944 }
6945 VBOX_RELEASE(progress);
6946 /*
6947 * The differential disk is created, we add it to the media registry and
6948 * the machine storage controller.
6949 */
6950
6951 disk = g_new0(virVBoxSnapshotConfHardDisk, 1);
6952
6953 rc = gVBoxAPI.UIMedium.GetId(newMedium, &iid);
6954 if (NS_FAILED(rc)) {
6955 virReportError(VIR_ERR_INTERNAL_ERROR,
6956 _("Unable to get medium uuid, rc=%08x"),
6957 (unsigned)rc);
6958 VIR_FREE(disk);
6959 goto cleanup;
6960 }
6961 gVBoxAPI.UIID.vboxIIDToUtf8(data, &iid, &uuid);
6962 disk->uuid = uuid;
6963 vboxIIDUnalloc(&iid);
6964
6965 disk->location = g_strdup(newLocationUtf8);
6966
6967 rc = gVBoxAPI.UIMedium.GetFormat(newMedium, &formatUtf16);
6968 VBOX_UTF16_TO_UTF8(formatUtf16, &format);
6969 disk->format = format;
6970 VBOX_UTF16_FREE(formatUtf16);
6971
6972 if (virVBoxSnapshotConfAddHardDiskToMediaRegistry(disk,
6973 snapshotMachineDesc->mediaRegistry,
6974 parentUuid) < 0) {
6975 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6976 _("Unable to add hard disk to the media registry"));
6977 goto cleanup;
6978 }
6979 /* Adding fake disks to the machine storage controllers */
6980
6981 resultSize = virStringSearch(snapshotMachineDesc->storageController,
6982 VBOX_UUID_REGEX,
6983 it + 1,
6984 &searchResultTab);
6985 if (resultSize != it + 1) {
6986 virReportError(VIR_ERR_INTERNAL_ERROR,
6987 _("Unable to find UUID %s"), searchResultTab[it]);
6988 goto cleanup;
6989 }
6990
6991 tmp = virStringReplace(snapshotMachineDesc->storageController,
6992 searchResultTab[it],
6993 disk->uuid);
6994 VIR_FREE(snapshotMachineDesc->storageController);
6995 if (!tmp)
6996 goto cleanup;
6997 snapshotMachineDesc->storageController = g_strdup(tmp);
6998
6999 VIR_FREE(tmp);
7000 /* Closing the "fake" disk */
7001 rc = gVBoxAPI.UIMedium.Close(newMedium);
7002 if (NS_FAILED(rc)) {
7003 virReportError(VIR_ERR_INTERNAL_ERROR,
7004 _("Unable to close the new medium, rc=%08x"),
7005 (unsigned)rc);
7006 goto cleanup;
7007 }
7008 }
7009 } else {
7010 for (it = 0; it < def->parent.dom->ndisks; it++) {
7011 const char *uuidRO = NULL;
7012 char *tmp = NULL;
7013 uuidRO = virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc,
7014 def->parent.dom->disks[it]->src->path);
7015 if (!uuidRO) {
7016 virReportError(VIR_ERR_INTERNAL_ERROR,
7017 _("No such disk in media registry %s"),
7018 def->parent.dom->disks[it]->src->path);
7019 goto cleanup;
7020 }
7021
7022 resultSize = virStringSearch(snapshotMachineDesc->storageController,
7023 VBOX_UUID_REGEX,
7024 it + 1,
7025 &searchResultTab);
7026 if (resultSize != it + 1) {
7027 virReportError(VIR_ERR_INTERNAL_ERROR,
7028 _("Unable to find UUID %s"),
7029 searchResultTab[it]);
7030 goto cleanup;
7031 }
7032
7033 tmp = virStringReplace(snapshotMachineDesc->storageController,
7034 searchResultTab[it],
7035 uuidRO);
7036 VIR_FREE(snapshotMachineDesc->storageController);
7037 if (!tmp)
7038 goto cleanup;
7039 snapshotMachineDesc->storageController = g_strdup(tmp);
7040
7041 VIR_FREE(tmp);
7042 }
7043 }
7044 }
7045 /* We remove the read write disks from the media registry */
7046 for (it = 0; it < def->ndisks; it++) {
7047 const char *uuidRW =
7048 virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc,
7049 def->disks[it].src->path);
7050 if (!uuidRW) {
7051 virReportError(VIR_ERR_INTERNAL_ERROR,
7052 _("Unable to find UUID for location %s"), def->disks[it].src->path);
7053 goto cleanup;
7054 }
7055 if (virVBoxSnapshotConfRemoveHardDisk(snapshotMachineDesc->mediaRegistry, uuidRW) < 0) {
7056 virReportError(VIR_ERR_INTERNAL_ERROR,
7057 _("Unable to remove disk from media registry. uuid = %s"), uuidRW);
7058 goto cleanup;
7059 }
7060 }
7061 /* If the parent snapshot is not NULL, we remove the-read only disks from the media registry */
7062 if (def->parent.parent_name != NULL) {
7063 for (it = 0; it < def->parent.dom->ndisks; it++) {
7064 const char *uuidRO =
7065 virVBoxSnapshotConfHardDiskUuidByLocation(snapshotMachineDesc,
7066 def->parent.dom->disks[it]->src->path);
7067 if (!uuidRO) {
7068 virReportError(VIR_ERR_INTERNAL_ERROR,
7069 _("Unable to find UUID for location %s"), def->parent.dom->disks[it]->src->path);
7070 goto cleanup;
7071 }
7072 if (virVBoxSnapshotConfRemoveHardDisk(snapshotMachineDesc->mediaRegistry, uuidRO) < 0) {
7073 virReportError(VIR_ERR_INTERNAL_ERROR,
7074 _("Unable to remove disk from media registry. uuid = %s"), uuidRO);
7075 goto cleanup;
7076 }
7077 }
7078 }
7079 rc = gVBoxAPI.UIMachine.Unregister(machine,
7080 CleanupMode_DetachAllReturnHardDisksOnly,
7081 &aMediaSize,
7082 &aMedia);
7083 if (NS_FAILED(rc)) {
7084 virReportError(VIR_ERR_INTERNAL_ERROR,
7085 _("Unable to unregister machine, rc=%08x"),
7086 (unsigned)rc);
7087 goto cleanup;
7088 }
7089 VBOX_RELEASE(machine);
7090 for (it = 0; it < aMediaSize; it++) {
7091 IMedium *medium = aMedia[it];
7092 PRUnichar *locationUtf16 = NULL;
7093 char *locationUtf8 = NULL;
7094
7095 if (!medium)
7096 continue;
7097
7098 rc = gVBoxAPI.UIMedium.GetLocation(medium, &locationUtf16);
7099 VBOX_UTF16_TO_UTF8(locationUtf16, &locationUtf8);
7100 if (isCurrent && strstr(locationUtf8, "fake") != NULL) {
7101 /* we delete the fake disk because we don't need it anymore */
7102 IProgress *progress = NULL;
7103 resultCodeUnion resultCode;
7104 rc = gVBoxAPI.UIMedium.DeleteStorage(medium, &progress);
7105 if (NS_FAILED(rc)) {
7106 virReportError(VIR_ERR_INTERNAL_ERROR,
7107 _("Unable to delete medium, rc=%08x"),
7108 (unsigned)rc);
7109 goto cleanup;
7110 }
7111 gVBoxAPI.UIProgress.WaitForCompletion(progress, -1);
7112 gVBoxAPI.UIProgress.GetResultCode(progress, &resultCode);
7113 if (RC_FAILED(resultCode)) {
7114 virReportError(VIR_ERR_INTERNAL_ERROR,
7115 _("Error while closing medium, rc=%08x"),
7116 resultCode.uResultCode);
7117 goto cleanup;
7118 }
7119 VBOX_RELEASE(progress);
7120 } else {
7121 /* This a comment from vboxmanage code in the handleUnregisterVM
7122 * function in VBoxManageMisc.cpp :
7123 * Note that the IMachine::Unregister method will return the medium
7124 * reference in a sane order, which means that closing will normally
7125 * succeed, unless there is still another machine which uses the
7126 * medium. No harm done if we ignore the error. */
7127 ignore_value(gVBoxAPI.UIMedium.Close(medium));
7128 }
7129 VBOX_UTF16_FREE(locationUtf16);
7130 VBOX_UTF8_FREE(locationUtf8);
7131 }
7132
7133 /* removing the snapshot */
7134 if (virVBoxSnapshotConfRemoveSnapshot(snapshotMachineDesc, def->parent.name) < 0) {
7135 virReportError(VIR_ERR_INTERNAL_ERROR,
7136 _("Unable to remove snapshot %s"), def->parent.name);
7137 goto cleanup;
7138 }
7139
7140 if (isCurrent) {
7141 VIR_FREE(snapshotMachineDesc->currentSnapshot);
7142 if (def->parent.parent_name != NULL) {
7143 virVBoxSnapshotConfSnapshot *snap = virVBoxSnapshotConfSnapshotByName(snapshotMachineDesc->snapshot, def->parent.parent_name);
7144 if (!snap) {
7145 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7146 _("Unable to get the snapshot to remove"));
7147 goto cleanup;
7148 }
7149 snapshotMachineDesc->currentSnapshot = g_strdup(snap->uuid);
7150 }
7151 }
7152
7153 /* Registering the machine */
7154 if (virVBoxSnapshotConfSaveVboxFile(snapshotMachineDesc, settingsFilepath) < 0) {
7155 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7156 _("Unable to serialize the machine description"));
7157 goto cleanup;
7158 }
7159 rc = gVBoxAPI.UIVirtualBox.OpenMachine(data->vboxObj,
7160 settingsFilePathUtf16,
7161 &machine);
7162 if (NS_FAILED(rc)) {
7163 virReportError(VIR_ERR_INTERNAL_ERROR,
7164 _("Unable to open Machine, rc=%08x"),
7165 (unsigned)rc);
7166 goto cleanup;
7167 }
7168
7169 rc = gVBoxAPI.UIVirtualBox.RegisterMachine(data->vboxObj, machine);
7170 if (NS_FAILED(rc)) {
7171 virReportError(VIR_ERR_INTERNAL_ERROR,
7172 _("Unable to register Machine, rc=%08x"),
7173 (unsigned)rc);
7174 goto cleanup;
7175 }
7176
7177 ret = 0;
7178 cleanup:
7179 VIR_FREE(def);
7180 VIR_FREE(defXml);
7181 VBOX_RELEASE(machine);
7182 VBOX_UTF16_FREE(settingsFilePathUtf16);
7183 VBOX_UTF8_FREE(settingsFilepath);
7184 VIR_FREE(snapshotMachineDesc);
7185 VBOX_UTF16_FREE(machineNameUtf16);
7186 VBOX_UTF8_FREE(machineName);
7187 VIR_FREE(machineLocationPath);
7188 VIR_FREE(nameTmpUse);
7189
7190 return ret;
7191 }
7192
vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,unsigned int flags)7193 static int vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
7194 unsigned int flags)
7195 {
7196 virDomainPtr dom = snapshot->domain;
7197 struct _vboxDriver *data = dom->conn->privateData;
7198 vboxIID domiid;
7199 IMachine *machine = NULL;
7200 ISnapshot *snap = NULL;
7201 IConsole *console = NULL;
7202 PRUint32 state;
7203 nsresult rc;
7204 vboxArray snapChildren = VBOX_ARRAY_INITIALIZER;
7205 int ret = -1;
7206
7207 if (!data->vboxObj)
7208 return ret;
7209
7210 virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
7211 VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
7212
7213 if (openSessionForMachine(data, dom->uuid, &domiid, &machine) < 0)
7214 goto cleanup;
7215
7216 snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name);
7217 if (!snap)
7218 goto cleanup;
7219
7220 rc = gVBoxAPI.UIMachine.GetState(machine, &state);
7221 if (NS_FAILED(rc)) {
7222 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7223 _("could not get domain state"));
7224 goto cleanup;
7225 }
7226
7227 /* In case we just want to delete the metadata, we will edit the vbox file in order
7228 *to remove the node concerning the snapshot
7229 */
7230 if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) {
7231 rc = gVBoxAPI.UArray.vboxArrayGet(&snapChildren, snap,
7232 gVBoxAPI.UArray.handleSnapshotGetChildren(snap));
7233 if (NS_FAILED(rc)) {
7234 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7235 _("could not get snapshot children"));
7236 goto cleanup;
7237 }
7238 if (snapChildren.count != 0) {
7239 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7240 _("cannot delete metadata of a snapshot with children"));
7241 goto cleanup;
7242 } else if (gVBoxAPI.vboxSnapshotRedefine) {
7243 ret = vboxDomainSnapshotDeleteMetadataOnly(snapshot);
7244 }
7245 goto cleanup;
7246 }
7247
7248 if (gVBoxAPI.machineStateChecker.Online(state)) {
7249 virReportError(VIR_ERR_OPERATION_INVALID, "%s",
7250 _("cannot delete snapshots of running domain"));
7251 goto cleanup;
7252 }
7253
7254 rc = gVBoxAPI.UISession.Open(data, &domiid, machine);
7255 if (NS_SUCCEEDED(rc))
7256 rc = gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
7257 if (NS_FAILED(rc)) {
7258 virReportError(VIR_ERR_INTERNAL_ERROR,
7259 _("could not open VirtualBox session with domain %s"),
7260 dom->name);
7261 goto cleanup;
7262 }
7263
7264 if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
7265 ret = vboxDomainSnapshotDeleteTree(data, console, snap);
7266 else
7267 ret = vboxDomainSnapshotDeleteSingle(data, console, snap);
7268
7269 cleanup:
7270 VBOX_RELEASE(console);
7271 VBOX_RELEASE(snap);
7272 vboxIIDUnalloc(&domiid);
7273 gVBoxAPI.UISession.Close(data->vboxSession);
7274 return ret;
7275 }
7276
7277 static char *
vboxDomainScreenshot(virDomainPtr dom,virStreamPtr st,unsigned int screen,unsigned int flags)7278 vboxDomainScreenshot(virDomainPtr dom,
7279 virStreamPtr st,
7280 unsigned int screen,
7281 unsigned int flags)
7282 {
7283 struct _vboxDriver *data = dom->conn->privateData;
7284 IConsole *console = NULL;
7285 vboxIID iid;
7286 IMachine *machine = NULL;
7287 nsresult rc;
7288 g_autofree char *tmp = NULL;
7289 g_autofree char *cacheDir = NULL;
7290 int tmp_fd = -1;
7291 unsigned int max_screen;
7292 bool privileged = geteuid() == 0;
7293 char *ret = NULL;
7294
7295 if (!data->vboxObj)
7296 return ret;
7297
7298 virCheckFlags(0, NULL);
7299
7300 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
7301 return NULL;
7302
7303 rc = gVBoxAPI.UIMachine.GetMonitorCount(machine, &max_screen);
7304 if (NS_FAILED(rc)) {
7305 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
7306 _("unable to get monitor count"));
7307 VBOX_RELEASE(machine);
7308 return NULL;
7309 }
7310
7311 if (screen >= max_screen) {
7312 virReportError(VIR_ERR_INVALID_ARG,
7313 _("screen ID higher than monitor "
7314 "count (%d)"), max_screen);
7315 VBOX_RELEASE(machine);
7316 return NULL;
7317 }
7318
7319 if (privileged) {
7320 cacheDir = g_strdup_printf("%s/cache/libvirt", LOCALSTATEDIR);
7321 } else {
7322 cacheDir = virGetUserCacheDirectory();
7323 }
7324
7325 tmp = g_strdup_printf("%s/vbox.screendump.XXXXXX", cacheDir);
7326
7327 if ((tmp_fd = g_mkstemp_full(tmp, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR)) == -1) {
7328 virReportSystemError(errno, _("g_mkstemp(\"%s\") failed"), tmp);
7329 VBOX_RELEASE(machine);
7330 return NULL;
7331 }
7332
7333
7334 rc = gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
7335 if (NS_SUCCEEDED(rc)) {
7336 rc = gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
7337 if (NS_SUCCEEDED(rc) && console) {
7338 IDisplay *display = NULL;
7339
7340 gVBoxAPI.UIConsole.GetDisplay(console, &display);
7341
7342 if (display) {
7343 PRUint32 width, height, bitsPerPixel;
7344 PRUint32 screenDataSize;
7345 PRUint8 *screenData = NULL;
7346 PRInt32 xOrigin, yOrigin;
7347
7348 rc = gVBoxAPI.UIDisplay.GetScreenResolution(display, screen,
7349 &width, &height,
7350 &bitsPerPixel,
7351 &xOrigin, &yOrigin);
7352
7353 if (NS_FAILED(rc) || !width || !height) {
7354 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
7355 _("unable to get screen resolution"));
7356 goto endjob;
7357 }
7358
7359 rc = gVBoxAPI.UIDisplay.TakeScreenShotPNGToArray(display, screen,
7360 width, height,
7361 &screenDataSize,
7362 &screenData);
7363 if (NS_FAILED(rc)) {
7364 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
7365 _("failed to take screenshot"));
7366 goto endjob;
7367 }
7368
7369 if (safewrite(tmp_fd, (char *) screenData,
7370 screenDataSize) < 0) {
7371 virReportSystemError(errno, _("unable to write data "
7372 "to '%s'"), tmp);
7373 goto endjob;
7374 }
7375
7376 if (VIR_CLOSE(tmp_fd) < 0) {
7377 virReportSystemError(errno, _("unable to close %s"), tmp);
7378 goto endjob;
7379 }
7380
7381 ret = g_strdup("image/png");
7382
7383 if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
7384 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
7385 _("unable to open stream"));
7386 VIR_FREE(ret);
7387 }
7388 endjob:
7389 VIR_FREE(screenData);
7390 VBOX_RELEASE(display);
7391 }
7392 VBOX_RELEASE(console);
7393 }
7394 gVBoxAPI.UISession.Close(data->vboxSession);
7395 }
7396
7397 VIR_FORCE_CLOSE(tmp_fd);
7398 unlink(tmp);
7399 VBOX_RELEASE(machine);
7400 vboxIIDUnalloc(&iid);
7401 return ret;
7402 }
7403
7404 #define MATCH(FLAG) (flags & (FLAG))
7405 static int
vboxConnectListAllDomains(virConnectPtr conn,virDomainPtr ** domains,unsigned int flags)7406 vboxConnectListAllDomains(virConnectPtr conn,
7407 virDomainPtr **domains,
7408 unsigned int flags)
7409 {
7410 struct _vboxDriver *data = conn->privateData;
7411 vboxArray machines = VBOX_ARRAY_INITIALIZER;
7412 char *machineNameUtf8 = NULL;
7413 PRUnichar *machineNameUtf16 = NULL;
7414 unsigned char uuid[VIR_UUID_BUFLEN];
7415 vboxIID iid;
7416 PRUint32 state;
7417 nsresult rc;
7418 size_t i;
7419 virDomainPtr dom;
7420 virDomainPtr *doms = NULL;
7421 int count = 0;
7422 bool active;
7423 PRUint32 snapshotCount;
7424 int ret = -1;
7425
7426 if (!data->vboxObj)
7427 return ret;
7428
7429 virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
7430
7431 /* filter out flag options that will produce 0 results in vbox driver:
7432 * - managed save: vbox guests don't have managed save images
7433 * - autostart: vbox doesn't support autostarting guests
7434 * - persistence: vbox doesn't support transient guests
7435 */
7436 if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
7437 !MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT)) ||
7438 (MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) &&
7439 !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART)) ||
7440 (MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) &&
7441 !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE))) {
7442 if (domains)
7443 *domains = g_new0(virDomainPtr, 1);
7444
7445 ret = 0;
7446 goto cleanup;
7447 }
7448
7449 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj, ARRAY_GET_MACHINES);
7450 if (NS_FAILED(rc)) {
7451 virReportError(VIR_ERR_INTERNAL_ERROR,
7452 _("Could not get list of domains, rc=%08x"), (unsigned)rc);
7453 goto cleanup;
7454 }
7455
7456 if (domains)
7457 doms = g_new0(virDomainPtr, machines.count + 1);
7458
7459 for (i = 0; i < machines.count; i++) {
7460 IMachine *machine = machines.items[i];
7461 PRBool isAccessible = PR_FALSE;
7462 int id = -1;
7463
7464 if (!machine)
7465 continue;
7466
7467 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
7468
7469 if (!isAccessible)
7470 continue;
7471
7472 gVBoxAPI.UIMachine.GetState(machine, &state);
7473
7474 if (gVBoxAPI.machineStateChecker.Online(state))
7475 active = true;
7476 else
7477 active = false;
7478
7479 /* filter by active state */
7480 if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
7481 !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
7482 (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
7483 continue;
7484
7485 /* filter by snapshot existence */
7486 if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
7487 rc = gVBoxAPI.UIMachine.GetSnapshotCount(machine, &snapshotCount);
7488 if (NS_FAILED(rc)) {
7489 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
7490 _("could not get snapshot count for listed domains"));
7491 goto cleanup;
7492 }
7493 if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) &&
7494 snapshotCount > 0) ||
7495 (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) &&
7496 snapshotCount == 0)))
7497 continue;
7498 }
7499
7500 /* filter by machine state */
7501 if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) &&
7502 !((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) &&
7503 gVBoxAPI.machineStateChecker.Running(state)) ||
7504 (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) &&
7505 gVBoxAPI.machineStateChecker.Paused(state)) ||
7506 (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) &&
7507 gVBoxAPI.machineStateChecker.PoweredOff(state)) ||
7508 (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) &&
7509 (!gVBoxAPI.machineStateChecker.Running(state) &&
7510 !gVBoxAPI.machineStateChecker.Paused(state) &&
7511 !gVBoxAPI.machineStateChecker.PoweredOff(state)))))
7512 continue;
7513
7514 /* just count the machines */
7515 if (!doms) {
7516 count++;
7517 continue;
7518 }
7519
7520 gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16);
7521 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
7522 gVBoxAPI.UIMachine.GetId(machine, &iid);
7523 vboxIIDToUUID(&iid, uuid);
7524 vboxIIDUnalloc(&iid);
7525
7526 if (active)
7527 id = i + 1;
7528
7529 dom = virGetDomain(conn, machineNameUtf8, uuid, id);
7530
7531 VBOX_UTF8_FREE(machineNameUtf8);
7532 VBOX_UTF16_FREE(machineNameUtf16);
7533
7534 if (!dom)
7535 goto cleanup;
7536
7537 doms[count++] = dom;
7538 }
7539
7540 if (doms) {
7541 VIR_REALLOC_N(doms, count + 1);
7542 *domains = g_steal_pointer(&doms);
7543 }
7544
7545 ret = count;
7546
7547 cleanup:
7548 if (doms) {
7549 for (i = 0; i < count; i++)
7550 virObjectUnref(doms[i]);
7551 }
7552 VIR_FREE(doms);
7553
7554 gVBoxAPI.UArray.vboxArrayRelease(&machines);
7555 return ret;
7556 }
7557 #undef MATCH
7558
7559 static int
vboxNodeGetInfo(virConnectPtr conn G_GNUC_UNUSED,virNodeInfoPtr nodeinfo)7560 vboxNodeGetInfo(virConnectPtr conn G_GNUC_UNUSED,
7561 virNodeInfoPtr nodeinfo)
7562 {
7563 return virCapabilitiesGetNodeInfo(nodeinfo);
7564 }
7565
7566 static int
vboxNodeGetCellsFreeMemory(virConnectPtr conn G_GNUC_UNUSED,unsigned long long * freeMems,int startCell,int maxCells)7567 vboxNodeGetCellsFreeMemory(virConnectPtr conn G_GNUC_UNUSED,
7568 unsigned long long *freeMems,
7569 int startCell,
7570 int maxCells)
7571 {
7572 return virHostMemGetCellsFree(freeMems, startCell, maxCells);
7573 }
7574
7575 static unsigned long long
vboxNodeGetFreeMemory(virConnectPtr conn G_GNUC_UNUSED)7576 vboxNodeGetFreeMemory(virConnectPtr conn G_GNUC_UNUSED)
7577 {
7578 unsigned long long freeMem;
7579 if (virHostMemGetInfo(NULL, &freeMem) < 0)
7580 return 0;
7581 return freeMem;
7582 }
7583
7584 static int
vboxNodeGetFreePages(virConnectPtr conn,unsigned int npages,unsigned int * pages,int startCell,unsigned int cellCount,unsigned long long * counts,unsigned int flags)7585 vboxNodeGetFreePages(virConnectPtr conn,
7586 unsigned int npages,
7587 unsigned int *pages,
7588 int startCell,
7589 unsigned int cellCount,
7590 unsigned long long *counts,
7591 unsigned int flags)
7592 {
7593 struct _vboxDriver *driver = conn->privateData;
7594 int lastCell;
7595
7596 virCheckFlags(0, -1);
7597
7598 virObjectLock(driver);
7599 lastCell = virCapabilitiesHostNUMAGetMaxNode(driver->caps->host.numa);
7600 virObjectUnlock(driver);
7601
7602 return virHostMemGetFreePages(npages, pages, startCell,
7603 cellCount, lastCell, counts);
7604 }
7605
7606 static int
vboxNodeAllocPages(virConnectPtr conn G_GNUC_UNUSED,unsigned int npages,unsigned int * pageSizes,unsigned long long * pageCounts,int startCell,unsigned int cellCount,unsigned int flags)7607 vboxNodeAllocPages(virConnectPtr conn G_GNUC_UNUSED,
7608 unsigned int npages,
7609 unsigned int *pageSizes,
7610 unsigned long long *pageCounts,
7611 int startCell,
7612 unsigned int cellCount,
7613 unsigned int flags)
7614 {
7615 struct _vboxDriver *driver = conn->privateData;
7616 int lastCell;
7617 bool add = !(flags & VIR_NODE_ALLOC_PAGES_SET);
7618
7619 virCheckFlags(VIR_NODE_ALLOC_PAGES_SET, -1);
7620
7621 virObjectLock(driver);
7622 lastCell = virCapabilitiesHostNUMAGetMaxNode(driver->caps->host.numa);
7623 virObjectUnlock(driver);
7624
7625 return virHostMemAllocPages(npages, pageSizes, pageCounts,
7626 startCell, cellCount, lastCell, add);
7627 }
7628
7629 static int
vboxDomainHasManagedSaveImage(virDomainPtr dom,unsigned int flags)7630 vboxDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
7631 {
7632 struct _vboxDriver *data = dom->conn->privateData;
7633 vboxArray machines = VBOX_ARRAY_INITIALIZER;
7634 vboxIID iid;
7635 char *machineNameUtf8 = NULL;
7636 PRUnichar *machineNameUtf16 = NULL;
7637 unsigned char uuid[VIR_UUID_BUFLEN];
7638 size_t i;
7639 bool matched = false;
7640 nsresult rc;
7641 int ret = -1;
7642
7643 virCheckFlags(0, -1);
7644
7645 if (!data->vboxObj)
7646 return ret;
7647
7648 VBOX_IID_INITIALIZE(&iid);
7649 rc = gVBoxAPI.UArray.vboxArrayGet(&machines, data->vboxObj, ARRAY_GET_MACHINES);
7650 if (NS_FAILED(rc)) {
7651 virReportError(VIR_ERR_INTERNAL_ERROR,
7652 _("Could not get list of machines, rc=%08x"), (unsigned)rc);
7653 return ret;
7654 }
7655
7656 for (i = 0; i < machines.count; ++i) {
7657 IMachine *machine = machines.items[i];
7658 PRBool isAccessible = PR_FALSE;
7659
7660 if (!machine)
7661 continue;
7662
7663 gVBoxAPI.UIMachine.GetAccessible(machine, &isAccessible);
7664 if (!isAccessible)
7665 continue;
7666
7667 gVBoxAPI.UIMachine.GetId(machine, &iid);
7668 if (NS_FAILED(rc))
7669 continue;
7670 vboxIIDToUUID(&iid, uuid);
7671 vboxIIDUnalloc(&iid);
7672
7673 if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
7674
7675 PRUint32 state;
7676
7677 matched = true;
7678
7679 gVBoxAPI.UIMachine.GetName(machine, &machineNameUtf16);
7680 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
7681
7682 gVBoxAPI.UIMachine.GetState(machine, &state);
7683
7684 ret = 0;
7685 }
7686
7687 if (matched)
7688 break;
7689 }
7690
7691 /* Do the cleanup and take care you dont leak any memory */
7692 VBOX_UTF8_FREE(machineNameUtf8);
7693 VBOX_COM_UNALLOC_MEM(machineNameUtf16);
7694 gVBoxAPI.UArray.vboxArrayRelease(&machines);
7695
7696 return ret;
7697 }
7698
7699 static int
vboxDomainSendKey(virDomainPtr dom,unsigned int codeset,unsigned int holdtime,unsigned int * keycodes,int nkeycodes,unsigned int flags)7700 vboxDomainSendKey(virDomainPtr dom,
7701 unsigned int codeset,
7702 unsigned int holdtime,
7703 unsigned int *keycodes,
7704 int nkeycodes,
7705 unsigned int flags)
7706 {
7707 int ret = -1;
7708 struct _vboxDriver *data = dom->conn->privateData;
7709 IConsole *console = NULL;
7710 vboxIID iid;
7711 IMachine *machine = NULL;
7712 IKeyboard *keyboard = NULL;
7713 PRInt32 *keyDownCodes = NULL;
7714 PRInt32 *keyUpCodes = NULL;
7715 PRUint32 codesStored = 0;
7716 nsresult rc;
7717 size_t i;
7718 int keycode;
7719
7720 if (!data->vboxObj)
7721 return ret;
7722
7723 virCheckFlags(0, -1);
7724
7725 keyDownCodes = (PRInt32 *) keycodes;
7726
7727 keyUpCodes = g_new0(PRInt32, nkeycodes);
7728
7729 /* translate keycodes to xt and generate keyup scancodes */
7730 for (i = 0; i < nkeycodes; i++) {
7731 if (codeset != VIR_KEYCODE_SET_XT) {
7732 keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_XT,
7733 keyDownCodes[i]);
7734 if (keycode < 0) {
7735 virReportError(VIR_ERR_INTERNAL_ERROR,
7736 _("cannot translate keycode %u of %s codeset to"
7737 " xt keycode"),
7738 keyDownCodes[i],
7739 virKeycodeSetTypeToString(codeset));
7740 goto cleanup;
7741 }
7742 keyDownCodes[i] = keycode;
7743 }
7744
7745 keyUpCodes[i] = keyDownCodes[i] + 0x80;
7746 }
7747
7748 if (openSessionForMachine(data, dom->uuid, &iid, &machine) < 0)
7749 goto cleanup;
7750
7751 rc = gVBoxAPI.UISession.OpenExisting(data, &iid, machine);
7752
7753 if (NS_FAILED(rc)) {
7754 virReportError(VIR_ERR_OPERATION_FAILED,
7755 _("Unable to open VirtualBox session with domain %s"),
7756 dom->name);
7757 goto cleanup;
7758 }
7759
7760 rc = gVBoxAPI.UISession.GetConsole(data->vboxSession, &console);
7761
7762 if (NS_FAILED(rc) || !console) {
7763 virReportError(VIR_ERR_OPERATION_FAILED,
7764 _("Unable to get Console object for domain %s"),
7765 dom->name);
7766 goto cleanup;
7767 }
7768
7769 rc = gVBoxAPI.UIConsole.GetKeyboard(console, &keyboard);
7770
7771 if (NS_FAILED(rc)) {
7772 virReportError(VIR_ERR_OPERATION_FAILED,
7773 _("Unable to get Keyboard object for domain %s"),
7774 dom->name);
7775 goto cleanup;
7776 }
7777
7778 rc = gVBoxAPI.UIKeyboard.PutScancodes(keyboard, nkeycodes, keyDownCodes,
7779 &codesStored);
7780
7781 if (NS_FAILED(rc)) {
7782 virReportError(VIR_ERR_OPERATION_FAILED,
7783 _("Unable to send keyboard scancodes for domain %s"),
7784 dom->name);
7785 goto cleanup;
7786 }
7787
7788 /* since VBOX does not support holdtime, simulate it by sleeping and
7789 then sending the release key scancodes */
7790 if (holdtime > 0)
7791 g_usleep(holdtime * 1000);
7792
7793 rc = gVBoxAPI.UIKeyboard.PutScancodes(keyboard, nkeycodes, keyUpCodes,
7794 &codesStored);
7795
7796 if (NS_FAILED(rc)) {
7797 virReportError(VIR_ERR_OPERATION_FAILED,
7798 _("Unable to send keyboard scan codes to domain %s"),
7799 dom->name);
7800 goto cleanup;
7801 }
7802
7803 ret = 0;
7804
7805 cleanup:
7806 VIR_FREE(keyUpCodes);
7807 VBOX_RELEASE(keyboard);
7808 VBOX_RELEASE(console);
7809 gVBoxAPI.UISession.Close(data->vboxSession);
7810 VBOX_RELEASE(machine);
7811 vboxIIDUnalloc(&iid);
7812
7813 return ret;
7814 }
7815
7816
7817 /**
7818 * Function Tables
7819 */
7820
7821 static virHypervisorDriver vboxCommonDriver = {
7822 .name = "VBOX",
7823 .connectURIProbe = vboxConnectURIProbe,
7824 .connectOpen = vboxConnectOpen, /* 0.6.3 */
7825 .connectClose = vboxConnectClose, /* 0.6.3 */
7826 .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */
7827 .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */
7828 .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */
7829 .nodeGetInfo = vboxNodeGetInfo, /* 0.6.3 */
7830 .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */
7831 .connectListDomains = vboxConnectListDomains, /* 0.6.3 */
7832 .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */
7833 .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */
7834 .domainCreateXML = vboxDomainCreateXML, /* 0.6.3 */
7835 .domainLookupByID = vboxDomainLookupByID, /* 0.6.3 */
7836 .domainLookupByUUID = vboxDomainLookupByUUID, /* 0.6.3 */
7837 .domainLookupByName = vboxDomainLookupByName, /* 0.6.3 */
7838 .domainSuspend = vboxDomainSuspend, /* 0.6.3 */
7839 .domainResume = vboxDomainResume, /* 0.6.3 */
7840 .domainShutdown = vboxDomainShutdown, /* 0.6.3 */
7841 .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
7842 .domainReboot = vboxDomainReboot, /* 0.6.3 */
7843 .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
7844 .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
7845 .domainGetOSType = vboxDomainGetOSType, /* 0.6.3 */
7846 .domainSetMemory = vboxDomainSetMemory, /* 0.6.3 */
7847 .domainGetInfo = vboxDomainGetInfo, /* 0.6.3 */
7848 .domainGetState = vboxDomainGetState, /* 0.9.2 */
7849 .domainSave = vboxDomainSave, /* 0.6.3 */
7850 .domainSetVcpus = vboxDomainSetVcpus, /* 0.7.1 */
7851 .domainSetVcpusFlags = vboxDomainSetVcpusFlags, /* 0.8.5 */
7852 .domainGetVcpusFlags = vboxDomainGetVcpusFlags, /* 0.8.5 */
7853 .domainGetMaxVcpus = vboxDomainGetMaxVcpus, /* 0.7.1 */
7854 .domainGetXMLDesc = vboxDomainGetXMLDesc, /* 0.6.3 */
7855 .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */
7856 .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */
7857 .domainCreate = vboxDomainCreate, /* 0.6.3 */
7858 .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */
7859 .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */
7860 .domainDefineXMLFlags = vboxDomainDefineXMLFlags, /* 1.2.12 */
7861 .domainUndefine = vboxDomainUndefine, /* 0.6.3 */
7862 .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */
7863 .domainAttachDevice = vboxDomainAttachDevice, /* 0.6.3 */
7864 .domainAttachDeviceFlags = vboxDomainAttachDeviceFlags, /* 0.7.7 */
7865 .domainDetachDevice = vboxDomainDetachDevice, /* 0.6.3 */
7866 .domainDetachDeviceFlags = vboxDomainDetachDeviceFlags, /* 0.7.7 */
7867 .domainUpdateDeviceFlags = vboxDomainUpdateDeviceFlags, /* 0.8.0 */
7868 .nodeGetCellsFreeMemory = vboxNodeGetCellsFreeMemory, /* 0.6.5 */
7869 .nodeGetFreeMemory = vboxNodeGetFreeMemory, /* 0.6.5 */
7870 .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */
7871 .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */
7872 .domainIsActive = vboxDomainIsActive, /* 0.7.3 */
7873 .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */
7874 .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */
7875 .domainSnapshotCreateXML = vboxDomainSnapshotCreateXML, /* 0.8.0 */
7876 .domainSnapshotGetXMLDesc = vboxDomainSnapshotGetXMLDesc, /* 0.8.0 */
7877 .domainSnapshotNum = vboxDomainSnapshotNum, /* 0.8.0 */
7878 .domainSnapshotListNames = vboxDomainSnapshotListNames, /* 0.8.0 */
7879 .domainSnapshotLookupByName = vboxDomainSnapshotLookupByName, /* 0.8.0 */
7880 .domainHasCurrentSnapshot = vboxDomainHasCurrentSnapshot, /* 0.8.0 */
7881 .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
7882 .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */
7883 .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */
7884 .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */
7885 .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */
7886 .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */
7887 .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */
7888 .nodeGetFreePages = vboxNodeGetFreePages, /* 1.2.6 */
7889 .nodeAllocPages = vboxNodeAllocPages, /* 1.2.9 */
7890 .domainHasManagedSaveImage = vboxDomainHasManagedSaveImage, /* 1.2.13 */
7891 .domainSendKey = vboxDomainSendKey, /* 1.2.15 */
7892 .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */
7893 };
7894
vboxGetHypervisorDriver(uint32_t uVersion)7895 virHypervisorDriver *vboxGetHypervisorDriver(uint32_t uVersion)
7896 {
7897 /* Install gVBoxAPI according to the vbox API version. */
7898 int result = 0;
7899 installUniformedAPI(gVBoxAPI, result);
7900 if (result < 0) {
7901 VIR_WARN("Libvirt doesn't support VirtualBox API version %u",
7902 uVersion);
7903 return NULL;
7904 }
7905
7906 return &vboxCommonDriver;
7907 }
7908