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                                                          &parallelPortCount);
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, &parallelPort);
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, &parallelPort);
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, &parallelPort);
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, &parallelPortCount);
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, &timestamp);
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, &current);
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