Imported Upstream version 1.2.5
[archive/platform/upstream/libvirt.git] / src / vbox / vbox_tmpl.c
1 /** @file vbox_tmpl.c
2  * Template File to support multiple versions of VirtualBox
3  * at runtime :).
4  *
5  * IMPORTANT:
6  * Please dont include this file in the src/Makefile.am, it
7  * is automatically include by other files.
8  */
9
10 /*
11  * Copyright (C) 2010-2014 Red Hat, Inc.
12  * Copyright (C) 2008-2009 Sun Microsystems, Inc.
13  *
14  * This file is part of a free software library; you can redistribute
15  * it and/or modify it under the terms of the GNU Lesser General
16  * Public License version 2.1 as published by the Free Software
17  * Foundation and shipped in the "COPYING.LESSER" file with this library.
18  * The library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY of any kind.
20  *
21  * Sun LGPL Disclaimer: For the avoidance of doubt, except that if
22  * any license choice other than GPL or LGPL is available it will
23  * apply instead, Sun elects to use only the Lesser General Public
24  * License version 2.1 (LGPLv2) at this time for any software where
25  * a choice of LGPL license versions is made available with the
26  * language indicating that LGPLv2 or any later version may be used,
27  * or where a choice of which version of the LGPL is applied is
28  * otherwise unspecified.
29  *
30  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
31  * Clara, CA 95054 USA or visit http://www.sun.com if you need
32  * additional information or have any questions.
33  */
34
35 #include <config.h>
36
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41
42 #include "internal.h"
43 #include "datatypes.h"
44 #include "domain_conf.h"
45 #include "snapshot_conf.h"
46 #include "network_conf.h"
47 #include "virerror.h"
48 #include "domain_event.h"
49 #include "storage_conf.h"
50 #include "virstoragefile.h"
51 #include "viruuid.h"
52 #include "viralloc.h"
53 #include "nodeinfo.h"
54 #include "virlog.h"
55 #include "vbox_driver.h"
56 #include "configmake.h"
57 #include "virfile.h"
58 #include "fdstream.h"
59 #include "viruri.h"
60 #include "virstring.h"
61
62 /* This one changes from version to version. */
63 #if VBOX_API_VERSION == 2002000
64 # include "vbox_CAPI_v2_2.h"
65 #elif VBOX_API_VERSION == 3000000
66 # include "vbox_CAPI_v3_0.h"
67 #elif VBOX_API_VERSION == 3001000
68 # include "vbox_CAPI_v3_1.h"
69 #elif VBOX_API_VERSION == 3002000
70 # include "vbox_CAPI_v3_2.h"
71 #elif VBOX_API_VERSION == 4000000
72 # include "vbox_CAPI_v4_0.h"
73 #elif VBOX_API_VERSION == 4001000
74 # include "vbox_CAPI_v4_1.h"
75 #elif VBOX_API_VERSION == 4002000
76 # include "vbox_CAPI_v4_2.h"
77 #elif VBOX_API_VERSION == 4002020
78 # include "vbox_CAPI_v4_2_20.h"
79 #elif VBOX_API_VERSION == 4003000
80 # include "vbox_CAPI_v4_3.h"
81 #elif VBOX_API_VERSION == 4003004
82 # include "vbox_CAPI_v4_3_4.h"
83 #else
84 # error "Unsupport VBOX_API_VERSION"
85 #endif
86
87 /* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */
88 #include "vbox_glue.h"
89
90
91 #define VIR_FROM_THIS                   VIR_FROM_VBOX
92
93 VIR_LOG_INIT("vbox.vbox_tmpl");
94
95 #define VBOX_UTF16_FREE(arg)                                            \
96     do {                                                                \
97         if (arg) {                                                      \
98             data->pFuncs->pfnUtf16Free(arg);                            \
99             (arg) = NULL;                                               \
100         }                                                               \
101     } while (0)
102
103 #define VBOX_UTF8_FREE(arg)                                             \
104     do {                                                                \
105         if (arg) {                                                      \
106             data->pFuncs->pfnUtf8Free(arg);                             \
107             (arg) = NULL;                                               \
108         }                                                               \
109     } while (0)
110
111 #define VBOX_COM_UNALLOC_MEM(arg)                                       \
112     do {                                                                \
113         if (arg) {                                                      \
114             data->pFuncs->pfnComUnallocMem(arg);                        \
115             (arg) = NULL;                                               \
116         }                                                               \
117     } while (0)
118
119 #define VBOX_UTF16_TO_UTF8(arg1, arg2)  data->pFuncs->pfnUtf16ToUtf8(arg1, arg2)
120 #define VBOX_UTF8_TO_UTF16(arg1, arg2)  data->pFuncs->pfnUtf8ToUtf16(arg1, arg2)
121
122 #define VBOX_ADDREF(arg) (arg)->vtbl->nsisupports.AddRef((nsISupports *)(arg))
123
124 #define VBOX_RELEASE(arg)                                                     \
125     do {                                                                      \
126         if (arg) {                                                            \
127             (arg)->vtbl->nsisupports.Release((nsISupports *)(arg));           \
128             (arg) = NULL;                                                     \
129         }                                                                     \
130     } while (0)
131
132 #define VBOX_OBJECT_CHECK(conn, type, value) \
133 vboxGlobalData *data = conn->privateData;\
134 type ret = value;\
135 if (!data->vboxObj) {\
136     return ret;\
137 }
138
139 #define VBOX_OBJECT_HOST_CHECK(conn, type, value) \
140 vboxGlobalData *data = conn->privateData;\
141 type ret = value;\
142 IHost *host = NULL;\
143 if (!data->vboxObj) {\
144     return ret;\
145 }\
146 data->vboxObj->vtbl->GetHost(data->vboxObj, &host);\
147 if (!host) {\
148     return ret;\
149 }
150
151 #if VBOX_API_VERSION < 3001000
152
153 # define VBOX_MEDIUM_RELEASE(arg) \
154 if (arg)\
155     (arg)->vtbl->imedium.nsisupports.Release((nsISupports *)(arg))
156 # define VBOX_MEDIUM_FUNC_ARG1(object, func, arg1) \
157     (object)->vtbl->imedium.func((IMedium *)(object), arg1)
158 # define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
159     (object)->vtbl->imedium.func((IMedium *)(object), arg1, arg2)
160
161 #else  /* VBOX_API_VERSION >= 3001000 */
162
163 typedef IMedium IHardDisk;
164 typedef IMediumAttachment IHardDiskAttachment;
165 # define MediaState_Inaccessible     MediumState_Inaccessible
166 # define HardDiskVariant_Standard    MediumVariant_Standard
167 # define HardDiskVariant_Fixed       MediumVariant_Fixed
168 # define VBOX_MEDIUM_RELEASE(arg) VBOX_RELEASE(arg)
169 # define VBOX_MEDIUM_FUNC_ARG1(object, func, arg1) \
170     (object)->vtbl->func(object, arg1)
171 # define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
172     (object)->vtbl->func(object, arg1, arg2)
173
174 #endif /* VBOX_API_VERSION >= 3001000 */
175
176 #define DEBUGPRUnichar(msg, strUtf16) \
177 if (strUtf16) {\
178     char *strUtf8 = NULL;\
179 \
180     g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);\
181     if (strUtf8) {\
182         VIR_DEBUG("%s: %s", msg, strUtf8);\
183         g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);\
184     }\
185 }
186
187 #define DEBUGUUID(msg, iid) \
188 {\
189     VIR_DEBUG(msg ": {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",\
190           (unsigned)(iid)->m0,\
191           (unsigned)(iid)->m1,\
192           (unsigned)(iid)->m2,\
193           (unsigned)(iid)->m3[0],\
194           (unsigned)(iid)->m3[1],\
195           (unsigned)(iid)->m3[2],\
196           (unsigned)(iid)->m3[3],\
197           (unsigned)(iid)->m3[4],\
198           (unsigned)(iid)->m3[5],\
199           (unsigned)(iid)->m3[6],\
200           (unsigned)(iid)->m3[7]);\
201 }\
202
203 typedef struct {
204     virMutex lock;
205     unsigned long version;
206
207     virCapsPtr caps;
208     virDomainXMLOptionPtr xmlopt;
209
210     IVirtualBox *vboxObj;
211     ISession *vboxSession;
212
213     /** Our version specific API table pointer. */
214     PCVBOXXPCOM pFuncs;
215
216 #if VBOX_API_VERSION == 2002000
217
218 } vboxGlobalData;
219
220 #else /* !(VBOX_API_VERSION == 2002000) */
221
222     /* Async event handling */
223     virObjectEventStatePtr domainEvents;
224     int fdWatch;
225
226 # if VBOX_API_VERSION <= 3002000
227     /* IVirtualBoxCallback is used in VirtualBox 3.x only */
228     IVirtualBoxCallback *vboxCallback;
229 # endif /* VBOX_API_VERSION <= 3002000 */
230
231     nsIEventQueue  *vboxQueue;
232     int volatile vboxCallBackRefCount;
233
234     /* pointer back to the connection */
235     virConnectPtr conn;
236
237 } vboxGlobalData;
238
239 /* g_pVBoxGlobalData has to be global variable,
240  * there is no other way to make the callbacks
241  * work other then having g_pVBoxGlobalData as
242  * global, because the functions namely AddRef,
243  * Release, etc consider it as global and you
244  * can't change the function definition as it
245  * is XPCOM nsISupport::* function and it expects
246  * them that way
247  */
248
249 static vboxGlobalData *g_pVBoxGlobalData = NULL;
250
251 #endif /* !(VBOX_API_VERSION == 2002000) */
252
253 #if VBOX_API_VERSION < 4000000
254
255 # define VBOX_OBJECT_GET_MACHINE(/* in */ iid_value, /* out */ machine) \
256     data->vboxObj->vtbl->GetMachine(data->vboxObj, iid_value, machine)
257
258 # define VBOX_SESSION_OPEN(/* in */ iid_value, /* unused */ machine) \
259     data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid_value)
260
261 # define VBOX_SESSION_OPEN_EXISTING(/* in */ iid_value, /* unused */ machine) \
262     data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid_value)
263
264 # define VBOX_SESSION_CLOSE() \
265     data->vboxSession->vtbl->Close(data->vboxSession)
266
267 #else /* VBOX_API_VERSION >= 4000000 */
268
269 # define VBOX_OBJECT_GET_MACHINE(/* in */ iid_value, /* out */ machine) \
270     data->vboxObj->vtbl->FindMachine(data->vboxObj, iid_value, machine)
271
272 # define VBOX_SESSION_OPEN(/* unused */ iid_value, /* in */ machine) \
273     machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Write)
274
275 # define VBOX_SESSION_OPEN_EXISTING(/* unused */ iid_value, /* in */ machine) \
276     machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Shared)
277
278 # define VBOX_SESSION_CLOSE() \
279     data->vboxSession->vtbl->UnlockMachine(data->vboxSession)
280
281 #endif /* VBOX_API_VERSION >= 4000000 */
282
283 static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml);
284 static int vboxDomainCreate(virDomainPtr dom);
285 static int vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags);
286
287 static void vboxDriverLock(vboxGlobalData *data)
288 {
289     virMutexLock(&data->lock);
290 }
291
292 static void vboxDriverUnlock(vboxGlobalData *data)
293 {
294     virMutexUnlock(&data->lock);
295 }
296
297 #if VBOX_API_VERSION == 2002000
298
299 static void nsIDtoChar(unsigned char *uuid, const nsID *iid)
300 {
301     char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
302     char uuidstrdst[VIR_UUID_STRING_BUFLEN];
303     unsigned char uuidinterim[VIR_UUID_BUFLEN];
304     size_t i;
305
306     memcpy(uuidinterim, iid, VIR_UUID_BUFLEN);
307     virUUIDFormat(uuidinterim, uuidstrsrc);
308
309     uuidstrdst[0]  = uuidstrsrc[6];
310     uuidstrdst[1]  = uuidstrsrc[7];
311     uuidstrdst[2]  = uuidstrsrc[4];
312     uuidstrdst[3]  = uuidstrsrc[5];
313     uuidstrdst[4]  = uuidstrsrc[2];
314     uuidstrdst[5]  = uuidstrsrc[3];
315     uuidstrdst[6]  = uuidstrsrc[0];
316     uuidstrdst[7]  = uuidstrsrc[1];
317
318     uuidstrdst[8]  = uuidstrsrc[8];
319
320     uuidstrdst[9]  = uuidstrsrc[11];
321     uuidstrdst[10] = uuidstrsrc[12];
322     uuidstrdst[11] = uuidstrsrc[9];
323     uuidstrdst[12] = uuidstrsrc[10];
324
325     uuidstrdst[13] = uuidstrsrc[13];
326
327     uuidstrdst[14] = uuidstrsrc[16];
328     uuidstrdst[15] = uuidstrsrc[17];
329     uuidstrdst[16] = uuidstrsrc[14];
330     uuidstrdst[17] = uuidstrsrc[15];
331
332     for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
333         uuidstrdst[i] = uuidstrsrc[i];
334     }
335
336     uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
337     ignore_value(virUUIDParse(uuidstrdst, uuid));
338 }
339
340 static void nsIDFromChar(nsID *iid, const unsigned char *uuid)
341 {
342     char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
343     char uuidstrdst[VIR_UUID_STRING_BUFLEN];
344     unsigned char uuidinterim[VIR_UUID_BUFLEN];
345     size_t i;
346
347     virUUIDFormat(uuid, uuidstrsrc);
348
349     uuidstrdst[0]  = uuidstrsrc[6];
350     uuidstrdst[1]  = uuidstrsrc[7];
351     uuidstrdst[2]  = uuidstrsrc[4];
352     uuidstrdst[3]  = uuidstrsrc[5];
353     uuidstrdst[4]  = uuidstrsrc[2];
354     uuidstrdst[5]  = uuidstrsrc[3];
355     uuidstrdst[6]  = uuidstrsrc[0];
356     uuidstrdst[7]  = uuidstrsrc[1];
357
358     uuidstrdst[8]  = uuidstrsrc[8];
359
360     uuidstrdst[9]  = uuidstrsrc[11];
361     uuidstrdst[10] = uuidstrsrc[12];
362     uuidstrdst[11] = uuidstrsrc[9];
363     uuidstrdst[12] = uuidstrsrc[10];
364
365     uuidstrdst[13] = uuidstrsrc[13];
366
367     uuidstrdst[14] = uuidstrsrc[16];
368     uuidstrdst[15] = uuidstrsrc[17];
369     uuidstrdst[16] = uuidstrsrc[14];
370     uuidstrdst[17] = uuidstrsrc[15];
371
372     for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
373         uuidstrdst[i] = uuidstrsrc[i];
374     }
375
376     uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
377     ignore_value(virUUIDParse(uuidstrdst, uuidinterim));
378     memcpy(iid, uuidinterim, VIR_UUID_BUFLEN);
379 }
380
381 # ifdef WIN32
382
383 typedef struct _vboxIID_v2_x_WIN32 vboxIID;
384 typedef struct _vboxIID_v2_x_WIN32 vboxIID_v2_x_WIN32;
385
386 struct _vboxIID_v2_x_WIN32 {
387     /* IID is represented by a GUID value. */
388     GUID value;
389 };
390
391 #  define VBOX_IID_INITIALIZER { { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } }
392
393 static void
394 vboxIIDUnalloc_v2_x_WIN32(vboxGlobalData *data ATTRIBUTE_UNUSED,
395                           vboxIID_v2_x_WIN32 *iid ATTRIBUTE_UNUSED)
396 {
397     /* Nothing to free */
398 }
399
400 static void
401 vboxIIDToUUID_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid, unsigned char *uuid)
402 {
403     nsIDtoChar(uuid, (nsID *)&iid->value);
404 }
405
406 static void
407 vboxIIDFromUUID_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid,
408                            const unsigned char *uuid)
409 {
410     vboxIIDUnalloc_v2_x_WIN32(data, iid);
411
412     nsIDFromChar((nsID *)&iid->value, uuid);
413 }
414
415 static bool
416 vboxIIDIsEqual_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid1, vboxIID_v2_x_WIN32 *iid2)
417 {
418     return memcmp(&iid1->value, &iid2->value, sizeof(GUID)) == 0;
419 }
420
421 static void
422 vboxIIDFromArrayItem_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid,
423                                 vboxArray *array, int idx)
424 {
425     GUID *items = (GUID *)array->items;
426
427     vboxIIDUnalloc_v2_x_WIN32(data, iid);
428
429     memcpy(&iid->value, &items[idx], sizeof(GUID));
430 }
431
432 #  define vboxIIDUnalloc(iid) vboxIIDUnalloc_v2_x_WIN32(data, iid)
433 #  define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v2_x_WIN32(iid, uuid)
434 #  define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v2_x_WIN32(data, iid, uuid)
435 #  define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v2_x_WIN32(iid1, iid2)
436 #  define vboxIIDFromArrayItem(iid, array, idx) \
437     vboxIIDFromArrayItem_v2_x_WIN32(data, iid, array, idx)
438 #  define DEBUGIID(msg, iid) DEBUGUUID(msg, (nsID *)&(iid))
439
440 # else /* !WIN32 */
441
442 typedef struct _vboxIID_v2_x vboxIID;
443 typedef struct _vboxIID_v2_x vboxIID_v2_x;
444
445 struct _vboxIID_v2_x {
446     /* IID is represented by a pointer to a nsID. */
447     nsID *value;
448
449     /* backing is used in cases where we need to create or copy an IID.
450      * We cannot allocate memory that can be freed by ComUnallocMem.
451      * Therefore, we use this stack allocated nsID instead. */
452     nsID backing;
453 };
454
455 #  define VBOX_IID_INITIALIZER { NULL, { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } }
456
457 static void
458 vboxIIDUnalloc_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid)
459 {
460     if (iid->value == NULL) {
461         return;
462     }
463
464     if (iid->value != &iid->backing) {
465         data->pFuncs->pfnComUnallocMem(iid->value);
466     }
467
468     iid->value = NULL;
469 }
470
471 static void
472 vboxIIDToUUID_v2_x(vboxIID_v2_x *iid, unsigned char *uuid)
473 {
474     nsIDtoChar(uuid, iid->value);
475 }
476
477 static void
478 vboxIIDFromUUID_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid,
479                      const unsigned char *uuid)
480 {
481     vboxIIDUnalloc_v2_x(data, iid);
482
483     iid->value = &iid->backing;
484
485     sa_assert(iid->value);
486     nsIDFromChar(iid->value, uuid);
487 }
488
489 static bool
490 vboxIIDIsEqual_v2_x(vboxIID_v2_x *iid1, vboxIID_v2_x *iid2)
491 {
492     return memcmp(iid1->value, iid2->value, sizeof(nsID)) == 0;
493 }
494
495 static void
496 vboxIIDFromArrayItem_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid,
497                           vboxArray *array, int idx)
498 {
499     vboxIIDUnalloc_v2_x(data, iid);
500
501     iid->value = &iid->backing;
502
503     memcpy(iid->value, array->items[idx], sizeof(nsID));
504 }
505
506 #  define vboxIIDUnalloc(iid) vboxIIDUnalloc_v2_x(data, iid)
507 #  define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v2_x(iid, uuid)
508 #  define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v2_x(data, iid, uuid)
509 #  define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v2_x(iid1, iid2)
510 #  define vboxIIDFromArrayItem(iid, array, idx) \
511     vboxIIDFromArrayItem_v2_x(data, iid, array, idx)
512 #  define DEBUGIID(msg, iid) DEBUGUUID(msg, iid)
513
514 # endif /* !WIN32 */
515
516 #else /* VBOX_API_VERSION != 2002000 */
517
518 typedef struct _vboxIID_v3_x vboxIID;
519 typedef struct _vboxIID_v3_x vboxIID_v3_x;
520
521 struct _vboxIID_v3_x {
522     /* IID is represented by a UTF-16 encoded UUID in string form. */
523     PRUnichar *value;
524
525     /* owner indicates if we own the value and need to free it. */
526     bool owner;
527 };
528
529 # define VBOX_IID_INITIALIZER { NULL, true }
530
531 static void
532 vboxIIDUnalloc_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid)
533 {
534     if (iid->value != NULL && iid->owner) {
535         data->pFuncs->pfnUtf16Free(iid->value);
536     }
537
538     iid->value = NULL;
539     iid->owner = true;
540 }
541
542 static void
543 vboxIIDToUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
544                    unsigned char *uuid)
545 {
546     char *utf8 = NULL;
547
548     data->pFuncs->pfnUtf16ToUtf8(iid->value, &utf8);
549
550     ignore_value(virUUIDParse(utf8, uuid));
551
552     data->pFuncs->pfnUtf8Free(utf8);
553 }
554
555 static void
556 vboxIIDFromUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
557                      const unsigned char *uuid)
558 {
559     char utf8[VIR_UUID_STRING_BUFLEN];
560
561     vboxIIDUnalloc_v3_x(data, iid);
562
563     virUUIDFormat(uuid, utf8);
564
565     data->pFuncs->pfnUtf8ToUtf16(utf8, &iid->value);
566 }
567
568 static bool
569 vboxIIDIsEqual_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid1,
570                     vboxIID_v3_x *iid2)
571 {
572     unsigned char uuid1[VIR_UUID_BUFLEN];
573     unsigned char uuid2[VIR_UUID_BUFLEN];
574
575     /* Note: we can't directly compare the utf8 strings here
576      * cause the two UUID's may have separators as space or '-'
577      * or mixture of both and we don't want to fail here by
578      * using direct string comparison. Here virUUIDParse() takes
579      * care of these cases. */
580     vboxIIDToUUID_v3_x(data, iid1, uuid1);
581     vboxIIDToUUID_v3_x(data, iid2, uuid2);
582
583     return memcmp(uuid1, uuid2, VIR_UUID_BUFLEN) == 0;
584 }
585
586
587 static void
588 vboxIIDFromArrayItem_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
589                           vboxArray *array, int idx)
590 {
591     vboxIIDUnalloc_v3_x(data, iid);
592
593     iid->value = array->items[idx];
594     iid->owner = false;
595 }
596
597
598 # define vboxIIDUnalloc(iid) vboxIIDUnalloc_v3_x(data, iid)
599 # define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v3_x(data, iid, uuid)
600 # define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v3_x(data, iid, uuid)
601 # define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v3_x(data, iid1, iid2)
602 # define vboxIIDFromArrayItem(iid, array, idx) \
603     vboxIIDFromArrayItem_v3_x(data, iid, array, idx)
604 # define DEBUGIID(msg, strUtf16) DEBUGPRUnichar(msg, strUtf16)
605
606 # if VBOX_API_VERSION >= 3001000
607
608 /**
609  * function to generate the name for medium,
610  * for e.g: hda, sda, etc
611  *
612  * @returns     null terminated string with device name or NULL
613  *              for failures
614  * @param       conn            Input Connection Pointer
615  * @param       storageBus      Input storage bus type
616  * @param       deviceInst      Input device instance number
617  * @param       devicePort      Input port number
618  * @param       deviceSlot      Input slot number
619  * @param       aMaxPortPerInst Input array of max port per device instance
620  * @param       aMaxSlotPerPort Input array of max slot per device port
621  *
622  */
623 static char *vboxGenerateMediumName(PRUint32  storageBus,
624                                     PRInt32   deviceInst,
625                                     PRInt32   devicePort,
626                                     PRInt32   deviceSlot,
627                                     PRUint32 *aMaxPortPerInst,
628                                     PRUint32 *aMaxSlotPerPort)
629 {
630     const char *prefix = NULL;
631     char *name  = NULL;
632     int   total = 0;
633     PRUint32 maxPortPerInst = 0;
634     PRUint32 maxSlotPerPort = 0;
635
636     if (!aMaxPortPerInst ||
637         !aMaxSlotPerPort)
638         return NULL;
639
640     if ((storageBus < StorageBus_IDE) ||
641         (storageBus > StorageBus_Floppy))
642         return NULL;
643
644     maxPortPerInst = aMaxPortPerInst[storageBus];
645     maxSlotPerPort = aMaxSlotPerPort[storageBus];
646     total =   (deviceInst * maxPortPerInst * maxSlotPerPort)
647             + (devicePort * maxSlotPerPort)
648             + deviceSlot;
649
650     if (storageBus == StorageBus_IDE) {
651         prefix = "hd";
652     } else if ((storageBus == StorageBus_SATA) ||
653                (storageBus == StorageBus_SCSI)) {
654         prefix = "sd";
655     } else if (storageBus == StorageBus_Floppy) {
656         prefix = "fd";
657     }
658
659     name = virIndexToDiskName(total, prefix);
660
661     VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
662           "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
663           NULLSTR(name), total, storageBus, deviceInst, devicePort,
664           deviceSlot, maxPortPerInst, maxSlotPerPort);
665     return name;
666 }
667
668 /**
669  * function to get the StorageBus, Port number
670  * and Device number for the given devicename
671  * e.g: hda has StorageBus = IDE, port = 0,
672  *      device = 0
673  *
674  * @returns     true on Success, false on failure.
675  * @param       deviceName      Input device name
676  * @param       aMaxPortPerInst Input array of max port per device instance
677  * @param       aMaxSlotPerPort Input array of max slot per device port
678  * @param       storageBus      Input storage bus type
679  * @param       deviceInst      Output device instance number
680  * @param       devicePort      Output port number
681  * @param       deviceSlot      Output slot number
682  *
683  */
684 static bool vboxGetDeviceDetails(const char *deviceName,
685                                  PRUint32   *aMaxPortPerInst,
686                                  PRUint32   *aMaxSlotPerPort,
687                                  PRUint32    storageBus,
688                                  PRInt32    *deviceInst,
689                                  PRInt32    *devicePort,
690                                  PRInt32    *deviceSlot) {
691     int total = 0;
692     PRUint32 maxPortPerInst = 0;
693     PRUint32 maxSlotPerPort = 0;
694
695     if (!deviceName ||
696         !deviceInst ||
697         !devicePort ||
698         !deviceSlot ||
699         !aMaxPortPerInst ||
700         !aMaxSlotPerPort)
701         return false;
702
703     if ((storageBus < StorageBus_IDE) ||
704         (storageBus > StorageBus_Floppy))
705         return false;
706
707     total = virDiskNameToIndex(deviceName);
708
709     maxPortPerInst = aMaxPortPerInst[storageBus];
710     maxSlotPerPort = aMaxSlotPerPort[storageBus];
711
712     if (!maxPortPerInst ||
713         !maxSlotPerPort ||
714         (total < 0))
715         return false;
716
717     *deviceInst = total / (maxPortPerInst * maxSlotPerPort);
718     *devicePort = (total % (maxPortPerInst * maxSlotPerPort)) / maxSlotPerPort;
719     *deviceSlot = (total % (maxPortPerInst * maxSlotPerPort)) % maxSlotPerPort;
720
721     VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
722           "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
723           deviceName, total, storageBus, *deviceInst, *devicePort,
724           *deviceSlot, maxPortPerInst, maxSlotPerPort);
725
726     return true;
727 }
728
729 /**
730  * function to get the values for max port per
731  * instance and max slots per port for the devices
732  *
733  * @returns     true on Success, false on failure.
734  * @param       vbox            Input IVirtualBox pointer
735  * @param       maxPortPerInst  Output array of max port per instance
736  * @param       maxSlotPerPort  Output array of max slot per port
737  *
738  */
739
740 static bool vboxGetMaxPortSlotValues(IVirtualBox *vbox,
741                                      PRUint32 *maxPortPerInst,
742                                      PRUint32 *maxSlotPerPort)
743 {
744     ISystemProperties *sysProps = NULL;
745
746     if (!vbox)
747         return false;
748
749     vbox->vtbl->GetSystemProperties(vbox, &sysProps);
750
751     if (!sysProps)
752         return false;
753
754     sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
755                                                  StorageBus_IDE,
756                                                  &maxPortPerInst[StorageBus_IDE]);
757     sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
758                                                  StorageBus_SATA,
759                                                  &maxPortPerInst[StorageBus_SATA]);
760     sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
761                                                  StorageBus_SCSI,
762                                                  &maxPortPerInst[StorageBus_SCSI]);
763     sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
764                                                  StorageBus_Floppy,
765                                                  &maxPortPerInst[StorageBus_Floppy]);
766
767     sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
768                                                       StorageBus_IDE,
769                                                       &maxSlotPerPort[StorageBus_IDE]);
770     sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
771                                                       StorageBus_SATA,
772                                                       &maxSlotPerPort[StorageBus_SATA]);
773     sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
774                                                       StorageBus_SCSI,
775                                                       &maxSlotPerPort[StorageBus_SCSI]);
776     sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
777                                                       StorageBus_Floppy,
778                                                       &maxSlotPerPort[StorageBus_Floppy]);
779
780     VBOX_RELEASE(sysProps);
781
782     return true;
783 }
784
785 /**
786  * Converts Utf-16 string to int
787  */
788 static int PRUnicharToInt(PRUnichar *strUtf16)
789 {
790     char *strUtf8 = NULL;
791     int ret = 0;
792
793     if (!strUtf16)
794         return -1;
795
796     g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);
797     if (!strUtf8)
798         return -1;
799
800     if (virStrToLong_i(strUtf8, NULL, 10, &ret) < 0)
801         ret = -1;
802
803     g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);
804
805     return ret;
806 }
807
808 /**
809  * Converts int to Utf-16 string
810  */
811 static PRUnichar *PRUnicharFromInt(int n) {
812     PRUnichar *strUtf16 = NULL;
813     char s[24];
814
815     snprintf(s, sizeof(s), "%d", n);
816
817     g_pVBoxGlobalData->pFuncs->pfnUtf8ToUtf16(s, &strUtf16);
818
819     return strUtf16;
820 }
821
822 # endif /* VBOX_API_VERSION >= 3001000 */
823
824 #endif /* !(VBOX_API_VERSION == 2002000) */
825
826 static PRUnichar *
827 vboxSocketFormatAddrUtf16(vboxGlobalData *data, virSocketAddrPtr addr)
828 {
829     char *utf8 = NULL;
830     PRUnichar *utf16 = NULL;
831
832     utf8 = virSocketAddrFormat(addr);
833
834     if (utf8 == NULL) {
835         return NULL;
836     }
837
838     VBOX_UTF8_TO_UTF16(utf8, &utf16);
839     VIR_FREE(utf8);
840
841     return utf16;
842 }
843
844 static int
845 vboxSocketParseAddrUtf16(vboxGlobalData *data, const PRUnichar *utf16,
846                          virSocketAddrPtr addr)
847 {
848     int result = -1;
849     char *utf8 = NULL;
850
851     VBOX_UTF16_TO_UTF8(utf16, &utf8);
852
853     if (virSocketAddrParse(addr, utf8, AF_UNSPEC) < 0) {
854         goto cleanup;
855     }
856
857     result = 0;
858
859  cleanup:
860     VBOX_UTF8_FREE(utf8);
861
862     return result;
863 }
864
865
866 static virDomainDefParserConfig vboxDomainDefParserConfig = {
867     .macPrefix = { 0x08, 0x00, 0x27 },
868 };
869
870
871 static virDomainXMLOptionPtr
872 vboxXMLConfInit(void)
873 {
874     return virDomainXMLOptionNew(&vboxDomainDefParserConfig,
875                                  NULL, NULL);
876 }
877
878
879 static virCapsPtr vboxCapsInit(void)
880 {
881     virCapsPtr caps;
882     virCapsGuestPtr guest;
883
884     if ((caps = virCapabilitiesNew(virArchFromHost(),
885                                    0, 0)) == NULL)
886         goto no_memory;
887
888     if (nodeCapsInitNUMA(caps) < 0)
889         goto no_memory;
890
891     if ((guest = virCapabilitiesAddGuest(caps,
892                                          "hvm",
893                                          caps->host.arch,
894                                          NULL,
895                                          NULL,
896                                          0,
897                                          NULL)) == NULL)
898         goto no_memory;
899
900     if (virCapabilitiesAddGuestDomain(guest,
901                                       "vbox",
902                                       NULL,
903                                       NULL,
904                                       0,
905                                       NULL) == NULL)
906         goto no_memory;
907
908     return caps;
909
910  no_memory:
911     virObjectUnref(caps);
912     return NULL;
913 }
914
915 static int
916 vboxInitialize(vboxGlobalData *data)
917 {
918     data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION);
919
920     if (data->pFuncs == NULL)
921         goto cleanup;
922
923 #if VBOX_XPCOMC_VERSION == 0x00010000U
924     data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
925 #else  /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
926     data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj,
927                                ISESSION_IID_STR, &data->vboxSession);
928
929 # if VBOX_API_VERSION == 2002000
930
931     /* No event queue functionality in 2.2.* as of now */
932
933 # else  /* !(VBOX_API_VERSION == 2002000) */
934
935     /* Initial the fWatch needed for Event Callbacks */
936     data->fdWatch = -1;
937
938     data->pFuncs->pfnGetEventQueue(&data->vboxQueue);
939
940     if (data->vboxQueue == NULL) {
941         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
942                        _("nsIEventQueue object is null"));
943         goto cleanup;
944     }
945
946 # endif /* !(VBOX_API_VERSION == 2002000) */
947 #endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
948
949     if (data->vboxObj == NULL) {
950         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
951                        _("IVirtualBox object is null"));
952         goto cleanup;
953     }
954
955     if (data->vboxSession == NULL) {
956         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
957                        _("ISession object is null"));
958         goto cleanup;
959     }
960
961     return 0;
962
963  cleanup:
964     return -1;
965 }
966
967 static int vboxExtractVersion(vboxGlobalData *data)
968 {
969     int ret = -1;
970     PRUnichar *versionUtf16 = NULL;
971     nsresult rc;
972
973     if (data->version > 0)
974         return 0;
975
976     rc = data->vboxObj->vtbl->GetVersion(data->vboxObj, &versionUtf16);
977     if (NS_SUCCEEDED(rc)) {
978         char *vboxVersion = NULL;
979
980         VBOX_UTF16_TO_UTF8(versionUtf16, &vboxVersion);
981
982         if (virParseVersionString(vboxVersion, &data->version, false) >= 0)
983             ret = 0;
984
985         VBOX_UTF8_FREE(vboxVersion);
986         VBOX_COM_UNALLOC_MEM(versionUtf16);
987     }
988
989     if (ret != 0)
990         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
991                        _("Could not extract VirtualBox version"));
992
993     return ret;
994 }
995
996 static void vboxUninitialize(vboxGlobalData *data)
997 {
998     if (!data)
999         return;
1000
1001     if (data->pFuncs)
1002         data->pFuncs->pfnComUninitialize();
1003
1004     virObjectUnref(data->caps);
1005     virObjectUnref(data->xmlopt);
1006 #if VBOX_API_VERSION == 2002000
1007     /* No domainEventCallbacks in 2.2.* version */
1008 #else  /* !(VBOX_API_VERSION == 2002000) */
1009     virObjectEventStateFree(data->domainEvents);
1010 #endif /* !(VBOX_API_VERSION == 2002000) */
1011     VIR_FREE(data);
1012 }
1013
1014
1015 static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
1016                                         virConnectAuthPtr auth ATTRIBUTE_UNUSED,
1017                                         unsigned int flags)
1018 {
1019     vboxGlobalData *data = NULL;
1020     uid_t uid = geteuid();
1021
1022     virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
1023
1024     if (conn->uri == NULL &&
1025         !(conn->uri = virURIParse(uid ? "vbox:///session" : "vbox:///system")))
1026         return VIR_DRV_OPEN_ERROR;
1027
1028     if (conn->uri->scheme == NULL ||
1029         STRNEQ(conn->uri->scheme, "vbox"))
1030         return VIR_DRV_OPEN_DECLINED;
1031
1032     /* Leave for remote driver */
1033     if (conn->uri->server != NULL)
1034         return VIR_DRV_OPEN_DECLINED;
1035
1036     if (conn->uri->path == NULL || STREQ(conn->uri->path, "")) {
1037         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1038                        _("no VirtualBox driver path specified (try vbox:///session)"));
1039         return VIR_DRV_OPEN_ERROR;
1040     }
1041
1042     if (uid != 0) {
1043         if (STRNEQ(conn->uri->path, "/session")) {
1044             virReportError(VIR_ERR_INTERNAL_ERROR,
1045                            _("unknown driver path '%s' specified (try vbox:///session)"), conn->uri->path);
1046             return VIR_DRV_OPEN_ERROR;
1047         }
1048     } else { /* root */
1049         if (STRNEQ(conn->uri->path, "/system") &&
1050             STRNEQ(conn->uri->path, "/session")) {
1051             virReportError(VIR_ERR_INTERNAL_ERROR,
1052                            _("unknown driver path '%s' specified (try vbox:///system)"), conn->uri->path);
1053             return VIR_DRV_OPEN_ERROR;
1054         }
1055     }
1056
1057     if (VIR_ALLOC(data) < 0)
1058         return VIR_DRV_OPEN_ERROR;
1059
1060     if (!(data->caps = vboxCapsInit()) ||
1061         vboxInitialize(data) < 0 ||
1062         vboxExtractVersion(data) < 0 ||
1063         !(data->xmlopt = vboxXMLConfInit())) {
1064         vboxUninitialize(data);
1065         return VIR_DRV_OPEN_ERROR;
1066     }
1067
1068 #if VBOX_API_VERSION == 2002000
1069
1070     /* No domainEventCallbacks in 2.2.* version */
1071
1072 #else  /* !(VBOX_API_VERSION == 2002000) */
1073
1074     if (!(data->domainEvents = virObjectEventStateNew())) {
1075         vboxUninitialize(data);
1076         return VIR_DRV_OPEN_ERROR;
1077     }
1078
1079     data->conn = conn;
1080     g_pVBoxGlobalData = data;
1081
1082 #endif /* !(VBOX_API_VERSION == 2002000) */
1083
1084     conn->privateData = data;
1085     VIR_DEBUG("in vboxOpen");
1086
1087     return VIR_DRV_OPEN_SUCCESS;
1088 }
1089
1090 static int vboxConnectClose(virConnectPtr conn)
1091 {
1092     vboxGlobalData *data = conn->privateData;
1093     VIR_DEBUG("%s: in vboxClose", conn->driver->name);
1094
1095     vboxUninitialize(data);
1096     conn->privateData = NULL;
1097
1098     return 0;
1099 }
1100
1101 static int vboxConnectGetVersion(virConnectPtr conn, unsigned long *version)
1102 {
1103     vboxGlobalData *data = conn->privateData;
1104     VIR_DEBUG("%s: in vboxGetVersion", conn->driver->name);
1105
1106     vboxDriverLock(data);
1107     *version = data->version;
1108     vboxDriverUnlock(data);
1109
1110     return 0;
1111 }
1112
1113
1114 static char *vboxConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
1115 {
1116     return virGetHostname();
1117 }
1118
1119
1120 static int vboxConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1121 {
1122     /* Driver is using local, non-network based transport */
1123     return 1;
1124 }
1125
1126 static int vboxConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1127 {
1128     /* No encryption is needed, or used on the local transport*/
1129     return 0;
1130 }
1131
1132 static int vboxConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1133 {
1134     return 1;
1135 }
1136
1137 static int
1138 vboxConnectGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED)
1139 {
1140     VBOX_OBJECT_CHECK(conn, int, -1);
1141     PRUint32 maxCPUCount = 0;
1142
1143     /* VirtualBox Supports only hvm and thus the type passed to it
1144      * has no meaning, setting it to ATTRIBUTE_UNUSED
1145      */
1146     ISystemProperties *systemProperties = NULL;
1147
1148     data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
1149     if (systemProperties) {
1150         systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
1151         VBOX_RELEASE(systemProperties);
1152     }
1153
1154     if (maxCPUCount > 0)
1155         ret = maxCPUCount;
1156
1157     return ret;
1158 }
1159
1160
1161 static char *vboxConnectGetCapabilities(virConnectPtr conn) {
1162     VBOX_OBJECT_CHECK(conn, char *, NULL);
1163
1164     vboxDriverLock(data);
1165     ret = virCapabilitiesFormatXML(data->caps);
1166     vboxDriverUnlock(data);
1167
1168     return ret;
1169 }
1170
1171 static int vboxConnectListDomains(virConnectPtr conn, int *ids, int nids)
1172 {
1173     VBOX_OBJECT_CHECK(conn, int, -1);
1174     vboxArray machines = VBOX_ARRAY_INITIALIZER;
1175     PRUint32 state;
1176     nsresult rc;
1177     size_t i, j;
1178
1179     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1180     if (NS_FAILED(rc)) {
1181         virReportError(VIR_ERR_INTERNAL_ERROR,
1182                        _("Could not get list of Domains, rc=%08x"),
1183                        (unsigned)rc);
1184         goto cleanup;
1185     }
1186
1187     ret = 0;
1188     for (i = 0, j = 0; (i < machines.count) && (j < nids); ++i) {
1189         IMachine *machine = machines.items[i];
1190
1191         if (machine) {
1192             PRBool isAccessible = PR_FALSE;
1193             machine->vtbl->GetAccessible(machine, &isAccessible);
1194             if (isAccessible) {
1195                 machine->vtbl->GetState(machine, &state);
1196                 if ((state >= MachineState_FirstOnline) &&
1197                     (state <= MachineState_LastOnline)) {
1198                     ret++;
1199                     ids[j++] = i + 1;
1200                 }
1201             }
1202         }
1203     }
1204
1205  cleanup:
1206     vboxArrayRelease(&machines);
1207     return ret;
1208 }
1209
1210 static int vboxConnectNumOfDomains(virConnectPtr conn)
1211 {
1212     VBOX_OBJECT_CHECK(conn, int, -1);
1213     vboxArray machines = VBOX_ARRAY_INITIALIZER;
1214     PRUint32 state;
1215     nsresult rc;
1216     size_t i;
1217
1218     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1219     if (NS_FAILED(rc)) {
1220         virReportError(VIR_ERR_INTERNAL_ERROR,
1221                        _("Could not get number of Domains, rc=%08x"), (unsigned)rc);
1222         goto cleanup;
1223     }
1224
1225     ret = 0;
1226     for (i = 0; i < machines.count; ++i) {
1227         IMachine *machine = machines.items[i];
1228
1229         if (machine) {
1230             PRBool isAccessible = PR_FALSE;
1231             machine->vtbl->GetAccessible(machine, &isAccessible);
1232             if (isAccessible) {
1233                 machine->vtbl->GetState(machine, &state);
1234                 if ((state >= MachineState_FirstOnline) &&
1235                     (state <= MachineState_LastOnline))
1236                     ret++;
1237             }
1238         }
1239     }
1240
1241  cleanup:
1242     vboxArrayRelease(&machines);
1243     return ret;
1244 }
1245
1246 static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml,
1247                                         unsigned int flags)
1248 {
1249     /* VirtualBox currently doesn't have support for running
1250      * virtual machines without actually defining them and thus
1251      * for time being just define new machine and start it.
1252      *
1253      * TODO: After the appropriate API's are added in VirtualBox
1254      * change this behaviour to the expected one.
1255      */
1256
1257     virDomainPtr dom;
1258
1259     virCheckFlags(0, NULL);
1260
1261     dom = vboxDomainDefineXML(conn, xml);
1262     if (dom == NULL)
1263         return NULL;
1264
1265     if (vboxDomainCreate(dom) < 0) {
1266         vboxDomainUndefineFlags(dom, 0);
1267         virObjectUnref(dom);
1268         return NULL;
1269     }
1270
1271     return dom;
1272 }
1273
1274 static virDomainPtr vboxDomainLookupByID(virConnectPtr conn, int id)
1275 {
1276     VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1277     vboxArray machines = VBOX_ARRAY_INITIALIZER;
1278     vboxIID iid = VBOX_IID_INITIALIZER;
1279     unsigned char uuid[VIR_UUID_BUFLEN];
1280     PRUint32 state;
1281     nsresult rc;
1282
1283     /* Internal vbox IDs start from 0, the public libvirt ID
1284      * starts from 1, so refuse id == 0, and adjust the rest*/
1285     if (id == 0) {
1286         virReportError(VIR_ERR_NO_DOMAIN,
1287                        _("no domain with matching id %d"), id);
1288         return NULL;
1289     }
1290     id = id - 1;
1291
1292     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1293     if (NS_FAILED(rc)) {
1294         virReportError(VIR_ERR_INTERNAL_ERROR,
1295                        _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1296         return NULL;
1297     }
1298
1299     if (id < machines.count) {
1300         IMachine *machine = machines.items[id];
1301
1302         if (machine) {
1303             PRBool isAccessible = PR_FALSE;
1304             machine->vtbl->GetAccessible(machine, &isAccessible);
1305             if (isAccessible) {
1306                 machine->vtbl->GetState(machine, &state);
1307                 if ((state >= MachineState_FirstOnline) &&
1308                     (state <= MachineState_LastOnline)) {
1309                     PRUnichar *machineNameUtf16 = NULL;
1310                     char      *machineNameUtf8  = NULL;
1311
1312                     machine->vtbl->GetName(machine, &machineNameUtf16);
1313                     VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1314
1315                     machine->vtbl->GetId(machine, &iid.value);
1316                     vboxIIDToUUID(&iid, uuid);
1317                     vboxIIDUnalloc(&iid);
1318
1319                     /* get a new domain pointer from virGetDomain, if it fails
1320                      * then no need to assign the id, else assign the id, cause
1321                      * it is -1 by default. rest is taken care by virGetDomain
1322                      * itself, so need not worry.
1323                      */
1324
1325                     ret = virGetDomain(conn, machineNameUtf8, uuid);
1326                     if (ret)
1327                         ret->id = id + 1;
1328
1329                     /* Cleanup all the XPCOM allocated stuff here */
1330                     VBOX_UTF8_FREE(machineNameUtf8);
1331                     VBOX_UTF16_FREE(machineNameUtf16);
1332                 }
1333             }
1334         }
1335     }
1336
1337     vboxArrayRelease(&machines);
1338
1339     return ret;
1340 }
1341
1342 static virDomainPtr
1343 vboxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
1344 {
1345     VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1346     vboxArray machines = VBOX_ARRAY_INITIALIZER;
1347     vboxIID iid = VBOX_IID_INITIALIZER;
1348     char      *machineNameUtf8  = NULL;
1349     PRUnichar *machineNameUtf16 = NULL;
1350     unsigned char iid_as_uuid[VIR_UUID_BUFLEN];
1351     size_t i;
1352     int matched = 0;
1353     nsresult rc;
1354
1355     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1356     if (NS_FAILED(rc)) {
1357         virReportError(VIR_ERR_INTERNAL_ERROR,
1358                        _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1359         return NULL;
1360     }
1361
1362     for (i = 0; i < machines.count; ++i) {
1363         IMachine *machine = machines.items[i];
1364         PRBool isAccessible = PR_FALSE;
1365
1366         if (!machine)
1367             continue;
1368
1369         machine->vtbl->GetAccessible(machine, &isAccessible);
1370         if (isAccessible) {
1371
1372             rc = machine->vtbl->GetId(machine, &iid.value);
1373             if (NS_FAILED(rc))
1374                 continue;
1375             vboxIIDToUUID(&iid, iid_as_uuid);
1376             vboxIIDUnalloc(&iid);
1377
1378             if (memcmp(uuid, iid_as_uuid, VIR_UUID_BUFLEN) == 0) {
1379
1380                 PRUint32 state;
1381
1382                 matched = 1;
1383
1384                 machine->vtbl->GetName(machine, &machineNameUtf16);
1385                 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1386
1387                 machine->vtbl->GetState(machine, &state);
1388
1389                 /* get a new domain pointer from virGetDomain, if it fails
1390                  * then no need to assign the id, else assign the id, cause
1391                  * it is -1 by default. rest is taken care by virGetDomain
1392                  * itself, so need not worry.
1393                  */
1394
1395                 ret = virGetDomain(conn, machineNameUtf8, iid_as_uuid);
1396                 if (ret &&
1397                     (state >= MachineState_FirstOnline) &&
1398                     (state <= MachineState_LastOnline))
1399                     ret->id = i + 1;
1400             }
1401
1402             if (matched == 1)
1403                 break;
1404         }
1405     }
1406
1407     /* Do the cleanup and take care you dont leak any memory */
1408     VBOX_UTF8_FREE(machineNameUtf8);
1409     VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1410     vboxArrayRelease(&machines);
1411
1412     return ret;
1413 }
1414
1415 static virDomainPtr
1416 vboxDomainLookupByName(virConnectPtr conn, const char *name)
1417 {
1418     VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1419     vboxArray machines = VBOX_ARRAY_INITIALIZER;
1420     vboxIID iid = VBOX_IID_INITIALIZER;
1421     char      *machineNameUtf8  = NULL;
1422     PRUnichar *machineNameUtf16 = NULL;
1423     unsigned char uuid[VIR_UUID_BUFLEN];
1424     size_t i;
1425     int matched = 0;
1426     nsresult rc;
1427
1428     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1429     if (NS_FAILED(rc)) {
1430         virReportError(VIR_ERR_INTERNAL_ERROR,
1431                        _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1432         return NULL;
1433     }
1434
1435     for (i = 0; i < machines.count; ++i) {
1436         IMachine *machine = machines.items[i];
1437         PRBool isAccessible = PR_FALSE;
1438
1439         if (!machine)
1440             continue;
1441
1442         machine->vtbl->GetAccessible(machine, &isAccessible);
1443         if (isAccessible) {
1444
1445             machine->vtbl->GetName(machine, &machineNameUtf16);
1446             VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1447
1448             if (STREQ(name, machineNameUtf8)) {
1449
1450                 PRUint32 state;
1451
1452                 matched = 1;
1453
1454                 machine->vtbl->GetId(machine, &iid.value);
1455                 vboxIIDToUUID(&iid, uuid);
1456                 vboxIIDUnalloc(&iid);
1457
1458                 machine->vtbl->GetState(machine, &state);
1459
1460                 /* get a new domain pointer from virGetDomain, if it fails
1461                  * then no need to assign the id, else assign the id, cause
1462                  * it is -1 by default. rest is taken care by virGetDomain
1463                  * itself, so need not worry.
1464                  */
1465
1466                 ret = virGetDomain(conn, machineNameUtf8, uuid);
1467                 if (ret &&
1468                     (state >= MachineState_FirstOnline) &&
1469                     (state <= MachineState_LastOnline))
1470                     ret->id = i + 1;
1471             }
1472
1473             VBOX_UTF8_FREE(machineNameUtf8);
1474             VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1475             if (matched == 1)
1476                 break;
1477         }
1478     }
1479
1480     vboxArrayRelease(&machines);
1481
1482     return ret;
1483 }
1484
1485
1486 static int vboxDomainIsActive(virDomainPtr dom)
1487 {
1488     VBOX_OBJECT_CHECK(dom->conn, int, -1);
1489     vboxArray machines = VBOX_ARRAY_INITIALIZER;
1490     vboxIID iid = VBOX_IID_INITIALIZER;
1491     char      *machineNameUtf8  = NULL;
1492     PRUnichar *machineNameUtf16 = NULL;
1493     unsigned char uuid[VIR_UUID_BUFLEN];
1494     size_t i;
1495     int matched = 0;
1496     nsresult rc;
1497
1498     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1499     if (NS_FAILED(rc)) {
1500         virReportError(VIR_ERR_INTERNAL_ERROR,
1501                        _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1502         return ret;
1503     }
1504
1505     for (i = 0; i < machines.count; ++i) {
1506         IMachine *machine = machines.items[i];
1507         PRBool isAccessible = PR_FALSE;
1508
1509         if (!machine)
1510             continue;
1511
1512         machine->vtbl->GetAccessible(machine, &isAccessible);
1513         if (isAccessible) {
1514
1515             rc = machine->vtbl->GetId(machine, &iid.value);
1516             if (NS_FAILED(rc))
1517                 continue;
1518             vboxIIDToUUID(&iid, uuid);
1519             vboxIIDUnalloc(&iid);
1520
1521             if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
1522
1523                 PRUint32 state;
1524
1525                 matched = 1;
1526
1527                 machine->vtbl->GetName(machine, &machineNameUtf16);
1528                 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1529
1530                 machine->vtbl->GetState(machine, &state);
1531
1532                 if ((state >= MachineState_FirstOnline) &&
1533                     (state <= MachineState_LastOnline))
1534                     ret = 1;
1535                 else
1536                     ret = 0;
1537             }
1538
1539             if (matched == 1)
1540                 break;
1541         }
1542     }
1543
1544     /* Do the cleanup and take care you dont leak any memory */
1545     VBOX_UTF8_FREE(machineNameUtf8);
1546     VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1547     vboxArrayRelease(&machines);
1548
1549     return ret;
1550 }
1551
1552
1553 static int vboxDomainIsPersistent(virDomainPtr dom ATTRIBUTE_UNUSED)
1554 {
1555     /* All domains are persistent.  However, we do want to check for
1556      * existence. */
1557     VBOX_OBJECT_CHECK(dom->conn, int, -1);
1558     vboxIID iid = VBOX_IID_INITIALIZER;
1559     IMachine *machine = NULL;
1560     nsresult rc;
1561
1562     vboxIIDFromUUID(&iid, dom->uuid);
1563     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1564     if (NS_FAILED(rc)) {
1565         virReportError(VIR_ERR_NO_DOMAIN, "%s",
1566                        _("no domain with matching UUID"));
1567         goto cleanup;
1568     }
1569
1570     ret = 1;
1571
1572  cleanup:
1573     VBOX_RELEASE(machine);
1574     vboxIIDUnalloc(&iid);
1575     return ret;
1576 }
1577
1578
1579 static int vboxDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
1580 {
1581     /* VBox domains never have a persistent state that differs from
1582      * current state.  However, we do want to check for existence.  */
1583     VBOX_OBJECT_CHECK(dom->conn, int, -1);
1584     vboxIID iid = VBOX_IID_INITIALIZER;
1585     IMachine *machine = NULL;
1586     nsresult rc;
1587
1588     vboxIIDFromUUID(&iid, dom->uuid);
1589     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1590     if (NS_FAILED(rc)) {
1591         virReportError(VIR_ERR_NO_DOMAIN, "%s",
1592                        _("no domain with matching UUID"));
1593         goto cleanup;
1594     }
1595
1596     ret = 0;
1597
1598  cleanup:
1599     VBOX_RELEASE(machine);
1600     vboxIIDUnalloc(&iid);
1601     return ret;
1602 }
1603
1604 static int vboxDomainSuspend(virDomainPtr dom)
1605 {
1606     VBOX_OBJECT_CHECK(dom->conn, int, -1);
1607     IMachine *machine    = NULL;
1608     vboxIID iid = VBOX_IID_INITIALIZER;
1609     IConsole *console    = NULL;
1610     PRBool isAccessible  = PR_FALSE;
1611     PRUint32 state;
1612     nsresult rc;
1613
1614     vboxIIDFromUUID(&iid, dom->uuid);
1615     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1616     if (NS_FAILED(rc)) {
1617         virReportError(VIR_ERR_NO_DOMAIN,
1618                        _("no domain with matching id %d"), dom->id);
1619         goto cleanup;
1620     }
1621
1622     if (!machine)
1623         goto cleanup;
1624
1625     machine->vtbl->GetAccessible(machine, &isAccessible);
1626     if (isAccessible) {
1627         machine->vtbl->GetState(machine, &state);
1628
1629         if (state == MachineState_Running) {
1630             /* set state pause */
1631             VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1632             data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
1633             if (console) {
1634                 console->vtbl->Pause(console);
1635                 VBOX_RELEASE(console);
1636                 ret = 0;
1637             } else {
1638                 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1639                                _("error while suspending the domain"));
1640                 goto cleanup;
1641             }
1642             VBOX_SESSION_CLOSE();
1643         } else {
1644             virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1645                            _("machine not in running state to suspend it"));
1646             goto cleanup;
1647         }
1648     }
1649
1650  cleanup:
1651     VBOX_RELEASE(machine);
1652     vboxIIDUnalloc(&iid);
1653     return ret;
1654 }
1655
1656 static int vboxDomainResume(virDomainPtr dom)
1657 {
1658     VBOX_OBJECT_CHECK(dom->conn, int, -1);
1659     IMachine *machine    = NULL;
1660     vboxIID iid = VBOX_IID_INITIALIZER;
1661     IConsole *console    = NULL;
1662     PRUint32 state       = MachineState_Null;
1663     nsresult rc;
1664
1665     PRBool isAccessible = PR_FALSE;
1666
1667     vboxIIDFromUUID(&iid, dom->uuid);
1668     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1669     if (NS_FAILED(rc)) {
1670         virReportError(VIR_ERR_NO_DOMAIN,
1671                        _("no domain with matching id %d"), dom->id);
1672         goto cleanup;
1673     }
1674
1675     if (!machine)
1676         goto cleanup;
1677
1678     machine->vtbl->GetAccessible(machine, &isAccessible);
1679     if (isAccessible) {
1680         machine->vtbl->GetState(machine, &state);
1681
1682         if (state == MachineState_Paused) {
1683             /* resume the machine here */
1684             VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1685             data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
1686             if (console) {
1687                 console->vtbl->Resume(console);
1688                 VBOX_RELEASE(console);
1689                 ret = 0;
1690             } else {
1691                 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1692                                _("error while resuming the domain"));
1693                 goto cleanup;
1694             }
1695             VBOX_SESSION_CLOSE();
1696         } else {
1697             virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1698                            _("machine not paused, so can't resume it"));
1699             goto cleanup;
1700         }
1701     }
1702
1703  cleanup:
1704     VBOX_RELEASE(machine);
1705     vboxIIDUnalloc(&iid);
1706     return ret;
1707 }
1708
1709 static int vboxDomainShutdownFlags(virDomainPtr dom,
1710                                    unsigned int flags)
1711 {
1712     VBOX_OBJECT_CHECK(dom->conn, int, -1);
1713     IMachine *machine    = NULL;
1714     vboxIID iid = VBOX_IID_INITIALIZER;
1715     IConsole *console    = NULL;
1716     PRUint32 state       = MachineState_Null;
1717     PRBool isAccessible  = PR_FALSE;
1718     nsresult rc;
1719
1720     virCheckFlags(0, -1);
1721
1722     vboxIIDFromUUID(&iid, dom->uuid);
1723     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1724     if (NS_FAILED(rc)) {
1725         virReportError(VIR_ERR_NO_DOMAIN,
1726                        _("no domain with matching id %d"), dom->id);
1727         goto cleanup;
1728     }
1729
1730     if (!machine)
1731         goto cleanup;
1732
1733     machine->vtbl->GetAccessible(machine, &isAccessible);
1734     if (isAccessible) {
1735         machine->vtbl->GetState(machine, &state);
1736
1737         if (state == MachineState_Paused) {
1738             virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1739                            _("machine paused, so can't power it down"));
1740             goto cleanup;
1741         } else if (state == MachineState_PoweredOff) {
1742             virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1743                            _("machine already powered down"));
1744             goto cleanup;
1745         }
1746
1747         VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1748         data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
1749         if (console) {
1750             console->vtbl->PowerButton(console);
1751             VBOX_RELEASE(console);
1752             ret = 0;
1753         }
1754         VBOX_SESSION_CLOSE();
1755     }
1756
1757  cleanup:
1758     VBOX_RELEASE(machine);
1759     vboxIIDUnalloc(&iid);
1760     return ret;
1761 }
1762
1763 static int vboxDomainShutdown(virDomainPtr dom)
1764 {
1765     return vboxDomainShutdownFlags(dom, 0);
1766 }
1767
1768
1769 static int vboxDomainReboot(virDomainPtr dom, unsigned int flags)
1770 {
1771     VBOX_OBJECT_CHECK(dom->conn, int, -1);
1772     IMachine *machine    = NULL;
1773     vboxIID iid = VBOX_IID_INITIALIZER;
1774     IConsole *console    = NULL;
1775     PRUint32 state       = MachineState_Null;
1776     PRBool isAccessible  = PR_FALSE;
1777     nsresult rc;
1778
1779     virCheckFlags(0, -1);
1780
1781     vboxIIDFromUUID(&iid, dom->uuid);
1782     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1783     if (NS_FAILED(rc)) {
1784         virReportError(VIR_ERR_NO_DOMAIN,
1785                        _("no domain with matching id %d"), dom->id);
1786         goto cleanup;
1787     }
1788
1789     if (!machine)
1790         goto cleanup;
1791
1792     machine->vtbl->GetAccessible(machine, &isAccessible);
1793     if (isAccessible) {
1794         machine->vtbl->GetState(machine, &state);
1795
1796         if (state == MachineState_Running) {
1797             VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1798             data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
1799             if (console) {
1800                 console->vtbl->Reset(console);
1801                 VBOX_RELEASE(console);
1802                 ret = 0;
1803             }
1804             VBOX_SESSION_CLOSE();
1805         } else {
1806             virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1807                            _("machine not running, so can't reboot it"));
1808             goto cleanup;
1809         }
1810     }
1811
1812  cleanup:
1813     VBOX_RELEASE(machine);
1814     vboxIIDUnalloc(&iid);
1815     return ret;
1816 }
1817
1818 static int
1819 vboxDomainDestroyFlags(virDomainPtr dom,
1820                        unsigned int flags)
1821 {
1822     VBOX_OBJECT_CHECK(dom->conn, int, -1);
1823     IMachine *machine    = NULL;
1824     vboxIID iid = VBOX_IID_INITIALIZER;
1825     IConsole *console    = NULL;
1826     PRUint32 state       = MachineState_Null;
1827     PRBool isAccessible  = PR_FALSE;
1828     nsresult rc;
1829
1830     virCheckFlags(0, -1);
1831
1832     vboxIIDFromUUID(&iid, dom->uuid);
1833     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1834     if (NS_FAILED(rc)) {
1835         virReportError(VIR_ERR_NO_DOMAIN,
1836                        _("no domain with matching id %d"), dom->id);
1837         goto cleanup;
1838     }
1839
1840     if (!machine)
1841         goto cleanup;
1842
1843     machine->vtbl->GetAccessible(machine, &isAccessible);
1844     if (isAccessible) {
1845         machine->vtbl->GetState(machine, &state);
1846
1847         if (state == MachineState_PoweredOff) {
1848             virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1849                            _("machine already powered down"));
1850             goto cleanup;
1851         }
1852
1853         VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1854         data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
1855         if (console) {
1856
1857 #if VBOX_API_VERSION == 2002000
1858             console->vtbl->PowerDown(console);
1859 #else
1860             IProgress *progress = NULL;
1861             console->vtbl->PowerDown(console, &progress);
1862             if (progress) {
1863                 progress->vtbl->WaitForCompletion(progress, -1);
1864                 VBOX_RELEASE(progress);
1865             }
1866 #endif
1867             VBOX_RELEASE(console);
1868             dom->id = -1;
1869             ret = 0;
1870         }
1871         VBOX_SESSION_CLOSE();
1872     }
1873
1874  cleanup:
1875     VBOX_RELEASE(machine);
1876     vboxIIDUnalloc(&iid);
1877     return ret;
1878 }
1879
1880 static int
1881 vboxDomainDestroy(virDomainPtr dom)
1882 {
1883     return vboxDomainDestroyFlags(dom, 0);
1884 }
1885
1886 static char *vboxDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) {
1887     /* Returning "hvm" always as suggested on list, cause
1888      * this functions seems to be badly named and it
1889      * is supposed to pass the ABI name and not the domain
1890      * operating system driver as I had imagined ;)
1891      */
1892     char *osType;
1893
1894     ignore_value(VIR_STRDUP(osType, "hvm"));
1895     return osType;
1896 }
1897
1898 static int vboxDomainSetMemory(virDomainPtr dom, unsigned long memory)
1899 {
1900     VBOX_OBJECT_CHECK(dom->conn, int, -1);
1901     IMachine *machine    = NULL;
1902     vboxIID iid = VBOX_IID_INITIALIZER;
1903     PRUint32 state       = MachineState_Null;
1904     PRBool isAccessible  = PR_FALSE;
1905     nsresult rc;
1906
1907     vboxIIDFromUUID(&iid, dom->uuid);
1908     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1909     if (NS_FAILED(rc)) {
1910         virReportError(VIR_ERR_NO_DOMAIN,
1911                        _("no domain with matching id %d"), dom->id);
1912         goto cleanup;
1913     }
1914
1915     if (!machine)
1916         goto cleanup;
1917
1918     machine->vtbl->GetAccessible(machine, &isAccessible);
1919     if (isAccessible) {
1920         machine->vtbl->GetState(machine, &state);
1921
1922         if (state != MachineState_PoweredOff) {
1923             virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1924                            _("memory size can't be changed unless domain is powered down"));
1925             goto cleanup;
1926         }
1927
1928         rc = VBOX_SESSION_OPEN(iid.value, machine);
1929         if (NS_SUCCEEDED(rc)) {
1930             rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
1931             if (NS_SUCCEEDED(rc) && machine) {
1932
1933                 rc = machine->vtbl->SetMemorySize(machine,
1934                                                   VIR_DIV_UP(memory, 1024));
1935                 if (NS_SUCCEEDED(rc)) {
1936                     machine->vtbl->SaveSettings(machine);
1937                     ret = 0;
1938                 } else {
1939                     virReportError(VIR_ERR_INTERNAL_ERROR,
1940                                    _("could not set the memory size of the "
1941                                      "domain to: %lu Kb, rc=%08x"),
1942                                    memory, (unsigned)rc);
1943                 }
1944             }
1945             VBOX_SESSION_CLOSE();
1946         }
1947     }
1948
1949  cleanup:
1950     VBOX_RELEASE(machine);
1951     vboxIIDUnalloc(&iid);
1952     return ret;
1953 }
1954
1955 static virDomainState vboxConvertState(enum MachineState state)
1956 {
1957     switch (state) {
1958         case MachineState_Running:
1959             return VIR_DOMAIN_RUNNING;
1960         case MachineState_Stuck:
1961             return VIR_DOMAIN_BLOCKED;
1962         case MachineState_Paused:
1963             return VIR_DOMAIN_PAUSED;
1964         case MachineState_Stopping:
1965             return VIR_DOMAIN_SHUTDOWN;
1966         case MachineState_PoweredOff:
1967         case MachineState_Saved:
1968             return VIR_DOMAIN_SHUTOFF;
1969         case MachineState_Aborted:
1970             return VIR_DOMAIN_CRASHED;
1971         case MachineState_Null:
1972         default:
1973             return VIR_DOMAIN_NOSTATE;
1974     }
1975 }
1976
1977 static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
1978 {
1979     VBOX_OBJECT_CHECK(dom->conn, int, -1);
1980     vboxArray machines = VBOX_ARRAY_INITIALIZER;
1981     char *machineName    = NULL;
1982     PRUnichar *machineNameUtf16 = NULL;
1983     nsresult rc;
1984     size_t i = 0;
1985
1986     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1987     if (NS_FAILED(rc)) {
1988         virReportError(VIR_ERR_INTERNAL_ERROR,
1989                        _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1990         goto cleanup;
1991     }
1992
1993     info->nrVirtCpu = 0;
1994     for (i = 0; i < machines.count; ++i) {
1995         IMachine *machine = machines.items[i];
1996         PRBool isAccessible = PR_FALSE;
1997
1998         if (!machine)
1999             continue;
2000
2001         machine->vtbl->GetAccessible(machine, &isAccessible);
2002         if (isAccessible) {
2003
2004             machine->vtbl->GetName(machine, &machineNameUtf16);
2005             VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
2006
2007             if (STREQ(dom->name, machineName)) {
2008                 /* Get the Machine State (also match it with
2009                 * virDomainState). Get the Machine memory and
2010                 * for time being set max_balloon and cur_balloon to same
2011                 * Also since there is no direct way of checking
2012                 * the cputime required (one condition being the
2013                 * VM is remote), return zero for cputime. Get the
2014                 * number of CPU.
2015                 */
2016                 PRUint32 CPUCount   = 0;
2017                 PRUint32 memorySize = 0;
2018                 PRUint32 state      = MachineState_Null;
2019                 PRUint32 maxMemorySize = 4 * 1024;
2020                 ISystemProperties *systemProperties = NULL;
2021
2022                 data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
2023                 if (systemProperties) {
2024                     systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
2025                     VBOX_RELEASE(systemProperties);
2026                     systemProperties = NULL;
2027                 }
2028
2029
2030                 machine->vtbl->GetCPUCount(machine, &CPUCount);
2031                 machine->vtbl->GetMemorySize(machine, &memorySize);
2032                 machine->vtbl->GetState(machine, &state);
2033
2034                 info->cpuTime = 0;
2035                 info->nrVirtCpu = CPUCount;
2036                 info->memory = memorySize * 1024;
2037                 info->maxMem = maxMemorySize * 1024;
2038                 info->state = vboxConvertState(state);
2039
2040                 ret = 0;
2041             }
2042
2043             VBOX_UTF8_FREE(machineName);
2044             VBOX_COM_UNALLOC_MEM(machineNameUtf16);
2045             if (info->nrVirtCpu)
2046                 break;
2047         }
2048
2049     }
2050
2051     vboxArrayRelease(&machines);
2052
2053  cleanup:
2054     return ret;
2055 }
2056
2057 static int
2058 vboxDomainGetState(virDomainPtr dom,
2059                    int *state,
2060                    int *reason,
2061                    unsigned int flags)
2062 {
2063     VBOX_OBJECT_CHECK(dom->conn, int, -1);
2064     vboxIID domiid = VBOX_IID_INITIALIZER;
2065     IMachine *machine = NULL;
2066     PRUint32 mstate = MachineState_Null;
2067     nsresult rc;
2068
2069     virCheckFlags(0, -1);
2070
2071     vboxIIDFromUUID(&domiid, dom->uuid);
2072     rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
2073     if (NS_FAILED(rc)) {
2074         virReportError(VIR_ERR_NO_DOMAIN, "%s",
2075                        _("no domain with matching UUID"));
2076         goto cleanup;
2077     }
2078
2079     machine->vtbl->GetState(machine, &mstate);
2080
2081     *state = vboxConvertState(mstate);
2082
2083     if (reason)
2084         *reason = 0;
2085
2086     ret = 0;
2087
2088  cleanup:
2089     vboxIIDUnalloc(&domiid);
2090     return ret;
2091 }
2092
2093 static int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED)
2094 {
2095     VBOX_OBJECT_CHECK(dom->conn, int, -1);
2096     IConsole *console    = NULL;
2097     vboxIID iid = VBOX_IID_INITIALIZER;
2098     IMachine *machine = NULL;
2099     nsresult rc;
2100
2101     /* VirtualBox currently doesn't support saving to a file
2102      * at a location other then the machine folder and thus
2103      * setting path to ATTRIBUTE_UNUSED for now, will change
2104      * this behaviour once get the VirtualBox API in right
2105      * shape to do this
2106      */
2107
2108     /* Open a Session for the machine */
2109     vboxIIDFromUUID(&iid, dom->uuid);
2110 #if VBOX_API_VERSION >= 4000000
2111     /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */
2112     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
2113     if (NS_FAILED(rc)) {
2114         virReportError(VIR_ERR_NO_DOMAIN, "%s",
2115                        _("no domain with matching uuid"));
2116         return -1;
2117     }
2118 #endif
2119
2120     rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
2121     if (NS_SUCCEEDED(rc)) {
2122         rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
2123         if (NS_SUCCEEDED(rc) && console) {
2124             IProgress *progress = NULL;
2125
2126             console->vtbl->SaveState(console, &progress);
2127
2128             if (progress) {
2129 #if VBOX_API_VERSION == 2002000
2130                 nsresult resultCode;
2131 #else
2132                 PRInt32 resultCode;
2133 #endif
2134
2135                 progress->vtbl->WaitForCompletion(progress, -1);
2136                 progress->vtbl->GetResultCode(progress, &resultCode);
2137                 if (NS_SUCCEEDED(resultCode)) {
2138                     ret = 0;
2139                 }
2140                 VBOX_RELEASE(progress);
2141             }
2142             VBOX_RELEASE(console);
2143         }
2144         VBOX_SESSION_CLOSE();
2145     }
2146
2147     DEBUGIID("UUID of machine being saved:", iid.value);
2148
2149     VBOX_RELEASE(machine);
2150     vboxIIDUnalloc(&iid);
2151     return ret;
2152 }
2153
2154 static int
2155 vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
2156                         unsigned int flags)
2157 {
2158     VBOX_OBJECT_CHECK(dom->conn, int, -1);
2159     IMachine *machine    = NULL;
2160     vboxIID iid = VBOX_IID_INITIALIZER;
2161     PRUint32  CPUCount   = nvcpus;
2162     nsresult rc;
2163
2164     if (flags != VIR_DOMAIN_AFFECT_LIVE) {
2165         virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2166         return -1;
2167     }
2168
2169     vboxIIDFromUUID(&iid, dom->uuid);
2170 #if VBOX_API_VERSION >= 4000000
2171     /* Get machine for the call to VBOX_SESSION_OPEN */
2172     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
2173     if (NS_FAILED(rc)) {
2174         virReportError(VIR_ERR_NO_DOMAIN, "%s",
2175                        _("no domain with matching uuid"));
2176         return -1;
2177     }
2178 #endif
2179
2180     rc = VBOX_SESSION_OPEN(iid.value, machine);
2181     if (NS_SUCCEEDED(rc)) {
2182         data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
2183         if (machine) {
2184             rc = machine->vtbl->SetCPUCount(machine, CPUCount);
2185             if (NS_SUCCEEDED(rc)) {
2186                 machine->vtbl->SaveSettings(machine);
2187                 ret = 0;
2188             } else {
2189                 virReportError(VIR_ERR_INTERNAL_ERROR,
2190                                _("could not set the number of cpus of the domain "
2191                                  "to: %u, rc=%08x"),
2192                                CPUCount, (unsigned)rc);
2193             }
2194             VBOX_RELEASE(machine);
2195         } else {
2196             virReportError(VIR_ERR_NO_DOMAIN,
2197                            _("no domain with matching id %d"), dom->id);
2198         }
2199     } else {
2200         virReportError(VIR_ERR_NO_DOMAIN,
2201                        _("can't open session to the domain with id %d"), dom->id);
2202     }
2203     VBOX_SESSION_CLOSE();
2204
2205     vboxIIDUnalloc(&iid);
2206     return ret;
2207 }
2208
2209 static int
2210 vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
2211 {
2212     return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2213 }
2214
2215 static int
2216 vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
2217 {
2218     VBOX_OBJECT_CHECK(dom->conn, int, -1);
2219     ISystemProperties *systemProperties = NULL;
2220     PRUint32 maxCPUCount = 0;
2221
2222     if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
2223         virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2224         return -1;
2225     }
2226
2227     /* Currently every domain supports the same number of max cpus
2228      * as that supported by vbox and thus take it directly from
2229      * the systemproperties.
2230      */
2231
2232     data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
2233     if (systemProperties) {
2234         systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
2235         VBOX_RELEASE(systemProperties);
2236     }
2237
2238     if (maxCPUCount > 0)
2239         ret = maxCPUCount;
2240
2241     return ret;
2242 }
2243
2244 static int
2245 vboxDomainGetMaxVcpus(virDomainPtr dom)
2246 {
2247     return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
2248                                          VIR_DOMAIN_VCPU_MAXIMUM));
2249 }
2250
2251 static void vboxHostDeviceGetXMLDesc(vboxGlobalData *data, virDomainDefPtr def, IMachine *machine)
2252 {
2253 #if VBOX_API_VERSION < 4003000
2254     IUSBController *USBController = NULL;
2255     PRBool enabled = PR_FALSE;
2256 #else
2257     IUSBDeviceFilters *USBDeviceFilters = NULL;
2258 #endif
2259     vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER;
2260     size_t i;
2261     PRUint32 USBFilterCount = 0;
2262
2263     def->nhostdevs = 0;
2264
2265 #if VBOX_API_VERSION < 4003000
2266     machine->vtbl->GetUSBController(machine, &USBController);
2267
2268     if (!USBController)
2269         return;
2270
2271     USBController->vtbl->GetEnabled(USBController, &enabled);
2272     if (!enabled)
2273         goto release_controller;
2274
2275     vboxArrayGet(&deviceFilters, USBController,
2276                  USBController->vtbl->GetDeviceFilters);
2277
2278 #else
2279     machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);
2280
2281     if (!USBDeviceFilters)
2282         return;
2283
2284     vboxArrayGet(&deviceFilters, USBDeviceFilters,
2285                  USBDeviceFilters->vtbl->GetDeviceFilters);
2286 #endif
2287
2288     if (deviceFilters.count <= 0)
2289         goto release_filters;
2290
2291     /* check if the filters are active and then only
2292      * alloc mem and set def->nhostdevs
2293      */
2294
2295     for (i = 0; i < deviceFilters.count; i++) {
2296         PRBool active = PR_FALSE;
2297         IUSBDeviceFilter *deviceFilter = deviceFilters.items[i];
2298
2299         deviceFilter->vtbl->GetActive(deviceFilter, &active);
2300         if (active) {
2301             def->nhostdevs++;
2302         }
2303     }
2304
2305     if (def->nhostdevs == 0)
2306         goto release_filters;
2307
2308     /* Alloc mem needed for the filters now */
2309     if (VIR_ALLOC_N(def->hostdevs, def->nhostdevs) < 0)
2310         goto release_filters;
2311
2312     for (i = 0; i < def->nhostdevs; i++) {
2313         def->hostdevs[i] = virDomainHostdevDefAlloc();
2314         if (!def->hostdevs[i])
2315             goto release_hostdevs;
2316     }
2317
2318     for (i = 0; i < deviceFilters.count; i++) {
2319         PRBool active                  = PR_FALSE;
2320         IUSBDeviceFilter *deviceFilter = deviceFilters.items[i];
2321         PRUnichar *vendorIdUtf16       = NULL;
2322         char *vendorIdUtf8             = NULL;
2323         unsigned vendorId              = 0;
2324         PRUnichar *productIdUtf16      = NULL;
2325         char *productIdUtf8            = NULL;
2326         unsigned productId             = 0;
2327         char *endptr                   = NULL;
2328
2329         deviceFilter->vtbl->GetActive(deviceFilter, &active);
2330         if (!active)
2331             continue;
2332
2333         def->hostdevs[USBFilterCount]->mode =
2334             VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
2335         def->hostdevs[USBFilterCount]->source.subsys.type =
2336             VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
2337
2338         deviceFilter->vtbl->GetVendorId(deviceFilter, &vendorIdUtf16);
2339         deviceFilter->vtbl->GetProductId(deviceFilter, &productIdUtf16);
2340
2341         VBOX_UTF16_TO_UTF8(vendorIdUtf16, &vendorIdUtf8);
2342         VBOX_UTF16_TO_UTF8(productIdUtf16, &productIdUtf8);
2343
2344         vendorId  = strtol(vendorIdUtf8, &endptr, 16);
2345         productId = strtol(productIdUtf8, &endptr, 16);
2346
2347         def->hostdevs[USBFilterCount]->source.subsys.u.usb.vendor  = vendorId;
2348         def->hostdevs[USBFilterCount]->source.subsys.u.usb.product = productId;
2349
2350         VBOX_UTF16_FREE(vendorIdUtf16);
2351         VBOX_UTF8_FREE(vendorIdUtf8);
2352
2353         VBOX_UTF16_FREE(productIdUtf16);
2354         VBOX_UTF8_FREE(productIdUtf8);
2355
2356         USBFilterCount++;
2357     }
2358
2359  release_filters:
2360     vboxArrayRelease(&deviceFilters);
2361 #if VBOX_API_VERSION < 4003000
2362  release_controller:
2363     VBOX_RELEASE(USBController);
2364 #else
2365     VBOX_RELEASE(USBDeviceFilters);
2366 #endif
2367
2368     return;
2369
2370  release_hostdevs:
2371     for (i = 0; i < def->nhostdevs; i++)
2372         virDomainHostdevDefFree(def->hostdevs[i]);
2373     VIR_FREE(def->hostdevs);
2374
2375     goto release_filters;
2376 }
2377
2378 static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
2379     VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
2380     virDomainDefPtr def  = NULL;
2381     IMachine *machine    = NULL;
2382     vboxIID iid = VBOX_IID_INITIALIZER;
2383     int gotAllABoutDef   = -1;
2384     nsresult rc;
2385
2386     /* Flags checked by virDomainDefFormat */
2387
2388     if (VIR_ALLOC(def) < 0)
2389         goto cleanup;
2390
2391     vboxIIDFromUUID(&iid, dom->uuid);
2392     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
2393     if (NS_SUCCEEDED(rc)) {
2394         PRBool accessible = PR_FALSE;
2395
2396         machine->vtbl->GetAccessible(machine, &accessible);
2397         if (accessible) {
2398             size_t i = 0;
2399             PRBool PAEEnabled                   = PR_FALSE;
2400             PRBool ACPIEnabled                  = PR_FALSE;
2401             PRBool IOAPICEnabled                = PR_FALSE;
2402             PRBool VRDxEnabled                  = PR_FALSE;
2403             PRUint32 CPUCount                   = 0;
2404             PRUint32 memorySize                 = 0;
2405             PRUint32 netAdpCnt                  = 0;
2406             PRUint32 netAdpIncCnt               = 0;
2407             PRUint32 maxMemorySize              = 4 * 1024;
2408             PRUint32 maxBootPosition            = 0;
2409             PRUint32 serialPortCount            = 0;
2410             PRUint32 serialPortIncCount         = 0;
2411             PRUint32 parallelPortCount          = 0;
2412             PRUint32 parallelPortIncCount       = 0;
2413             IBIOSSettings *bios                 = NULL;
2414 #if VBOX_API_VERSION < 3001000
2415             PRInt32       hddNum                = 0;
2416             IDVDDrive    *dvdDrive              = NULL;
2417             IHardDisk    *hardDiskPM            = NULL;
2418             IHardDisk    *hardDiskPS            = NULL;
2419             IHardDisk    *hardDiskSS            = NULL;
2420             const char   *hddBus                = "IDE";
2421             PRUnichar    *hddBusUtf16           = NULL;
2422             IFloppyDrive *floppyDrive           = NULL;
2423 #else  /* VBOX_API_VERSION >= 3001000 */
2424             vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
2425 #endif /* VBOX_API_VERSION >= 3001000 */
2426 #if VBOX_API_VERSION < 4000000
2427             IVRDPServer *VRDxServer             = NULL;
2428 #else  /* VBOX_API_VERSION >= 4000000 */
2429             IVRDEServer *VRDxServer             = NULL;
2430 #endif /* VBOX_API_VERSION >= 4000000 */
2431             IAudioAdapter *audioAdapter         = NULL;
2432 #if VBOX_API_VERSION >= 4001000
2433             PRUint32 chipsetType                = ChipsetType_Null;
2434 #endif /* VBOX_API_VERSION >= 4001000 */
2435             ISystemProperties *systemProperties = NULL;
2436
2437
2438             def->virtType = VIR_DOMAIN_VIRT_VBOX;
2439             def->id = dom->id;
2440             memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
2441             if (VIR_STRDUP(def->name, dom->name) < 0)
2442                 goto cleanup;
2443
2444             machine->vtbl->GetMemorySize(machine, &memorySize);
2445             def->mem.cur_balloon = memorySize * 1024;
2446
2447 #if VBOX_API_VERSION >= 4001000
2448             machine->vtbl->GetChipsetType(machine, &chipsetType);
2449 #endif /* VBOX_API_VERSION >= 4001000 */
2450
2451             data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
2452             if (systemProperties) {
2453                 systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
2454                 systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
2455 #if VBOX_API_VERSION < 4001000
2456                 systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt);
2457 #else  /* VBOX_API_VERSION >= 4000000 */
2458                 systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType, &netAdpCnt);
2459 #endif /* VBOX_API_VERSION >= 4000000 */
2460                 systemProperties->vtbl->GetSerialPortCount(systemProperties, &serialPortCount);
2461                 systemProperties->vtbl->GetParallelPortCount(systemProperties, &parallelPortCount);
2462                 VBOX_RELEASE(systemProperties);
2463                 systemProperties = NULL;
2464             }
2465             /* Currently setting memory and maxMemory as same, cause
2466              * the notation here seems to be inconsistent while
2467              * reading and while dumping xml
2468              */
2469             /* def->mem.max_balloon = maxMemorySize * 1024; */
2470             def->mem.max_balloon = memorySize * 1024;
2471
2472             machine->vtbl->GetCPUCount(machine, &CPUCount);
2473             def->maxvcpus = def->vcpus = CPUCount;
2474
2475             /* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */
2476
2477             if (VIR_STRDUP(def->os.type, "hvm") < 0)
2478                 goto cleanup;
2479
2480             def->os.arch = virArchFromHost();
2481
2482             def->os.nBootDevs = 0;
2483             for (i = 0; (i < VIR_DOMAIN_BOOT_LAST) && (i < maxBootPosition); i++) {
2484                 PRUint32 device = DeviceType_Null;
2485
2486                 machine->vtbl->GetBootOrder(machine, i+1, &device);
2487
2488                 if (device == DeviceType_Floppy) {
2489                     def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
2490                     def->os.nBootDevs++;
2491                 } else if (device == DeviceType_DVD) {
2492                     def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
2493                     def->os.nBootDevs++;
2494                 } else if (device == DeviceType_HardDisk) {
2495                     def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
2496                     def->os.nBootDevs++;
2497                 } else if (device == DeviceType_Network) {
2498                     def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
2499                     def->os.nBootDevs++;
2500                 } else if (device == DeviceType_USB) {
2501                     /* Not supported by libvirt yet */
2502                 } else if (device == DeviceType_SharedFolder) {
2503                     /* Not supported by libvirt yet */
2504                     /* Can VirtualBox really boot from a shared folder? */
2505                 }
2506             }
2507
2508 #if VBOX_API_VERSION < 3001000
2509             machine->vtbl->GetPAEEnabled(machine, &PAEEnabled);
2510 #elif VBOX_API_VERSION == 3001000
2511             machine->vtbl->GetCpuProperty(machine, CpuPropertyType_PAE, &PAEEnabled);
2512 #elif VBOX_API_VERSION >= 3002000
2513             machine->vtbl->GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled);
2514 #endif
2515             if (PAEEnabled)
2516                 def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_DOMAIN_FEATURE_STATE_ON;
2517
2518             machine->vtbl->GetBIOSSettings(machine, &bios);
2519             if (bios) {
2520                 bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled);
2521                 if (ACPIEnabled)
2522                     def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_DOMAIN_FEATURE_STATE_ON;
2523
2524                 bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled);
2525                 if (IOAPICEnabled)
2526                     def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_DOMAIN_FEATURE_STATE_ON;
2527
2528                 VBOX_RELEASE(bios);
2529             }
2530
2531             /* Currently VirtualBox always uses locatime
2532              * so locatime is always true here */
2533             def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
2534
2535             /* dump video options vram/2d/3d/directx/etc. */
2536             {
2537                 /* Currently supports only one graphics card */
2538                 def->nvideos = 1;
2539                 if (VIR_ALLOC_N(def->videos, def->nvideos) >= 0) {
2540                     if (VIR_ALLOC(def->videos[0]) >= 0) {
2541                         /* the default is: vram is 8MB, One monitor, 3dAccel Off */
2542                         PRUint32 VRAMSize          = 8;
2543                         PRUint32 monitorCount      = 1;
2544                         PRBool accelerate3DEnabled = PR_FALSE;
2545                         PRBool accelerate2DEnabled = PR_FALSE;
2546
2547                         machine->vtbl->GetVRAMSize(machine, &VRAMSize);
2548                         machine->vtbl->GetMonitorCount(machine, &monitorCount);
2549                         machine->vtbl->GetAccelerate3DEnabled(machine, &accelerate3DEnabled);
2550 #if VBOX_API_VERSION >= 3001000
2551                         machine->vtbl->GetAccelerate2DVideoEnabled(machine, &accelerate2DEnabled);
2552 #endif /* VBOX_API_VERSION >= 3001000 */
2553
2554                         def->videos[0]->type            = VIR_DOMAIN_VIDEO_TYPE_VBOX;
2555                         def->videos[0]->vram            = VRAMSize * 1024;
2556                         def->videos[0]->heads           = monitorCount;
2557                         if (VIR_ALLOC(def->videos[0]->accel) >= 0) {
2558                             def->videos[0]->accel->support3d = accelerate3DEnabled;
2559                             def->videos[0]->accel->support2d = accelerate2DEnabled;
2560                         }
2561                     }
2562                 }
2563             }
2564
2565             /* dump display options vrdp/gui/sdl */
2566             {
2567                 int vrdpPresent           = 0;
2568                 int sdlPresent            = 0;
2569                 int guiPresent            = 0;
2570                 int totalPresent          = 0;
2571                 char *guiDisplay          = NULL;
2572                 char *sdlDisplay          = NULL;
2573                 PRUnichar *keyTypeUtf16   = NULL;
2574                 PRUnichar *valueTypeUtf16 = NULL;
2575                 char      *valueTypeUtf8  = NULL;
2576
2577                 def->ngraphics = 0;
2578
2579                 VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
2580                 machine->vtbl->GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16);
2581                 VBOX_UTF16_FREE(keyTypeUtf16);
2582
2583                 if (valueTypeUtf16) {
2584                     VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
2585                     VBOX_UTF16_FREE(valueTypeUtf16);
2586
2587                     if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
2588                         PRUnichar *keyDislpayUtf16   = NULL;
2589                         PRUnichar *valueDisplayUtf16 = NULL;
2590                         char      *valueDisplayUtf8  = NULL;
2591
2592                         VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
2593                         machine->vtbl->GetExtraData(machine, keyDislpayUtf16, &valueDisplayUtf16);
2594                         VBOX_UTF16_FREE(keyDislpayUtf16);
2595
2596                         if (valueDisplayUtf16) {
2597                             VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
2598                             VBOX_UTF16_FREE(valueDisplayUtf16);
2599
2600                             if (strlen(valueDisplayUtf8) <= 0)
2601                                 VBOX_UTF8_FREE(valueDisplayUtf8);
2602                         }
2603
2604                         if (STREQ(valueTypeUtf8, "sdl")) {
2605                             sdlPresent = 1;
2606                             if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) {
2607                                 /* just don't go to cleanup yet as it is ok to have
2608                                  * sdlDisplay as NULL and we check it below if it
2609                                  * exist and then only use it there
2610                                  */
2611                             }
2612                             totalPresent++;
2613                         }
2614
2615                         if (STREQ(valueTypeUtf8, "gui")) {
2616                             guiPresent = 1;
2617                             if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) {
2618                                 /* just don't go to cleanup yet as it is ok to have
2619                                  * guiDisplay as NULL and we check it below if it
2620                                  * exist and then only use it there
2621                                  */
2622                             }
2623                             totalPresent++;
2624                         }
2625                         VBOX_UTF8_FREE(valueDisplayUtf8);
2626                     }
2627
2628                     if (STREQ(valueTypeUtf8, "vrdp"))
2629                         vrdpPresent = 1;
2630
2631                     VBOX_UTF8_FREE(valueTypeUtf8);
2632                 }
2633
2634                 if ((totalPresent > 0) && (VIR_ALLOC_N(def->graphics, totalPresent) >= 0)) {
2635                     if ((guiPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
2636                         def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
2637                         if (guiDisplay)
2638                             def->graphics[def->ngraphics]->data.desktop.display = guiDisplay;
2639                         def->ngraphics++;
2640                     }
2641
2642                     if ((sdlPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
2643                         def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
2644                         if (sdlDisplay)
2645                             def->graphics[def->ngraphics]->data.sdl.display = sdlDisplay;
2646                         def->ngraphics++;
2647                     }
2648                 } else if ((vrdpPresent != 1) && (totalPresent == 0) && (VIR_ALLOC_N(def->graphics, 1) >= 0)) {
2649                     if (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0) {
2650                         const char *tmp;
2651                         def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
2652                         tmp = virGetEnvBlockSUID("DISPLAY");
2653                         if (VIR_STRDUP(def->graphics[def->ngraphics]->data.desktop.display, tmp) < 0) {
2654                             /* just don't go to cleanup yet as it is ok to have
2655                              * display as NULL
2656                              */
2657                         }
2658                         totalPresent++;
2659                         def->ngraphics++;
2660                     }
2661                 }
2662
2663 #if VBOX_API_VERSION < 4000000
2664                 machine->vtbl->GetVRDPServer(machine, &VRDxServer);
2665 #else  /* VBOX_API_VERSION >= 4000000 */
2666                 machine->vtbl->GetVRDEServer(machine, &VRDxServer);
2667 #endif /* VBOX_API_VERSION >= 4000000 */
2668                 if (VRDxServer) {
2669                     VRDxServer->vtbl->GetEnabled(VRDxServer, &VRDxEnabled);
2670                     if (VRDxEnabled) {
2671
2672                         totalPresent++;
2673
2674                         if ((VIR_REALLOC_N(def->graphics, totalPresent) >= 0) &&
2675                             (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
2676                             PRUnichar *netAddressUtf16   = NULL;
2677                             char      *netAddressUtf8    = NULL;
2678                             PRBool allowMultiConnection  = PR_FALSE;
2679                             PRBool reuseSingleConnection = PR_FALSE;
2680 #if VBOX_API_VERSION < 3001000
2681                             PRUint32 VRDPport = 0;
2682                             VRDxServer->vtbl->GetPort(VRDxServer, &VRDPport);
2683                             if (VRDPport) {
2684                                 def->graphics[def->ngraphics]->data.rdp.port = VRDPport;
2685                             } else {
2686                                 def->graphics[def->ngraphics]->data.rdp.autoport = true;
2687                             }
2688 #elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */
2689                             PRUnichar *VRDPport = NULL;
2690                             VRDxServer->vtbl->GetPorts(VRDxServer, &VRDPport);
2691                             if (VRDPport) {
2692                                 /* even if vbox supports mutilpe ports, single port for now here */
2693                                 def->graphics[def->ngraphics]->data.rdp.port = PRUnicharToInt(VRDPport);
2694                                 VBOX_UTF16_FREE(VRDPport);
2695                             } else {
2696                                 def->graphics[def->ngraphics]->data.rdp.autoport = true;
2697                             }
2698 #else /* VBOX_API_VERSION >= 4000000 */
2699                             PRUnichar *VRDEPortsKey = NULL;
2700                             PRUnichar *VRDEPortsValue = NULL;
2701                             VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey);
2702                             VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDEPortsKey, &VRDEPortsValue);
2703                             VBOX_UTF16_FREE(VRDEPortsKey);
2704                             if (VRDEPortsValue) {
2705                                 /* even if vbox supports mutilpe ports, single port for now here */
2706                                 def->graphics[def->ngraphics]->data.rdp.port = PRUnicharToInt(VRDEPortsValue);
2707                                 VBOX_UTF16_FREE(VRDEPortsValue);
2708                             } else {
2709                                 def->graphics[def->ngraphics]->data.rdp.autoport = true;
2710                             }
2711 #endif /* VBOX_API_VERSION >= 4000000 */
2712
2713                             def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;
2714
2715 #if VBOX_API_VERSION >= 4000000
2716                             PRUnichar *VRDENetAddressKey = NULL;
2717                             VBOX_UTF8_TO_UTF16("TCP/Address", &VRDENetAddressKey);
2718                             VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDENetAddressKey, &netAddressUtf16);
2719                             VBOX_UTF16_FREE(VRDENetAddressKey);
2720 #else /* VBOX_API_VERSION < 4000000 */
2721                             VRDxServer->vtbl->GetNetAddress(VRDxServer, &netAddressUtf16);
2722 #endif /* VBOX_API_VERSION < 4000000 */
2723                             if (netAddressUtf16) {
2724                                 VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8);
2725                                 if (STRNEQ(netAddressUtf8, ""))
2726                                     virDomainGraphicsListenSetAddress(def->graphics[def->ngraphics], 0,
2727                                                                       netAddressUtf8, -1, true);
2728                                 VBOX_UTF16_FREE(netAddressUtf16);
2729                                 VBOX_UTF8_FREE(netAddressUtf8);
2730                             }
2731
2732                             VRDxServer->vtbl->GetAllowMultiConnection(VRDxServer, &allowMultiConnection);
2733                             if (allowMultiConnection) {
2734                                 def->graphics[def->ngraphics]->data.rdp.multiUser = true;
2735                             }
2736
2737                             VRDxServer->vtbl->GetReuseSingleConnection(VRDxServer, &reuseSingleConnection);
2738                             if (reuseSingleConnection) {
2739                                 def->graphics[def->ngraphics]->data.rdp.replaceUser = true;
2740                             }
2741
2742                             def->ngraphics++;
2743                         } else
2744                             virReportOOMError();
2745                     }
2746                     VBOX_RELEASE(VRDxServer);
2747                 }
2748             }
2749
2750 #if VBOX_API_VERSION < 3001000
2751             /* dump IDE hdds if present */
2752             VBOX_UTF8_TO_UTF16(hddBus, &hddBusUtf16);
2753
2754             def->ndisks = 0;
2755             machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 0,  &hardDiskPM);
2756             if (hardDiskPM)
2757                 def->ndisks++;
2758
2759             machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 1,  &hardDiskPS);
2760             if (hardDiskPS)
2761                 def->ndisks++;
2762
2763             machine->vtbl->GetHardDisk(machine, hddBusUtf16, 1, 1,  &hardDiskSS);
2764             if (hardDiskSS)
2765                 def->ndisks++;
2766
2767             VBOX_UTF16_FREE(hddBusUtf16);
2768
2769             if ((def->ndisks > 0) && (VIR_ALLOC_N(def->disks, def->ndisks) >= 0)) {
2770                 for (i = 0; i < def->ndisks; i++) {
2771                     if (VIR_ALLOC(def->disks[i]) >= 0) {
2772                         def->disks[i]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
2773                         def->disks[i]->bus = VIR_DOMAIN_DISK_BUS_IDE;
2774                         virDomainDiskSetType(def->disks[i],
2775                                              VIR_STORAGE_TYPE_FILE);
2776                     }
2777                 }
2778             }
2779
2780             if (hardDiskPM) {
2781                 PRUnichar *hddlocationUtf16 = NULL;
2782                 char *hddlocation           = NULL;
2783                 PRUint32 hddType            = HardDiskType_Normal;
2784
2785                 hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16);
2786                 VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2787
2788                 hardDiskPM->vtbl->GetType(hardDiskPM, &hddType);
2789
2790                 if (hddType == HardDiskType_Immutable)
2791                     def->disks[hddNum]->readonly = true;
2792                 ignore_value(virDomainDiskSetSource(def->disks[hddNum],
2793                                                     hddlocation));
2794                 ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hda"));
2795                 hddNum++;
2796
2797                 VBOX_UTF8_FREE(hddlocation);
2798                 VBOX_UTF16_FREE(hddlocationUtf16);
2799                 VBOX_MEDIUM_RELEASE(hardDiskPM);
2800             }
2801
2802             if (hardDiskPS) {
2803                 PRUnichar *hddlocationUtf16 = NULL;
2804                 char *hddlocation           = NULL;
2805                 PRUint32 hddType            = HardDiskType_Normal;
2806
2807                 hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16);
2808                 VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2809
2810                 hardDiskPS->vtbl->GetType(hardDiskPS, &hddType);
2811
2812                 if (hddType == HardDiskType_Immutable)
2813                     def->disks[hddNum]->readonly = true;
2814                 ignore_value(virDomainDiskSetSource(def->disks[hddNum],
2815                                                     hddlocation));
2816                 ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdb"));
2817                 hddNum++;
2818
2819                 VBOX_UTF8_FREE(hddlocation);
2820                 VBOX_UTF16_FREE(hddlocationUtf16);
2821                 VBOX_MEDIUM_RELEASE(hardDiskPS);
2822             }
2823
2824             if (hardDiskSS) {
2825                 PRUnichar *hddlocationUtf16 = NULL;
2826                 char *hddlocation           = NULL;
2827                 PRUint32 hddType            = HardDiskType_Normal;
2828
2829                 hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16);
2830                 VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2831
2832                 hardDiskSS->vtbl->GetType(hardDiskSS, &hddType);
2833
2834                 if (hddType == HardDiskType_Immutable)
2835                     def->disks[hddNum]->readonly = true;
2836                 ignore_value(virDomainDiskSetSource(def->disks[hddNum],
2837                                                     hddlocation));
2838                 ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdd"));
2839                 hddNum++;
2840
2841                 VBOX_UTF8_FREE(hddlocation);
2842                 VBOX_UTF16_FREE(hddlocationUtf16);
2843                 VBOX_MEDIUM_RELEASE(hardDiskSS);
2844             }
2845 #else  /* VBOX_API_VERSION >= 3001000 */
2846             /* dump IDE hdds if present */
2847
2848             bool error = false;
2849             int diskCount = 0;
2850             PRUint32   maxPortPerInst[StorageBus_Floppy + 1] = {};
2851             PRUint32   maxSlotPerPort[StorageBus_Floppy + 1] = {};
2852             def->ndisks = 0;
2853             vboxArrayGet(&mediumAttachments, machine, machine->vtbl->GetMediumAttachments);
2854
2855             /* get the number of attachments */
2856             for (i = 0; i < mediumAttachments.count; i++) {
2857                 IMediumAttachment *imediumattach = mediumAttachments.items[i];
2858                 if (imediumattach) {
2859                     IMedium *medium = NULL;
2860
2861                     imediumattach->vtbl->GetMedium(imediumattach, &medium);
2862                     if (medium) {
2863                         def->ndisks++;
2864                         VBOX_RELEASE(medium);
2865                     }
2866                 }
2867             }
2868
2869             /* Allocate mem, if fails return error */
2870             if (VIR_ALLOC_N(def->disks, def->ndisks) >= 0) {
2871                 for (i = 0; i < def->ndisks; i++) {
2872                     if (VIR_ALLOC(def->disks[i]) < 0) {
2873                         error = true;
2874                         break;
2875                     }
2876                 }
2877             } else {
2878                 error = true;
2879             }
2880
2881             if (!error)
2882                 error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort);
2883
2884             /* get the attachment details here */
2885             for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) {
2886                 IMediumAttachment *imediumattach = mediumAttachments.items[i];
2887                 IStorageController *storageController = NULL;
2888                 PRUnichar *storageControllerName = NULL;
2889                 PRUint32   deviceType     = DeviceType_Null;
2890                 PRUint32   storageBus     = StorageBus_Null;
2891                 PRBool     readOnly       = PR_FALSE;
2892                 IMedium   *medium         = NULL;
2893                 PRUnichar *mediumLocUtf16 = NULL;
2894                 char      *mediumLocUtf8  = NULL;
2895                 PRUint32   deviceInst     = 0;
2896                 PRInt32    devicePort     = 0;
2897                 PRInt32    deviceSlot     = 0;
2898
2899                 if (!imediumattach)
2900                     continue;
2901
2902                 imediumattach->vtbl->GetMedium(imediumattach, &medium);
2903                 if (!medium)
2904                     continue;
2905
2906                 imediumattach->vtbl->GetController(imediumattach, &storageControllerName);
2907                 if (!storageControllerName) {
2908                     VBOX_RELEASE(medium);
2909                     continue;
2910                 }
2911
2912                 machine->vtbl->GetStorageControllerByName(machine,
2913                                                           storageControllerName,
2914                                                           &storageController);
2915                 VBOX_UTF16_FREE(storageControllerName);
2916                 if (!storageController) {
2917                     VBOX_RELEASE(medium);
2918                     continue;
2919                 }
2920
2921                 medium->vtbl->GetLocation(medium, &mediumLocUtf16);
2922                 VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
2923                 VBOX_UTF16_FREE(mediumLocUtf16);
2924                 ignore_value(virDomainDiskSetSource(def->disks[diskCount],
2925                                                     mediumLocUtf8));
2926                 VBOX_UTF8_FREE(mediumLocUtf8);
2927
2928                 if (!virDomainDiskGetSource(def->disks[diskCount])) {
2929                     VBOX_RELEASE(medium);
2930                     VBOX_RELEASE(storageController);
2931                     error = true;
2932                     break;
2933                 }
2934
2935                 storageController->vtbl->GetBus(storageController, &storageBus);
2936                 if (storageBus == StorageBus_IDE) {
2937                     def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE;
2938                 } else if (storageBus == StorageBus_SATA) {
2939                     def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA;
2940                 } else if (storageBus == StorageBus_SCSI) {
2941                     def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI;
2942                 } else if (storageBus == StorageBus_Floppy) {
2943                     def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC;
2944                 }
2945
2946                 imediumattach->vtbl->GetType(imediumattach, &deviceType);
2947                 if (deviceType == DeviceType_HardDisk)
2948                     def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
2949                 else if (deviceType == DeviceType_Floppy)
2950                     def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
2951                 else if (deviceType == DeviceType_DVD)
2952                     def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
2953
2954                 imediumattach->vtbl->GetPort(imediumattach, &devicePort);
2955                 imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot);
2956                 def->disks[diskCount]->dst = vboxGenerateMediumName(storageBus,
2957                                                                     deviceInst,
2958                                                                     devicePort,
2959                                                                     deviceSlot,
2960                                                                     maxPortPerInst,
2961                                                                     maxSlotPerPort);
2962                 if (!def->disks[diskCount]->dst) {
2963                     virReportError(VIR_ERR_INTERNAL_ERROR,
2964                                    _("Could not generate medium name for the disk "
2965                                      "at: controller instance:%u, port:%d, slot:%d"),
2966                                    deviceInst, devicePort, deviceSlot);
2967                     VBOX_RELEASE(medium);
2968                     VBOX_RELEASE(storageController);
2969                     error = true;
2970                     break;
2971                 }
2972
2973                 medium->vtbl->GetReadOnly(medium, &readOnly);
2974                 if (readOnly == PR_TRUE)
2975                     def->disks[diskCount]->readonly = true;
2976
2977                 virDomainDiskSetType(def->disks[diskCount],
2978                                      VIR_STORAGE_TYPE_FILE);
2979
2980                 VBOX_RELEASE(medium);
2981                 VBOX_RELEASE(storageController);
2982                 diskCount++;
2983             }
2984
2985             vboxArrayRelease(&mediumAttachments);
2986
2987             /* cleanup on error */
2988             if (error) {
2989                 for (i = 0; i < def->ndisks; i++) {
2990                     VIR_FREE(def->disks[i]);
2991                 }
2992                 VIR_FREE(def->disks);
2993                 def->ndisks = 0;
2994             }
2995
2996 #endif /* VBOX_API_VERSION >= 3001000 */
2997
2998             /* shared folders */
2999             vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER;
3000
3001             def->nfss = 0;
3002
3003             vboxArrayGet(&sharedFolders, machine,
3004                          machine->vtbl->GetSharedFolders);
3005
3006             if (sharedFolders.count > 0) {
3007                 if (VIR_ALLOC_N(def->fss, sharedFolders.count) < 0)
3008                     goto sharedFoldersCleanup;
3009
3010                 for (i = 0; i < sharedFolders.count; i++) {
3011                     ISharedFolder *sharedFolder = sharedFolders.items[i];
3012                     PRUnichar *nameUtf16 = NULL;
3013                     char *name = NULL;
3014                     PRUnichar *hostPathUtf16 = NULL;
3015                     char *hostPath = NULL;
3016                     PRBool writable = PR_FALSE;
3017
3018                     if (VIR_ALLOC(def->fss[i]) < 0)
3019                         goto sharedFoldersCleanup;
3020
3021                     def->fss[i]->type = VIR_DOMAIN_FS_TYPE_MOUNT;
3022
3023                     sharedFolder->vtbl->GetHostPath(sharedFolder, &hostPathUtf16);
3024                     VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath);
3025                     if (VIR_STRDUP(def->fss[i]->src, hostPath) < 0) {
3026                         VBOX_UTF8_FREE(hostPath);
3027                         VBOX_UTF16_FREE(hostPathUtf16);
3028                         goto sharedFoldersCleanup;
3029                     }
3030                     VBOX_UTF8_FREE(hostPath);
3031                     VBOX_UTF16_FREE(hostPathUtf16);
3032
3033                     sharedFolder->vtbl->GetName(sharedFolder, &nameUtf16);
3034                     VBOX_UTF16_TO_UTF8(nameUtf16, &name);
3035                     if (VIR_STRDUP(def->fss[i]->dst, name) < 0) {
3036                         VBOX_UTF8_FREE(name);
3037                         VBOX_UTF16_FREE(nameUtf16);
3038                         goto sharedFoldersCleanup;
3039                     }
3040                     VBOX_UTF8_FREE(name);
3041                     VBOX_UTF16_FREE(nameUtf16);
3042
3043                     sharedFolder->vtbl->GetWritable(sharedFolder, &writable);
3044                     def->fss[i]->readonly = !writable;
3045
3046                     ++def->nfss;
3047                 }
3048             }
3049
3050  sharedFoldersCleanup:
3051             vboxArrayRelease(&sharedFolders);
3052
3053             /* dump network cards if present */
3054             def->nnets = 0;
3055             /* Get which network cards are enabled */
3056             for (i = 0; i < netAdpCnt; i++) {
3057                 INetworkAdapter *adapter = NULL;
3058
3059                 machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
3060                 if (adapter) {
3061                     PRBool enabled = PR_FALSE;
3062
3063                     adapter->vtbl->GetEnabled(adapter, &enabled);
3064                     if (enabled) {
3065                         def->nnets++;
3066                     }
3067
3068                     VBOX_RELEASE(adapter);
3069                 }
3070             }
3071
3072             /* Allocate memory for the networkcards which are enabled */
3073             if ((def->nnets > 0) && (VIR_ALLOC_N(def->nets, def->nnets) >= 0)) {
3074                 for (i = 0; i < def->nnets; i++) {
3075                     ignore_value(VIR_ALLOC(def->nets[i]));
3076                 }
3077             }
3078
3079             /* Now get the details about the network cards here */
3080             for (i = 0; netAdpIncCnt < def->nnets && i < netAdpCnt; i++) {
3081                 INetworkAdapter *adapter = NULL;
3082
3083                 machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
3084                 if (adapter) {
3085                     PRBool enabled = PR_FALSE;
3086
3087                     adapter->vtbl->GetEnabled(adapter, &enabled);
3088                     if (enabled) {
3089                         PRUint32 attachmentType    = NetworkAttachmentType_Null;
3090                         PRUint32 adapterType       = NetworkAdapterType_Null;
3091                         PRUnichar *MACAddressUtf16 = NULL;
3092                         char *MACAddress           = NULL;
3093                         char macaddr[VIR_MAC_STRING_BUFLEN] = {0};
3094
3095                         adapter->vtbl->GetAttachmentType(adapter, &attachmentType);
3096                         if (attachmentType == NetworkAttachmentType_NAT) {
3097
3098                             def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
3099
3100                         } else if (attachmentType == NetworkAttachmentType_Bridged) {
3101                             PRUnichar *hostIntUtf16 = NULL;
3102                             char *hostInt           = NULL;
3103
3104                             def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
3105
3106 #if VBOX_API_VERSION < 4001000
3107                             adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
3108 #else /* VBOX_API_VERSION >= 4001000 */
3109                             adapter->vtbl->GetBridgedInterface(adapter, &hostIntUtf16);
3110 #endif /* VBOX_API_VERSION >= 4001000 */
3111
3112                             VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
3113                             ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.bridge.brname, hostInt));
3114
3115                             VBOX_UTF8_FREE(hostInt);
3116                             VBOX_UTF16_FREE(hostIntUtf16);
3117
3118                         } else if (attachmentType == NetworkAttachmentType_Internal) {
3119                             PRUnichar *intNetUtf16 = NULL;
3120                             char *intNet           = NULL;
3121
3122                             def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL;
3123
3124                             adapter->vtbl->GetInternalNetwork(adapter, &intNetUtf16);
3125
3126                             VBOX_UTF16_TO_UTF8(intNetUtf16, &intNet);
3127                             ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.internal.name, intNet));
3128
3129                             VBOX_UTF8_FREE(intNet);
3130                             VBOX_UTF16_FREE(intNetUtf16);
3131
3132                         } else if (attachmentType == NetworkAttachmentType_HostOnly) {
3133                             PRUnichar *hostIntUtf16 = NULL;
3134                             char *hostInt           = NULL;
3135
3136                             def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_NETWORK;
3137
3138 #if VBOX_API_VERSION < 4001000
3139                             adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
3140 #else /* VBOX_API_VERSION >= 4001000 */
3141                             adapter->vtbl->GetHostOnlyInterface(adapter, &hostIntUtf16);
3142 #endif /* VBOX_API_VERSION >= 4001000 */
3143
3144                             VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
3145                             ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.network.name, hostInt));
3146
3147                             VBOX_UTF8_FREE(hostInt);
3148                             VBOX_UTF16_FREE(hostIntUtf16);
3149
3150                         } else {
3151                             /* default to user type i.e. NAT in VirtualBox if this
3152                              * dump is ever used to create a machine.
3153                              */
3154                             def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
3155                         }
3156
3157                         adapter->vtbl->GetAdapterType(adapter, &adapterType);
3158                         if (adapterType == NetworkAdapterType_Am79C970A) {
3159                             ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C970A"));
3160                         } else if (adapterType == NetworkAdapterType_Am79C973) {
3161                             ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C973"));
3162                         } else if (adapterType == NetworkAdapterType_I82540EM) {
3163                             ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82540EM"));
3164                         } else if (adapterType == NetworkAdapterType_I82545EM) {
3165                             ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82545EM"));
3166                         } else if (adapterType == NetworkAdapterType_I82543GC) {
3167                             ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82543GC"));
3168 #if VBOX_API_VERSION >= 3001000
3169                         } else if (adapterType == NetworkAdapterType_Virtio) {
3170                             ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "virtio"));
3171 #endif /* VBOX_API_VERSION >= 3001000 */
3172                         }
3173
3174                         adapter->vtbl->GetMACAddress(adapter, &MACAddressUtf16);
3175                         VBOX_UTF16_TO_UTF8(MACAddressUtf16, &MACAddress);
3176                         snprintf(macaddr, VIR_MAC_STRING_BUFLEN,
3177                                  "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
3178                                  MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3],
3179                                  MACAddress[4], MACAddress[5], MACAddress[6], MACAddress[7],
3180                                  MACAddress[8], MACAddress[9], MACAddress[10], MACAddress[11]);
3181
3182                         /* XXX some real error handling here some day ... */
3183                         if (virMacAddrParse(macaddr, &def->nets[netAdpIncCnt]->mac) < 0)
3184                         {}
3185
3186                         netAdpIncCnt++;
3187
3188                         VBOX_UTF16_FREE(MACAddressUtf16);
3189                         VBOX_UTF8_FREE(MACAddress);
3190                     }
3191
3192                     VBOX_RELEASE(adapter);
3193                 }
3194             }
3195
3196             /* dump sound card if active */
3197
3198             /* Set def->nsounds to one as VirtualBox currently supports
3199              * only one sound card
3200              */
3201
3202             machine->vtbl->GetAudioAdapter(machine, &audioAdapter);
3203             if (audioAdapter) {
3204                 PRBool enabled = PR_FALSE;
3205
3206                 audioAdapter->vtbl->GetEnabled(audioAdapter, &enabled);
3207                 if (enabled) {
3208                     PRUint32 audioController = AudioControllerType_AC97;
3209
3210                     def->nsounds = 1;
3211                     if (VIR_ALLOC_N(def->sounds, def->nsounds) >= 0) {
3212                         if (VIR_ALLOC(def->sounds[0]) >= 0) {
3213                             audioAdapter->vtbl->GetAudioController(audioAdapter, &audioController);
3214                             if (audioController == AudioControllerType_SB16) {
3215                                 def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_SB16;
3216                             } else if (audioController == AudioControllerType_AC97) {
3217                                 def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_AC97;
3218                             }
3219                         } else {
3220                             VIR_FREE(def->sounds);
3221                             def->nsounds = 0;
3222                         }
3223                     } else {
3224                         def->nsounds = 0;
3225                     }
3226                 }
3227                 VBOX_RELEASE(audioAdapter);
3228             }
3229
3230 #if VBOX_API_VERSION < 3001000
3231             /* dump CDROM/DVD if the drive is attached and has DVD/CD in it */
3232             machine->vtbl->GetDVDDrive(machine, &dvdDrive);
3233             if (dvdDrive) {
3234                 PRUint32 state = DriveState_Null;
3235
3236                 dvdDrive->vtbl->GetState(dvdDrive, &state);
3237                 if (state == DriveState_ImageMounted) {
3238                     IDVDImage *dvdImage = NULL;
3239
3240                     dvdDrive->vtbl->GetImage(dvdDrive, &dvdImage);
3241                     if (dvdImage) {
3242                         PRUnichar *locationUtf16 = NULL;
3243                         char *location           = NULL;
3244
3245                         dvdImage->vtbl->imedium.GetLocation((IMedium *)dvdImage, &locationUtf16);
3246                         VBOX_UTF16_TO_UTF8(locationUtf16, &location);
3247
3248                         def->ndisks++;
3249                         if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
3250                             if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
3251                                 def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
3252                                 def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_IDE;
3253                                 virDomainDiskSetType(def->disks[def->ndisks - 1],
3254                                                      VIR_STORAGE_TYPE_FILE);
3255                                 def->disks[def->ndisks - 1]->readonly = true;
3256                                 ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location));
3257                                 ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "hdc"));
3258                                 def->ndisks--;
3259                             } else {
3260                                 def->ndisks--;
3261                             }
3262                         } else {
3263                             def->ndisks--;
3264                         }
3265
3266                         VBOX_UTF8_FREE(location);
3267                         VBOX_UTF16_FREE(locationUtf16);
3268                         VBOX_MEDIUM_RELEASE(dvdImage);
3269                     }
3270                 }
3271                 VBOX_RELEASE(dvdDrive);
3272             }
3273
3274             /* dump Floppy if the drive is attached and has floppy in it */
3275             machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
3276             if (floppyDrive) {
3277                 PRBool enabled = PR_FALSE;
3278
3279                 floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled);
3280                 if (enabled) {
3281                     PRUint32 state = DriveState_Null;
3282
3283                     floppyDrive->vtbl->GetState(floppyDrive, &state);
3284                     if (state == DriveState_ImageMounted) {
3285                         IFloppyImage *floppyImage = NULL;
3286
3287                         floppyDrive->vtbl->GetImage(floppyDrive, &floppyImage);
3288                         if (floppyImage) {
3289                             PRUnichar *locationUtf16 = NULL;
3290                             char *location           = NULL;
3291
3292                             floppyImage->vtbl->imedium.GetLocation((IMedium *)floppyImage, &locationUtf16);
3293                             VBOX_UTF16_TO_UTF8(locationUtf16, &location);
3294
3295                             def->ndisks++;
3296                             if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
3297                                 if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
3298                                     def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
3299                                     def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC;
3300                                     virDomainDiskSetType(def->disks[def->ndisks - 1],
3301                                                          VIR_STORAGE_TYPE_FILE);
3302                                     def->disks[def->ndisks - 1]->readonly = false;
3303                                     ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location));
3304                                     ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "fda"));
3305                                     def->ndisks--;
3306                                 } else {
3307                                     def->ndisks--;
3308                                 }
3309                             } else {
3310                                 def->ndisks--;
3311                             }
3312
3313                             VBOX_UTF8_FREE(location);
3314                             VBOX_UTF16_FREE(locationUtf16);
3315                             VBOX_MEDIUM_RELEASE(floppyImage);
3316                         }
3317                     }
3318                 }
3319
3320                 VBOX_RELEASE(floppyDrive);
3321             }
3322 #else  /* VBOX_API_VERSION >= 3001000 */
3323 #endif /* VBOX_API_VERSION >= 3001000 */
3324
3325             /* dump serial port if active */
3326             def->nserials = 0;
3327             /* Get which serial ports are enabled/active */
3328             for (i = 0; i < serialPortCount; i++) {
3329                 ISerialPort *serialPort = NULL;
3330
3331                 machine->vtbl->GetSerialPort(machine, i, &serialPort);
3332                 if (serialPort) {
3333                     PRBool enabled = PR_FALSE;
3334
3335                     serialPort->vtbl->GetEnabled(serialPort, &enabled);
3336                     if (enabled) {
3337                         def->nserials++;
3338                     }
3339
3340                     VBOX_RELEASE(serialPort);
3341                 }
3342             }
3343
3344             /* Allocate memory for the serial ports which are enabled */
3345             if ((def->nserials > 0) && (VIR_ALLOC_N(def->serials, def->nserials) >= 0)) {
3346                 for (i = 0; i < def->nserials; i++) {
3347                     ignore_value(VIR_ALLOC(def->serials[i]));
3348                 }
3349             }
3350
3351             /* Now get the details about the serial ports here */
3352             for (i = 0;
3353                  serialPortIncCount < def->nserials && i < serialPortCount;
3354                  i++) {
3355                 ISerialPort *serialPort = NULL;
3356
3357                 machine->vtbl->GetSerialPort(machine, i, &serialPort);
3358                 if (serialPort) {
3359                     PRBool enabled = PR_FALSE;
3360
3361                     serialPort->vtbl->GetEnabled(serialPort, &enabled);
3362                     if (enabled) {
3363                         PRUint32 hostMode    = PortMode_Disconnected;
3364                         PRUint32 IOBase      = 0;
3365                         PRUint32 IRQ         = 0;
3366                         PRUnichar *pathUtf16 = NULL;
3367                         char *path           = NULL;
3368
3369                         serialPort->vtbl->GetHostMode(serialPort, &hostMode);
3370                         if (hostMode == PortMode_HostPipe) {
3371                             def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
3372                         } else if (hostMode == PortMode_HostDevice) {
3373                             def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
3374 #if VBOX_API_VERSION >= 3000000
3375                         } else if (hostMode == PortMode_RawFile) {
3376                             def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3377 #endif /* VBOX_API_VERSION >= 3000000 */
3378                         } else {
3379                             def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_NULL;
3380                         }
3381
3382                         def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
3383
3384                         serialPort->vtbl->GetIRQ(serialPort, &IRQ);
3385                         serialPort->vtbl->GetIOBase(serialPort, &IOBase);
3386                         if ((IRQ == 4) && (IOBase == 1016)) {
3387                             def->serials[serialPortIncCount]->target.port = 0;
3388                         } else if ((IRQ == 3) && (IOBase == 760)) {
3389                             def->serials[serialPortIncCount]->target.port = 1;
3390                         }
3391
3392                         serialPort->vtbl->GetPath(serialPort, &pathUtf16);
3393
3394                         if (pathUtf16) {
3395                             VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3396                             ignore_value(VIR_STRDUP(def->serials[serialPortIncCount]->source.data.file.path, path));
3397                         }
3398
3399                         serialPortIncCount++;
3400
3401                         VBOX_UTF16_FREE(pathUtf16);
3402                         VBOX_UTF8_FREE(path);
3403                     }
3404
3405                     VBOX_RELEASE(serialPort);
3406                 }
3407             }
3408
3409             /* dump parallel ports if active */
3410             def->nparallels = 0;
3411             /* Get which parallel ports are enabled/active */
3412             for (i = 0; i < parallelPortCount; i++) {
3413                 IParallelPort *parallelPort = NULL;
3414
3415                 machine->vtbl->GetParallelPort(machine, i, &parallelPort);
3416                 if (parallelPort) {
3417                     PRBool enabled = PR_FALSE;
3418
3419                     parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
3420                     if (enabled) {
3421                         def->nparallels++;
3422                     }
3423
3424                     VBOX_RELEASE(parallelPort);
3425                 }
3426             }
3427
3428             /* Allocate memory for the parallel ports which are enabled */
3429             if ((def->nparallels > 0) && (VIR_ALLOC_N(def->parallels, def->nparallels) >= 0)) {
3430                 for (i = 0; i < def->nparallels; i++) {
3431                     ignore_value(VIR_ALLOC(def->parallels[i]));
3432                 }
3433             }
3434
3435             /* Now get the details about the parallel ports here */
3436             for (i = 0;
3437                  parallelPortIncCount < def->nparallels &&
3438                      i < parallelPortCount;
3439                  i++) {
3440                 IParallelPort *parallelPort = NULL;
3441
3442                 machine->vtbl->GetParallelPort(machine, i, &parallelPort);
3443                 if (parallelPort) {
3444                     PRBool enabled = PR_FALSE;
3445
3446                     parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
3447                     if (enabled) {
3448                         PRUint32 IOBase      = 0;
3449                         PRUint32 IRQ         = 0;
3450                         PRUnichar *pathUtf16 = NULL;
3451                         char *path           = NULL;
3452
3453                         parallelPort->vtbl->GetIRQ(parallelPort, &IRQ);
3454                         parallelPort->vtbl->GetIOBase(parallelPort, &IOBase);
3455                         if ((IRQ == 7) && (IOBase == 888)) {
3456                             def->parallels[parallelPortIncCount]->target.port = 0;
3457                         } else if ((IRQ == 5) && (IOBase == 632)) {
3458                             def->parallels[parallelPortIncCount]->target.port = 1;
3459                         }
3460
3461                         def->parallels[parallelPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3462                         def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
3463
3464                         parallelPort->vtbl->GetPath(parallelPort, &pathUtf16);
3465
3466                         VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3467                         ignore_value(VIR_STRDUP(def->parallels[parallelPortIncCount]->source.data.file.path, path));
3468
3469                         parallelPortIncCount++;
3470
3471                         VBOX_UTF16_FREE(pathUtf16);
3472                         VBOX_UTF8_FREE(path);
3473                     }
3474
3475                     VBOX_RELEASE(parallelPort);
3476                 }
3477             }
3478
3479             /* dump USB devices/filters if active */
3480             vboxHostDeviceGetXMLDesc(data, def, machine);
3481
3482             /* all done so set gotAllABoutDef and pass def to virDomainDefFormat
3483              * to generate XML for it
3484              */
3485             gotAllABoutDef = 0;
3486         }
3487         VBOX_RELEASE(machine);
3488         machine = NULL;
3489     }
3490
3491     if (gotAllABoutDef == 0)
3492         ret = virDomainDefFormat(def, flags);
3493
3494  cleanup:
3495     vboxIIDUnalloc(&iid);
3496     virDomainDefFree(def);
3497     return ret;
3498 }
3499
3500 static int vboxConnectListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) {
3501     VBOX_OBJECT_CHECK(conn, int, -1);
3502     vboxArray machines = VBOX_ARRAY_INITIALIZER;
3503     char *machineName    = NULL;
3504     PRUnichar *machineNameUtf16 = NULL;
3505     PRUint32 state;
3506     nsresult rc;
3507     size_t i, j;
3508
3509     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3510     if (NS_FAILED(rc)) {
3511         virReportError(VIR_ERR_INTERNAL_ERROR,
3512                        _("Could not get list of Defined Domains, rc=%08x"),
3513                        (unsigned)rc);
3514         goto cleanup;
3515     }
3516
3517     memset(names, 0, sizeof(names[i]) * maxnames);
3518
3519     ret = 0;
3520     for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) {
3521         IMachine *machine = machines.items[i];
3522
3523         if (machine) {
3524             PRBool isAccessible = PR_FALSE;
3525             machine->vtbl->GetAccessible(machine, &isAccessible);
3526             if (isAccessible) {
3527                 machine->vtbl->GetState(machine, &state);
3528                 if ((state < MachineState_FirstOnline) ||
3529                     (state > MachineState_LastOnline)) {
3530                     machine->vtbl->GetName(machine, &machineNameUtf16);
3531                     VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
3532                     if (VIR_STRDUP(names[j], machineName) < 0) {
3533                         VBOX_UTF16_FREE(machineNameUtf16);
3534                         VBOX_UTF8_FREE(machineName);
3535                         for (j = 0; j < maxnames; j++)
3536                             VIR_FREE(names[j]);
3537                         ret = -1;
3538                         goto cleanup;
3539                     }
3540                     VBOX_UTF16_FREE(machineNameUtf16);
3541                     VBOX_UTF8_FREE(machineName);
3542                     j++;
3543                     ret++;
3544                 }
3545             }
3546         }
3547     }
3548
3549  cleanup:
3550     vboxArrayRelease(&machines);
3551     return ret;
3552 }
3553
3554 static int vboxConnectNumOfDefinedDomains(virConnectPtr conn)
3555 {
3556     VBOX_OBJECT_CHECK(conn, int, -1);
3557     vboxArray machines = VBOX_ARRAY_INITIALIZER;
3558     PRUint32 state       = MachineState_Null;
3559     nsresult rc;
3560     size_t i;
3561
3562     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3563     if (NS_FAILED(rc)) {
3564         virReportError(VIR_ERR_INTERNAL_ERROR,
3565                        _("Could not get number of Defined Domains, rc=%08x"),
3566                        (unsigned)rc);
3567         goto cleanup;
3568     }
3569
3570     ret = 0;
3571     for (i = 0; i < machines.count; ++i) {
3572         IMachine *machine = machines.items[i];
3573
3574         if (machine) {
3575             PRBool isAccessible = PR_FALSE;
3576             machine->vtbl->GetAccessible(machine, &isAccessible);
3577             if (isAccessible) {
3578                 machine->vtbl->GetState(machine, &state);
3579                 if ((state < MachineState_FirstOnline) ||
3580                     (state > MachineState_LastOnline)) {
3581                     ret++;
3582                 }
3583             }
3584         }
3585     }
3586
3587  cleanup:
3588     vboxArrayRelease(&machines);
3589     return ret;
3590 }
3591
3592
3593 static int
3594 vboxStartMachine(virDomainPtr dom, int maxDomID, IMachine *machine,
3595                  vboxIID *iid ATTRIBUTE_UNUSED /* >= 4.0 */)
3596 {
3597     VBOX_OBJECT_CHECK(dom->conn, int, -1);
3598     int vrdpPresent              = 0;
3599     int sdlPresent               = 0;
3600     int guiPresent               = 0;
3601     char *guiDisplay             = NULL;
3602     char *sdlDisplay             = NULL;
3603     PRUnichar *keyTypeUtf16      = NULL;
3604     PRUnichar *valueTypeUtf16    = NULL;
3605     char      *valueTypeUtf8     = NULL;
3606     PRUnichar *keyDislpayUtf16   = NULL;
3607     PRUnichar *valueDisplayUtf16 = NULL;
3608     char      *valueDisplayUtf8  = NULL;
3609     IProgress *progress          = NULL;
3610     PRUnichar *env               = NULL;
3611     PRUnichar *sessionType       = NULL;
3612     nsresult rc;
3613
3614     VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
3615     machine->vtbl->GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16);
3616     VBOX_UTF16_FREE(keyTypeUtf16);
3617
3618     if (valueTypeUtf16) {
3619         VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
3620         VBOX_UTF16_FREE(valueTypeUtf16);
3621
3622         if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
3623
3624             VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
3625             machine->vtbl->GetExtraData(machine, keyDislpayUtf16,
3626                                         &valueDisplayUtf16);
3627             VBOX_UTF16_FREE(keyDislpayUtf16);
3628
3629             if (valueDisplayUtf16) {
3630                 VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
3631                 VBOX_UTF16_FREE(valueDisplayUtf16);
3632
3633                 if (strlen(valueDisplayUtf8) <= 0)
3634                     VBOX_UTF8_FREE(valueDisplayUtf8);
3635             }
3636
3637             if (STREQ(valueTypeUtf8, "sdl")) {
3638                 sdlPresent = 1;
3639                 if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) {
3640                     /* just don't go to cleanup yet as it is ok to have
3641                      * sdlDisplay as NULL and we check it below if it
3642                      * exist and then only use it there
3643                      */
3644                 }
3645             }
3646
3647             if (STREQ(valueTypeUtf8, "gui")) {
3648                 guiPresent = 1;
3649                 if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) {
3650                     /* just don't go to cleanup yet as it is ok to have
3651                      * guiDisplay as NULL and we check it below if it
3652                      * exist and then only use it there
3653                      */
3654                 }
3655             }
3656         }
3657
3658         if (STREQ(valueTypeUtf8, "vrdp")) {
3659             vrdpPresent = 1;
3660         }
3661
3662         if (!vrdpPresent && !sdlPresent && !guiPresent) {
3663             /* if nothing is selected it means either the machine xml
3664              * file is really old or some values are missing so fallback
3665              */
3666             guiPresent = 1;
3667         }
3668
3669         VBOX_UTF8_FREE(valueTypeUtf8);
3670
3671     } else {
3672         guiPresent = 1;
3673     }
3674     VBOX_UTF8_FREE(valueDisplayUtf8);
3675
3676     if (guiPresent) {
3677         if (guiDisplay) {
3678             char *displayutf8;
3679             if (virAsprintf(&displayutf8, "DISPLAY=%s", guiDisplay) >= 0) {
3680                 VBOX_UTF8_TO_UTF16(displayutf8, &env);
3681                 VIR_FREE(displayutf8);
3682             }
3683             VIR_FREE(guiDisplay);
3684         }
3685
3686         VBOX_UTF8_TO_UTF16("gui", &sessionType);
3687     }
3688
3689     if (sdlPresent) {
3690         if (sdlDisplay) {
3691             char *displayutf8;
3692             if (virAsprintf(&displayutf8, "DISPLAY=%s", sdlDisplay) >= 0) {
3693                 VBOX_UTF8_TO_UTF16(displayutf8, &env);
3694                 VIR_FREE(displayutf8);
3695             }
3696             VIR_FREE(sdlDisplay);
3697         }
3698
3699         VBOX_UTF8_TO_UTF16("sdl", &sessionType);
3700     }
3701
3702     if (vrdpPresent) {
3703         VBOX_UTF8_TO_UTF16("vrdp", &sessionType);
3704     }
3705
3706 #if VBOX_API_VERSION < 4000000
3707     rc = data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj,
3708                                                 data->vboxSession,
3709                                                 iid->value,
3710                                                 sessionType,
3711                                                 env,
3712                                                 &progress);
3713 #else /* VBOX_API_VERSION >= 4000000 */
3714     rc = machine->vtbl->LaunchVMProcess(machine, data->vboxSession,
3715                                         sessionType, env, &progress);
3716 #endif /* VBOX_API_VERSION >= 4000000 */
3717
3718     if (NS_FAILED(rc)) {
3719         virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3720                        _("OpenRemoteSession/LaunchVMProcess failed, domain can't be started"));
3721         ret = -1;
3722     } else {
3723         PRBool completed = 0;
3724 #if VBOX_API_VERSION == 2002000
3725         nsresult resultCode;
3726 #else
3727         PRInt32  resultCode;
3728 #endif
3729         progress->vtbl->WaitForCompletion(progress, -1);
3730         rc = progress->vtbl->GetCompleted(progress, &completed);
3731         if (NS_FAILED(rc)) {
3732             /* error */
3733             ret = -1;
3734         }
3735         progress->vtbl->GetResultCode(progress, &resultCode);
3736         if (NS_FAILED(resultCode)) {
3737             /* error */
3738             ret = -1;
3739         } else {
3740             /* all ok set the domid */
3741             dom->id = maxDomID + 1;
3742             ret = 0;
3743         }
3744     }
3745
3746     VBOX_RELEASE(progress);
3747
3748     VBOX_SESSION_CLOSE();
3749
3750     VBOX_UTF16_FREE(env);
3751     VBOX_UTF16_FREE(sessionType);
3752
3753     return ret;
3754 }
3755
3756 static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
3757 {
3758     VBOX_OBJECT_CHECK(dom->conn, int, -1);
3759     vboxArray machines = VBOX_ARRAY_INITIALIZER;
3760     unsigned char uuid[VIR_UUID_BUFLEN] = {0};
3761     nsresult rc;
3762     size_t i = 0;
3763
3764     virCheckFlags(0, -1);
3765
3766     if (!dom->name) {
3767         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3768                        _("Error while reading the domain name"));
3769         goto cleanup;
3770     }
3771
3772     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3773     if (NS_FAILED(rc)) {
3774         virReportError(VIR_ERR_INTERNAL_ERROR,
3775                        _("Could not get list of machines, rc=%08x"), (unsigned)rc);
3776         goto cleanup;
3777     }
3778
3779     for (i = 0; i < machines.count; ++i) {
3780         IMachine *machine = machines.items[i];
3781         PRBool isAccessible = PR_FALSE;
3782
3783         if (!machine)
3784             continue;
3785
3786         machine->vtbl->GetAccessible(machine, &isAccessible);
3787         if (isAccessible) {
3788             vboxIID iid = VBOX_IID_INITIALIZER;
3789
3790             rc = machine->vtbl->GetId(machine, &iid.value);
3791             if (NS_FAILED(rc))
3792                 continue;
3793             vboxIIDToUUID(&iid, uuid);
3794
3795             if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
3796                 PRUint32 state = MachineState_Null;
3797                 machine->vtbl->GetState(machine, &state);
3798
3799                 if ((state == MachineState_PoweredOff) ||
3800                     (state == MachineState_Saved) ||
3801                     (state == MachineState_Aborted)) {
3802                     ret = vboxStartMachine(dom, i, machine, &iid);
3803                 } else {
3804                     virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3805                                    _("machine is not in "
3806                                      "poweroff|saved|aborted state, so "
3807                                      "couldn't start it"));
3808                     ret = -1;
3809                 }
3810             }
3811             vboxIIDUnalloc(&iid);
3812             if (ret != -1)
3813                 break;
3814         }
3815     }
3816
3817     /* Do the cleanup and take care you dont leak any memory */
3818     vboxArrayRelease(&machines);
3819
3820  cleanup:
3821     return ret;
3822 }
3823
3824 static int vboxDomainCreate(virDomainPtr dom)
3825 {
3826     return vboxDomainCreateWithFlags(dom, 0);
3827 }
3828
3829 static void
3830 vboxSetBootDeviceOrder(virDomainDefPtr def, vboxGlobalData *data,
3831                        IMachine *machine)
3832 {
3833     ISystemProperties *systemProperties = NULL;
3834     PRUint32 maxBootPosition            = 0;
3835     size_t i = 0;
3836
3837     VIR_DEBUG("def->os.type             %s", def->os.type);
3838     VIR_DEBUG("def->os.arch             %s", virArchToString(def->os.arch));
3839     VIR_DEBUG("def->os.machine          %s", def->os.machine);
3840     VIR_DEBUG("def->os.nBootDevs        %zu", def->os.nBootDevs);
3841     VIR_DEBUG("def->os.bootDevs[0]      %d", def->os.bootDevs[0]);
3842     VIR_DEBUG("def->os.bootDevs[1]      %d", def->os.bootDevs[1]);
3843     VIR_DEBUG("def->os.bootDevs[2]      %d", def->os.bootDevs[2]);
3844     VIR_DEBUG("def->os.bootDevs[3]      %d", def->os.bootDevs[3]);
3845     VIR_DEBUG("def->os.init             %s", def->os.init);
3846     VIR_DEBUG("def->os.kernel           %s", def->os.kernel);
3847     VIR_DEBUG("def->os.initrd           %s", def->os.initrd);
3848     VIR_DEBUG("def->os.cmdline          %s", def->os.cmdline);
3849     VIR_DEBUG("def->os.root             %s", def->os.root);
3850     VIR_DEBUG("def->os.loader           %s", def->os.loader);
3851     VIR_DEBUG("def->os.bootloader       %s", def->os.bootloader);
3852     VIR_DEBUG("def->os.bootloaderArgs   %s", def->os.bootloaderArgs);
3853
3854     data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
3855     if (systemProperties) {
3856         systemProperties->vtbl->GetMaxBootPosition(systemProperties,
3857                                                    &maxBootPosition);
3858         VBOX_RELEASE(systemProperties);
3859         systemProperties = NULL;
3860     }
3861
3862     /* Clear the defaults first */
3863     for (i = 0; i < maxBootPosition; i++) {
3864         machine->vtbl->SetBootOrder(machine, i+1, DeviceType_Null);
3865     }
3866
3867     for (i = 0; (i < def->os.nBootDevs) && (i < maxBootPosition); i++) {
3868         PRUint32 device = DeviceType_Null;
3869
3870         if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) {
3871             device = DeviceType_Floppy;
3872         } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) {
3873             device = DeviceType_DVD;
3874         } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_DISK) {
3875             device = DeviceType_HardDisk;
3876         } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_NET) {
3877             device = DeviceType_Network;
3878         }
3879         machine->vtbl->SetBootOrder(machine, i+1, device);
3880     }
3881 }
3882
3883 static void
3884 vboxAttachDrives(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
3885 {
3886     size_t i;
3887     nsresult rc;
3888
3889 #if VBOX_API_VERSION < 3001000
3890     if (def->ndisks == 0)
3891         return;
3892
3893     for (i = 0; i < def->ndisks; i++) {
3894         const char *src = virDomainDiskGetSource(def->disks[i]);
3895         int type = virDomainDiskGetType(def->disks[i]);
3896         int format = virDomainDiskGetFormat(def->disks[i]);
3897
3898         VIR_DEBUG("disk(%zu) type:       %d", i, type);
3899         VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
3900         VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
3901         VIR_DEBUG("disk(%zu) src:        %s", i, src);
3902         VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
3903         VIR_DEBUG("disk(%zu) driverName: %s", i,
3904                   virDomainDiskGetDriver(def->disks[i]));
3905         VIR_DEBUG("disk(%zu) driverType: %s", i,
3906                   virStorageFileFormatTypeToString(format));
3907         VIR_DEBUG("disk(%zu) cachemode:  %d", i, def->disks[i]->cachemode);
3908         VIR_DEBUG("disk(%zu) readonly:   %s", i, (def->disks[i]->readonly
3909                                              ? "True" : "False"));
3910         VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->shared
3911                                              ? "True" : "False"));
3912
3913         if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
3914             if (type == VIR_STORAGE_TYPE_FILE && src) {
3915                 IDVDDrive *dvdDrive = NULL;
3916                 /* Currently CDROM/DVD Drive is always IDE
3917                  * Secondary Master so neglecting the following
3918                  * parameters:
3919                  *      def->disks[i]->bus
3920                  *      def->disks[i]->dst
3921                  */
3922
3923                 machine->vtbl->GetDVDDrive(machine, &dvdDrive);
3924                 if (dvdDrive) {
3925                     IDVDImage *dvdImage          = NULL;
3926                     PRUnichar *dvdfileUtf16      = NULL;
3927                     vboxIID dvduuid = VBOX_IID_INITIALIZER;
3928                     vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
3929
3930                     VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
3931
3932                     data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
3933                                                       dvdfileUtf16, &dvdImage);
3934                     if (!dvdImage) {
3935                         data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
3936                                                           dvdfileUtf16,
3937                                                           dvdemptyuuid.value,
3938                                                           &dvdImage);
3939                     }
3940                     if (dvdImage) {
3941                         rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage,
3942                                                            &dvduuid.value);
3943                         if (NS_FAILED(rc)) {
3944                             virReportError(VIR_ERR_INTERNAL_ERROR,
3945                                            _("can't get the uuid of the file to "
3946                                              "be attached to cdrom: %s, rc=%08x"),
3947                                            src, (unsigned)rc);
3948                         } else {
3949                             rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
3950                             if (NS_FAILED(rc)) {
3951                                 virReportError(VIR_ERR_INTERNAL_ERROR,
3952                                                _("could not attach the file to cdrom: %s, rc=%08x"),
3953                                                src, (unsigned)rc);
3954                             } else {
3955                                 DEBUGIID("CD/DVDImage UUID:", dvduuid.value);
3956                             }
3957                         }
3958
3959                         VBOX_MEDIUM_RELEASE(dvdImage);
3960                     }
3961                     vboxIIDUnalloc(&dvduuid);
3962                     VBOX_UTF16_FREE(dvdfileUtf16);
3963                     VBOX_RELEASE(dvdDrive);
3964                 }
3965             } else if (type == VIR_STORAGE_TYPE_BLOCK) {
3966             }
3967         } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
3968             if (type == VIR_STORAGE_TYPE_FILE && src) {
3969                 IHardDisk *hardDisk     = NULL;
3970                 PRUnichar *hddfileUtf16 = NULL;
3971                 vboxIID hdduuid = VBOX_IID_INITIALIZER;
3972                 PRUnichar *hddEmpty     = NULL;
3973                 /* Current Limitation: Harddisk can't be connected to
3974                  * Secondary Master as Secondary Master is always used
3975                  * for CD/DVD Drive, so don't connect the harddisk if it
3976                  * is requested to be connected to Secondary master
3977                  */
3978
3979                 VBOX_UTF8_TO_UTF16(src, &hddfileUtf16);
3980                 VBOX_UTF8_TO_UTF16("", &hddEmpty);
3981
3982                 data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16,
3983                                                   &hardDisk);
3984
3985                 if (!hardDisk) {
3986 # if VBOX_API_VERSION == 2002000
3987                     data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
3988                                                       hddfileUtf16,
3989                                                       AccessMode_ReadWrite,
3990                                                       &hardDisk);
3991 # else
3992                     data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
3993                                                       hddfileUtf16,
3994                                                       AccessMode_ReadWrite,
3995                                                       0,
3996                                                       hddEmpty,
3997                                                       0,
3998                                                       hddEmpty,
3999                                                       &hardDisk);
4000 # endif
4001                 }
4002
4003                 if (hardDisk) {
4004                     rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk,
4005                                                        &hdduuid.value);
4006                     if (NS_FAILED(rc)) {
4007                         virReportError(VIR_ERR_INTERNAL_ERROR,
4008                                        _("can't get the uuid of the file to be "
4009                                          "attached as harddisk: %s, rc=%08x"),
4010                                        src, (unsigned)rc);
4011                     } else {
4012                         if (def->disks[i]->readonly) {
4013                             hardDisk->vtbl->SetType(hardDisk,
4014                                                     HardDiskType_Immutable);
4015                             VIR_DEBUG("setting harddisk to readonly");
4016                         } else if (!def->disks[i]->readonly) {
4017                             hardDisk->vtbl->SetType(hardDisk,
4018                                                     HardDiskType_Normal);
4019                             VIR_DEBUG("setting harddisk type to normal");
4020                         }
4021                         if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
4022                             if (STREQ(def->disks[i]->dst, "hdc")) {
4023                                 VIR_DEBUG("Not connecting harddisk to hdc as hdc"
4024                                        " is taken by CD/DVD Drive");
4025                             } else {
4026                                 PRInt32 channel          = 0;
4027                                 PRInt32 device           = 0;
4028                                 PRUnichar *hddcnameUtf16 = NULL;
4029
4030                                 char *hddcname;
4031                                 ignore_value(VIR_STRDUP(hddcname, "IDE"));
4032                                 VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16);
4033                                 VIR_FREE(hddcname);
4034
4035                                 if (STREQ(def->disks[i]->dst, "hda")) {
4036                                     channel = 0;
4037                                     device  = 0;
4038                                 } else if (STREQ(def->disks[i]->dst, "hdb")) {
4039                                     channel = 0;
4040                                     device  = 1;
4041                                 } else if (STREQ(def->disks[i]->dst, "hdd")) {
4042                                     channel = 1;
4043                                     device  = 1;
4044                                 }
4045
4046                                 rc = machine->vtbl->AttachHardDisk(machine,
4047                                                                    hdduuid.value,
4048                                                                    hddcnameUtf16,
4049                                                                    channel,
4050                                                                    device);
4051                                 VBOX_UTF16_FREE(hddcnameUtf16);
4052
4053                                 if (NS_FAILED(rc)) {
4054                                     virReportError(VIR_ERR_INTERNAL_ERROR,
4055                                                    _("could not attach the file as "
4056                                                      "harddisk: %s, rc=%08x"),
4057                                                    src, (unsigned)rc);
4058                                 } else {
4059                                     DEBUGIID("Attached HDD with UUID", hdduuid.value);
4060                                 }
4061                             }
4062                         }
4063                     }
4064                     VBOX_MEDIUM_RELEASE(hardDisk);
4065                 }
4066                 vboxIIDUnalloc(&hdduuid);
4067                 VBOX_UTF16_FREE(hddEmpty);
4068                 VBOX_UTF16_FREE(hddfileUtf16);
4069             } else if (type == VIR_STORAGE_TYPE_BLOCK) {
4070             }
4071         } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
4072             if (type == VIR_STORAGE_TYPE_FILE && src) {
4073                 IFloppyDrive *floppyDrive;
4074                 machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
4075                 if (floppyDrive) {
4076                     rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1);
4077                     if (NS_SUCCEEDED(rc)) {
4078                         IFloppyImage *floppyImage   = NULL;
4079                         PRUnichar *fdfileUtf16      = NULL;
4080                         vboxIID fduuid = VBOX_IID_INITIALIZER;
4081                         vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
4082
4083                         VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
4084                         rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
4085                                                                   fdfileUtf16,
4086                                                                   &floppyImage);
4087
4088                         if (!floppyImage) {
4089                             data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
4090                                                                  fdfileUtf16,
4091                                                                  fdemptyuuid.value,
4092                                                                  &floppyImage);
4093                         }
4094
4095                         if (floppyImage) {
4096                             rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage,
4097                                                                   &fduuid.value);
4098                             if (NS_FAILED(rc)) {
4099                                 virReportError(VIR_ERR_INTERNAL_ERROR,
4100                                                _("can't get the uuid of the file to "
4101                                                  "be attached to floppy drive: %s, rc=%08x"),
4102                                                src, (unsigned)rc);
4103                             } else {
4104                                 rc = floppyDrive->vtbl->MountImage(floppyDrive,
4105                                                                    fduuid.value);
4106                                 if (NS_FAILED(rc)) {
4107                                     virReportError(VIR_ERR_INTERNAL_ERROR,
4108                                                    _("could not attach the file to "
4109                                                      "floppy drive: %s, rc=%08x"),
4110                                                    src, (unsigned)rc);
4111                                 } else {
4112                                     DEBUGIID("floppyImage UUID", fduuid.value);
4113                                 }
4114                             }
4115                             VBOX_MEDIUM_RELEASE(floppyImage);
4116                         }
4117                         vboxIIDUnalloc(&fduuid);
4118                         VBOX_UTF16_FREE(fdfileUtf16);
4119                     }
4120                     VBOX_RELEASE(floppyDrive);
4121                 }
4122             } else if (type == VIR_STORAGE_TYPE_BLOCK) {
4123             }
4124         }
4125     }
4126 #else  /* VBOX_API_VERSION >= 3001000 */
4127     PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {};
4128     PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {};
4129     PRUnichar *storageCtlName = NULL;
4130     bool error = false;
4131
4132     /* get the max port/slots/etc for the given storage bus */
4133     error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst,
4134                                       maxSlotPerPort);
4135
4136     /* add a storage controller for the mediums to be attached */
4137     /* this needs to change when multiple controller are supported for
4138      * ver > 3.1 */
4139     {
4140         IStorageController *storageCtl = NULL;
4141         PRUnichar *sName = NULL;
4142
4143         VBOX_UTF8_TO_UTF16("IDE Controller", &sName);
4144         machine->vtbl->AddStorageController(machine,
4145                                             sName,
4146                                             StorageBus_IDE,
4147                                             &storageCtl);
4148         VBOX_UTF16_FREE(sName);
4149         VBOX_RELEASE(storageCtl);
4150
4151         VBOX_UTF8_TO_UTF16("SATA Controller", &sName);
4152         machine->vtbl->AddStorageController(machine,
4153                                             sName,
4154                                             StorageBus_SATA,
4155                                             &storageCtl);
4156         VBOX_UTF16_FREE(sName);
4157         VBOX_RELEASE(storageCtl);
4158
4159         VBOX_UTF8_TO_UTF16("SCSI Controller", &sName);
4160         machine->vtbl->AddStorageController(machine,
4161                                             sName,
4162                                             StorageBus_SCSI,
4163                                             &storageCtl);
4164         VBOX_UTF16_FREE(sName);
4165         VBOX_RELEASE(storageCtl);
4166
4167         VBOX_UTF8_TO_UTF16("Floppy Controller", &sName);
4168         machine->vtbl->AddStorageController(machine,
4169                                             sName,
4170                                             StorageBus_Floppy,
4171                                             &storageCtl);
4172         VBOX_UTF16_FREE(sName);
4173         VBOX_RELEASE(storageCtl);
4174     }
4175
4176     for (i = 0; i < def->ndisks && !error; i++) {
4177         const char *src = virDomainDiskGetSource(def->disks[i]);
4178         int type = virDomainDiskGetType(def->disks[i]);
4179         int format = virDomainDiskGetFormat(def->disks[i]);
4180
4181         VIR_DEBUG("disk(%zu) type:       %d", i, type);
4182         VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
4183         VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
4184         VIR_DEBUG("disk(%zu) src:        %s", i, src);
4185         VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
4186         VIR_DEBUG("disk(%zu) driverName: %s", i,
4187                   virDomainDiskGetDriver(def->disks[i]));
4188         VIR_DEBUG("disk(%zu) driverType: %s", i,
4189                   virStorageFileFormatTypeToString(format));
4190         VIR_DEBUG("disk(%zu) cachemode:  %d", i, def->disks[i]->cachemode);
4191         VIR_DEBUG("disk(%zu) readonly:   %s", i, (def->disks[i]->readonly
4192                                              ? "True" : "False"));
4193         VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->shared
4194                                              ? "True" : "False"));
4195
4196         if (type == VIR_STORAGE_TYPE_FILE && src) {
4197             IMedium   *medium          = NULL;
4198             PRUnichar *mediumUUID      = NULL;
4199             PRUnichar *mediumFileUtf16 = NULL;
4200             PRUint32   storageBus      = StorageBus_Null;
4201             PRUint32   deviceType      = DeviceType_Null;
4202 # if VBOX_API_VERSION >= 4000000
4203             PRUint32   accessMode      = AccessMode_ReadOnly;
4204 # endif
4205             PRInt32    deviceInst      = 0;
4206             PRInt32    devicePort      = 0;
4207             PRInt32    deviceSlot      = 0;
4208
4209             VBOX_UTF8_TO_UTF16(src, &mediumFileUtf16);
4210
4211             if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
4212                 deviceType = DeviceType_HardDisk;
4213 # if VBOX_API_VERSION < 4000000
4214                 data->vboxObj->vtbl->FindHardDisk(data->vboxObj,
4215                                                   mediumFileUtf16, &medium);
4216 # else
4217                 accessMode = AccessMode_ReadWrite;
4218 # endif
4219             } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
4220                 deviceType = DeviceType_DVD;
4221 # if VBOX_API_VERSION < 4000000
4222                 data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
4223                                                   mediumFileUtf16, &medium);
4224 # else
4225                 accessMode = AccessMode_ReadOnly;
4226 # endif
4227             } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
4228                 deviceType = DeviceType_Floppy;
4229 # if VBOX_API_VERSION < 4000000
4230                 data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
4231                                                      mediumFileUtf16, &medium);
4232 # else
4233                 accessMode = AccessMode_ReadWrite;
4234 # endif
4235             } else {
4236                 VBOX_UTF16_FREE(mediumFileUtf16);
4237                 continue;
4238             }
4239
4240 # if VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
4241             data->vboxObj->vtbl->FindMedium(data->vboxObj, mediumFileUtf16,
4242                                             deviceType, &medium);
4243 # elif VBOX_API_VERSION >= 4002000
4244             data->vboxObj->vtbl->OpenMedium(data->vboxObj, mediumFileUtf16,
4245                                             deviceType, accessMode, PR_FALSE, &medium);
4246 # endif
4247
4248             if (!medium) {
4249                 PRUnichar *mediumEmpty = NULL;
4250
4251                 VBOX_UTF8_TO_UTF16("", &mediumEmpty);
4252
4253 # if VBOX_API_VERSION < 4000000
4254                 if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
4255                     rc = data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
4256                                                            mediumFileUtf16,
4257                                                            AccessMode_ReadWrite,
4258                                                            false,
4259                                                            mediumEmpty,
4260                                                            false,
4261                                                            mediumEmpty,
4262                                                            &medium);
4263                 } else if (def->disks[i]->device ==
4264                            VIR_DOMAIN_DISK_DEVICE_CDROM) {
4265                     rc = data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
4266                                                            mediumFileUtf16,
4267                                                            mediumEmpty,
4268                                                            &medium);
4269                 } else if (def->disks[i]->device ==
4270                            VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
4271                     rc = data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
4272                                                               mediumFileUtf16,
4273                                                               mediumEmpty,
4274                                                               &medium);
4275                 } else {
4276                     rc = 0;
4277                 }
4278 # elif VBOX_API_VERSION == 4000000
4279                 rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
4280                                                      mediumFileUtf16,
4281                                                      deviceType, accessMode,
4282                                                      &medium);
4283 # elif VBOX_API_VERSION >= 4001000
4284                 rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
4285                                                      mediumFileUtf16,
4286                                                      deviceType, accessMode,
4287                                                      false,
4288                                                      &medium);
4289 # endif /* VBOX_API_VERSION >= 4001000 */
4290
4291                 VBOX_UTF16_FREE(mediumEmpty);
4292             }
4293
4294             if (!medium) {
4295                 virReportError(VIR_ERR_INTERNAL_ERROR,
4296                                _("Failed to attach the following disk/dvd/floppy "
4297                                  "to the machine: %s, rc=%08x"),
4298                                src, (unsigned)rc);
4299                 VBOX_UTF16_FREE(mediumFileUtf16);
4300                 continue;
4301             }
4302
4303             rc = medium->vtbl->GetId(medium, &mediumUUID);
4304             if (NS_FAILED(rc)) {
4305                 virReportError(VIR_ERR_INTERNAL_ERROR,
4306                                _("can't get the uuid of the file to be attached "
4307                                  "as harddisk/dvd/floppy: %s, rc=%08x"),
4308                                src, (unsigned)rc);
4309                 VBOX_RELEASE(medium);
4310                 VBOX_UTF16_FREE(mediumFileUtf16);
4311                 continue;
4312             }
4313
4314             if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
4315                 if (def->disks[i]->readonly) {
4316                     medium->vtbl->SetType(medium, MediumType_Immutable);
4317                     VIR_DEBUG("setting harddisk to immutable");
4318                 } else if (!def->disks[i]->readonly) {
4319                     medium->vtbl->SetType(medium, MediumType_Normal);
4320                     VIR_DEBUG("setting harddisk type to normal");
4321                 }
4322             }
4323
4324             if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
4325                 VBOX_UTF8_TO_UTF16("IDE Controller", &storageCtlName);
4326                 storageBus = StorageBus_IDE;
4327             } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_SATA) {
4328                 VBOX_UTF8_TO_UTF16("SATA Controller", &storageCtlName);
4329                 storageBus = StorageBus_SATA;
4330             } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
4331                 VBOX_UTF8_TO_UTF16("SCSI Controller", &storageCtlName);
4332                 storageBus = StorageBus_SCSI;
4333             } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_FDC) {
4334                 VBOX_UTF8_TO_UTF16("Floppy Controller", &storageCtlName);
4335                 storageBus = StorageBus_Floppy;
4336             }
4337
4338             /* get the device details i.e instance, port and slot */
4339             if (!vboxGetDeviceDetails(def->disks[i]->dst,
4340                                       maxPortPerInst,
4341                                       maxSlotPerPort,
4342                                       storageBus,
4343                                       &deviceInst,
4344                                       &devicePort,
4345                                       &deviceSlot)) {
4346                 virReportError(VIR_ERR_INTERNAL_ERROR,
4347                                _("can't get the port/slot number of "
4348                                  "harddisk/dvd/floppy to be attached: "
4349                                  "%s, rc=%08x"),
4350                                src, (unsigned)rc);
4351                 VBOX_RELEASE(medium);
4352                 VBOX_UTF16_FREE(mediumUUID);
4353                 VBOX_UTF16_FREE(mediumFileUtf16);
4354                 continue;
4355             }
4356
4357             /* attach the harddisk/dvd/Floppy to the storage controller */
4358             rc = machine->vtbl->AttachDevice(machine,
4359                                              storageCtlName,
4360                                              devicePort,
4361                                              deviceSlot,
4362                                              deviceType,
4363 # if VBOX_API_VERSION < 4000000
4364                                              mediumUUID);
4365 # else /* VBOX_API_VERSION >= 4000000 */
4366                                              medium);
4367 # endif /* VBOX_API_VERSION >= 4000000 */
4368
4369             if (NS_FAILED(rc)) {
4370                 virReportError(VIR_ERR_INTERNAL_ERROR,
4371                                _("could not attach the file as "
4372                                  "harddisk/dvd/floppy: %s, rc=%08x"),
4373                                src, (unsigned)rc);
4374             } else {
4375                 DEBUGIID("Attached HDD/DVD/Floppy with UUID", mediumUUID);
4376             }
4377
4378             VBOX_RELEASE(medium);
4379             VBOX_UTF16_FREE(mediumUUID);
4380             VBOX_UTF16_FREE(mediumFileUtf16);
4381             VBOX_UTF16_FREE(storageCtlName);
4382         }
4383     }
4384 #endif /* VBOX_API_VERSION >= 3001000 */
4385 }
4386
4387 static void
4388 vboxAttachSound(virDomainDefPtr def, IMachine *machine)
4389 {
4390     nsresult rc;
4391
4392     /* Check if def->nsounds is one as VirtualBox currently supports
4393      * only one sound card
4394      */
4395     if (def->nsounds == 1) {
4396         IAudioAdapter *audioAdapter = NULL;
4397
4398         machine->vtbl->GetAudioAdapter(machine, &audioAdapter);
4399         if (audioAdapter) {
4400             rc = audioAdapter->vtbl->SetEnabled(audioAdapter, 1);
4401             if (NS_SUCCEEDED(rc)) {
4402                 if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_SB16) {
4403                     audioAdapter->vtbl->SetAudioController(audioAdapter,
4404                                                            AudioControllerType_SB16);
4405                 } else if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_AC97) {
4406                     audioAdapter->vtbl->SetAudioController(audioAdapter,
4407                                                            AudioControllerType_AC97);
4408                 }
4409             }
4410             VBOX_RELEASE(audioAdapter);
4411         }
4412     }
4413 }
4414
4415 static void
4416 vboxAttachNetwork(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
4417 {
4418     ISystemProperties *systemProperties = NULL;
4419 #if VBOX_API_VERSION >= 4001000
4420     PRUint32 chipsetType                = ChipsetType_Null;
4421 #endif /* VBOX_API_VERSION >= 4001000 */
4422     PRUint32 networkAdapterCount        = 0;
4423     size_t i = 0;
4424
4425 #if VBOX_API_VERSION >= 4001000
4426     machine->vtbl->GetChipsetType(machine, &chipsetType);
4427 #endif /* VBOX_API_VERSION >= 4001000 */
4428
4429     data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
4430     if (systemProperties) {
4431 #if VBOX_API_VERSION < 4001000
4432         systemProperties->vtbl->GetNetworkAdapterCount(systemProperties,
4433                                                        &networkAdapterCount);
4434 #else  /* VBOX_API_VERSION >= 4000000 */
4435         systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType,
4436                                                       &networkAdapterCount);
4437 #endif /* VBOX_API_VERSION >= 4000000 */
4438         VBOX_RELEASE(systemProperties);
4439         systemProperties = NULL;
4440     }
4441
4442     VIR_DEBUG("Number of Network Cards to be connected: %zu", def->nnets);
4443     VIR_DEBUG("Number of Network Cards available: %d", networkAdapterCount);
4444
4445     for (i = 0; (i < def->nnets) && (i < networkAdapterCount); i++) {
4446         INetworkAdapter *adapter = NULL;
4447         PRUint32 adapterType     = NetworkAdapterType_Null;
4448         char macaddr[VIR_MAC_STRING_BUFLEN] = {0};
4449         char macaddrvbox[VIR_MAC_STRING_BUFLEN - 5] = {0};
4450
4451         virMacAddrFormat(&def->nets[i]->mac, macaddr);
4452         snprintf(macaddrvbox, VIR_MAC_STRING_BUFLEN - 5,
4453                  "%02X%02X%02X%02X%02X%02X",
4454                  def->nets[i]->mac.addr[0],
4455                  def->nets[i]->mac.addr[1],
4456                  def->nets[i]->mac.addr[2],
4457                  def->nets[i]->mac.addr[3],
4458                  def->nets[i]->mac.addr[4],
4459                  def->nets[i]->mac.addr[5]);
4460         macaddrvbox[VIR_MAC_STRING_BUFLEN - 6] = '\0';
4461
4462         VIR_DEBUG("NIC(%zu): Type:   %d", i, def->nets[i]->type);
4463         VIR_DEBUG("NIC(%zu): Model:  %s", i, def->nets[i]->model);
4464         VIR_DEBUG("NIC(%zu): Mac:    %s", i, macaddr);
4465         VIR_DEBUG("NIC(%zu): ifname: %s", i, def->nets[i]->ifname);
4466         if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4467             VIR_DEBUG("NIC(%zu): name:    %s", i, def->nets[i]->data.network.name);
4468         } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
4469             VIR_DEBUG("NIC(%zu): name:   %s", i, def->nets[i]->data.internal.name);
4470         } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
4471             VIR_DEBUG("NIC(%zu): NAT.", i);
4472         } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
4473             VIR_DEBUG("NIC(%zu): brname: %s", i, def->nets[i]->data.bridge.brname);
4474             VIR_DEBUG("NIC(%zu): script: %s", i, def->nets[i]->script);
4475             VIR_DEBUG("NIC(%zu): ipaddr: %s", i, def->nets[i]->data.bridge.ipaddr);
4476         }
4477
4478         machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
4479         if (adapter) {
4480             PRUnichar *MACAddress = NULL;
4481
4482             adapter->vtbl->SetEnabled(adapter, 1);
4483
4484             if (def->nets[i]->model) {
4485                 if (STRCASEEQ(def->nets[i]->model, "Am79C970A")) {
4486                     adapterType = NetworkAdapterType_Am79C970A;
4487                 } else if (STRCASEEQ(def->nets[i]->model, "Am79C973")) {
4488                     adapterType = NetworkAdapterType_Am79C973;
4489                 } else if (STRCASEEQ(def->nets[i]->model, "82540EM")) {
4490                     adapterType = NetworkAdapterType_I82540EM;
4491                 } else if (STRCASEEQ(def->nets[i]->model, "82545EM")) {
4492                     adapterType = NetworkAdapterType_I82545EM;
4493                 } else if (STRCASEEQ(def->nets[i]->model, "82543GC")) {
4494                     adapterType = NetworkAdapterType_I82543GC;
4495 #if VBOX_API_VERSION >= 3001000
4496                 } else if (STRCASEEQ(def->nets[i]->model, "virtio")) {
4497                     adapterType = NetworkAdapterType_Virtio;
4498 #endif /* VBOX_API_VERSION >= 3001000 */
4499                 }
4500             } else {
4501                 adapterType = NetworkAdapterType_Am79C973;
4502             }
4503
4504             adapter->vtbl->SetAdapterType(adapter, adapterType);
4505
4506             if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
4507                 PRUnichar *hostInterface = NULL;
4508                 /* Bridged Network */
4509
4510 #if VBOX_API_VERSION < 4001000
4511                 adapter->vtbl->AttachToBridgedInterface(adapter);
4512 #else /* VBOX_API_VERSION >= 4001000 */
4513                 adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Bridged);
4514 #endif /* VBOX_API_VERSION >= 4001000 */
4515
4516                 if (def->nets[i]->data.bridge.brname) {
4517                     VBOX_UTF8_TO_UTF16(def->nets[i]->data.bridge.brname,
4518                                        &hostInterface);
4519 #if VBOX_API_VERSION < 4001000
4520                     adapter->vtbl->SetHostInterface(adapter, hostInterface);
4521 #else /* VBOX_API_VERSION >= 4001000 */
4522                     adapter->vtbl->SetBridgedInterface(adapter, hostInterface);
4523 #endif /* VBOX_API_VERSION >= 4001000 */
4524                     VBOX_UTF16_FREE(hostInterface);
4525                 }
4526             } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
4527                 PRUnichar *internalNetwork = NULL;
4528                 /* Internal Network */
4529
4530 #if VBOX_API_VERSION < 4001000
4531                 adapter->vtbl->AttachToInternalNetwork(adapter);
4532 #else /* VBOX_API_VERSION >= 4001000 */
4533                 adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Internal);
4534 #endif /* VBOX_API_VERSION >= 4001000 */
4535
4536                 if (def->nets[i]->data.internal.name) {
4537                     VBOX_UTF8_TO_UTF16(def->nets[i]->data.internal.name,
4538                                        &internalNetwork);
4539                     adapter->vtbl->SetInternalNetwork(adapter, internalNetwork);
4540                     VBOX_UTF16_FREE(internalNetwork);
4541                 }
4542             } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4543                 PRUnichar *hostInterface = NULL;
4544                 /* Host Only Networking (currently only vboxnet0 available
4545                  * on *nix and mac, on windows you can create and configure
4546                  * as many as you want)
4547                  */
4548 #if VBOX_API_VERSION < 4001000
4549                 adapter->vtbl->AttachToHostOnlyInterface(adapter);
4550 #else /* VBOX_API_VERSION >= 4001000 */
4551                 adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_HostOnly);
4552 #endif /* VBOX_API_VERSION >= 4001000 */
4553
4554                 if (def->nets[i]->data.network.name) {
4555                     VBOX_UTF8_TO_UTF16(def->nets[i]->data.network.name,
4556                                        &hostInterface);
4557 #if VBOX_API_VERSION < 4001000
4558                     adapter->vtbl->SetHostInterface(adapter, hostInterface);
4559 #else /* VBOX_API_VERSION >= 4001000 */
4560                     adapter->vtbl->SetHostOnlyInterface(adapter, hostInterface);
4561 #endif /* VBOX_API_VERSION >= 4001000 */
4562                     VBOX_UTF16_FREE(hostInterface);
4563                 }
4564             } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
4565                 /* NAT */
4566 #if VBOX_API_VERSION < 4001000
4567                 adapter->vtbl->AttachToNAT(adapter);
4568 #else /* VBOX_API_VERSION >= 4001000 */
4569                 adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
4570 #endif /* VBOX_API_VERSION >= 4001000 */
4571             } else {
4572                 /* else always default to NAT if we don't understand
4573                  * what option is been passed to us
4574                  */
4575 #if VBOX_API_VERSION < 4001000
4576                 adapter->vtbl->AttachToNAT(adapter);
4577 #else /* VBOX_API_VERSION >= 4001000 */
4578                 adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
4579 #endif /* VBOX_API_VERSION >= 4001000 */
4580             }
4581
4582             VBOX_UTF8_TO_UTF16(macaddrvbox, &MACAddress);
4583             adapter->vtbl->SetMACAddress(adapter, MACAddress);
4584             VBOX_UTF16_FREE(MACAddress);
4585         }
4586     }
4587 }
4588
4589 static void
4590 vboxAttachSerial(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
4591 {
4592     ISystemProperties *systemProperties = NULL;
4593     PRUint32 serialPortCount            = 0;
4594     size_t i = 0;
4595
4596     data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
4597     if (systemProperties) {
4598         systemProperties->vtbl->GetSerialPortCount(systemProperties,
4599                                                    &serialPortCount);
4600         VBOX_RELEASE(systemProperties);
4601         systemProperties = NULL;
4602     }
4603
4604     VIR_DEBUG("Number of Serial Ports to be connected: %zu", def->nserials);
4605     VIR_DEBUG("Number of Serial Ports available: %d", serialPortCount);
4606     for (i = 0; (i < def->nserials) && (i < serialPortCount); i++) {
4607         ISerialPort *serialPort = NULL;
4608
4609         VIR_DEBUG("SerialPort(%zu): Type: %d", i, def->serials[i]->source.type);
4610         VIR_DEBUG("SerialPort(%zu): target.port: %d", i,
4611               def->serials[i]->target.port);
4612
4613         machine->vtbl->GetSerialPort(machine, i, &serialPort);
4614         if (serialPort) {
4615             PRUnichar *pathUtf16 = NULL;
4616
4617             serialPort->vtbl->SetEnabled(serialPort, 1);
4618
4619             if (def->serials[i]->source.data.file.path) {
4620                 VBOX_UTF8_TO_UTF16(def->serials[i]->source.data.file.path,
4621                                    &pathUtf16);
4622                 serialPort->vtbl->SetPath(serialPort, pathUtf16);
4623             }
4624
4625             /* For now hard code the serial ports to COM1 and COM2,
4626              * COM1 (Base Addr: 0x3F8 (decimal: 1016), IRQ: 4)
4627              * COM2 (Base Addr: 0x2F8 (decimal:  760), IRQ: 3)
4628              * TODO: make this more flexible
4629              */
4630             /* TODO: to improve the libvirt XMl handling so
4631              * that def->serials[i]->target.port shows real port
4632              * and not always start at 0
4633              */
4634             if (def->serials[i]->target.port == 0) {
4635                 serialPort->vtbl->SetIRQ(serialPort, 4);
4636                 serialPort->vtbl->SetIOBase(serialPort, 1016);
4637                 VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4638                       i, 4, 1016, def->serials[i]->source.data.file.path);
4639             } else if (def->serials[i]->target.port == 1) {
4640                 serialPort->vtbl->SetIRQ(serialPort, 3);
4641                 serialPort->vtbl->SetIOBase(serialPort, 760);
4642                 VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4643                       i, 3, 760, def->serials[i]->source.data.file.path);
4644             }
4645
4646             if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV) {
4647                 serialPort->vtbl->SetHostMode(serialPort, PortMode_HostDevice);
4648             } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE) {
4649                 serialPort->vtbl->SetHostMode(serialPort, PortMode_HostPipe);
4650 #if VBOX_API_VERSION >= 3000000
4651             } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE) {
4652                 serialPort->vtbl->SetHostMode(serialPort, PortMode_RawFile);
4653 #endif /* VBOX_API_VERSION >= 3000000 */
4654             } else {
4655                 serialPort->vtbl->SetHostMode(serialPort,
4656                                               PortMode_Disconnected);
4657             }
4658
4659             VBOX_RELEASE(serialPort);
4660             VBOX_UTF16_FREE(pathUtf16);
4661         }
4662     }
4663 }
4664
4665 static void
4666 vboxAttachParallel(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
4667 {
4668     ISystemProperties *systemProperties = NULL;
4669     PRUint32 parallelPortCount          = 0;
4670     size_t i = 0;
4671
4672     data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
4673     if (systemProperties) {
4674         systemProperties->vtbl->GetParallelPortCount(systemProperties,
4675                                                      &parallelPortCount);
4676         VBOX_RELEASE(systemProperties);
4677         systemProperties = NULL;
4678     }
4679
4680     VIR_DEBUG("Number of Parallel Ports to be connected: %zu", def->nparallels);
4681     VIR_DEBUG("Number of Parallel Ports available: %d", parallelPortCount);
4682     for (i = 0; (i < def->nparallels) && (i < parallelPortCount); i++) {
4683         IParallelPort *parallelPort = NULL;
4684
4685         VIR_DEBUG("ParallelPort(%zu): Type: %d", i, def->parallels[i]->source.type);
4686         VIR_DEBUG("ParallelPort(%zu): target.port: %d", i,
4687               def->parallels[i]->target.port);
4688
4689         machine->vtbl->GetParallelPort(machine, i, &parallelPort);
4690         if (parallelPort) {
4691             PRUnichar *pathUtf16 = NULL;
4692
4693             VBOX_UTF8_TO_UTF16(def->parallels[i]->source.data.file.path, &pathUtf16);
4694
4695             /* For now hard code the parallel ports to
4696              * LPT1 (Base Addr: 0x378 (decimal: 888), IRQ: 7)
4697              * LPT2 (Base Addr: 0x278 (decimal: 632), IRQ: 5)
4698              * TODO: make this more flexible
4699              */
4700             if ((def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV)  ||
4701                 (def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY)  ||
4702                 (def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE) ||
4703                 (def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE)) {
4704                 parallelPort->vtbl->SetPath(parallelPort, pathUtf16);
4705                 if (i == 0) {
4706                     parallelPort->vtbl->SetIRQ(parallelPort, 7);
4707                     parallelPort->vtbl->SetIOBase(parallelPort, 888);
4708                     VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4709                           i, 7, 888, def->parallels[i]->source.data.file.path);
4710                 } else if (i == 1) {
4711                     parallelPort->vtbl->SetIRQ(parallelPort, 5);
4712                     parallelPort->vtbl->SetIOBase(parallelPort, 632);
4713                     VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4714                           i, 5, 632, def->parallels[i]->source.data.file.path);
4715                 }
4716             }
4717
4718             /* like serial port, parallel port can't be enabled unless
4719              * correct IRQ and IOBase values are specified.
4720              */
4721             parallelPort->vtbl->SetEnabled(parallelPort, 1);
4722
4723             VBOX_RELEASE(parallelPort);
4724             VBOX_UTF16_FREE(pathUtf16);
4725         }
4726     }
4727 }
4728
4729 static void
4730 vboxAttachVideo(virDomainDefPtr def, IMachine *machine)
4731 {
4732     if ((def->nvideos == 1) &&
4733         (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_VBOX)) {
4734         machine->vtbl->SetVRAMSize(machine,
4735                                    VIR_DIV_UP(def->videos[0]->vram, 1024));
4736         machine->vtbl->SetMonitorCount(machine, def->videos[0]->heads);
4737         if (def->videos[0]->accel) {
4738             machine->vtbl->SetAccelerate3DEnabled(machine,
4739                                                   def->videos[0]->accel->support3d);
4740 #if VBOX_API_VERSION >= 3001000
4741             machine->vtbl->SetAccelerate2DVideoEnabled(machine,
4742                                                        def->videos[0]->accel->support2d);
4743 #endif /* VBOX_API_VERSION >= 3001000 */
4744         } else {
4745             machine->vtbl->SetAccelerate3DEnabled(machine, 0);
4746 #if VBOX_API_VERSION >= 3001000
4747             machine->vtbl->SetAccelerate2DVideoEnabled(machine, 0);
4748 #endif /* VBOX_API_VERSION >= 3001000 */
4749         }
4750     }
4751 }
4752
4753 static void
4754 vboxAttachDisplay(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
4755 {
4756     int vrdpPresent  = 0;
4757     int sdlPresent   = 0;
4758     int guiPresent   = 0;
4759     char *guiDisplay = NULL;
4760     char *sdlDisplay = NULL;
4761     size_t i = 0;
4762
4763     for (i = 0; i < def->ngraphics; i++) {
4764 #if VBOX_API_VERSION < 4000000
4765         IVRDPServer *VRDxServer = NULL;
4766 #else /* VBOX_API_VERSION >= 4000000 */
4767         IVRDEServer *VRDxServer = NULL;
4768 #endif /* VBOX_API_VERSION >= 4000000 */
4769
4770         if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) &&
4771             (vrdpPresent == 0)) {
4772
4773             vrdpPresent = 1;
4774 #if VBOX_API_VERSION < 4000000
4775             machine->vtbl->GetVRDPServer(machine, &VRDxServer);
4776 #else /* VBOX_API_VERSION >= 4000000 */
4777             machine->vtbl->GetVRDEServer(machine, &VRDxServer);
4778 #endif /* VBOX_API_VERSION >= 4000000 */
4779             if (VRDxServer) {
4780                 const char *listenAddr
4781                     = virDomainGraphicsListenGetAddress(def->graphics[i], 0);
4782
4783                 VRDxServer->vtbl->SetEnabled(VRDxServer, PR_TRUE);
4784                 VIR_DEBUG("VRDP Support turned ON.");
4785
4786 #if VBOX_API_VERSION < 3001000
4787                 if (def->graphics[i]->data.rdp.port) {
4788                     VRDxServer->vtbl->SetPort(VRDxServer,
4789                                               def->graphics[i]->data.rdp.port);
4790                     VIR_DEBUG("VRDP Port changed to: %d",
4791                           def->graphics[i]->data.rdp.port);
4792                 } else if (def->graphics[i]->data.rdp.autoport) {
4793                     /* Setting the port to 0 will reset its value to
4794                      * the default one which is 3389 currently
4795                      */
4796                     VRDxServer->vtbl->SetPort(VRDxServer, 0);
4797                     VIR_DEBUG("VRDP Port changed to default, which is 3389 currently");
4798                 }
4799 #elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */
4800                 PRUnichar *portUtf16 = NULL;
4801                 portUtf16 = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
4802                 VRDxServer->vtbl->SetPorts(VRDxServer, portUtf16);
4803                 VBOX_UTF16_FREE(portUtf16);
4804 #else /* VBOX_API_VERSION >= 4000000 */
4805                 PRUnichar *VRDEPortsKey = NULL;
4806                 PRUnichar *VRDEPortsValue = NULL;
4807                 VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey);
4808                 VRDEPortsValue = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
4809                 VRDxServer->vtbl->SetVRDEProperty(VRDxServer, VRDEPortsKey,
4810                                                   VRDEPortsValue);
4811                 VBOX_UTF16_FREE(VRDEPortsKey);
4812                 VBOX_UTF16_FREE(VRDEPortsValue);
4813 #endif /* VBOX_API_VERSION >= 4000000 */
4814
4815                 if (def->graphics[i]->data.rdp.replaceUser) {
4816                     VRDxServer->vtbl->SetReuseSingleConnection(VRDxServer,
4817                                                                PR_TRUE);
4818                     VIR_DEBUG("VRDP set to reuse single connection");
4819                 }
4820
4821                 if (def->graphics[i]->data.rdp.multiUser) {
4822                     VRDxServer->vtbl->SetAllowMultiConnection(VRDxServer,
4823                                                               PR_TRUE);
4824                     VIR_DEBUG("VRDP set to allow multiple connection");
4825                 }
4826
4827                 if (listenAddr) {
4828 #if VBOX_API_VERSION >= 4000000
4829                     PRUnichar *netAddressKey = NULL;
4830 #endif
4831                     PRUnichar *netAddressUtf16 = NULL;
4832
4833                     VBOX_UTF8_TO_UTF16(listenAddr, &netAddressUtf16);
4834 #if VBOX_API_VERSION < 4000000
4835                     VRDxServer->vtbl->SetNetAddress(VRDxServer,
4836                                                     netAddressUtf16);
4837 #else /* VBOX_API_VERSION >= 4000000 */
4838                     VBOX_UTF8_TO_UTF16("TCP/Address", &netAddressKey);
4839                     VRDxServer->vtbl->SetVRDEProperty(VRDxServer, netAddressKey,
4840                                                       netAddressUtf16);
4841                     VBOX_UTF16_FREE(netAddressKey);
4842 #endif /* VBOX_API_VERSION >= 4000000 */
4843                     VIR_DEBUG("VRDP listen address is set to: %s",
4844                               listenAddr);
4845
4846                     VBOX_UTF16_FREE(netAddressUtf16);
4847                 }
4848
4849                 VBOX_RELEASE(VRDxServer);
4850             }
4851         }
4852
4853         if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) &&
4854             (guiPresent == 0)) {
4855             guiPresent = 1;
4856             if (VIR_STRDUP(guiDisplay, def->graphics[i]->data.desktop.display) < 0) {
4857                 /* just don't go to cleanup yet as it is ok to have
4858                  * guiDisplay as NULL and we check it below if it
4859                  * exist and then only use it there
4860                  */
4861             }
4862         }
4863
4864         if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) &&
4865             (sdlPresent == 0)) {
4866             sdlPresent = 1;
4867             if (VIR_STRDUP(sdlDisplay, def->graphics[i]->data.sdl.display) < 0) {
4868                 /* just don't go to cleanup yet as it is ok to have
4869                  * sdlDisplay as NULL and we check it below if it
4870                  * exist and then only use it there
4871                  */
4872             }
4873         }
4874     }
4875
4876     if ((vrdpPresent == 1) && (guiPresent == 0) && (sdlPresent == 0)) {
4877         /* store extradata key that frontend is set to vrdp */
4878         PRUnichar *keyTypeUtf16   = NULL;
4879         PRUnichar *valueTypeUtf16 = NULL;
4880
4881         VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
4882         VBOX_UTF8_TO_UTF16("vrdp", &valueTypeUtf16);
4883
4884         machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
4885
4886         VBOX_UTF16_FREE(keyTypeUtf16);
4887         VBOX_UTF16_FREE(valueTypeUtf16);
4888
4889     } else if ((guiPresent == 0) && (sdlPresent == 1)) {
4890         /* store extradata key that frontend is set to sdl */
4891         PRUnichar *keyTypeUtf16      = NULL;
4892         PRUnichar *valueTypeUtf16    = NULL;
4893         PRUnichar *keyDislpayUtf16   = NULL;
4894         PRUnichar *valueDisplayUtf16 = NULL;
4895
4896         VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
4897         VBOX_UTF8_TO_UTF16("sdl", &valueTypeUtf16);
4898
4899         machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
4900
4901         VBOX_UTF16_FREE(keyTypeUtf16);
4902         VBOX_UTF16_FREE(valueTypeUtf16);
4903
4904         if (sdlDisplay) {
4905             VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
4906             VBOX_UTF8_TO_UTF16(sdlDisplay, &valueDisplayUtf16);
4907
4908             machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
4909                                         valueDisplayUtf16);
4910
4911             VBOX_UTF16_FREE(keyDislpayUtf16);
4912             VBOX_UTF16_FREE(valueDisplayUtf16);
4913         }
4914
4915     } else {
4916         /* if all are set then default is gui, with vrdp turned on */
4917         PRUnichar *keyTypeUtf16      = NULL;
4918         PRUnichar *valueTypeUtf16    = NULL;
4919         PRUnichar *keyDislpayUtf16   = NULL;
4920         PRUnichar *valueDisplayUtf16 = NULL;
4921
4922         VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
4923         VBOX_UTF8_TO_UTF16("gui", &valueTypeUtf16);
4924
4925         machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
4926
4927         VBOX_UTF16_FREE(keyTypeUtf16);
4928         VBOX_UTF16_FREE(valueTypeUtf16);
4929
4930         if (guiDisplay) {
4931             VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
4932             VBOX_UTF8_TO_UTF16(guiDisplay, &valueDisplayUtf16);
4933
4934             machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
4935                                         valueDisplayUtf16);
4936
4937             VBOX_UTF16_FREE(keyDislpayUtf16);
4938             VBOX_UTF16_FREE(valueDisplayUtf16);
4939         }
4940     }
4941
4942     VIR_FREE(guiDisplay);
4943     VIR_FREE(sdlDisplay);
4944 }
4945
4946 static void
4947 vboxAttachUSB(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
4948 {
4949 #if VBOX_API_VERSION < 4003000
4950     IUSBController *USBController = NULL;
4951 #else
4952     IUSBDeviceFilters *USBDeviceFilters = NULL;
4953 #endif
4954     size_t i = 0;
4955     bool isUSB = false;
4956
4957     if (def->nhostdevs == 0)
4958         return;
4959
4960     /* Loop through the devices first and see if you
4961      * have a USB Device, only if you have one then
4962      * start the USB controller else just proceed as
4963      * usual
4964      */
4965     for (i = 0; i < def->nhostdevs; i++) {
4966         if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
4967             continue;
4968
4969         if (def->hostdevs[i]->source.subsys.type !=
4970             VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
4971             continue;
4972
4973         if (!def->hostdevs[i]->source.subsys.u.usb.vendor &&
4974             !def->hostdevs[i]->source.subsys.u.usb.product)
4975             continue;
4976
4977         VIR_DEBUG("USB Device detected, VendorId:0x%x, ProductId:0x%x",
4978                   def->hostdevs[i]->source.subsys.u.usb.vendor,
4979                   def->hostdevs[i]->source.subsys.u.usb.product);
4980         isUSB = true;
4981         break;
4982     }
4983
4984     if (!isUSB)
4985         return;
4986
4987 #if VBOX_API_VERSION < 4003000
4988     /* First Start the USB Controller and then loop
4989      * to attach USB Devices to it
4990      */
4991     machine->vtbl->GetUSBController(machine, &USBController);
4992
4993     if (!USBController)
4994         return;
4995
4996     USBController->vtbl->SetEnabled(USBController, 1);
4997 # if VBOX_API_VERSION < 4002000
4998     USBController->vtbl->SetEnabledEhci(USBController, 1);
4999 # else
5000     USBController->vtbl->SetEnabledEHCI(USBController, 1);
5001 # endif
5002 #else
5003     machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);
5004
5005     if (!USBDeviceFilters)
5006         return;
5007 #endif
5008
5009     for (i = 0; i < def->nhostdevs; i++) {
5010         char *filtername           = NULL;
5011         PRUnichar *filternameUtf16 = NULL;
5012         IUSBDeviceFilter *filter   = NULL;
5013         PRUnichar *vendorIdUtf16  = NULL;
5014         char vendorId[40]         = {0};
5015         PRUnichar *productIdUtf16 = NULL;
5016         char productId[40]        = {0};
5017
5018         if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
5019             continue;
5020
5021         if (def->hostdevs[i]->source.subsys.type !=
5022             VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
5023             continue;
5024
5025         /* Zero pad for nice alignment when fewer than 9999
5026          * devices.
5027          */
5028         if (virAsprintf(&filtername, "filter%04zu", i) >= 0) {
5029             VBOX_UTF8_TO_UTF16(filtername, &filternameUtf16);
5030             VIR_FREE(filtername);
5031 #if VBOX_API_VERSION < 4003000
5032             USBController->vtbl->CreateDeviceFilter(USBController,
5033                                                     filternameUtf16,
5034                                                     &filter);
5035 #else
5036             USBDeviceFilters->vtbl->CreateDeviceFilter(USBDeviceFilters,
5037                                                        filternameUtf16,
5038                                                        &filter);
5039 #endif
5040         }
5041         VBOX_UTF16_FREE(filternameUtf16);
5042
5043         if (!filter)
5044             continue;
5045
5046         if (!def->hostdevs[i]->source.subsys.u.usb.vendor &&
5047             !def->hostdevs[i]->source.subsys.u.usb.product)
5048             continue;
5049
5050         if (def->hostdevs[i]->source.subsys.u.usb.vendor) {
5051             snprintf(vendorId, sizeof(vendorId), "%x",
5052                      def->hostdevs[i]->source.subsys.u.usb.vendor);
5053             VBOX_UTF8_TO_UTF16(vendorId, &vendorIdUtf16);
5054             filter->vtbl->SetVendorId(filter, vendorIdUtf16);
5055             VBOX_UTF16_FREE(vendorIdUtf16);
5056         }
5057         if (def->hostdevs[i]->source.subsys.u.usb.product) {
5058             snprintf(productId, sizeof(productId), "%x",
5059                      def->hostdevs[i]->source.subsys.u.usb.product);
5060             VBOX_UTF8_TO_UTF16(productId, &productIdUtf16);
5061             filter->vtbl->SetProductId(filter,
5062                                        productIdUtf16);
5063             VBOX_UTF16_FREE(productIdUtf16);
5064         }
5065         filter->vtbl->SetActive(filter, 1);
5066 #if VBOX_API_VERSION < 4003000
5067         USBController->vtbl->InsertDeviceFilter(USBController,
5068                                                 i,
5069                                                 filter);
5070 #else
5071         USBDeviceFilters->vtbl->InsertDeviceFilter(USBDeviceFilters,
5072                                                    i,
5073                                                    filter);
5074 #endif
5075         VBOX_RELEASE(filter);
5076     }
5077
5078 #if VBOX_API_VERSION < 4003000
5079     VBOX_RELEASE(USBController);
5080 #else
5081     VBOX_RELEASE(USBDeviceFilters);
5082 #endif
5083 }
5084
5085 static void
5086 vboxAttachSharedFolder(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
5087 {
5088     size_t i;
5089     PRUnichar *nameUtf16;
5090     PRUnichar *hostPathUtf16;
5091     PRBool writable;
5092
5093     if (def->nfss == 0)
5094         return;
5095
5096     for (i = 0; i < def->nfss; i++) {
5097         if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
5098             continue;
5099
5100         VBOX_UTF8_TO_UTF16(def->fss[i]->dst, &nameUtf16);
5101         VBOX_UTF8_TO_UTF16(def->fss[i]->src, &hostPathUtf16);
5102         writable = !def->fss[i]->readonly;
5103
5104 #if VBOX_API_VERSION < 4000000
5105         machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
5106                                           writable);
5107 #else /* VBOX_API_VERSION >= 4000000 */
5108         machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
5109                                           writable, PR_FALSE);
5110 #endif /* VBOX_API_VERSION >= 4000000 */
5111
5112         VBOX_UTF16_FREE(nameUtf16);
5113         VBOX_UTF16_FREE(hostPathUtf16);
5114     }
5115 }
5116
5117 static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml)
5118 {
5119     VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
5120     IMachine       *machine     = NULL;
5121     IBIOSSettings  *bios        = NULL;
5122     vboxIID iid = VBOX_IID_INITIALIZER;
5123     vboxIID mchiid = VBOX_IID_INITIALIZER;
5124     virDomainDefPtr def         = NULL;
5125     PRUnichar *machineNameUtf16 = NULL;
5126 #if VBOX_API_VERSION >= 3002000 && VBOX_API_VERSION < 4002000
5127     PRBool override             = PR_FALSE;
5128 #endif
5129     nsresult rc;
5130     char uuidstr[VIR_UUID_STRING_BUFLEN];
5131 #if VBOX_API_VERSION >= 4002000
5132     const char *flagsUUIDPrefix = "UUID=";
5133     const char *flagsForceOverwrite = "forceOverwrite=0";
5134     const char *flagsSeparator = ",";
5135     char createFlags[strlen(flagsUUIDPrefix) + VIR_UUID_STRING_BUFLEN + strlen(flagsSeparator) + strlen(flagsForceOverwrite) + 1];
5136     PRUnichar *createFlagsUtf16 = NULL;
5137 #endif
5138
5139     if (!(def = virDomainDefParseString(xml, data->caps, data->xmlopt,
5140                                         1 << VIR_DOMAIN_VIRT_VBOX,
5141                                         VIR_DOMAIN_XML_INACTIVE))) {
5142         goto cleanup;
5143     }
5144
5145     VBOX_UTF8_TO_UTF16(def->name, &machineNameUtf16);
5146     vboxIIDFromUUID(&iid, def->uuid);
5147     virUUIDFormat(def->uuid, uuidstr);
5148
5149 #if VBOX_API_VERSION < 3002000
5150     rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
5151                                             machineNameUtf16,
5152                                             NULL,
5153                                             NULL,
5154                                             iid.value,
5155                                             &machine);
5156 #elif VBOX_API_VERSION < 4000000 /* 3002000 <= VBOX_API_VERSION < 4000000 */
5157     rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
5158                                             machineNameUtf16,
5159                                             NULL,
5160                                             NULL,
5161                                             iid.value,
5162                                             override,
5163                                             &machine);
5164 #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
5165     rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
5166                                             NULL,
5167                                             machineNameUtf16,
5168                                             NULL,
5169                                             iid.value,
5170                                             override,
5171                                             &machine);
5172 #else /* VBOX_API_VERSION >= 4002000 */
5173     snprintf(createFlags, sizeof(createFlags), "%s%s%s%s",
5174              flagsUUIDPrefix,
5175              uuidstr,
5176              flagsSeparator,
5177              flagsForceOverwrite
5178             );
5179     VBOX_UTF8_TO_UTF16(createFlags, &createFlagsUtf16);
5180     rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
5181                                             NULL,
5182                                             machineNameUtf16,
5183                                             0,
5184                                             nsnull,
5185                                             nsnull,
5186                                             createFlagsUtf16,
5187                                             &machine);
5188 #endif /* VBOX_API_VERSION >= 4002000 */
5189     VBOX_UTF16_FREE(machineNameUtf16);
5190
5191     if (NS_FAILED(rc)) {
5192         virReportError(VIR_ERR_INTERNAL_ERROR,
5193                        _("could not define a domain, rc=%08x"), (unsigned)rc);
5194         goto cleanup;
5195     }
5196
5197     rc = machine->vtbl->SetMemorySize(machine,
5198                                       VIR_DIV_UP(def->mem.cur_balloon, 1024));
5199     if (NS_FAILED(rc)) {
5200         virReportError(VIR_ERR_INTERNAL_ERROR,
5201                        _("could not set the memory size of the domain to: %llu Kb, "
5202                          "rc=%08x"),
5203                        def->mem.cur_balloon, (unsigned)rc);
5204     }
5205
5206     if (def->vcpus != def->maxvcpus) {
5207         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
5208                        _("current vcpu count must equal maximum"));
5209     }
5210     rc = machine->vtbl->SetCPUCount(machine, def->maxvcpus);
5211     if (NS_FAILED(rc)) {
5212         virReportError(VIR_ERR_INTERNAL_ERROR,
5213                        _("could not set the number of virtual CPUs to: %u, rc=%08x"),
5214                        def->maxvcpus, (unsigned)rc);
5215     }
5216
5217 #if VBOX_API_VERSION < 3001000
5218     rc = machine->vtbl->SetPAEEnabled(machine,
5219                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
5220                                       VIR_DOMAIN_FEATURE_STATE_ON);
5221 #elif VBOX_API_VERSION == 3001000
5222     rc = machine->vtbl->SetCpuProperty(machine, CpuPropertyType_PAE,
5223                                        def->features[VIR_DOMAIN_FEATURE_PAE] ==
5224                                        VIR_DOMAIN_FEATURE_STATE_ON);
5225 #elif VBOX_API_VERSION >= 3002000
5226     rc = machine->vtbl->SetCPUProperty(machine, CPUPropertyType_PAE,
5227                                        def->features[VIR_DOMAIN_FEATURE_PAE] ==
5228                                        VIR_DOMAIN_FEATURE_STATE_ON);
5229 #endif
5230     if (NS_FAILED(rc)) {
5231         virReportError(VIR_ERR_INTERNAL_ERROR,
5232                        _("could not change PAE status to: %s, rc=%08x"),
5233                        (def->features[VIR_DOMAIN_FEATURE_PAE] == VIR_DOMAIN_FEATURE_STATE_ON)
5234                        ? _("Enabled") : _("Disabled"), (unsigned)rc);
5235     }
5236
5237     machine->vtbl->GetBIOSSettings(machine, &bios);
5238     if (bios) {
5239         rc = bios->vtbl->SetACPIEnabled(bios,
5240                                         def->features[VIR_DOMAIN_FEATURE_ACPI] ==
5241                                         VIR_DOMAIN_FEATURE_STATE_ON);
5242         if (NS_FAILED(rc)) {
5243             virReportError(VIR_ERR_INTERNAL_ERROR,
5244                            _("could not change ACPI status to: %s, rc=%08x"),
5245                            (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_DOMAIN_FEATURE_STATE_ON)
5246                            ? _("Enabled") : _("Disabled"), (unsigned)rc);
5247         }
5248         rc = bios->vtbl->SetIOAPICEnabled(bios,
5249                                           def->features[VIR_DOMAIN_FEATURE_APIC] ==
5250                                           VIR_DOMAIN_FEATURE_STATE_ON);
5251         if (NS_FAILED(rc)) {
5252             virReportError(VIR_ERR_INTERNAL_ERROR,
5253                            _("could not change APIC status to: %s, rc=%08x"),
5254                            (def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_DOMAIN_FEATURE_STATE_ON)
5255                            ? _("Enabled") : _("Disabled"), (unsigned)rc);
5256         }
5257         VBOX_RELEASE(bios);
5258     }
5259
5260     /* Register the machine before attaching other devices to it */
5261     rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
5262     if (NS_FAILED(rc)) {
5263         virReportError(VIR_ERR_INTERNAL_ERROR,
5264                        _("could not define a domain, rc=%08x"), (unsigned)rc);
5265         goto cleanup;
5266     }
5267
5268     /* Get the uuid of the machine, currently it is immutable
5269      * object so open a session to it and get it back, so that
5270      * you can make changes to the machine setting
5271      */
5272     machine->vtbl->GetId(machine, &mchiid.value);
5273     VBOX_SESSION_OPEN(mchiid.value, machine);
5274     data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
5275
5276     vboxSetBootDeviceOrder(def, data, machine);
5277     vboxAttachDrives(def, data, machine);
5278     vboxAttachSound(def, machine);
5279     vboxAttachNetwork(def, data, machine);
5280     vboxAttachSerial(def, data, machine);
5281     vboxAttachParallel(def, data, machine);
5282     vboxAttachVideo(def, machine);
5283     vboxAttachDisplay(def, data, machine);
5284     vboxAttachUSB(def, data, machine);
5285     vboxAttachSharedFolder(def, data, machine);
5286
5287     /* Save the machine settings made till now and close the
5288      * session. also free up the mchiid variable used.
5289      */
5290     rc = machine->vtbl->SaveSettings(machine);
5291     VBOX_SESSION_CLOSE();
5292     vboxIIDUnalloc(&mchiid);
5293
5294     ret = virGetDomain(conn, def->name, def->uuid);
5295     VBOX_RELEASE(machine);
5296
5297     vboxIIDUnalloc(&iid);
5298     virDomainDefFree(def);
5299
5300     return ret;
5301
5302  cleanup:
5303     VBOX_RELEASE(machine);
5304     vboxIIDUnalloc(&iid);
5305     virDomainDefFree(def);
5306     return NULL;
5307 }
5308
5309 static int
5310 vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags)
5311 {
5312     VBOX_OBJECT_CHECK(dom->conn, int, -1);
5313     IMachine *machine    = NULL;
5314     vboxIID iid = VBOX_IID_INITIALIZER;
5315     nsresult rc;
5316 #if VBOX_API_VERSION >= 4000000
5317     vboxArray media = VBOX_ARRAY_INITIALIZER;
5318 #endif
5319     /* No managed save, so we explicitly reject
5320      * VIR_DOMAIN_UNDEFINE_MANAGED_SAVE.  No snapshot metadata for
5321      * VBox, so we can trivially ignore that flag.  */
5322     virCheckFlags(VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
5323
5324     vboxIIDFromUUID(&iid, dom->uuid);
5325
5326 #if VBOX_API_VERSION < 4000000
5327     /* Block for checking if HDD's are attched to VM.
5328      * considering just IDE bus for now. Also skipped
5329      * chanel=1 and device=0 (Secondary Master) as currenlty
5330      * it is allocated to CD/DVD Drive by default.
5331      *
5332      * Only do this for VirtualBox 3.x and before. Since
5333      * VirtualBox 4.0 the Unregister method can do this for use.
5334      */
5335     {
5336         PRUnichar *hddcnameUtf16 = NULL;
5337
5338         char *hddcname;
5339         ignore_value(VIR_STRDUP(hddcname, "IDE"));
5340         VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16);
5341         VIR_FREE(hddcname);
5342
5343         /* Open a Session for the machine */
5344         rc = VBOX_SESSION_OPEN(iid.value, machine);
5345         if (NS_SUCCEEDED(rc)) {
5346             rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
5347             if (NS_SUCCEEDED(rc) && machine) {
5348
5349 # if VBOX_API_VERSION < 3001000
5350                 /* Disconnect all the drives if present */
5351                 machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 0);
5352                 machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 1);
5353                 machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 1, 1);
5354 # else  /* VBOX_API_VERSION >= 3001000 */
5355                 /* get all the controller first, then the attachments and
5356                  * remove them all so that the machine can be undefined
5357                  */
5358                 vboxArray storageControllers = VBOX_ARRAY_INITIALIZER;
5359                 size_t i = 0, j = 0;
5360
5361                 vboxArrayGet(&storageControllers, machine,
5362                              machine->vtbl->GetStorageControllers);
5363
5364                 for (i = 0; i < storageControllers.count; i++) {
5365                     IStorageController *strCtl = storageControllers.items[i];
5366                     PRUnichar *strCtlName = NULL;
5367                     vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
5368
5369                     if (!strCtl)
5370                         continue;
5371
5372                     strCtl->vtbl->GetName(strCtl, &strCtlName);
5373                     vboxArrayGetWithPtrArg(&mediumAttachments, machine,
5374                                            machine->vtbl->GetMediumAttachmentsOfController,
5375                                            strCtlName);
5376
5377                     for (j = 0; j < mediumAttachments.count; j++) {
5378                         IMediumAttachment *medAtt = mediumAttachments.items[j];
5379                         PRInt32 port = ~0U;
5380                         PRInt32 device = ~0U;
5381
5382                         if (!medAtt)
5383                             continue;
5384
5385                         medAtt->vtbl->GetPort(medAtt, &port);
5386                         medAtt->vtbl->GetDevice(medAtt, &device);
5387
5388                         if ((port != ~0U) && (device != ~0U)) {
5389                             machine->vtbl->DetachDevice(machine,
5390                                                         strCtlName,
5391                                                         port,
5392                                                         device);
5393                         }
5394                     }
5395
5396                     vboxArrayRelease(&storageControllers);
5397
5398                     machine->vtbl->RemoveStorageController(machine, strCtlName);
5399                     VBOX_UTF16_FREE(strCtlName);
5400                 }
5401
5402                 vboxArrayRelease(&storageControllers);
5403 # endif /* VBOX_API_VERSION >= 3001000 */
5404
5405                 machine->vtbl->SaveSettings(machine);
5406             }
5407             VBOX_SESSION_CLOSE();
5408         }
5409         VBOX_UTF16_FREE(hddcnameUtf16);
5410     }
5411 #endif
5412
5413 #if VBOX_API_VERSION < 4000000
5414     rc = data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, iid.value, &machine);
5415 #else /* VBOX_API_VERSION >= 4000000 */
5416     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5417     if (NS_FAILED(rc)) {
5418         virReportError(VIR_ERR_NO_DOMAIN, "%s",
5419                        _("no domain with matching uuid"));
5420         return -1;
5421     }
5422
5423     /* We're not interested in the array returned by the Unregister method,
5424      * but in the side effect of unregistering the virtual machine. In order
5425      * to call the Unregister method correctly we need to use the vboxArray
5426      * wrapper here. */
5427     rc = vboxArrayGetWithUintArg(&media, machine, machine->vtbl->Unregister,
5428                                  CleanupMode_DetachAllReturnNone);
5429 #endif /* VBOX_API_VERSION >= 4000000 */
5430     DEBUGIID("UUID of machine being undefined", iid.value);
5431
5432     if (NS_SUCCEEDED(rc)) {
5433 #if VBOX_API_VERSION < 4000000
5434         machine->vtbl->DeleteSettings(machine);
5435 #else /* VBOX_API_VERSION >= 4000000 */
5436         IProgress *progress = NULL;
5437
5438         /* The IMachine Delete method takes an array of IMedium items to be
5439          * deleted along with the virtual machine. We just want to pass an
5440          * empty array. But instead of adding a full vboxArraySetWithReturn to
5441          * the glue layer (in order to handle the required signature of the
5442          * Delete method) we use a local solution here. */
5443 # ifdef WIN32
5444         SAFEARRAY *safeArray = NULL;
5445         typedef HRESULT __stdcall (*IMachine_Delete)(IMachine *self,
5446                                                      SAFEARRAY **media,
5447                                                      IProgress **progress);
5448
5449 #  if VBOX_API_VERSION < 4003000
5450         ((IMachine_Delete)machine->vtbl->Delete)(machine, &safeArray, &progress);
5451 #  else
5452         ((IMachine_Delete)machine->vtbl->DeleteConfig)(machine, &safeArray, &progress);
5453 #  endif
5454 # else
5455         /* XPCOM doesn't like NULL as an array, even when the array size is 0.
5456          * Instead pass it a dummy array to avoid passing NULL. */
5457         IMedium *array[] = { NULL };
5458 #  if VBOX_API_VERSION < 4003000
5459         machine->vtbl->Delete(machine, 0, array, &progress);
5460 #  else
5461         machine->vtbl->DeleteConfig(machine, 0, array, &progress);
5462 #  endif
5463 # endif
5464         if (progress != NULL) {
5465             progress->vtbl->WaitForCompletion(progress, -1);
5466             VBOX_RELEASE(progress);
5467         }
5468 #endif /* VBOX_API_VERSION >= 4000000 */
5469         ret = 0;
5470     } else {
5471         virReportError(VIR_ERR_INTERNAL_ERROR,
5472                        _("could not delete the domain, rc=%08x"), (unsigned)rc);
5473     }
5474
5475 #if VBOX_API_VERSION >= 4000000
5476     vboxArrayUnalloc(&media);
5477 #endif
5478     vboxIIDUnalloc(&iid);
5479     VBOX_RELEASE(machine);
5480
5481     return ret;
5482 }
5483
5484 static int
5485 vboxDomainUndefine(virDomainPtr dom)
5486 {
5487     return vboxDomainUndefineFlags(dom, 0);
5488 }
5489
5490 static int vboxDomainAttachDeviceImpl(virDomainPtr dom,
5491                                       const char *xml,
5492                                       int mediaChangeOnly ATTRIBUTE_UNUSED)
5493 {
5494     VBOX_OBJECT_CHECK(dom->conn, int, -1);
5495     IMachine *machine    = NULL;
5496     vboxIID iid = VBOX_IID_INITIALIZER;
5497     PRUint32 state       = MachineState_Null;
5498     virDomainDefPtr def  = NULL;
5499     virDomainDeviceDefPtr dev  = NULL;
5500     nsresult rc;
5501
5502     if (VIR_ALLOC(def) < 0)
5503         return ret;
5504
5505     if (VIR_STRDUP(def->os.type, "hvm") < 0)
5506         goto cleanup;
5507
5508     dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
5509                                   VIR_DOMAIN_XML_INACTIVE);
5510     if (dev == NULL)
5511         goto cleanup;
5512
5513     vboxIIDFromUUID(&iid, dom->uuid);
5514     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5515     if (NS_FAILED(rc)) {
5516         virReportError(VIR_ERR_NO_DOMAIN, "%s",
5517                        _("no domain with matching uuid"));
5518         goto cleanup;
5519     }
5520
5521     if (machine) {
5522         machine->vtbl->GetState(machine, &state);
5523
5524         if ((state == MachineState_Running) ||
5525             (state == MachineState_Paused)) {
5526             rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5527         } else {
5528             rc = VBOX_SESSION_OPEN(iid.value, machine);
5529         }
5530         if (NS_SUCCEEDED(rc)) {
5531             rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
5532             if (NS_SUCCEEDED(rc) && machine) {
5533                 if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5534 #if VBOX_API_VERSION < 3001000
5535                     const char *src = virDomainDiskGetSource(dev->data.disk);
5536                     int type = virDomainDiskGetType(dev->data.disk);
5537
5538                     if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
5539                         if (type == VIR_STORAGE_TYPE_FILE && src) {
5540                             IDVDDrive *dvdDrive = NULL;
5541                             /* Currently CDROM/DVD Drive is always IDE
5542                              * Secondary Master so neglecting the following
5543                              * parameter dev->data.disk->bus
5544                              */
5545                             machine->vtbl->GetDVDDrive(machine, &dvdDrive);
5546                             if (dvdDrive) {
5547                                 IDVDImage *dvdImage          = NULL;
5548                                 PRUnichar *dvdfileUtf16      = NULL;
5549                                 vboxIID dvduuid = VBOX_IID_INITIALIZER;
5550                                 vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
5551
5552                                 VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
5553
5554                                 data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
5555                                 if (!dvdImage) {
5556                                     data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage);
5557                                 }
5558                                 if (dvdImage) {
5559                                     rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value);
5560                                     if (NS_FAILED(rc)) {
5561                                         virReportError(VIR_ERR_INTERNAL_ERROR,
5562                                                        _("can't get the uuid of the file to "
5563                                                          "be attached to cdrom: %s, rc=%08x"),
5564                                                        src, (unsigned)rc);
5565                                     } else {
5566                                         /* unmount the previous mounted image */
5567                                         dvdDrive->vtbl->Unmount(dvdDrive);
5568                                         rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
5569                                         if (NS_FAILED(rc)) {
5570                                             virReportError(VIR_ERR_INTERNAL_ERROR,
5571                                                            _("could not attach the file to cdrom: %s, rc=%08x"),
5572                                                            src, (unsigned)rc);
5573                                         } else {
5574                                             ret = 0;
5575                                             DEBUGIID("CD/DVD Image UUID:", dvduuid.value);
5576                                         }
5577                                     }
5578
5579                                     VBOX_MEDIUM_RELEASE(dvdImage);
5580                                 }
5581                                 vboxIIDUnalloc(&dvduuid);
5582                                 VBOX_UTF16_FREE(dvdfileUtf16);
5583                                 VBOX_RELEASE(dvdDrive);
5584                             }
5585                         } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5586                         }
5587                     } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
5588                         if (type == VIR_STORAGE_TYPE_FILE && src) {
5589                             IFloppyDrive *floppyDrive;
5590                             machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
5591                             if (floppyDrive) {
5592                                 rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1);
5593                                 if (NS_SUCCEEDED(rc)) {
5594                                     IFloppyImage *floppyImage   = NULL;
5595                                     PRUnichar *fdfileUtf16      = NULL;
5596                                     vboxIID fduuid = VBOX_IID_INITIALIZER;
5597                                     vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
5598                                     VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
5599                                     rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
5600                                                                               fdfileUtf16,
5601                                                                               &floppyImage);
5602
5603                                     if (!floppyImage) {
5604                                         data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
5605                                                                              fdfileUtf16,
5606                                                                              fdemptyuuid.value,
5607                                                                              &floppyImage);
5608                                     }
5609
5610                                     if (floppyImage) {
5611                                         rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value);
5612                                         if (NS_FAILED(rc)) {
5613                                             virReportError(VIR_ERR_INTERNAL_ERROR,
5614                                                            _("can't get the uuid of the file to be "
5615                                                              "attached to floppy drive: %s, rc=%08x"),
5616                                                            src, (unsigned)rc);
5617                                         } else {
5618                                             rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value);
5619                                             if (NS_FAILED(rc)) {
5620                                                 virReportError(VIR_ERR_INTERNAL_ERROR,
5621                                                                _("could not attach the file to floppy drive: %s, rc=%08x"),
5622                                                                src, (unsigned)rc);
5623                                             } else {
5624                                                 ret = 0;
5625                                                 DEBUGIID("attached floppy, UUID:", fduuid.value);
5626                                             }
5627                                         }
5628                                         VBOX_MEDIUM_RELEASE(floppyImage);
5629                                     }
5630                                     vboxIIDUnalloc(&fduuid);
5631                                     VBOX_UTF16_FREE(fdfileUtf16);
5632                                 }
5633                                 VBOX_RELEASE(floppyDrive);
5634                             }
5635                         } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5636                         }
5637                     }
5638 #else  /* VBOX_API_VERSION >= 3001000 */
5639 #endif /* VBOX_API_VERSION >= 3001000 */
5640                 } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
5641                 } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
5642                     if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
5643                         if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
5644                         }
5645                     }
5646                 } else if (dev->type == VIR_DOMAIN_DEVICE_FS &&
5647                            dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) {
5648                     PRUnichar *nameUtf16;
5649                     PRUnichar *hostPathUtf16;
5650                     PRBool writable;
5651
5652                     VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16);
5653                     VBOX_UTF8_TO_UTF16(dev->data.fs->src, &hostPathUtf16);
5654                     writable = !dev->data.fs->readonly;
5655
5656 #if VBOX_API_VERSION < 4000000
5657                     rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
5658                                                            writable);
5659 #else /* VBOX_API_VERSION >= 4000000 */
5660                     rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
5661                                                            writable, PR_FALSE);
5662 #endif /* VBOX_API_VERSION >= 4000000 */
5663
5664                     if (NS_FAILED(rc)) {
5665                         virReportError(VIR_ERR_INTERNAL_ERROR,
5666                                        _("could not attach shared folder '%s', rc=%08x"),
5667                                        dev->data.fs->dst, (unsigned)rc);
5668                     } else {
5669                         ret = 0;
5670                     }
5671
5672                     VBOX_UTF16_FREE(nameUtf16);
5673                     VBOX_UTF16_FREE(hostPathUtf16);
5674                 }
5675                 machine->vtbl->SaveSettings(machine);
5676                 VBOX_RELEASE(machine);
5677             }
5678             VBOX_SESSION_CLOSE();
5679         }
5680     }
5681
5682  cleanup:
5683     vboxIIDUnalloc(&iid);
5684     virDomainDefFree(def);
5685     virDomainDeviceDefFree(dev);
5686     return ret;
5687 }
5688
5689 static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml)
5690 {
5691     return vboxDomainAttachDeviceImpl(dom, xml, 0);
5692 }
5693
5694 static int
5695 vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
5696                             unsigned int flags)
5697 {
5698     virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);
5699
5700     if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5701         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
5702                        _("cannot modify the persistent configuration of a domain"));
5703         return -1;
5704     }
5705
5706     return vboxDomainAttachDeviceImpl(dom, xml, 0);
5707 }
5708
5709 static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
5710                                        unsigned int flags)
5711 {
5712     virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
5713                   VIR_DOMAIN_AFFECT_LIVE |
5714                   VIR_DOMAIN_AFFECT_CONFIG, -1);
5715
5716     if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5717         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
5718                        _("cannot modify the persistent configuration of a domain"));
5719         return -1;
5720     }
5721
5722     return vboxDomainAttachDeviceImpl(dom, xml, 1);
5723 }
5724
5725 static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml)
5726 {
5727     VBOX_OBJECT_CHECK(dom->conn, int, -1);
5728     IMachine *machine    = NULL;
5729     vboxIID iid = VBOX_IID_INITIALIZER;
5730     PRUint32 state       = MachineState_Null;
5731     virDomainDefPtr def  = NULL;
5732     virDomainDeviceDefPtr dev  = NULL;
5733     nsresult rc;
5734
5735     if (VIR_ALLOC(def) < 0)
5736         return ret;
5737
5738     if (VIR_STRDUP(def->os.type, "hvm") < 0)
5739         goto cleanup;
5740
5741     dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
5742                                   VIR_DOMAIN_XML_INACTIVE);
5743     if (dev == NULL)
5744         goto cleanup;
5745
5746     vboxIIDFromUUID(&iid, dom->uuid);
5747     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5748     if (NS_FAILED(rc)) {
5749         virReportError(VIR_ERR_NO_DOMAIN, "%s",
5750                        _("no domain with matching uuid"));
5751         goto cleanup;
5752     }
5753
5754     if (machine) {
5755         machine->vtbl->GetState(machine, &state);
5756
5757         if ((state == MachineState_Running) ||
5758             (state == MachineState_Paused)) {
5759             rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5760         } else {
5761             rc = VBOX_SESSION_OPEN(iid.value, machine);
5762         }
5763
5764         if (NS_SUCCEEDED(rc)) {
5765             rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
5766             if (NS_SUCCEEDED(rc) && machine) {
5767                 if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5768 #if VBOX_API_VERSION < 3001000
5769                     int type = virDomainDiskGetType(dev->data.disk);
5770
5771                     if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
5772                         if (type == VIR_STORAGE_TYPE_FILE) {
5773                             IDVDDrive *dvdDrive = NULL;
5774                             /* Currently CDROM/DVD Drive is always IDE
5775                              * Secondary Master so neglecting the following
5776                              * parameter dev->data.disk->bus
5777                              */
5778                             machine->vtbl->GetDVDDrive(machine, &dvdDrive);
5779                             if (dvdDrive) {
5780                                 rc = dvdDrive->vtbl->Unmount(dvdDrive);
5781                                 if (NS_FAILED(rc)) {
5782                                     virReportError(VIR_ERR_INTERNAL_ERROR,
5783                                                    _("could not de-attach the mounted ISO, rc=%08x"),
5784                                                    (unsigned)rc);
5785                                 } else {
5786                                     ret = 0;
5787                                 }
5788                                 VBOX_RELEASE(dvdDrive);
5789                             }
5790                         } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5791                         }
5792                     } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
5793                         if (type == VIR_STORAGE_TYPE_FILE) {
5794                             IFloppyDrive *floppyDrive;
5795                             machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
5796                             if (floppyDrive) {
5797                                 PRBool enabled = PR_FALSE;
5798
5799                                 floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled);
5800                                 if (enabled) {
5801                                     rc = floppyDrive->vtbl->Unmount(floppyDrive);
5802                                     if (NS_FAILED(rc)) {
5803                                         virReportError(VIR_ERR_INTERNAL_ERROR,
5804                                                        _("could not attach the file "
5805                                                          "to floppy drive, rc=%08x"),
5806                                                        (unsigned)rc);
5807                                     } else {
5808                                         ret = 0;
5809                                     }
5810                                 } else {
5811                                     /* If you are here means floppy drive is already unmounted
5812                                      * so don't flag error, just say everything is fine and quit
5813                                      */
5814                                     ret = 0;
5815                                 }
5816                                 VBOX_RELEASE(floppyDrive);
5817                             }
5818                         } else if (type == VIR_STORAGE_TYPE_BLOCK) {
5819                         }
5820                     }
5821 #else  /* VBOX_API_VERSION >= 3001000 */
5822 #endif /* VBOX_API_VERSION >= 3001000 */
5823                 } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
5824                 } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
5825                     if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
5826                         if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
5827                         }
5828                     }
5829                 } else if (dev->type == VIR_DOMAIN_DEVICE_FS &&
5830                            dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) {
5831                     PRUnichar *nameUtf16;
5832
5833                     VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16);
5834
5835                     rc = machine->vtbl->RemoveSharedFolder(machine, nameUtf16);
5836
5837                     if (NS_FAILED(rc)) {
5838                         virReportError(VIR_ERR_INTERNAL_ERROR,
5839                                        _("could not detach shared folder '%s', rc=%08x"),
5840                                        dev->data.fs->dst, (unsigned)rc);
5841                     } else {
5842                         ret = 0;
5843                     }
5844
5845                     VBOX_UTF16_FREE(nameUtf16);
5846                 }
5847                 machine->vtbl->SaveSettings(machine);
5848                 VBOX_RELEASE(machine);
5849             }
5850             VBOX_SESSION_CLOSE();
5851         }
5852     }
5853
5854  cleanup:
5855     vboxIIDUnalloc(&iid);
5856     virDomainDefFree(def);
5857     virDomainDeviceDefFree(dev);
5858     return ret;
5859 }
5860
5861 static int
5862 vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
5863                             unsigned int flags)
5864 {
5865     virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);
5866
5867     if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5868         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
5869                        _("cannot modify the persistent configuration of a domain"));
5870         return -1;
5871     }
5872
5873     return vboxDomainDetachDevice(dom, xml);
5874 }
5875
5876 static int
5877 vboxDomainSnapshotGetAll(virDomainPtr dom,
5878                          IMachine *machine,
5879                          ISnapshot ***snapshots)
5880 {
5881     vboxIID empty = VBOX_IID_INITIALIZER;
5882     ISnapshot **list = NULL;
5883     PRUint32 count;
5884     nsresult rc;
5885     unsigned int next;
5886     unsigned int top;
5887
5888     rc = machine->vtbl->GetSnapshotCount(machine, &count);
5889     if (NS_FAILED(rc)) {
5890         virReportError(VIR_ERR_INTERNAL_ERROR,
5891                        _("could not get snapshot count for domain %s"),
5892                        dom->name);
5893         goto error;
5894     }
5895
5896     if (count == 0)
5897         goto out;
5898
5899     if (VIR_ALLOC_N(list, count) < 0)
5900         goto error;
5901
5902 #if VBOX_API_VERSION < 4000000
5903     rc = machine->vtbl->GetSnapshot(machine, empty.value, list);
5904 #else /* VBOX_API_VERSION >= 4000000 */
5905     rc = machine->vtbl->FindSnapshot(machine, empty.value, list);
5906 #endif /* VBOX_API_VERSION >= 4000000 */
5907     if (NS_FAILED(rc) || !list[0]) {
5908         virReportError(VIR_ERR_INTERNAL_ERROR,
5909                        _("could not get root snapshot for domain %s"),
5910                        dom->name);
5911         goto error;
5912     }
5913
5914     /* BFS walk through snapshot tree */
5915     top = 1;
5916     for (next = 0; next < count; next++) {
5917         vboxArray children = VBOX_ARRAY_INITIALIZER;
5918         size_t i;
5919
5920         if (!list[next]) {
5921             virReportError(VIR_ERR_INTERNAL_ERROR,
5922                            _("unexpected number of snapshots < %u"), count);
5923             goto error;
5924         }
5925
5926         rc = vboxArrayGet(&children, list[next],
5927                                list[next]->vtbl->GetChildren);
5928         if (NS_FAILED(rc)) {
5929             virReportError(VIR_ERR_INTERNAL_ERROR,
5930                            "%s", _("could not get children snapshots"));
5931             goto error;
5932         }
5933         for (i = 0; i < children.count; i++) {
5934             ISnapshot *child = children.items[i];
5935             if (!child)
5936                 continue;
5937             if (top == count) {
5938                 virReportError(VIR_ERR_INTERNAL_ERROR,
5939                                _("unexpected number of snapshots > %u"), count);
5940                 vboxArrayRelease(&children);
5941                 goto error;
5942             }
5943             VBOX_ADDREF(child);
5944             list[top++] = child;
5945         }
5946         vboxArrayRelease(&children);
5947     }
5948
5949  out:
5950     *snapshots = list;
5951     return count;
5952
5953  error:
5954     if (list) {
5955         for (next = 0; next < count; next++)
5956             VBOX_RELEASE(list[next]);
5957     }
5958     VIR_FREE(list);
5959
5960     return -1;
5961 }
5962
5963 static ISnapshot *
5964 vboxDomainSnapshotGet(vboxGlobalData *data,
5965                       virDomainPtr dom,
5966                       IMachine *machine,
5967                       const char *name)
5968 {
5969     ISnapshot **snapshots = NULL;
5970     ISnapshot *snapshot = NULL;
5971     nsresult rc;
5972     int count = 0;
5973     size_t i;
5974
5975     if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
5976         goto cleanup;
5977
5978     for (i = 0; i < count; i++) {
5979         PRUnichar *nameUtf16;
5980         char *nameUtf8;
5981
5982         rc = snapshots[i]->vtbl->GetName(snapshots[i], &nameUtf16);
5983         if (NS_FAILED(rc) || !nameUtf16) {
5984             virReportError(VIR_ERR_INTERNAL_ERROR,
5985                            "%s", _("could not get snapshot name"));
5986             goto cleanup;
5987         }
5988         VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
5989         VBOX_UTF16_FREE(nameUtf16);
5990         if (STREQ(name, nameUtf8))
5991             snapshot = snapshots[i];
5992         VBOX_UTF8_FREE(nameUtf8);
5993
5994         if (snapshot)
5995             break;
5996     }
5997
5998     if (!snapshot) {
5999         virReportError(VIR_ERR_OPERATION_INVALID,
6000                        _("domain %s has no snapshots with name %s"),
6001                        dom->name, name);
6002         goto cleanup;
6003     }
6004
6005  cleanup:
6006     if (count > 0) {
6007         for (i = 0; i < count; i++) {
6008             if (snapshots[i] != snapshot)
6009                 VBOX_RELEASE(snapshots[i]);
6010         }
6011     }
6012     VIR_FREE(snapshots);
6013     return snapshot;
6014 }
6015
6016 static virDomainSnapshotPtr
6017 vboxDomainSnapshotCreateXML(virDomainPtr dom,
6018                             const char *xmlDesc,
6019                             unsigned int flags)
6020 {
6021     VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6022     virDomainSnapshotDefPtr def = NULL;
6023     vboxIID domiid = VBOX_IID_INITIALIZER;
6024     IMachine *machine = NULL;
6025     IConsole *console = NULL;
6026     IProgress *progress = NULL;
6027     ISnapshot *snapshot = NULL;
6028     PRUnichar *name = NULL;
6029     PRUnichar *description = NULL;
6030     PRUint32 state;
6031     nsresult rc;
6032 #if VBOX_API_VERSION == 2002000
6033     nsresult result;
6034 #else
6035     PRInt32 result;
6036 #endif
6037
6038     /* VBox has no snapshot metadata, so this flag is trivial.  */
6039     virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
6040
6041     if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps,
6042                                                 data->xmlopt, 0, 0)))
6043         goto cleanup;
6044
6045     if (def->ndisks) {
6046         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
6047                        _("disk snapshots not supported yet"));
6048         goto cleanup;
6049     }
6050
6051     vboxIIDFromUUID(&domiid, dom->uuid);
6052     rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
6053     if (NS_FAILED(rc)) {
6054         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6055                        _("no domain with matching UUID"));
6056         goto cleanup;
6057     }
6058
6059     rc = machine->vtbl->GetState(machine, &state);
6060     if (NS_FAILED(rc)) {
6061         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6062                        _("could not get domain state"));
6063         goto cleanup;
6064     }
6065
6066     if ((state >= MachineState_FirstOnline)
6067         && (state <= MachineState_LastOnline)) {
6068         rc = VBOX_SESSION_OPEN_EXISTING(domiid.value, machine);
6069     } else {
6070         rc = VBOX_SESSION_OPEN(domiid.value, machine);
6071     }
6072
6073     if (NS_SUCCEEDED(rc))
6074         rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
6075     if (NS_FAILED(rc)) {
6076         virReportError(VIR_ERR_INTERNAL_ERROR,
6077                        _("could not open VirtualBox session with domain %s"),
6078                        dom->name);
6079         goto cleanup;
6080     }
6081
6082     VBOX_UTF8_TO_UTF16(def->name, &name);
6083     if (!name) {
6084         virReportOOMError();
6085         goto cleanup;
6086     }
6087
6088     if (def->description) {
6089         VBOX_UTF8_TO_UTF16(def->description, &description);
6090         if (!description) {
6091             virReportOOMError();
6092             goto cleanup;
6093         }
6094     }
6095
6096     rc = console->vtbl->TakeSnapshot(console, name, description, &progress);
6097     if (NS_FAILED(rc) || !progress) {
6098         virReportError(VIR_ERR_INTERNAL_ERROR,
6099                        _("could not take snapshot of domain %s"), dom->name);
6100         goto cleanup;
6101     }
6102
6103     progress->vtbl->WaitForCompletion(progress, -1);
6104     progress->vtbl->GetResultCode(progress, &result);
6105     if (NS_FAILED(result)) {
6106         virReportError(VIR_ERR_INTERNAL_ERROR,
6107                        _("could not take snapshot of domain %s"), dom->name);
6108         goto cleanup;
6109     }
6110
6111     rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
6112     if (NS_FAILED(rc)) {
6113         virReportError(VIR_ERR_INTERNAL_ERROR,
6114                        _("could not get current snapshot of domain %s"),
6115                   dom->name);
6116         goto cleanup;
6117     }
6118
6119     ret = virGetDomainSnapshot(dom, def->name);
6120
6121  cleanup:
6122     VBOX_RELEASE(progress);
6123     VBOX_UTF16_FREE(description);
6124     VBOX_UTF16_FREE(name);
6125     VBOX_RELEASE(console);
6126     VBOX_SESSION_CLOSE();
6127     VBOX_RELEASE(machine);
6128     vboxIIDUnalloc(&domiid);
6129     virDomainSnapshotDefFree(def);
6130     return ret;
6131 }
6132
6133 static char *
6134 vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
6135                              unsigned int flags)
6136 {
6137     virDomainPtr dom = snapshot->domain;
6138     VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
6139     vboxIID domiid = VBOX_IID_INITIALIZER;
6140     IMachine *machine = NULL;
6141     ISnapshot *snap = NULL;
6142     ISnapshot *parent = NULL;
6143     nsresult rc;
6144     virDomainSnapshotDefPtr def = NULL;
6145     PRUnichar *str16;
6146     char *str8;
6147     PRInt64 timestamp;
6148     PRBool online = PR_FALSE;
6149     char uuidstr[VIR_UUID_STRING_BUFLEN];
6150
6151     virCheckFlags(0, NULL);
6152
6153     vboxIIDFromUUID(&domiid, dom->uuid);
6154     rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
6155     if (NS_FAILED(rc)) {
6156         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6157                        _("no domain with matching UUID"));
6158         goto cleanup;
6159     }
6160
6161     if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
6162         goto cleanup;
6163
6164     if (VIR_ALLOC(def) < 0)
6165         goto cleanup;
6166     if (VIR_STRDUP(def->name, snapshot->name) < 0)
6167         goto cleanup;
6168
6169     rc = snap->vtbl->GetDescription(snap, &str16);
6170     if (NS_FAILED(rc)) {
6171         virReportError(VIR_ERR_INTERNAL_ERROR,
6172                        _("could not get description of snapshot %s"),
6173                        snapshot->name);
6174         goto cleanup;
6175     }
6176     if (str16) {
6177         VBOX_UTF16_TO_UTF8(str16, &str8);
6178         VBOX_UTF16_FREE(str16);
6179         if (VIR_STRDUP(def->description, str8) < 0) {
6180             VBOX_UTF8_FREE(str8);
6181             goto cleanup;
6182         }
6183         VBOX_UTF8_FREE(str8);
6184     }
6185
6186     rc = snap->vtbl->GetTimeStamp(snap, &timestamp);
6187     if (NS_FAILED(rc)) {
6188         virReportError(VIR_ERR_INTERNAL_ERROR,
6189                        _("could not get creation time of snapshot %s"),
6190                        snapshot->name);
6191         goto cleanup;
6192     }
6193     /* timestamp is in milliseconds while creationTime in seconds */
6194     def->creationTime = timestamp / 1000;
6195
6196     rc = snap->vtbl->GetParent(snap, &parent);
6197     if (NS_FAILED(rc)) {
6198         virReportError(VIR_ERR_INTERNAL_ERROR,
6199                        _("could not get parent of snapshot %s"),
6200                        snapshot->name);
6201         goto cleanup;
6202     }
6203     if (parent) {
6204         rc = parent->vtbl->GetName(parent, &str16);
6205         if (NS_FAILED(rc) || !str16) {
6206             virReportError(VIR_ERR_INTERNAL_ERROR,
6207                            _("could not get name of parent of snapshot %s"),
6208                            snapshot->name);
6209             goto cleanup;
6210         }
6211         VBOX_UTF16_TO_UTF8(str16, &str8);
6212         VBOX_UTF16_FREE(str16);
6213         if (VIR_STRDUP(def->parent, str8) < 0) {
6214             VBOX_UTF8_FREE(str8);
6215             goto cleanup;
6216         }
6217         VBOX_UTF8_FREE(str8);
6218     }
6219
6220     rc = snap->vtbl->GetOnline(snap, &online);
6221     if (NS_FAILED(rc)) {
6222         virReportError(VIR_ERR_INTERNAL_ERROR,
6223                        _("could not get online state of snapshot %s"),
6224                        snapshot->name);
6225         goto cleanup;
6226     }
6227     if (online)
6228         def->state = VIR_DOMAIN_RUNNING;
6229     else
6230         def->state = VIR_DOMAIN_SHUTOFF;
6231
6232     virUUIDFormat(dom->uuid, uuidstr);
6233     ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0);
6234
6235  cleanup:
6236     virDomainSnapshotDefFree(def);
6237     VBOX_RELEASE(parent);
6238     VBOX_RELEASE(snap);
6239     VBOX_RELEASE(machine);
6240     vboxIIDUnalloc(&domiid);
6241     return ret;
6242 }
6243
6244 static int
6245 vboxDomainSnapshotNum(virDomainPtr dom,
6246                       unsigned int flags)
6247 {
6248     VBOX_OBJECT_CHECK(dom->conn, int, -1);
6249     vboxIID iid = VBOX_IID_INITIALIZER;
6250     IMachine *machine = NULL;
6251     nsresult rc;
6252     PRUint32 snapshotCount;
6253
6254     virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
6255                   VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6256
6257     vboxIIDFromUUID(&iid, dom->uuid);
6258     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6259     if (NS_FAILED(rc)) {
6260         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6261                        _("no domain with matching UUID"));
6262         goto cleanup;
6263     }
6264
6265     /* VBox snapshots do not require libvirt to maintain any metadata.  */
6266     if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
6267         ret = 0;
6268         goto cleanup;
6269     }
6270
6271     rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
6272     if (NS_FAILED(rc)) {
6273         virReportError(VIR_ERR_INTERNAL_ERROR,
6274                        _("could not get snapshot count for domain %s"),
6275                        dom->name);
6276         goto cleanup;
6277     }
6278
6279     /* VBox has at most one root snapshot.  */
6280     if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS))
6281         ret = 1;
6282     else
6283         ret = snapshotCount;
6284
6285  cleanup:
6286     VBOX_RELEASE(machine);
6287     vboxIIDUnalloc(&iid);
6288     return ret;
6289 }
6290
6291 static int
6292 vboxDomainSnapshotListNames(virDomainPtr dom,
6293                             char **names,
6294                             int nameslen,
6295                             unsigned int flags)
6296 {
6297     VBOX_OBJECT_CHECK(dom->conn, int, -1);
6298     vboxIID iid = VBOX_IID_INITIALIZER;
6299     IMachine *machine = NULL;
6300     nsresult rc;
6301     ISnapshot **snapshots = NULL;
6302     int count = 0;
6303     size_t i;
6304
6305     virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
6306                   VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6307
6308     vboxIIDFromUUID(&iid, dom->uuid);
6309     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6310     if (NS_FAILED(rc)) {
6311         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6312                        _("no domain with matching UUID"));
6313         goto cleanup;
6314     }
6315
6316     if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
6317         ret = 0;
6318         goto cleanup;
6319     }
6320
6321     if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) {
6322         vboxIID empty = VBOX_IID_INITIALIZER;
6323
6324         if (VIR_ALLOC_N(snapshots, 1) < 0)
6325             goto cleanup;
6326 #if VBOX_API_VERSION < 4000000
6327         rc = machine->vtbl->GetSnapshot(machine, empty.value, snapshots);
6328 #else /* VBOX_API_VERSION >= 4000000 */
6329         rc = machine->vtbl->FindSnapshot(machine, empty.value, snapshots);
6330 #endif /* VBOX_API_VERSION >= 4000000 */
6331         if (NS_FAILED(rc) || !snapshots[0]) {
6332             virReportError(VIR_ERR_INTERNAL_ERROR,
6333                            _("could not get root snapshot for domain %s"),
6334                            dom->name);
6335             goto cleanup;
6336         }
6337         count = 1;
6338     } else {
6339         if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
6340             goto cleanup;
6341     }
6342
6343     for (i = 0; i < nameslen; i++) {
6344         PRUnichar *nameUtf16;
6345         char *name;
6346
6347         if (i >= count)
6348             break;
6349
6350         rc = snapshots[i]->vtbl->GetName(snapshots[i], &nameUtf16);
6351         if (NS_FAILED(rc) || !nameUtf16) {
6352             virReportError(VIR_ERR_INTERNAL_ERROR,
6353                            "%s", _("could not get snapshot name"));
6354             goto cleanup;
6355         }
6356         VBOX_UTF16_TO_UTF8(nameUtf16, &name);
6357         VBOX_UTF16_FREE(nameUtf16);
6358         if (VIR_STRDUP(names[i], name) < 0) {
6359             VBOX_UTF8_FREE(name);
6360             goto cleanup;
6361         }
6362         VBOX_UTF8_FREE(name);
6363     }
6364
6365     if (count <= nameslen)
6366         ret = count;
6367     else
6368         ret = nameslen;
6369
6370  cleanup:
6371     if (count > 0) {
6372         for (i = 0; i < count; i++)
6373             VBOX_RELEASE(snapshots[i]);
6374     }
6375     VIR_FREE(snapshots);
6376     VBOX_RELEASE(machine);
6377     vboxIIDUnalloc(&iid);
6378     return ret;
6379 }
6380
6381 static virDomainSnapshotPtr
6382 vboxDomainSnapshotLookupByName(virDomainPtr dom,
6383                                const char *name,
6384                                unsigned int flags)
6385 {
6386     VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6387     vboxIID iid = VBOX_IID_INITIALIZER;
6388     IMachine *machine = NULL;
6389     ISnapshot *snapshot = NULL;
6390     nsresult rc;
6391
6392     virCheckFlags(0, NULL);
6393
6394     vboxIIDFromUUID(&iid, dom->uuid);
6395     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6396     if (NS_FAILED(rc)) {
6397         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6398                        _("no domain with matching UUID"));
6399         goto cleanup;
6400     }
6401
6402     if (!(snapshot = vboxDomainSnapshotGet(data, dom, machine, name)))
6403         goto cleanup;
6404
6405     ret = virGetDomainSnapshot(dom, name);
6406
6407  cleanup:
6408     VBOX_RELEASE(snapshot);
6409     VBOX_RELEASE(machine);
6410     vboxIIDUnalloc(&iid);
6411     return ret;
6412 }
6413
6414 static int
6415 vboxDomainHasCurrentSnapshot(virDomainPtr dom,
6416                              unsigned int flags)
6417 {
6418     VBOX_OBJECT_CHECK(dom->conn, int, -1);
6419     vboxIID iid = VBOX_IID_INITIALIZER;
6420     IMachine *machine = NULL;
6421     ISnapshot *snapshot = NULL;
6422     nsresult rc;
6423
6424     virCheckFlags(0, -1);
6425
6426     vboxIIDFromUUID(&iid, dom->uuid);
6427     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6428     if (NS_FAILED(rc)) {
6429         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6430                        _("no domain with matching UUID"));
6431         goto cleanup;
6432     }
6433
6434     rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
6435     if (NS_FAILED(rc)) {
6436         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6437                        _("could not get current snapshot"));
6438         goto cleanup;
6439     }
6440
6441     if (snapshot)
6442         ret = 1;
6443     else
6444         ret = 0;
6445
6446  cleanup:
6447     VBOX_RELEASE(machine);
6448     vboxIIDUnalloc(&iid);
6449     return ret;
6450 }
6451
6452 static virDomainSnapshotPtr
6453 vboxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
6454                             unsigned int flags)
6455 {
6456     virDomainPtr dom = snapshot->domain;
6457     VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6458     vboxIID iid = VBOX_IID_INITIALIZER;
6459     IMachine *machine = NULL;
6460     ISnapshot *snap = NULL;
6461     ISnapshot *parent = NULL;
6462     PRUnichar *nameUtf16 = NULL;
6463     char *name = NULL;
6464     nsresult rc;
6465
6466     virCheckFlags(0, NULL);
6467
6468     vboxIIDFromUUID(&iid, dom->uuid);
6469     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6470     if (NS_FAILED(rc)) {
6471         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6472                        _("no domain with matching UUID"));
6473         goto cleanup;
6474     }
6475
6476     if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
6477         goto cleanup;
6478
6479     rc = snap->vtbl->GetParent(snap, &parent);
6480     if (NS_FAILED(rc)) {
6481         virReportError(VIR_ERR_INTERNAL_ERROR,
6482                        _("could not get parent of snapshot %s"),
6483                        snapshot->name);
6484         goto cleanup;
6485     }
6486     if (!parent) {
6487         virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
6488                        _("snapshot '%s' does not have a parent"),
6489                        snapshot->name);
6490         goto cleanup;
6491     }
6492
6493     rc = parent->vtbl->GetName(parent, &nameUtf16);
6494     if (NS_FAILED(rc) || !nameUtf16) {
6495         virReportError(VIR_ERR_INTERNAL_ERROR,
6496                        _("could not get name of parent of snapshot %s"),
6497                        snapshot->name);
6498         goto cleanup;
6499     }
6500     VBOX_UTF16_TO_UTF8(nameUtf16, &name);
6501     if (!name) {
6502         virReportOOMError();
6503         goto cleanup;
6504     }
6505
6506     ret = virGetDomainSnapshot(dom, name);
6507
6508  cleanup:
6509     VBOX_UTF8_FREE(name);
6510     VBOX_UTF16_FREE(nameUtf16);
6511     VBOX_RELEASE(snap);
6512     VBOX_RELEASE(parent);
6513     VBOX_RELEASE(machine);
6514     vboxIIDUnalloc(&iid);
6515     return ret;
6516 }
6517
6518 static virDomainSnapshotPtr
6519 vboxDomainSnapshotCurrent(virDomainPtr dom,
6520                           unsigned int flags)
6521 {
6522     VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6523     vboxIID iid = VBOX_IID_INITIALIZER;
6524     IMachine *machine = NULL;
6525     ISnapshot *snapshot = NULL;
6526     PRUnichar *nameUtf16 = NULL;
6527     char *name = NULL;
6528     nsresult rc;
6529
6530     virCheckFlags(0, NULL);
6531
6532     vboxIIDFromUUID(&iid, dom->uuid);
6533     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6534     if (NS_FAILED(rc)) {
6535         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6536                        _("no domain with matching UUID"));
6537         goto cleanup;
6538     }
6539
6540     rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
6541     if (NS_FAILED(rc)) {
6542         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6543                        _("could not get current snapshot"));
6544         goto cleanup;
6545     }
6546
6547     if (!snapshot) {
6548         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6549                        _("domain has no snapshots"));
6550         goto cleanup;
6551     }
6552
6553     rc = snapshot->vtbl->GetName(snapshot, &nameUtf16);
6554     if (NS_FAILED(rc) || !nameUtf16) {
6555         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6556                        _("could not get current snapshot name"));
6557         goto cleanup;
6558     }
6559
6560     VBOX_UTF16_TO_UTF8(nameUtf16, &name);
6561     if (!name) {
6562         virReportOOMError();
6563         goto cleanup;
6564     }
6565
6566     ret = virGetDomainSnapshot(dom, name);
6567
6568  cleanup:
6569     VBOX_UTF8_FREE(name);
6570     VBOX_UTF16_FREE(nameUtf16);
6571     VBOX_RELEASE(snapshot);
6572     VBOX_RELEASE(machine);
6573     vboxIIDUnalloc(&iid);
6574     return ret;
6575 }
6576
6577 static int
6578 vboxDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
6579                             unsigned int flags)
6580 {
6581     virDomainPtr dom = snapshot->domain;
6582     VBOX_OBJECT_CHECK(dom->conn, int, -1);
6583     vboxIID iid = VBOX_IID_INITIALIZER;
6584     IMachine *machine = NULL;
6585     ISnapshot *snap = NULL;
6586     ISnapshot *current = NULL;
6587     PRUnichar *nameUtf16 = NULL;
6588     char *name = NULL;
6589     nsresult rc;
6590
6591     virCheckFlags(0, -1);
6592
6593     vboxIIDFromUUID(&iid, dom->uuid);
6594     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6595     if (NS_FAILED(rc)) {
6596         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6597                        _("no domain with matching UUID"));
6598         goto cleanup;
6599     }
6600
6601     if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
6602         goto cleanup;
6603
6604     rc = machine->vtbl->GetCurrentSnapshot(machine, &current);
6605     if (NS_FAILED(rc)) {
6606         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6607                        _("could not get current snapshot"));
6608         goto cleanup;
6609     }
6610     if (!current) {
6611         ret = 0;
6612         goto cleanup;
6613     }
6614
6615     rc = current->vtbl->GetName(current, &nameUtf16);
6616     if (NS_FAILED(rc) || !nameUtf16) {
6617         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6618                        _("could not get current snapshot name"));
6619         goto cleanup;
6620     }
6621
6622     VBOX_UTF16_TO_UTF8(nameUtf16, &name);
6623     if (!name) {
6624         virReportOOMError();
6625         goto cleanup;
6626     }
6627
6628     ret = STREQ(snapshot->name, name);
6629
6630  cleanup:
6631     VBOX_UTF8_FREE(name);
6632     VBOX_UTF16_FREE(nameUtf16);
6633     VBOX_RELEASE(snap);
6634     VBOX_RELEASE(current);
6635     VBOX_RELEASE(machine);
6636     vboxIIDUnalloc(&iid);
6637     return ret;
6638 }
6639
6640 static int
6641 vboxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
6642                               unsigned int flags)
6643 {
6644     virDomainPtr dom = snapshot->domain;
6645     VBOX_OBJECT_CHECK(dom->conn, int, -1);
6646     vboxIID iid = VBOX_IID_INITIALIZER;
6647     IMachine *machine = NULL;
6648     ISnapshot *snap = NULL;
6649     nsresult rc;
6650
6651     virCheckFlags(0, -1);
6652
6653     vboxIIDFromUUID(&iid, dom->uuid);
6654     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6655     if (NS_FAILED(rc)) {
6656         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6657                        _("no domain with matching UUID"));
6658         goto cleanup;
6659     }
6660
6661     /* Check that snapshot exists.  If so, there is no metadata.  */
6662     if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
6663         goto cleanup;
6664
6665     ret = 0;
6666
6667  cleanup:
6668     VBOX_RELEASE(snap);
6669     VBOX_RELEASE(machine);
6670     vboxIIDUnalloc(&iid);
6671     return ret;
6672 }
6673
6674 #if VBOX_API_VERSION < 3001000
6675 static int
6676 vboxDomainSnapshotRestore(virDomainPtr dom,
6677                           IMachine *machine,
6678                           ISnapshot *snapshot)
6679 {
6680     VBOX_OBJECT_CHECK(dom->conn, int, -1);
6681     vboxIID iid = VBOX_IID_INITIALIZER;
6682     nsresult rc;
6683
6684     rc = snapshot->vtbl->GetId(snapshot, &iid.value);
6685     if (NS_FAILED(rc)) {
6686         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6687                        _("could not get snapshot UUID"));
6688         goto cleanup;
6689     }
6690
6691     rc = machine->vtbl->SetCurrentSnapshot(machine, iid.value);
6692     if (NS_FAILED(rc)) {
6693         virReportError(VIR_ERR_INTERNAL_ERROR,
6694                        _("could not restore snapshot for domain %s"), dom->name);
6695         goto cleanup;
6696     }
6697
6698     ret = 0;
6699
6700  cleanup:
6701     vboxIIDUnalloc(&iid);
6702     return ret;
6703 }
6704 #else
6705 static int
6706 vboxDomainSnapshotRestore(virDomainPtr dom,
6707                           IMachine *machine,
6708                           ISnapshot *snapshot)
6709 {
6710     VBOX_OBJECT_CHECK(dom->conn, int, -1);
6711     IConsole *console = NULL;
6712     IProgress *progress = NULL;
6713     PRUint32 state;
6714     nsresult rc;
6715     PRInt32 result;
6716     vboxIID domiid = VBOX_IID_INITIALIZER;
6717
6718     rc = machine->vtbl->GetId(machine, &domiid.value);
6719     if (NS_FAILED(rc)) {
6720         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6721                        _("could not get domain UUID"));
6722         goto cleanup;
6723     }
6724
6725     rc = machine->vtbl->GetState(machine, &state);
6726     if (NS_FAILED(rc)) {
6727         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6728                        _("could not get domain state"));
6729         goto cleanup;
6730     }
6731
6732     if (state >= MachineState_FirstOnline
6733         && state <= MachineState_LastOnline) {
6734         virReportError(VIR_ERR_OPERATION_INVALID,
6735                        _("domain %s is already running"), dom->name);
6736         goto cleanup;
6737     }
6738
6739     rc = VBOX_SESSION_OPEN(domiid.value, machine);
6740     if (NS_SUCCEEDED(rc))
6741         rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
6742     if (NS_FAILED(rc)) {
6743         virReportError(VIR_ERR_INTERNAL_ERROR,
6744                        _("could not open VirtualBox session with domain %s"),
6745                        dom->name);
6746         goto cleanup;
6747     }
6748
6749     rc = console->vtbl->RestoreSnapshot(console, snapshot, &progress);
6750     if (NS_FAILED(rc) || !progress) {
6751         if (rc == VBOX_E_INVALID_VM_STATE) {
6752             virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6753                            _("cannot restore domain snapshot for running domain"));
6754         } else {
6755             virReportError(VIR_ERR_INTERNAL_ERROR,
6756                            _("could not restore snapshot for domain %s"),
6757                            dom->name);
6758         }
6759         goto cleanup;
6760     }
6761
6762     progress->vtbl->WaitForCompletion(progress, -1);
6763     progress->vtbl->GetResultCode(progress, &result);
6764     if (NS_FAILED(result)) {
6765         virReportError(VIR_ERR_INTERNAL_ERROR,
6766                        _("could not restore snapshot for domain %s"), dom->name);
6767         goto cleanup;
6768     }
6769
6770     ret = 0;
6771
6772  cleanup:
6773     VBOX_RELEASE(progress);
6774     VBOX_RELEASE(console);
6775     VBOX_SESSION_CLOSE();
6776     vboxIIDUnalloc(&domiid);
6777     return ret;
6778 }
6779 #endif
6780
6781 static int
6782 vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
6783                            unsigned int flags)
6784 {
6785     virDomainPtr dom = snapshot->domain;
6786     VBOX_OBJECT_CHECK(dom->conn, int, -1);
6787     vboxIID domiid = VBOX_IID_INITIALIZER;
6788     IMachine *machine = NULL;
6789     ISnapshot *newSnapshot = NULL;
6790     ISnapshot *prevSnapshot = NULL;
6791     PRBool online = PR_FALSE;
6792     PRUint32 state;
6793     nsresult rc;
6794
6795     virCheckFlags(0, -1);
6796
6797     vboxIIDFromUUID(&domiid, dom->uuid);
6798     rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
6799     if (NS_FAILED(rc)) {
6800         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6801                        _("no domain with matching UUID"));
6802         goto cleanup;
6803     }
6804
6805     newSnapshot = vboxDomainSnapshotGet(data, dom, machine, snapshot->name);
6806     if (!newSnapshot)
6807         goto cleanup;
6808
6809     rc = newSnapshot->vtbl->GetOnline(newSnapshot, &online);
6810     if (NS_FAILED(rc)) {
6811         virReportError(VIR_ERR_INTERNAL_ERROR,
6812                        _("could not get online state of snapshot %s"),
6813                        snapshot->name);
6814         goto cleanup;
6815     }
6816
6817     rc = machine->vtbl->GetCurrentSnapshot(machine, &prevSnapshot);
6818     if (NS_FAILED(rc)) {
6819         virReportError(VIR_ERR_INTERNAL_ERROR,
6820                        _("could not get current snapshot of domain %s"),
6821                        dom->name);
6822         goto cleanup;
6823     }
6824
6825     rc = machine->vtbl->GetState(machine, &state);
6826     if (NS_FAILED(rc)) {
6827         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6828                        _("could not get domain state"));
6829         goto cleanup;
6830     }
6831
6832     if (state >= MachineState_FirstOnline
6833         && state <= MachineState_LastOnline) {
6834         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6835                        _("cannot revert snapshot of running domain"));
6836         goto cleanup;
6837     }
6838
6839     if (vboxDomainSnapshotRestore(dom, machine, newSnapshot))
6840         goto cleanup;
6841
6842     if (online) {
6843         ret = vboxDomainCreate(dom);
6844         if (!ret)
6845             vboxDomainSnapshotRestore(dom, machine, prevSnapshot);
6846     } else
6847         ret = 0;
6848
6849  cleanup:
6850     VBOX_RELEASE(prevSnapshot);
6851     VBOX_RELEASE(newSnapshot);
6852     vboxIIDUnalloc(&domiid);
6853     return ret;
6854 }
6855
6856 static int
6857 vboxDomainSnapshotDeleteSingle(vboxGlobalData *data,
6858                                IConsole *console,
6859                                ISnapshot *snapshot)
6860 {
6861     IProgress *progress = NULL;
6862     vboxIID iid = VBOX_IID_INITIALIZER;
6863     int ret = -1;
6864     nsresult rc;
6865 #if VBOX_API_VERSION == 2002000
6866     nsresult result;
6867 #else
6868     PRInt32 result;
6869 #endif
6870
6871     rc = snapshot->vtbl->GetId(snapshot, &iid.value);
6872     if (NS_FAILED(rc)) {
6873         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6874                        _("could not get snapshot UUID"));
6875         goto cleanup;
6876     }
6877
6878 #if VBOX_API_VERSION < 3001000
6879     rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress);
6880 #else
6881     rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress);
6882 #endif
6883     if (NS_FAILED(rc) || !progress) {
6884         if (rc == VBOX_E_INVALID_VM_STATE) {
6885             virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6886                            _("cannot delete domain snapshot for running domain"));
6887         } else {
6888             virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6889                            _("could not delete snapshot"));
6890         }
6891         goto cleanup;
6892     }
6893
6894     progress->vtbl->WaitForCompletion(progress, -1);
6895     progress->vtbl->GetResultCode(progress, &result);
6896     if (NS_FAILED(result)) {
6897         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6898                        _("could not delete snapshot"));
6899         goto cleanup;
6900     }
6901
6902     ret = 0;
6903
6904  cleanup:
6905     VBOX_RELEASE(progress);
6906     vboxIIDUnalloc(&iid);
6907     return ret;
6908 }
6909
6910 static int
6911 vboxDomainSnapshotDeleteTree(vboxGlobalData *data,
6912                              IConsole *console,
6913                              ISnapshot *snapshot)
6914 {
6915     vboxArray children = VBOX_ARRAY_INITIALIZER;
6916     int ret = -1;
6917     nsresult rc;
6918     size_t i;
6919
6920     rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren);
6921     if (NS_FAILED(rc)) {
6922         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6923                        _("could not get children snapshots"));
6924         goto cleanup;
6925     }
6926
6927     for (i = 0; i < children.count; i++) {
6928         if (vboxDomainSnapshotDeleteTree(data, console, children.items[i]))
6929             goto cleanup;
6930     }
6931
6932     ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot);
6933
6934  cleanup:
6935     vboxArrayRelease(&children);
6936     return ret;
6937 }
6938
6939 static int
6940 vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
6941                          unsigned int flags)
6942 {
6943     virDomainPtr dom = snapshot->domain;
6944     VBOX_OBJECT_CHECK(dom->conn, int, -1);
6945     vboxIID domiid = VBOX_IID_INITIALIZER;
6946     IMachine *machine = NULL;
6947     ISnapshot *snap = NULL;
6948     IConsole *console = NULL;
6949     PRUint32 state;
6950     nsresult rc;
6951
6952     virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
6953                   VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
6954
6955     vboxIIDFromUUID(&domiid, dom->uuid);
6956     rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
6957     if (NS_FAILED(rc)) {
6958         virReportError(VIR_ERR_NO_DOMAIN, "%s",
6959                        _("no domain with matching UUID"));
6960         goto cleanup;
6961     }
6962
6963     snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name);
6964     if (!snap)
6965         goto cleanup;
6966
6967     rc = machine->vtbl->GetState(machine, &state);
6968     if (NS_FAILED(rc)) {
6969         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
6970                        _("could not get domain state"));
6971         goto cleanup;
6972     }
6973
6974     /* VBOX snapshots do not require any libvirt metadata, making this
6975      * flag trivial once we know we have a valid snapshot.  */
6976     if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) {
6977         ret = 0;
6978         goto cleanup;
6979     }
6980
6981     if (state >= MachineState_FirstOnline
6982         && state <= MachineState_LastOnline) {
6983         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6984                        _("cannot delete snapshots of running domain"));
6985         goto cleanup;
6986     }
6987
6988     rc = VBOX_SESSION_OPEN(domiid.value, machine);
6989     if (NS_SUCCEEDED(rc))
6990         rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
6991     if (NS_FAILED(rc)) {
6992         virReportError(VIR_ERR_INTERNAL_ERROR,
6993                        _("could not open VirtualBox session with domain %s"),
6994                        dom->name);
6995         goto cleanup;
6996     }
6997
6998     if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
6999         ret = vboxDomainSnapshotDeleteTree(data, console, snap);
7000     else
7001         ret = vboxDomainSnapshotDeleteSingle(data, console, snap);
7002
7003  cleanup:
7004     VBOX_RELEASE(console);
7005     VBOX_RELEASE(snap);
7006     vboxIIDUnalloc(&domiid);
7007     VBOX_SESSION_CLOSE();
7008     return ret;
7009 }
7010
7011 #if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
7012     /* No Callback support for VirtualBox 2.2.* series */
7013     /* No Callback support for VirtualBox 4.* series */
7014 #else /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
7015
7016 /* Functions needed for Callbacks */
7017 static nsresult PR_COM_METHOD
7018 vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7019                                  PRUnichar *machineId, PRUint32 state)
7020 {
7021     virDomainPtr dom = NULL;
7022     int event        = 0;
7023     int detail       = 0;
7024
7025     vboxDriverLock(g_pVBoxGlobalData);
7026
7027     VIR_DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state);
7028     DEBUGPRUnichar("machineId", machineId);
7029
7030     if (machineId) {
7031         char *machineIdUtf8       = NULL;
7032         unsigned char uuid[VIR_UUID_BUFLEN];
7033
7034         g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
7035         ignore_value(virUUIDParse(machineIdUtf8, uuid));
7036
7037         dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
7038         if (dom) {
7039             virObjectEventPtr ev;
7040
7041             if (state == MachineState_Starting) {
7042                 event  = VIR_DOMAIN_EVENT_STARTED;
7043                 detail = VIR_DOMAIN_EVENT_STARTED_BOOTED;
7044             } else if (state == MachineState_Restoring) {
7045                 event  = VIR_DOMAIN_EVENT_STARTED;
7046                 detail = VIR_DOMAIN_EVENT_STARTED_RESTORED;
7047             } else if (state == MachineState_Paused) {
7048                 event  = VIR_DOMAIN_EVENT_SUSPENDED;
7049                 detail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
7050             } else if (state == MachineState_Running) {
7051                 event  = VIR_DOMAIN_EVENT_RESUMED;
7052                 detail = VIR_DOMAIN_EVENT_RESUMED_UNPAUSED;
7053             } else if (state == MachineState_PoweredOff) {
7054                 event  = VIR_DOMAIN_EVENT_STOPPED;
7055                 detail = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
7056             } else if (state == MachineState_Stopping) {
7057                 event  = VIR_DOMAIN_EVENT_STOPPED;
7058                 detail = VIR_DOMAIN_EVENT_STOPPED_DESTROYED;
7059             } else if (state == MachineState_Aborted) {
7060                 event  = VIR_DOMAIN_EVENT_STOPPED;
7061                 detail = VIR_DOMAIN_EVENT_STOPPED_CRASHED;
7062             } else if (state == MachineState_Saving) {
7063                 event  = VIR_DOMAIN_EVENT_STOPPED;
7064                 detail = VIR_DOMAIN_EVENT_STOPPED_SAVED;
7065             } else {
7066                 event  = VIR_DOMAIN_EVENT_STOPPED;
7067                 detail = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
7068             }
7069
7070             ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
7071
7072             if (ev)
7073                 virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
7074         }
7075     }
7076
7077     vboxDriverUnlock(g_pVBoxGlobalData);
7078
7079     return NS_OK;
7080 }
7081
7082 static nsresult PR_COM_METHOD
7083 vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7084                                 PRUnichar *machineId)
7085 {
7086     VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7087     DEBUGPRUnichar("machineId", machineId);
7088
7089     return NS_OK;
7090 }
7091
7092 static nsresult PR_COM_METHOD
7093 vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7094                                  PRUnichar *machineId, PRUnichar *key,
7095                                  PRUnichar *value,
7096                                  PRUnichar **error ATTRIBUTE_UNUSED,
7097                                  PRBool *allowChange ATTRIBUTE_UNUSED)
7098 {
7099     VIR_DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false");
7100     DEBUGPRUnichar("machineId", machineId);
7101     DEBUGPRUnichar("key", key);
7102     DEBUGPRUnichar("value", value);
7103
7104     return NS_OK;
7105 }
7106
7107 static nsresult PR_COM_METHOD
7108 vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7109                               PRUnichar *machineId,
7110                               PRUnichar *key, PRUnichar *value)
7111 {
7112     VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7113     DEBUGPRUnichar("machineId", machineId);
7114     DEBUGPRUnichar("key", key);
7115     DEBUGPRUnichar("value", value);
7116
7117     return NS_OK;
7118 }
7119
7120 # if VBOX_API_VERSION < 3001000
7121 static nsresult PR_COM_METHOD
7122 vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7123                               PRUnichar *mediaId,
7124                               PRUint32 mediaType ATTRIBUTE_UNUSED,
7125                               PRBool registered ATTRIBUTE_UNUSED)
7126 {
7127     VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
7128     VIR_DEBUG("mediaType: %d", mediaType);
7129     DEBUGPRUnichar("mediaId", mediaId);
7130
7131     return NS_OK;
7132 }
7133 # else  /* VBOX_API_VERSION >= 3001000 */
7134 # endif /* VBOX_API_VERSION >= 3001000 */
7135
7136 static nsresult PR_COM_METHOD
7137 vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7138                                 PRUnichar *machineId, PRBool registered)
7139 {
7140     virDomainPtr dom = NULL;
7141     int event        = 0;
7142     int detail       = 0;
7143
7144     vboxDriverLock(g_pVBoxGlobalData);
7145
7146     VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
7147     DEBUGPRUnichar("machineId", machineId);
7148
7149     if (machineId) {
7150         char *machineIdUtf8       = NULL;
7151         unsigned char uuid[VIR_UUID_BUFLEN];
7152
7153         g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
7154         ignore_value(virUUIDParse(machineIdUtf8, uuid));
7155
7156         dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
7157         if (dom) {
7158             virObjectEventPtr ev;
7159
7160             /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED
7161              * event because the when the machine is de-registered the call
7162              * to vboxDomainLookupByUUID fails and thus we don't get any
7163              * dom pointer which is necessary (null dom pointer doesn't work)
7164              * to show the VIR_DOMAIN_EVENT_UNDEFINED event
7165              */
7166             if (registered) {
7167                 event  = VIR_DOMAIN_EVENT_DEFINED;
7168                 detail = VIR_DOMAIN_EVENT_DEFINED_ADDED;
7169             } else {
7170                 event  = VIR_DOMAIN_EVENT_UNDEFINED;
7171                 detail = VIR_DOMAIN_EVENT_UNDEFINED_REMOVED;
7172             }
7173
7174             ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
7175
7176             if (ev)
7177                 virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
7178         }
7179     }
7180
7181     vboxDriverUnlock(g_pVBoxGlobalData);
7182
7183     return NS_OK;
7184 }
7185
7186 static nsresult PR_COM_METHOD
7187 vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7188                                  PRUnichar *machineId,
7189                                  PRUint32 state ATTRIBUTE_UNUSED)
7190 {
7191     VIR_DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state);
7192     DEBUGPRUnichar("machineId", machineId);
7193
7194     return NS_OK;
7195 }
7196
7197 static nsresult PR_COM_METHOD
7198 vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7199                             PRUnichar *machineId,
7200                             PRUnichar *snapshotId)
7201 {
7202     VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7203     DEBUGPRUnichar("machineId", machineId);
7204     DEBUGPRUnichar("snapshotId", snapshotId);
7205
7206     return NS_OK;
7207 }
7208
7209 static nsresult PR_COM_METHOD
7210 vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7211                                 PRUnichar *machineId,
7212                                 PRUnichar *snapshotId)
7213 {
7214     VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7215     DEBUGPRUnichar("machineId", machineId);
7216     DEBUGPRUnichar("snapshotId", snapshotId);
7217
7218     return NS_OK;
7219 }
7220
7221 static nsresult PR_COM_METHOD
7222 vboxCallbackOnSnapshotChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7223                              PRUnichar *machineId,
7224                              PRUnichar *snapshotId)
7225 {
7226     VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7227     DEBUGPRUnichar("machineId", machineId);
7228     DEBUGPRUnichar("snapshotId", snapshotId);
7229
7230     return NS_OK;
7231 }
7232
7233 static nsresult PR_COM_METHOD
7234 vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7235                                   PRUnichar *machineId, PRUnichar *name,
7236                                   PRUnichar *value, PRUnichar *flags)
7237 {
7238     VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7239     DEBUGPRUnichar("machineId", machineId);
7240     DEBUGPRUnichar("name", name);
7241     DEBUGPRUnichar("value", value);
7242     DEBUGPRUnichar("flags", flags);
7243
7244     return NS_OK;
7245 }
7246
7247 static nsresult PR_COM_METHOD
7248 vboxCallbackAddRef(nsISupports *pThis ATTRIBUTE_UNUSED)
7249 {
7250     nsresult c;
7251
7252     c = ++g_pVBoxGlobalData->vboxCallBackRefCount;
7253
7254     VIR_DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c);
7255
7256     return c;
7257 }
7258
7259 static nsresult PR_COM_METHOD
7260 vboxCallbackRelease(nsISupports *pThis)
7261 {
7262     nsresult c;
7263
7264     c = --g_pVBoxGlobalData->vboxCallBackRefCount;
7265     if (c == 0) {
7266         /* delete object */
7267         VIR_FREE(pThis->vtbl);
7268         VIR_FREE(pThis);
7269     }
7270
7271     VIR_DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c);
7272
7273     return c;
7274 }
7275
7276 static nsresult PR_COM_METHOD
7277 vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp)
7278 {
7279     IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis;
7280     static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID;
7281     static const nsID isupportIID = NS_ISUPPORTS_IID;
7282
7283     /* Match UUID for IVirtualBoxCallback class */
7284     if (memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 ||
7285         memcmp(iid, &isupportIID, sizeof(nsID)) == 0) {
7286         g_pVBoxGlobalData->vboxCallBackRefCount++;
7287         *resultp = that;
7288
7289         VIR_DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount);
7290
7291         return NS_OK;
7292     }
7293
7294
7295     VIR_DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis);
7296     DEBUGUUID("The UUID Callback Interface expects", iid);
7297     DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID);
7298     return NS_NOINTERFACE;
7299 }
7300
7301
7302 static IVirtualBoxCallback *vboxAllocCallbackObj(void) {
7303     IVirtualBoxCallback *vboxCallback = NULL;
7304
7305     /* Allocate, Initialize and return a valid
7306      * IVirtualBoxCallback object here
7307      */
7308     if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) {
7309         VIR_FREE(vboxCallback);
7310         return NULL;
7311     }
7312
7313     {
7314         vboxCallback->vtbl->nsisupports.AddRef          = &vboxCallbackAddRef;
7315         vboxCallback->vtbl->nsisupports.Release         = &vboxCallbackRelease;
7316         vboxCallback->vtbl->nsisupports.QueryInterface  = &vboxCallbackQueryInterface;
7317         vboxCallback->vtbl->OnMachineStateChange        = &vboxCallbackOnMachineStateChange;
7318         vboxCallback->vtbl->OnMachineDataChange         = &vboxCallbackOnMachineDataChange;
7319         vboxCallback->vtbl->OnExtraDataCanChange        = &vboxCallbackOnExtraDataCanChange;
7320         vboxCallback->vtbl->OnExtraDataChange           = &vboxCallbackOnExtraDataChange;
7321 # if VBOX_API_VERSION < 3001000
7322         vboxCallback->vtbl->OnMediaRegistered           = &vboxCallbackOnMediaRegistered;
7323 # else  /* VBOX_API_VERSION >= 3001000 */
7324 # endif /* VBOX_API_VERSION >= 3001000 */
7325         vboxCallback->vtbl->OnMachineRegistered         = &vboxCallbackOnMachineRegistered;
7326         vboxCallback->vtbl->OnSessionStateChange        = &vboxCallbackOnSessionStateChange;
7327         vboxCallback->vtbl->OnSnapshotTaken             = &vboxCallbackOnSnapshotTaken;
7328 # if VBOX_API_VERSION < 3002000
7329         vboxCallback->vtbl->OnSnapshotDiscarded         = &vboxCallbackOnSnapshotDiscarded;
7330 # else /* VBOX_API_VERSION >= 3002000 */
7331         vboxCallback->vtbl->OnSnapshotDeleted           = &vboxCallbackOnSnapshotDiscarded;
7332 # endif /* VBOX_API_VERSION >= 3002000 */
7333         vboxCallback->vtbl->OnSnapshotChange            = &vboxCallbackOnSnapshotChange;
7334         vboxCallback->vtbl->OnGuestPropertyChange       = &vboxCallbackOnGuestPropertyChange;
7335         g_pVBoxGlobalData->vboxCallBackRefCount = 1;
7336
7337     }
7338
7339     return vboxCallback;
7340 }
7341
7342 static void vboxReadCallback(int watch ATTRIBUTE_UNUSED,
7343                              int fd,
7344                              int events ATTRIBUTE_UNUSED,
7345                              void *opaque ATTRIBUTE_UNUSED)
7346 {
7347     if (fd >= 0) {
7348         g_pVBoxGlobalData->vboxQueue->vtbl->ProcessPendingEvents(g_pVBoxGlobalData->vboxQueue);
7349     } else {
7350         nsresult rc;
7351         PLEvent *pEvent = NULL;
7352
7353         rc = g_pVBoxGlobalData->vboxQueue->vtbl->WaitForEvent(g_pVBoxGlobalData->vboxQueue, &pEvent);
7354         if (NS_SUCCEEDED(rc))
7355             g_pVBoxGlobalData->vboxQueue->vtbl->HandleEvent(g_pVBoxGlobalData->vboxQueue, pEvent);
7356     }
7357 }
7358
7359 static int
7360 vboxConnectDomainEventRegister(virConnectPtr conn,
7361                                virConnectDomainEventCallback callback,
7362                                void *opaque,
7363                                virFreeCallback freecb)
7364 {
7365     VBOX_OBJECT_CHECK(conn, int, -1);
7366     int vboxRet          = -1;
7367     nsresult rc;
7368
7369     /* Locking has to be there as callbacks are not
7370      * really fully thread safe
7371      */
7372     vboxDriverLock(data);
7373
7374     if (data->vboxCallback == NULL) {
7375         data->vboxCallback = vboxAllocCallbackObj();
7376         if (data->vboxCallback != NULL) {
7377             rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
7378             if (NS_SUCCEEDED(rc)) {
7379                 vboxRet = 0;
7380             }
7381         }
7382     } else {
7383         vboxRet = 0;
7384     }
7385
7386     /* Get the vbox file handle and add a event handle to it
7387      * so that the events can be passed down to the user
7388      */
7389     if (vboxRet == 0) {
7390         if (data->fdWatch < 0) {
7391             PRInt32 vboxFileHandle;
7392             vboxFileHandle = data->vboxQueue->vtbl->GetEventQueueSelectFD(data->vboxQueue);
7393
7394             data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL);
7395         }
7396
7397         if (data->fdWatch >= 0) {
7398             /* Once a callback is registered with virtualbox, use a list
7399              * to store the callbacks registered with libvirt so that
7400              * later you can iterate over them
7401              */
7402
7403             ret = virDomainEventStateRegister(conn, data->domainEvents,
7404                                               callback, opaque, freecb);
7405             VIR_DEBUG("virObjectEventStateRegister (ret = %d) (conn: %p, "
7406                       "callback: %p, opaque: %p, "
7407                       "freecb: %p)", ret, conn, callback,
7408                       opaque, freecb);
7409         }
7410     }
7411
7412     vboxDriverUnlock(data);
7413
7414     if (ret >= 0) {
7415         return 0;
7416     } else {
7417         if (data->vboxObj && data->vboxCallback) {
7418             data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
7419         }
7420         return -1;
7421     }
7422 }
7423
7424 static int
7425 vboxConnectDomainEventDeregister(virConnectPtr conn,
7426                                  virConnectDomainEventCallback callback)
7427 {
7428     VBOX_OBJECT_CHECK(conn, int, -1);
7429     int cnt;
7430
7431     /* Locking has to be there as callbacks are not
7432      * really fully thread safe
7433      */
7434     vboxDriverLock(data);
7435
7436     cnt = virDomainEventStateDeregister(conn, data->domainEvents,
7437                                         callback);
7438
7439     if (data->vboxCallback && cnt == 0) {
7440         data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
7441         VBOX_RELEASE(data->vboxCallback);
7442
7443         /* Remove the Event file handle on which we are listening as well */
7444         virEventRemoveHandle(data->fdWatch);
7445         data->fdWatch = -1;
7446     }
7447
7448     vboxDriverUnlock(data);
7449
7450     if (cnt >= 0)
7451         ret = 0;
7452
7453     return ret;
7454 }
7455
7456 static int vboxConnectDomainEventRegisterAny(virConnectPtr conn,
7457                                              virDomainPtr dom,
7458                                              int eventID,
7459                                              virConnectDomainEventGenericCallback callback,
7460                                              void *opaque,
7461                                              virFreeCallback freecb)
7462 {
7463     VBOX_OBJECT_CHECK(conn, int, -1);
7464     int vboxRet          = -1;
7465     nsresult rc;
7466
7467     /* Locking has to be there as callbacks are not
7468      * really fully thread safe
7469      */
7470     vboxDriverLock(data);
7471
7472     if (data->vboxCallback == NULL) {
7473         data->vboxCallback = vboxAllocCallbackObj();
7474         if (data->vboxCallback != NULL) {
7475             rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
7476             if (NS_SUCCEEDED(rc)) {
7477                 vboxRet = 0;
7478             }
7479         }
7480     } else {
7481         vboxRet = 0;
7482     }
7483
7484     /* Get the vbox file handle and add a event handle to it
7485      * so that the events can be passed down to the user
7486      */
7487     if (vboxRet == 0) {
7488         if (data->fdWatch < 0) {
7489             PRInt32 vboxFileHandle;
7490             vboxFileHandle = data->vboxQueue->vtbl->GetEventQueueSelectFD(data->vboxQueue);
7491
7492             data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL);
7493         }
7494
7495         if (data->fdWatch >= 0) {
7496             /* Once a callback is registered with virtualbox, use a list
7497              * to store the callbacks registered with libvirt so that
7498              * later you can iterate over them
7499              */
7500
7501             if (virDomainEventStateRegisterID(conn, data->domainEvents,
7502                                               dom, eventID,
7503                                               callback, opaque, freecb, &ret) < 0)
7504                 ret = -1;
7505             VIR_DEBUG("virDomainEventStateRegisterID (ret = %d) (conn: %p, "
7506                       "callback: %p, opaque: %p, "
7507                       "freecb: %p)", ret, conn, callback,
7508                       opaque, freecb);
7509         }
7510     }
7511
7512     vboxDriverUnlock(data);
7513
7514     if (ret >= 0) {
7515         return ret;
7516     } else {
7517         if (data->vboxObj && data->vboxCallback) {
7518             data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
7519         }
7520         return -1;
7521     }
7522 }
7523
7524 static int
7525 vboxConnectDomainEventDeregisterAny(virConnectPtr conn,
7526                                     int callbackID)
7527 {
7528     VBOX_OBJECT_CHECK(conn, int, -1);
7529     int cnt;
7530
7531     /* Locking has to be there as callbacks are not
7532      * really fully thread safe
7533      */
7534     vboxDriverLock(data);
7535
7536     cnt = virObjectEventStateDeregisterID(conn, data->domainEvents,
7537                                           callbackID);
7538
7539     if (data->vboxCallback && cnt == 0) {
7540         data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
7541         VBOX_RELEASE(data->vboxCallback);
7542
7543         /* Remove the Event file handle on which we are listening as well */
7544         virEventRemoveHandle(data->fdWatch);
7545         data->fdWatch = -1;
7546     }
7547
7548     vboxDriverUnlock(data);
7549
7550     if (cnt >= 0)
7551         ret = 0;
7552
7553     return ret;
7554 }
7555
7556 #endif /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
7557
7558 /**
7559  * The Network Functions here on
7560  */
7561 static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn,
7562                                         virConnectAuthPtr auth ATTRIBUTE_UNUSED,
7563                                         unsigned int flags)
7564 {
7565     vboxGlobalData *data = conn->privateData;
7566
7567     virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
7568
7569     if (STRNEQ(conn->driver->name, "VBOX"))
7570         goto cleanup;
7571
7572     if ((data->pFuncs      == NULL) ||
7573         (data->vboxObj     == NULL) ||
7574         (data->vboxSession == NULL))
7575         goto cleanup;
7576
7577     VIR_DEBUG("network initialized");
7578     /* conn->networkPrivateData = some network specific data */
7579     return VIR_DRV_OPEN_SUCCESS;
7580
7581  cleanup:
7582     return VIR_DRV_OPEN_DECLINED;
7583 }
7584
7585 static int vboxNetworkClose(virConnectPtr conn)
7586 {
7587     VIR_DEBUG("network uninitialized");
7588     conn->networkPrivateData = NULL;
7589     return 0;
7590 }
7591
7592 static int vboxConnectNumOfNetworks(virConnectPtr conn)
7593 {
7594     VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7595     vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7596     size_t i = 0;
7597
7598     vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7599
7600     for (i = 0; i < networkInterfaces.count; i++) {
7601         IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7602
7603         if (networkInterface) {
7604             PRUint32 interfaceType = 0;
7605
7606             networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7607             if (interfaceType == HostNetworkInterfaceType_HostOnly) {
7608                 PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7609
7610                 networkInterface->vtbl->GetStatus(networkInterface, &status);
7611
7612                 if (status == HostNetworkInterfaceStatus_Up)
7613                     ret++;
7614             }
7615         }
7616     }
7617
7618     vboxArrayRelease(&networkInterfaces);
7619
7620     VBOX_RELEASE(host);
7621
7622     VIR_DEBUG("numActive: %d", ret);
7623     return ret;
7624 }
7625
7626 static int vboxConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
7627     VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7628     vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7629     size_t i = 0;
7630
7631     vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7632
7633     for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
7634         IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7635
7636         if (networkInterface) {
7637             PRUint32 interfaceType = 0;
7638
7639             networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7640
7641             if (interfaceType == HostNetworkInterfaceType_HostOnly) {
7642                 PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7643
7644                 networkInterface->vtbl->GetStatus(networkInterface, &status);
7645
7646                 if (status == HostNetworkInterfaceStatus_Up) {
7647                     char *nameUtf8       = NULL;
7648                     PRUnichar *nameUtf16 = NULL;
7649
7650                     networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7651                     VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7652
7653                     VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
7654                     if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
7655                         ret++;
7656
7657                     VBOX_UTF8_FREE(nameUtf8);
7658                     VBOX_UTF16_FREE(nameUtf16);
7659                 }
7660             }
7661         }
7662     }
7663
7664     vboxArrayRelease(&networkInterfaces);
7665
7666     VBOX_RELEASE(host);
7667
7668     return ret;
7669 }
7670
7671 static int vboxConnectNumOfDefinedNetworks(virConnectPtr conn)
7672 {
7673     VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7674     vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7675     size_t i = 0;
7676
7677     vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7678
7679     for (i = 0; i < networkInterfaces.count; i++) {
7680         IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7681
7682         if (networkInterface) {
7683             PRUint32 interfaceType = 0;
7684
7685             networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7686             if (interfaceType == HostNetworkInterfaceType_HostOnly) {
7687                 PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7688
7689                 networkInterface->vtbl->GetStatus(networkInterface, &status);
7690
7691                 if (status == HostNetworkInterfaceStatus_Down)
7692                     ret++;
7693             }
7694         }
7695     }
7696
7697     vboxArrayRelease(&networkInterfaces);
7698
7699     VBOX_RELEASE(host);
7700
7701     VIR_DEBUG("numActive: %d", ret);
7702     return ret;
7703 }
7704
7705 static int vboxConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
7706     VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7707     vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7708     size_t i = 0;
7709
7710     vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7711
7712     for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
7713         IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7714
7715         if (networkInterface) {
7716             PRUint32 interfaceType = 0;
7717
7718             networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7719
7720             if (interfaceType == HostNetworkInterfaceType_HostOnly) {
7721                 PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7722
7723                 networkInterface->vtbl->GetStatus(networkInterface, &status);
7724
7725                 if (status == HostNetworkInterfaceStatus_Down) {
7726                     char *nameUtf8       = NULL;
7727                     PRUnichar *nameUtf16 = NULL;
7728
7729                     networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7730                     VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7731
7732                     VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
7733                     if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
7734                         ret++;
7735
7736                     VBOX_UTF8_FREE(nameUtf8);
7737                     VBOX_UTF16_FREE(nameUtf16);
7738                 }
7739             }
7740         }
7741     }
7742
7743     vboxArrayRelease(&networkInterfaces);
7744
7745     VBOX_RELEASE(host);
7746
7747     return ret;
7748 }
7749
7750 static virNetworkPtr
7751 vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
7752 {
7753     VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
7754     vboxIID iid = VBOX_IID_INITIALIZER;
7755
7756     vboxIIDFromUUID(&iid, uuid);
7757
7758     /* TODO: "internal" networks are just strings and
7759      * thus can't do much with them
7760      */
7761     IHostNetworkInterface *networkInterface = NULL;
7762
7763     host->vtbl->FindHostNetworkInterfaceById(host, iid.value, &networkInterface);
7764     if (networkInterface) {
7765         PRUint32 interfaceType = 0;
7766
7767         networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7768
7769         if (interfaceType == HostNetworkInterfaceType_HostOnly) {
7770             char *nameUtf8       = NULL;
7771             PRUnichar *nameUtf16 = NULL;
7772
7773             networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7774             VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7775
7776             ret = virGetNetwork(conn, nameUtf8, uuid);
7777
7778             VIR_DEBUG("Network Name: %s", nameUtf8);
7779             DEBUGIID("Network UUID", iid.value);
7780
7781             VBOX_UTF8_FREE(nameUtf8);
7782             VBOX_UTF16_FREE(nameUtf16);
7783         }
7784
7785         VBOX_RELEASE(networkInterface);
7786     }
7787
7788     VBOX_RELEASE(host);
7789
7790     vboxIIDUnalloc(&iid);
7791     return ret;
7792 }
7793
7794 static virNetworkPtr
7795 vboxNetworkLookupByName(virConnectPtr conn, const char *name)
7796 {
7797     VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
7798     PRUnichar *nameUtf16                    = NULL;
7799     IHostNetworkInterface *networkInterface = NULL;
7800
7801     VBOX_UTF8_TO_UTF16(name, &nameUtf16);
7802
7803     host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface);
7804
7805     if (networkInterface) {
7806         PRUint32 interfaceType = 0;
7807
7808         networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7809
7810         if (interfaceType == HostNetworkInterfaceType_HostOnly) {
7811             unsigned char uuid[VIR_UUID_BUFLEN];
7812             vboxIID iid = VBOX_IID_INITIALIZER;
7813
7814             networkInterface->vtbl->GetId(networkInterface, &iid.value);
7815             vboxIIDToUUID(&iid, uuid);
7816             ret = virGetNetwork(conn, name, uuid);
7817             VIR_DEBUG("Network Name: %s", name);
7818
7819             DEBUGIID("Network UUID", iid.value);
7820             vboxIIDUnalloc(&iid);
7821         }
7822
7823         VBOX_RELEASE(networkInterface);
7824     }
7825
7826     VBOX_UTF16_FREE(nameUtf16);
7827     VBOX_RELEASE(host);
7828
7829     return ret;
7830 }
7831
7832 static virNetworkPtr
7833 vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
7834 {
7835     VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
7836     PRUnichar *networkInterfaceNameUtf16    = NULL;
7837     char      *networkInterfaceNameUtf8     = NULL;
7838     IHostNetworkInterface *networkInterface = NULL;
7839     nsresult rc;
7840
7841     virNetworkDefPtr def = virNetworkDefParseString(xml);
7842     virNetworkIpDefPtr ipdef;
7843     virSocketAddr netmask;
7844
7845     if ((!def) ||
7846         (def->forward.type != VIR_NETWORK_FORWARD_NONE) ||
7847         (def->nips == 0 || !def->ips))
7848         goto cleanup;
7849
7850     /* Look for the first IPv4 IP address definition and use that.
7851      * If there weren't any IPv4 addresses, ignore the network (since it's
7852      * required below to have an IPv4 address)
7853     */
7854     ipdef = virNetworkDefGetIpByIndex(def, AF_INET, 0);
7855     if (!ipdef)
7856         goto cleanup;
7857
7858     if (virNetworkIpDefNetmask(ipdef, &netmask) < 0)
7859         goto cleanup;
7860
7861     /* the current limitation of hostonly network is that you can't
7862      * assign a name to it and it defaults to vboxnet*, for e.g:
7863      * vboxnet0, vboxnet1, etc. Also the UUID is assigned to it
7864      * automatically depending on the mac address and thus both
7865      * these paramters are ignored here for now.
7866      */
7867
7868 #if VBOX_API_VERSION == 2002000
7869     if (STREQ(def->name, "vboxnet0")) {
7870         PRUint32 interfaceType = 0;
7871
7872         VBOX_UTF8_TO_UTF16(def->name, &networkInterfaceNameUtf16);
7873         host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7874
7875         networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7876         if (interfaceType != HostNetworkInterfaceType_HostOnly) {
7877             VBOX_RELEASE(networkInterface);
7878             networkInterface = NULL;
7879         }
7880     }
7881 #else /* VBOX_API_VERSION != 2002000 */
7882     {
7883         IProgress *progress = NULL;
7884         host->vtbl->CreateHostOnlyNetworkInterface(host, &networkInterface,
7885                                                    &progress);
7886
7887         if (progress) {
7888             progress->vtbl->WaitForCompletion(progress, -1);
7889             VBOX_RELEASE(progress);
7890         }
7891     }
7892 #endif /* VBOX_API_VERSION != 2002000 */
7893
7894     if (networkInterface) {
7895         unsigned char uuid[VIR_UUID_BUFLEN];
7896         char      *networkNameUtf8  = NULL;
7897         PRUnichar *networkNameUtf16 = NULL;
7898         vboxIID vboxnetiid = VBOX_IID_INITIALIZER;
7899
7900         networkInterface->vtbl->GetName(networkInterface, &networkInterfaceNameUtf16);
7901         if (networkInterfaceNameUtf16) {
7902             VBOX_UTF16_TO_UTF8(networkInterfaceNameUtf16, &networkInterfaceNameUtf8);
7903
7904             if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", networkInterfaceNameUtf8) < 0) {
7905                 VBOX_RELEASE(host);
7906                 VBOX_RELEASE(networkInterface);
7907                 goto cleanup;
7908             }
7909         }
7910
7911         VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
7912
7913         /* Currently support only one dhcp server per network
7914          * with contigious address space from start to end
7915          */
7916         if ((ipdef->nranges >= 1) &&
7917             VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
7918             VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
7919             IDHCPServer *dhcpServer = NULL;
7920
7921             data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
7922                                                              networkNameUtf16,
7923                                                              &dhcpServer);
7924             if (!dhcpServer) {
7925                 /* create a dhcp server */
7926                 data->vboxObj->vtbl->CreateDHCPServer(data->vboxObj,
7927                                                       networkNameUtf16,
7928                                                       &dhcpServer);
7929                 VIR_DEBUG("couldn't find dhcp server so creating one");
7930             }
7931             if (dhcpServer) {
7932                 PRUnichar *ipAddressUtf16     = NULL;
7933                 PRUnichar *networkMaskUtf16   = NULL;
7934                 PRUnichar *fromIPAddressUtf16 = NULL;
7935                 PRUnichar *toIPAddressUtf16   = NULL;
7936                 PRUnichar *trunkTypeUtf16     = NULL;
7937
7938                 ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
7939                 networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
7940                 fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
7941                 toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
7942
7943                 if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL ||
7944                     fromIPAddressUtf16 == NULL || toIPAddressUtf16 == NULL) {
7945                     VBOX_UTF16_FREE(ipAddressUtf16);
7946                     VBOX_UTF16_FREE(networkMaskUtf16);
7947                     VBOX_UTF16_FREE(fromIPAddressUtf16);
7948                     VBOX_UTF16_FREE(toIPAddressUtf16);
7949                     VBOX_RELEASE(dhcpServer);
7950                     goto cleanup;
7951                 }
7952
7953                 VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);
7954
7955                 dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);
7956
7957                 dhcpServer->vtbl->SetConfiguration(dhcpServer,
7958                                                    ipAddressUtf16,
7959                                                    networkMaskUtf16,
7960                                                    fromIPAddressUtf16,
7961                                                    toIPAddressUtf16);
7962
7963                 if (start)
7964                     dhcpServer->vtbl->Start(dhcpServer,
7965                                             networkNameUtf16,
7966                                             networkInterfaceNameUtf16,
7967                                             trunkTypeUtf16);
7968
7969                 VBOX_UTF16_FREE(ipAddressUtf16);
7970                 VBOX_UTF16_FREE(networkMaskUtf16);
7971                 VBOX_UTF16_FREE(fromIPAddressUtf16);
7972                 VBOX_UTF16_FREE(toIPAddressUtf16);
7973                 VBOX_UTF16_FREE(trunkTypeUtf16);
7974                 VBOX_RELEASE(dhcpServer);
7975             }
7976         }
7977
7978         if ((ipdef->nhosts >= 1) &&
7979             VIR_SOCKET_ADDR_VALID(&ipdef->hosts[0].ip)) {
7980             PRUnichar *ipAddressUtf16   = NULL;
7981             PRUnichar *networkMaskUtf16 = NULL;
7982
7983             ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip);
7984             networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
7985
7986             if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) {
7987                 VBOX_UTF16_FREE(ipAddressUtf16);
7988                 VBOX_UTF16_FREE(networkMaskUtf16);
7989                 goto cleanup;
7990             }
7991
7992             /* Current drawback is that since EnableStaticIpConfig() sets
7993              * IP and enables the interface so even if the dhcpserver is not
7994              * started the interface is still up and running
7995              */
7996 #if VBOX_API_VERSION < 4002000
7997             networkInterface->vtbl->EnableStaticIpConfig(networkInterface,
7998                                                          ipAddressUtf16,
7999                                                          networkMaskUtf16);
8000 #else
8001             networkInterface->vtbl->EnableStaticIPConfig(networkInterface,
8002                                                          ipAddressUtf16,
8003                                                          networkMaskUtf16);
8004 #endif
8005
8006             VBOX_UTF16_FREE(ipAddressUtf16);
8007             VBOX_UTF16_FREE(networkMaskUtf16);
8008         } else {
8009 #if VBOX_API_VERSION < 4002000
8010             networkInterface->vtbl->EnableDynamicIpConfig(networkInterface);
8011             networkInterface->vtbl->DhcpRediscover(networkInterface);
8012 #else
8013             networkInterface->vtbl->EnableDynamicIPConfig(networkInterface);
8014             networkInterface->vtbl->DHCPRediscover(networkInterface);
8015 #endif
8016         }
8017
8018         rc = networkInterface->vtbl->GetId(networkInterface, &vboxnetiid.value);
8019         if (NS_SUCCEEDED(rc)) {
8020             vboxIIDToUUID(&vboxnetiid, uuid);
8021             DEBUGIID("Real Network UUID", vboxnetiid.value);
8022             vboxIIDUnalloc(&vboxnetiid);
8023             ret = virGetNetwork(conn, networkInterfaceNameUtf8, uuid);
8024         }
8025
8026         VIR_FREE(networkNameUtf8);
8027         VBOX_UTF16_FREE(networkNameUtf16);
8028         VBOX_RELEASE(networkInterface);
8029     }
8030
8031     VBOX_UTF8_FREE(networkInterfaceNameUtf8);
8032     VBOX_UTF16_FREE(networkInterfaceNameUtf16);
8033     VBOX_RELEASE(host);
8034
8035  cleanup:
8036     virNetworkDefFree(def);
8037     return ret;
8038 }
8039
8040 static virNetworkPtr vboxNetworkCreateXML(virConnectPtr conn, const char *xml)
8041 {
8042     return vboxNetworkDefineCreateXML(conn, xml, true);
8043 }
8044
8045 static virNetworkPtr vboxNetworkDefineXML(virConnectPtr conn, const char *xml)
8046 {
8047     return vboxNetworkDefineCreateXML(conn, xml, false);
8048 }
8049
8050 static int
8051 vboxNetworkUndefineDestroy(virNetworkPtr network, bool removeinterface)
8052 {
8053     VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
8054     char *networkNameUtf8 = NULL;
8055     PRUnichar *networkInterfaceNameUtf16    = NULL;
8056     IHostNetworkInterface *networkInterface = NULL;
8057
8058     /* Current limitation of the function for VirtualBox 2.2.* is
8059      * that you can't delete the default hostonly adaptor namely:
8060      * vboxnet0 and thus all this functions does is remove the
8061      * dhcp server configuration, but the network can still be used
8062      * by giving the machine static IP and also it will still
8063      * show up in the net-list in virsh
8064      */
8065
8066     if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
8067         goto cleanup;
8068
8069     VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8070
8071     host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8072
8073     if (networkInterface) {
8074         PRUint32 interfaceType = 0;
8075
8076         networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8077
8078         if (interfaceType == HostNetworkInterfaceType_HostOnly) {
8079             PRUnichar *networkNameUtf16 = NULL;
8080             IDHCPServer *dhcpServer     = NULL;
8081
8082 #if VBOX_API_VERSION != 2002000
8083             if (removeinterface) {
8084                 PRUnichar *iidUtf16 = NULL;
8085                 IProgress *progress = NULL;
8086
8087                 networkInterface->vtbl->GetId(networkInterface, &iidUtf16);
8088
8089                 if (iidUtf16) {
8090 # if VBOX_API_VERSION == 3000000
8091                     IHostNetworkInterface *netInt = NULL;
8092                     host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &netInt, &progress);
8093                     VBOX_RELEASE(netInt);
8094 # else  /* VBOX_API_VERSION > 3000000 */
8095                     host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &progress);
8096 # endif /* VBOX_API_VERSION > 3000000 */
8097                     VBOX_UTF16_FREE(iidUtf16);
8098                 }
8099
8100                 if (progress) {
8101                     progress->vtbl->WaitForCompletion(progress, -1);
8102                     VBOX_RELEASE(progress);
8103                 }
8104             }
8105 #endif /* VBOX_API_VERSION != 2002000 */
8106
8107             VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8108
8109             data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
8110                                                              networkNameUtf16,
8111                                                              &dhcpServer);
8112             if (dhcpServer) {
8113                 dhcpServer->vtbl->SetEnabled(dhcpServer, PR_FALSE);
8114                 dhcpServer->vtbl->Stop(dhcpServer);
8115                 if (removeinterface)
8116                     data->vboxObj->vtbl->RemoveDHCPServer(data->vboxObj, dhcpServer);
8117                 VBOX_RELEASE(dhcpServer);
8118             }
8119
8120             VBOX_UTF16_FREE(networkNameUtf16);
8121
8122         }
8123         VBOX_RELEASE(networkInterface);
8124     }
8125
8126     VBOX_UTF16_FREE(networkInterfaceNameUtf16);
8127     VBOX_RELEASE(host);
8128
8129     ret = 0;
8130
8131  cleanup:
8132     VIR_FREE(networkNameUtf8);
8133     return ret;
8134 }
8135
8136 static int vboxNetworkUndefine(virNetworkPtr network)
8137 {
8138     return vboxNetworkUndefineDestroy(network, true);
8139 }
8140
8141 static int vboxNetworkCreate(virNetworkPtr network)
8142 {
8143     VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
8144     char *networkNameUtf8 = NULL;
8145     PRUnichar *networkInterfaceNameUtf16    = NULL;
8146     IHostNetworkInterface *networkInterface = NULL;
8147
8148     /* Current limitation of the function for VirtualBox 2.2.* is
8149      * that the default hostonly network "vboxnet0" is always active
8150      * and thus all this functions does is start the dhcp server,
8151      * but the network can still be used without starting the dhcp
8152      * server by giving the machine static IP
8153      */
8154
8155     if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
8156         goto cleanup;
8157
8158     VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8159
8160     host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8161
8162     if (networkInterface) {
8163         PRUint32 interfaceType = 0;
8164
8165         networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8166
8167         if (interfaceType == HostNetworkInterfaceType_HostOnly) {
8168             PRUnichar *networkNameUtf16 = NULL;
8169             IDHCPServer *dhcpServer     = NULL;
8170
8171
8172             VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8173
8174             data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
8175                                                              networkNameUtf16,
8176                                                              &dhcpServer);
8177             if (dhcpServer) {
8178                 PRUnichar *trunkTypeUtf16 = NULL;
8179
8180                 dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);
8181
8182                 VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);
8183
8184                 dhcpServer->vtbl->Start(dhcpServer,
8185                                         networkNameUtf16,
8186                                         networkInterfaceNameUtf16,
8187                                         trunkTypeUtf16);
8188
8189                 VBOX_UTF16_FREE(trunkTypeUtf16);
8190                 VBOX_RELEASE(dhcpServer);
8191             }
8192
8193             VBOX_UTF16_FREE(networkNameUtf16);
8194         }
8195
8196         VBOX_RELEASE(networkInterface);
8197     }
8198
8199     VBOX_UTF16_FREE(networkInterfaceNameUtf16);
8200     VBOX_RELEASE(host);
8201
8202     ret = 0;
8203
8204  cleanup:
8205     VIR_FREE(networkNameUtf8);
8206     return ret;
8207 }
8208
8209 static int vboxNetworkDestroy(virNetworkPtr network)
8210 {
8211     return vboxNetworkUndefineDestroy(network, false);
8212 }
8213
8214 static char *vboxNetworkGetXMLDesc(virNetworkPtr network,
8215                                    unsigned int flags)
8216 {
8217     VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
8218     virNetworkDefPtr def  = NULL;
8219     virNetworkIpDefPtr ipdef = NULL;
8220     char *networkNameUtf8 = NULL;
8221     PRUnichar *networkInterfaceNameUtf16    = NULL;
8222     IHostNetworkInterface *networkInterface = NULL;
8223
8224     virCheckFlags(0, NULL);
8225
8226     if (VIR_ALLOC(def) < 0)
8227         goto cleanup;
8228     if (VIR_ALLOC(ipdef) < 0)
8229         goto cleanup;
8230     def->ips = ipdef;
8231     def->nips = 1;
8232
8233     if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
8234         goto cleanup;
8235
8236     VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8237
8238     host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8239
8240     if (networkInterface) {
8241         PRUint32 interfaceType = 0;
8242
8243         networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8244
8245         if (interfaceType == HostNetworkInterfaceType_HostOnly) {
8246             if (VIR_STRDUP(def->name, network->name) >= 0) {
8247                 PRUnichar *networkNameUtf16 = NULL;
8248                 IDHCPServer *dhcpServer     = NULL;
8249                 vboxIID vboxnet0IID = VBOX_IID_INITIALIZER;
8250
8251                 networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID.value);
8252                 vboxIIDToUUID(&vboxnet0IID, def->uuid);
8253
8254                 VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8255
8256                 def->forward.type = VIR_NETWORK_FORWARD_NONE;
8257
8258                 data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
8259                                                                  networkNameUtf16,
8260                                                                  &dhcpServer);
8261                 if (dhcpServer) {
8262                     ipdef->nranges = 1;
8263                     if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >=0) {
8264                         PRUnichar *ipAddressUtf16     = NULL;
8265                         PRUnichar *networkMaskUtf16   = NULL;
8266                         PRUnichar *fromIPAddressUtf16 = NULL;
8267                         PRUnichar *toIPAddressUtf16   = NULL;
8268                         bool errorOccurred = false;
8269
8270                         dhcpServer->vtbl->GetIPAddress(dhcpServer, &ipAddressUtf16);
8271                         dhcpServer->vtbl->GetNetworkMask(dhcpServer, &networkMaskUtf16);
8272                         dhcpServer->vtbl->GetLowerIP(dhcpServer, &fromIPAddressUtf16);
8273                         dhcpServer->vtbl->GetUpperIP(dhcpServer, &toIPAddressUtf16);
8274                         /* Currently virtualbox supports only one dhcp server per network
8275                          * with contigious address space from start to end
8276                          */
8277                         if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8278                                                      &ipdef->address) < 0 ||
8279                             vboxSocketParseAddrUtf16(data, networkMaskUtf16,
8280                                                      &ipdef->netmask) < 0 ||
8281                             vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
8282                                                      &ipdef->ranges[0].start) < 0 ||
8283                             vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
8284                                                      &ipdef->ranges[0].end) < 0) {
8285                             errorOccurred = true;
8286                         }
8287
8288                         VBOX_UTF16_FREE(ipAddressUtf16);
8289                         VBOX_UTF16_FREE(networkMaskUtf16);
8290                         VBOX_UTF16_FREE(fromIPAddressUtf16);
8291                         VBOX_UTF16_FREE(toIPAddressUtf16);
8292
8293                         if (errorOccurred) {
8294                             goto cleanup;
8295                         }
8296                     } else {
8297                         ipdef->nranges = 0;
8298                     }
8299
8300                     ipdef->nhosts = 1;
8301                     if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >=0) {
8302                         if (VIR_STRDUP(ipdef->hosts[0].name, network->name) < 0) {
8303                             VIR_FREE(ipdef->hosts);
8304                             ipdef->nhosts = 0;
8305                         } else {
8306                             PRUnichar *macAddressUtf16 = NULL;
8307                             PRUnichar *ipAddressUtf16  = NULL;
8308                             bool errorOccurred = false;
8309
8310                             networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
8311                             networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);
8312
8313                             VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac);
8314
8315                             if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8316                                                          &ipdef->hosts[0].ip) < 0) {
8317                                 errorOccurred = true;
8318                             }
8319
8320                             VBOX_UTF16_FREE(macAddressUtf16);
8321                             VBOX_UTF16_FREE(ipAddressUtf16);
8322
8323                             if (errorOccurred) {
8324                                 goto cleanup;
8325                             }
8326                         }
8327                     } else {
8328                         ipdef->nhosts = 0;
8329                     }
8330
8331                     VBOX_RELEASE(dhcpServer);
8332                 } else {
8333                     PRUnichar *networkMaskUtf16 = NULL;
8334                     PRUnichar *ipAddressUtf16   = NULL;
8335                     bool errorOccurred = false;
8336
8337                     networkInterface->vtbl->GetNetworkMask(networkInterface, &networkMaskUtf16);
8338                     networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);
8339
8340                     if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
8341                                                  &ipdef->netmask) < 0 ||
8342                         vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8343                                                  &ipdef->address) < 0) {
8344                         errorOccurred = true;
8345                     }
8346
8347                     VBOX_UTF16_FREE(networkMaskUtf16);
8348                     VBOX_UTF16_FREE(ipAddressUtf16);
8349
8350                     if (errorOccurred) {
8351                         goto cleanup;
8352                     }
8353                 }
8354
8355                 DEBUGIID("Network UUID", vboxnet0IID.value);
8356                 vboxIIDUnalloc(&vboxnet0IID);
8357                 VBOX_UTF16_FREE(networkNameUtf16);
8358             }
8359         }
8360
8361         VBOX_RELEASE(networkInterface);
8362     }
8363
8364     VBOX_UTF16_FREE(networkInterfaceNameUtf16);
8365     VBOX_RELEASE(host);
8366
8367     ret = virNetworkDefFormat(def, 0);
8368
8369  cleanup:
8370     virNetworkDefFree(def);
8371     VIR_FREE(networkNameUtf8);
8372     return ret;
8373 }
8374
8375 /**
8376  * The Storage Functions here on
8377  */
8378
8379 static virDrvOpenStatus vboxStorageOpen(virConnectPtr conn,
8380                                         virConnectAuthPtr auth ATTRIBUTE_UNUSED,
8381                                         unsigned int flags)
8382 {
8383     vboxGlobalData *data = conn->privateData;
8384
8385     virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
8386
8387     if (STRNEQ(conn->driver->name, "VBOX"))
8388         return VIR_DRV_OPEN_DECLINED;
8389
8390     if ((data->pFuncs      == NULL) ||
8391         (data->vboxObj     == NULL) ||
8392         (data->vboxSession == NULL))
8393         return VIR_DRV_OPEN_ERROR;
8394
8395     VIR_DEBUG("vbox storage initialized");
8396     /* conn->storagePrivateData = some storage specific data */
8397     return VIR_DRV_OPEN_SUCCESS;
8398 }
8399
8400 static int vboxStorageClose(virConnectPtr conn)
8401 {
8402     VIR_DEBUG("vbox storage uninitialized");
8403     conn->storagePrivateData = NULL;
8404     return 0;
8405 }
8406
8407 static int vboxConnectNumOfStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED)
8408 {
8409
8410     /** Currently only one pool supported, the default one
8411      * given by ISystemProperties::defaultHardDiskFolder()
8412      */
8413
8414     return 1;
8415 }
8416
8417 static int vboxConnectListStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
8418                                        char **const names, int nnames) {
8419     int numActive = 0;
8420
8421     if (nnames == 1 &&
8422         VIR_STRDUP(names[numActive], "default-pool") > 0)
8423         numActive++;
8424     return numActive;
8425 }
8426
8427 static virStoragePoolPtr
8428 vboxStoragePoolLookupByName(virConnectPtr conn, const char *name)
8429 {
8430     virStoragePoolPtr ret = NULL;
8431
8432     /** Current limitation of the function: since
8433      * the default pool doesn't have UUID just assign
8434      * one till vbox can handle pools
8435      */
8436     if (STREQ("default-pool", name)) {
8437         unsigned char uuid[VIR_UUID_BUFLEN];
8438         const char *uuidstr = "1deff1ff-1481-464f-967f-a50fe8936cc4";
8439
8440         ignore_value(virUUIDParse(uuidstr, uuid));
8441
8442         ret = virGetStoragePool(conn, name, uuid, NULL, NULL);
8443     }
8444
8445     return ret;
8446 }
8447
8448 static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool)
8449 {
8450     VBOX_OBJECT_CHECK(pool->conn, int, -1);
8451     vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8452     PRUint32 hardDiskAccessible = 0;
8453     nsresult rc;
8454     size_t i;
8455
8456     rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8457     if (NS_SUCCEEDED(rc)) {
8458         for (i = 0; i < hardDisks.count; ++i) {
8459             IHardDisk *hardDisk = hardDisks.items[i];
8460             if (hardDisk) {
8461                 PRUint32 hddstate;
8462
8463                 VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
8464                 if (hddstate != MediaState_Inaccessible)
8465                     hardDiskAccessible++;
8466             }
8467         }
8468
8469         vboxArrayRelease(&hardDisks);
8470
8471         ret = hardDiskAccessible;
8472     } else {
8473         ret = -1;
8474         virReportError(VIR_ERR_INTERNAL_ERROR,
8475                        _("could not get number of volumes in the pool: %s, rc=%08x"),
8476                        pool->name, (unsigned)rc);
8477     }
8478
8479     return ret;
8480 }
8481
8482 static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) {
8483     VBOX_OBJECT_CHECK(pool->conn, int, -1);
8484     vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8485     PRUint32 numActive     = 0;
8486     nsresult rc;
8487     size_t i;
8488
8489     rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8490     if (NS_SUCCEEDED(rc)) {
8491         for (i = 0; i < hardDisks.count && numActive < nnames; ++i) {
8492             IHardDisk *hardDisk = hardDisks.items[i];
8493
8494             if (hardDisk) {
8495                 PRUint32 hddstate;
8496                 char      *nameUtf8  = NULL;
8497                 PRUnichar *nameUtf16 = NULL;
8498
8499                 VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
8500                 if (hddstate != MediaState_Inaccessible) {
8501                     VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8502
8503                     VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
8504                     VBOX_UTF16_FREE(nameUtf16);
8505
8506                     if (nameUtf8) {
8507                         VIR_DEBUG("nnames[%d]: %s", numActive, nameUtf8);
8508                         if (VIR_STRDUP(names[numActive], nameUtf8) > 0)
8509                             numActive++;
8510
8511                         VBOX_UTF8_FREE(nameUtf8);
8512                     }
8513                 }
8514             }
8515         }
8516
8517         vboxArrayRelease(&hardDisks);
8518
8519         ret = numActive;
8520     } else {
8521         ret = -1;
8522         virReportError(VIR_ERR_INTERNAL_ERROR,
8523                        _("could not get the volume list in the pool: %s, rc=%08x"),
8524                        pool->name, (unsigned)rc);
8525     }
8526
8527     return ret;
8528 }
8529
8530 static virStorageVolPtr
8531 vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name)
8532 {
8533     VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8534     vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8535     nsresult rc;
8536     size_t i;
8537
8538     if (!name)
8539         return ret;
8540
8541     rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8542     if (NS_SUCCEEDED(rc)) {
8543         for (i = 0; i < hardDisks.count; ++i) {
8544             IHardDisk *hardDisk = hardDisks.items[i];
8545
8546             if (hardDisk) {
8547                 PRUint32 hddstate;
8548                 char      *nameUtf8  = NULL;
8549                 PRUnichar *nameUtf16 = NULL;
8550
8551                 VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
8552                 if (hddstate != MediaState_Inaccessible) {
8553                     VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8554
8555                     if (nameUtf16) {
8556                         VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
8557                         VBOX_UTF16_FREE(nameUtf16);
8558                     }
8559
8560                     if (nameUtf8 && STREQ(nameUtf8, name)) {
8561                         vboxIID hddIID = VBOX_IID_INITIALIZER;
8562                         unsigned char uuid[VIR_UUID_BUFLEN];
8563                         char key[VIR_UUID_STRING_BUFLEN] = "";
8564
8565                         rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
8566                         if (NS_SUCCEEDED(rc)) {
8567                             vboxIIDToUUID(&hddIID, uuid);
8568                             virUUIDFormat(uuid, key);
8569
8570                             ret = virGetStorageVol(pool->conn, pool->name, name, key,
8571                                                    NULL, NULL);
8572
8573                             VIR_DEBUG("virStorageVolPtr: %p", ret);
8574                             VIR_DEBUG("Storage Volume Name: %s", name);
8575                             VIR_DEBUG("Storage Volume key : %s", key);
8576                             VIR_DEBUG("Storage Volume Pool: %s", pool->name);
8577                         }
8578
8579                         vboxIIDUnalloc(&hddIID);
8580                         VBOX_UTF8_FREE(nameUtf8);
8581                         break;
8582                     }
8583
8584                     VBOX_UTF8_FREE(nameUtf8);
8585                 }
8586             }
8587         }
8588
8589         vboxArrayRelease(&hardDisks);
8590     }
8591
8592     return ret;
8593 }
8594
8595 static virStorageVolPtr
8596 vboxStorageVolLookupByKey(virConnectPtr conn, const char *key)
8597 {
8598     VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
8599     vboxIID hddIID = VBOX_IID_INITIALIZER;
8600     unsigned char uuid[VIR_UUID_BUFLEN];
8601     IHardDisk *hardDisk  = NULL;
8602     nsresult rc;
8603
8604     if (!key)
8605         return ret;
8606
8607     if (virUUIDParse(key, uuid) < 0) {
8608         virReportError(VIR_ERR_INVALID_ARG,
8609                        _("Could not parse UUID from '%s'"), key);
8610         return NULL;
8611     }
8612
8613     vboxIIDFromUUID(&hddIID, uuid);
8614 #if VBOX_API_VERSION < 4000000
8615     rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8616 #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
8617     rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
8618                                          DeviceType_HardDisk, &hardDisk);
8619 #else
8620     rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
8621                                          DeviceType_HardDisk, AccessMode_ReadWrite,
8622                                          PR_FALSE, &hardDisk);
8623 #endif /* VBOX_API_VERSION >= 4000000 */
8624     if (NS_SUCCEEDED(rc)) {
8625         PRUint32 hddstate;
8626
8627         VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
8628         if (hddstate != MediaState_Inaccessible) {
8629             PRUnichar *hddNameUtf16 = NULL;
8630             char      *hddNameUtf8  = NULL;
8631
8632             VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
8633             VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
8634
8635             if (hddNameUtf8) {
8636                 if (vboxConnectNumOfStoragePools(conn) == 1) {
8637                     ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
8638                                            NULL, NULL);
8639                     VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
8640                 } else {
8641                     /* TODO: currently only one default pool and thus
8642                      * nothing here, change it when pools are supported
8643                      */
8644                 }
8645
8646                 VIR_DEBUG("Storage Volume Name: %s", key);
8647                 VIR_DEBUG("Storage Volume key : %s", hddNameUtf8);
8648
8649                 VBOX_UTF8_FREE(hddNameUtf8);
8650                 VBOX_UTF16_FREE(hddNameUtf16);
8651             }
8652         }
8653
8654         VBOX_MEDIUM_RELEASE(hardDisk);
8655     }
8656
8657     vboxIIDUnalloc(&hddIID);
8658     return ret;
8659 }
8660
8661 static virStorageVolPtr
8662 vboxStorageVolLookupByPath(virConnectPtr conn, const char *path)
8663 {
8664     VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
8665     PRUnichar *hddPathUtf16 = NULL;
8666     IHardDisk *hardDisk     = NULL;
8667     nsresult rc;
8668
8669     if (!path)
8670         return ret;
8671
8672     VBOX_UTF8_TO_UTF16(path, &hddPathUtf16);
8673
8674     if (!hddPathUtf16)
8675         return ret;
8676
8677 #if VBOX_API_VERSION < 4000000
8678     rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk);
8679 #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
8680     rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddPathUtf16,
8681                                          DeviceType_HardDisk, &hardDisk);
8682 #else
8683     rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddPathUtf16,
8684                                          DeviceType_HardDisk, AccessMode_ReadWrite,
8685                                          PR_FALSE, &hardDisk);
8686 #endif /* VBOX_API_VERSION >= 4000000 */
8687     if (NS_SUCCEEDED(rc)) {
8688         PRUint32 hddstate;
8689
8690         VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
8691         if (hddstate != MediaState_Inaccessible) {
8692             PRUnichar *hddNameUtf16 = NULL;
8693             char      *hddNameUtf8  = NULL;
8694
8695             VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
8696
8697             if (hddNameUtf16) {
8698                 VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
8699                 VBOX_UTF16_FREE(hddNameUtf16);
8700             }
8701
8702             if (hddNameUtf8) {
8703                 vboxIID hddIID = VBOX_IID_INITIALIZER;
8704                 unsigned char uuid[VIR_UUID_BUFLEN];
8705                 char key[VIR_UUID_STRING_BUFLEN] = "";
8706
8707                 rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
8708                 if (NS_SUCCEEDED(rc)) {
8709                     vboxIIDToUUID(&hddIID, uuid);
8710                     virUUIDFormat(uuid, key);
8711
8712                     /* TODO: currently only one default pool and thus
8713                      * the check below, change it when pools are supported
8714                      */
8715                     if (vboxConnectNumOfStoragePools(conn) == 1)
8716                         ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
8717                                                NULL, NULL);
8718
8719                     VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
8720                     VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8);
8721                     VIR_DEBUG("Storage Volume key : %s", key);
8722                 }
8723
8724                 vboxIIDUnalloc(&hddIID);
8725             }
8726
8727             VBOX_UTF8_FREE(hddNameUtf8);
8728         }
8729
8730         VBOX_MEDIUM_RELEASE(hardDisk);
8731     }
8732
8733     VBOX_UTF16_FREE(hddPathUtf16);
8734
8735     return ret;
8736 }
8737
8738 static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
8739                                                 const char *xml,
8740                                                 unsigned int flags)
8741 {
8742     VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8743     virStorageVolDefPtr  def  = NULL;
8744     PRUnichar *hddFormatUtf16 = NULL;
8745     PRUnichar *hddNameUtf16   = NULL;
8746     virStoragePoolDef poolDef;
8747     nsresult rc;
8748
8749     virCheckFlags(0, NULL);
8750
8751     /* since there is currently one default pool now
8752      * and virStorageVolDefFormat() just checks it type
8753      * so just assign it for now, change the behaviour
8754      * when vbox supports pools.
8755      */
8756     memset(&poolDef, 0, sizeof(poolDef));
8757     poolDef.type = VIR_STORAGE_POOL_DIR;
8758
8759     if ((def = virStorageVolDefParseString(&poolDef, xml)) == NULL)
8760         goto cleanup;
8761
8762     if (!def->name ||
8763         (def->type != VIR_STORAGE_VOL_FILE))
8764         goto cleanup;
8765
8766     /* For now only the vmdk, vpc and vdi type harddisk
8767      * variants can be created.  For historical reason, we default to vdi */
8768     if (def->target.format == VIR_STORAGE_FILE_VMDK) {
8769         VBOX_UTF8_TO_UTF16("VMDK", &hddFormatUtf16);
8770     } else if (def->target.format == VIR_STORAGE_FILE_VPC) {
8771         VBOX_UTF8_TO_UTF16("VHD", &hddFormatUtf16);
8772     } else {
8773         VBOX_UTF8_TO_UTF16("VDI", &hddFormatUtf16);
8774     }
8775
8776     VBOX_UTF8_TO_UTF16(def->name, &hddNameUtf16);
8777
8778     if (hddFormatUtf16 && hddNameUtf16) {
8779         IHardDisk *hardDisk = NULL;
8780
8781         rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk);
8782         if (NS_SUCCEEDED(rc)) {
8783             IProgress *progress    = NULL;
8784             PRUint64   logicalSize = VIR_DIV_UP(def->target.capacity,
8785                                                 1024 * 1024);
8786             PRUint32   variant     = HardDiskVariant_Standard;
8787
8788             if (def->target.capacity == def->target.allocation)
8789                 variant = HardDiskVariant_Fixed;
8790
8791 #if VBOX_API_VERSION < 4003000
8792             rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress);
8793 #else
8794             rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, 1, &variant, &progress);
8795 #endif
8796             if (NS_SUCCEEDED(rc) && progress) {
8797 #if VBOX_API_VERSION == 2002000
8798                 nsresult resultCode;
8799 #else
8800                 PRInt32  resultCode;
8801 #endif
8802
8803                 progress->vtbl->WaitForCompletion(progress, -1);
8804                 progress->vtbl->GetResultCode(progress, &resultCode);
8805
8806                 if (NS_SUCCEEDED(resultCode)) {
8807                     vboxIID hddIID = VBOX_IID_INITIALIZER;
8808                     unsigned char uuid[VIR_UUID_BUFLEN];
8809                     char key[VIR_UUID_STRING_BUFLEN] = "";
8810
8811                     rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
8812                     if (NS_SUCCEEDED(rc)) {
8813                         vboxIIDToUUID(&hddIID, uuid);
8814                         virUUIDFormat(uuid, key);
8815
8816                         ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
8817                                                NULL, NULL);
8818                     }
8819
8820                     vboxIIDUnalloc(&hddIID);
8821                 }
8822
8823                 VBOX_RELEASE(progress);
8824             }
8825         }
8826     }
8827
8828     VBOX_UTF16_FREE(hddFormatUtf16);
8829     VBOX_UTF16_FREE(hddNameUtf16);
8830
8831  cleanup:
8832     virStorageVolDefFree(def);
8833     return ret;
8834 }
8835
8836 static int vboxStorageVolDelete(virStorageVolPtr vol,
8837                                 unsigned int flags)
8838 {
8839     VBOX_OBJECT_CHECK(vol->conn, int, -1);
8840     vboxIID hddIID = VBOX_IID_INITIALIZER;
8841     unsigned char uuid[VIR_UUID_BUFLEN];
8842     IHardDisk *hardDisk  = NULL;
8843     int deregister = 0;
8844     nsresult rc;
8845     size_t i = 0;
8846     size_t j = 0;
8847
8848     virCheckFlags(0, -1);
8849
8850     if (virUUIDParse(vol->key, uuid) < 0) {
8851         virReportError(VIR_ERR_INVALID_ARG,
8852                        _("Could not parse UUID from '%s'"), vol->key);
8853         return -1;
8854     }
8855
8856     vboxIIDFromUUID(&hddIID, uuid);
8857 #if VBOX_API_VERSION < 4000000
8858     rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8859 #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
8860     rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
8861                                          DeviceType_HardDisk, &hardDisk);
8862 #else
8863     rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
8864                                          DeviceType_HardDisk, AccessMode_ReadWrite,
8865                                          PR_FALSE, &hardDisk);
8866 #endif /* VBOX_API_VERSION >= 4000000 */
8867     if (NS_SUCCEEDED(rc)) {
8868         PRUint32 hddstate;
8869
8870         VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
8871         if (hddstate != MediaState_Inaccessible) {
8872             PRUint32  machineIdsSize = 0;
8873             vboxArray machineIds = VBOX_ARRAY_INITIALIZER;
8874
8875 #if VBOX_API_VERSION < 3001000
8876             vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->imedium.GetMachineIds);
8877 #else  /* VBOX_API_VERSION >= 3001000 */
8878             vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->GetMachineIds);
8879 #endif /* VBOX_API_VERSION >= 3001000 */
8880
8881 #if VBOX_API_VERSION == 2002000 && defined WIN32
8882             /* VirtualBox 2.2 on Windows represents IIDs as GUIDs and the
8883              * machineIds array contains direct instances of the GUID struct
8884              * instead of pointers to the actual struct instances. But there
8885              * is no 128bit width simple item type for a SafeArray to fit a
8886              * GUID in. The largest simple type it 64bit width and VirtualBox
8887              * uses two of this 64bit items to represents one GUID. Therefore,
8888              * we divide the size of the SafeArray by two, to compensate for
8889              * this workaround in VirtualBox */
8890             machineIds.count /= 2;
8891 #endif /* VBOX_API_VERSION >= 2002000 */
8892
8893             machineIdsSize = machineIds.count;
8894
8895             for (i = 0; i < machineIds.count; i++) {
8896                 IMachine *machine = NULL;
8897                 vboxIID machineId = VBOX_IID_INITIALIZER;
8898
8899                 vboxIIDFromArrayItem(&machineId, &machineIds, i);
8900
8901 #if VBOX_API_VERSION >= 4000000
8902                 rc = VBOX_OBJECT_GET_MACHINE(machineId.value, &machine);
8903                 if (NS_FAILED(rc)) {
8904                     virReportError(VIR_ERR_NO_DOMAIN, "%s",
8905                                    _("no domain with matching uuid"));
8906                     break;
8907                 }
8908 #endif
8909
8910                 rc = VBOX_SESSION_OPEN(machineId.value, machine);
8911
8912                 if (NS_SUCCEEDED(rc)) {
8913
8914                     rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
8915                     if (NS_SUCCEEDED(rc)) {
8916                         vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER;
8917
8918 #if VBOX_API_VERSION < 3001000
8919                         vboxArrayGet(&hddAttachments, machine,
8920                                      machine->vtbl->GetHardDiskAttachments);
8921 #else  /* VBOX_API_VERSION >= 3001000 */
8922                         vboxArrayGet(&hddAttachments, machine,
8923                                      machine->vtbl->GetMediumAttachments);
8924 #endif /* VBOX_API_VERSION >= 3001000 */
8925                         for (j = 0; j < hddAttachments.count; j++) {
8926                             IHardDiskAttachment *hddAttachment = hddAttachments.items[j];
8927
8928                             if (hddAttachment) {
8929                                 IHardDisk *hdd = NULL;
8930
8931 #if VBOX_API_VERSION < 3001000
8932                                 rc = hddAttachment->vtbl->GetHardDisk(hddAttachment, &hdd);
8933 #else  /* VBOX_API_VERSION >= 3001000 */
8934                                 rc = hddAttachment->vtbl->GetMedium(hddAttachment, &hdd);
8935 #endif /* VBOX_API_VERSION >= 3001000 */
8936                                 if (NS_SUCCEEDED(rc) && hdd) {
8937                                     vboxIID iid = VBOX_IID_INITIALIZER;
8938
8939                                     rc = VBOX_MEDIUM_FUNC_ARG1(hdd, GetId, &iid.value);
8940                                     if (NS_SUCCEEDED(rc)) {
8941
8942                                             DEBUGIID("HardDisk (to delete) UUID", hddIID.value);
8943                                             DEBUGIID("HardDisk (currently processing) UUID", iid.value);
8944
8945                                         if (vboxIIDIsEqual(&hddIID, &iid)) {
8946                                             PRUnichar *controller = NULL;
8947                                             PRInt32    port       = 0;
8948                                             PRInt32    device     = 0;
8949
8950                                             DEBUGIID("Found HardDisk to delete, UUID", hddIID.value);
8951
8952                                             hddAttachment->vtbl->GetController(hddAttachment, &controller);
8953                                             hddAttachment->vtbl->GetPort(hddAttachment, &port);
8954                                             hddAttachment->vtbl->GetDevice(hddAttachment, &device);
8955
8956 #if VBOX_API_VERSION < 3001000
8957                                             rc = machine->vtbl->DetachHardDisk(machine, controller, port, device);
8958 #else  /* VBOX_API_VERSION >= 3001000 */
8959                                             rc = machine->vtbl->DetachDevice(machine, controller, port, device);
8960 #endif /* VBOX_API_VERSION >= 3001000 */
8961                                             if (NS_SUCCEEDED(rc)) {
8962                                                 rc = machine->vtbl->SaveSettings(machine);
8963                                                 VIR_DEBUG("saving machine settings");
8964                                             }
8965
8966                                             if (NS_SUCCEEDED(rc)) {
8967                                                 deregister++;
8968                                                 VIR_DEBUG("deregistering hdd:%d", deregister);
8969                                             }
8970
8971                                             VBOX_UTF16_FREE(controller);
8972                                         }
8973                                         vboxIIDUnalloc(&iid);
8974                                     }
8975                                     VBOX_MEDIUM_RELEASE(hdd);
8976                                 }
8977                             }
8978                         }
8979                         vboxArrayRelease(&hddAttachments);
8980                         VBOX_RELEASE(machine);
8981                     }
8982                     VBOX_SESSION_CLOSE();
8983                 }
8984
8985                 vboxIIDUnalloc(&machineId);
8986             }
8987
8988             vboxArrayUnalloc(&machineIds);
8989
8990             if (machineIdsSize == 0 || machineIdsSize == deregister) {
8991                 IProgress *progress = NULL;
8992
8993                 rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress);
8994
8995                 if (NS_SUCCEEDED(rc) && progress) {
8996                     progress->vtbl->WaitForCompletion(progress, -1);
8997                     VBOX_RELEASE(progress);
8998                     DEBUGIID("HardDisk deleted, UUID", hddIID.value);
8999                     ret = 0;
9000                 }
9001             }
9002         }
9003
9004         VBOX_MEDIUM_RELEASE(hardDisk);
9005     }
9006
9007     vboxIIDUnalloc(&hddIID);
9008
9009     return ret;
9010 }
9011
9012 static int
9013 vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info)
9014 {
9015     VBOX_OBJECT_CHECK(vol->conn, int, -1);
9016     IHardDisk *hardDisk  = NULL;
9017     unsigned char uuid[VIR_UUID_BUFLEN];
9018     vboxIID hddIID = VBOX_IID_INITIALIZER;
9019     nsresult rc;
9020
9021     if (!info)
9022         return ret;
9023
9024     if (virUUIDParse(vol->key, uuid) < 0) {
9025         virReportError(VIR_ERR_INVALID_ARG,
9026                        _("Could not parse UUID from '%s'"), vol->key);
9027         return ret;
9028     }
9029
9030     vboxIIDFromUUID(&hddIID, uuid);
9031 #if VBOX_API_VERSION < 4000000
9032     rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9033 #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
9034     rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
9035                                          DeviceType_HardDisk, &hardDisk);
9036 #else
9037     rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
9038                                          DeviceType_HardDisk, AccessMode_ReadWrite,
9039                                          PR_FALSE, &hardDisk);
9040 #endif /* VBOX_API_VERSION >= 4000000 */
9041     if (NS_SUCCEEDED(rc)) {
9042         PRUint32 hddstate;
9043
9044         VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
9045         if (hddstate != MediaState_Inaccessible) {
9046 #if VBOX_API_VERSION < 4000000
9047             PRUint64 hddLogicalSize;
9048             PRUint64 hddActualSize;
9049 #else /* VBOX_API_VERSION >= 4000000 */
9050             PRInt64 hddLogicalSize;
9051             PRInt64 hddActualSize;
9052 #endif /* VBOX_API_VERSION >= 4000000 */
9053
9054             info->type = VIR_STORAGE_VOL_FILE;
9055
9056             hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
9057 #if VBOX_API_VERSION < 4000000
9058             info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
9059 #else /* VBOX_API_VERSION >= 4000000 */
9060             info->capacity = hddLogicalSize;
9061 #endif /* VBOX_API_VERSION >= 4000000 */
9062
9063             VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
9064             info->allocation = hddActualSize;
9065
9066             ret = 0;
9067
9068             VIR_DEBUG("Storage Volume Name: %s", vol->name);
9069             VIR_DEBUG("Storage Volume Type: %s", info->type == VIR_STORAGE_VOL_BLOCK ? "Block" : "File");
9070             VIR_DEBUG("Storage Volume Capacity: %llu", info->capacity);
9071             VIR_DEBUG("Storage Volume Allocation: %llu", info->allocation);
9072         }
9073
9074         VBOX_MEDIUM_RELEASE(hardDisk);
9075     }
9076
9077     vboxIIDUnalloc(&hddIID);
9078
9079     return ret;
9080 }
9081
9082 static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
9083 {
9084     VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
9085     IHardDisk *hardDisk  = NULL;
9086     unsigned char uuid[VIR_UUID_BUFLEN];
9087     vboxIID hddIID = VBOX_IID_INITIALIZER;
9088     virStoragePoolDef pool;
9089     virStorageVolDef def;
9090     int defOk = 0;
9091     nsresult rc;
9092
9093     virCheckFlags(0, NULL);
9094
9095     memset(&pool, 0, sizeof(pool));
9096     memset(&def, 0, sizeof(def));
9097
9098     if (virUUIDParse(vol->key, uuid) < 0) {
9099         virReportError(VIR_ERR_INVALID_ARG,
9100                        _("Could not parse UUID from '%s'"), vol->key);
9101         return ret;
9102     }
9103
9104     vboxIIDFromUUID(&hddIID, uuid);
9105 #if VBOX_API_VERSION < 4000000
9106     rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9107 #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
9108     rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
9109                                          DeviceType_HardDisk, &hardDisk);
9110 #else
9111     rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
9112                                          DeviceType_HardDisk, AccessMode_ReadWrite,
9113                                          PR_FALSE, &hardDisk);
9114 #endif /* VBOX_API_VERSION >= 4000000 */
9115     if (NS_SUCCEEDED(rc)) {
9116         PRUint32 hddstate;
9117
9118         VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
9119         if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) {
9120             PRUnichar *hddFormatUtf16 = NULL;
9121 #if VBOX_API_VERSION < 4000000
9122             PRUint64 hddLogicalSize;
9123             PRUint64 hddActualSize;
9124 #else /* VBOX_API_VERSION >= 4000000 */
9125             PRInt64 hddLogicalSize;
9126             PRInt64 hddActualSize;
9127 #endif /* VBOX_API_VERSION >= 4000000 */
9128
9129             /* since there is currently one default pool now
9130              * and virStorageVolDefFormat() just checks it type
9131              * so just assign it for now, change the behaviour
9132              * when vbox supports pools.
9133              */
9134             pool.type = VIR_STORAGE_POOL_DIR;
9135             def.type = VIR_STORAGE_VOL_FILE;
9136             defOk = 1;
9137
9138             rc = hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
9139             if (NS_SUCCEEDED(rc) && defOk) {
9140 #if VBOX_API_VERSION < 4000000
9141                 def.target.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
9142 #else /* VBOX_API_VERSION >= 4000000 */
9143                 def.target.capacity = hddLogicalSize;
9144 #endif /* VBOX_API_VERSION >= 4000000 */
9145             } else
9146                 defOk = 0;
9147
9148             rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
9149             if (NS_SUCCEEDED(rc) && defOk)
9150                 def.target.allocation = hddActualSize;
9151             else
9152                 defOk = 0;
9153
9154             if (VIR_STRDUP(def.name, vol->name) < 0)
9155                 defOk = 0;
9156
9157             if (VIR_STRDUP(def.key, vol->key) < 0)
9158                 defOk = 0;
9159
9160             rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16);
9161             if (NS_SUCCEEDED(rc) && defOk) {
9162                 char *hddFormatUtf8 = NULL;
9163
9164                 VBOX_UTF16_TO_UTF8(hddFormatUtf16, &hddFormatUtf8);
9165                 if (hddFormatUtf8) {
9166
9167                     VIR_DEBUG("Storage Volume Format: %s", hddFormatUtf8);
9168
9169                     if (STRCASEEQ("vmdk", hddFormatUtf8))
9170                         def.target.format = VIR_STORAGE_FILE_VMDK;
9171                     else if (STRCASEEQ("vhd", hddFormatUtf8))
9172                         def.target.format = VIR_STORAGE_FILE_VPC;
9173                     else if (STRCASEEQ("vdi", hddFormatUtf8))
9174                         def.target.format = VIR_STORAGE_FILE_VDI;
9175                     else
9176                         def.target.format = VIR_STORAGE_FILE_RAW;
9177
9178                     VBOX_UTF8_FREE(hddFormatUtf8);
9179                 }
9180
9181                 VBOX_UTF16_FREE(hddFormatUtf16);
9182             } else {
9183                 defOk = 0;
9184             }
9185         }
9186
9187         VBOX_MEDIUM_RELEASE(hardDisk);
9188     }
9189
9190     vboxIIDUnalloc(&hddIID);
9191
9192     if (defOk)
9193         ret = virStorageVolDefFormat(&pool, &def);
9194
9195     return ret;
9196 }
9197
9198 static char *vboxStorageVolGetPath(virStorageVolPtr vol) {
9199     VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
9200     IHardDisk *hardDisk  = NULL;
9201     unsigned char uuid[VIR_UUID_BUFLEN];
9202     vboxIID hddIID = VBOX_IID_INITIALIZER;
9203     nsresult rc;
9204
9205     if (virUUIDParse(vol->key, uuid) < 0) {
9206         virReportError(VIR_ERR_INVALID_ARG,
9207                        _("Could not parse UUID from '%s'"), vol->key);
9208         return ret;
9209     }
9210
9211     vboxIIDFromUUID(&hddIID, uuid);
9212 #if VBOX_API_VERSION < 4000000
9213     rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9214 #elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
9215     rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
9216                                          DeviceType_HardDisk, &hardDisk);
9217 #else
9218     rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
9219                                          DeviceType_HardDisk, AccessMode_ReadWrite,
9220                                          PR_FALSE, &hardDisk);
9221 #endif /* VBOX_API_VERSION >= 4000000 */
9222     if (NS_SUCCEEDED(rc)) {
9223         PRUint32 hddstate;
9224
9225         VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
9226         if (hddstate != MediaState_Inaccessible) {
9227             PRUnichar *hddLocationUtf16 = NULL;
9228             char      *hddLocationUtf8  = NULL;
9229
9230             VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetLocation, &hddLocationUtf16);
9231
9232             VBOX_UTF16_TO_UTF8(hddLocationUtf16, &hddLocationUtf8);
9233             if (hddLocationUtf8) {
9234
9235                 ignore_value(VIR_STRDUP(ret, hddLocationUtf8));
9236
9237                 VIR_DEBUG("Storage Volume Name: %s", vol->name);
9238                 VIR_DEBUG("Storage Volume Path: %s", hddLocationUtf8);
9239                 VIR_DEBUG("Storage Volume Pool: %s", vol->pool);
9240
9241                 VBOX_UTF8_FREE(hddLocationUtf8);
9242             }
9243
9244             VBOX_UTF16_FREE(hddLocationUtf16);
9245         }
9246
9247         VBOX_MEDIUM_RELEASE(hardDisk);
9248     }
9249
9250     vboxIIDUnalloc(&hddIID);
9251
9252     return ret;
9253 }
9254
9255 #if VBOX_API_VERSION >= 4000000
9256 static char *
9257 vboxDomainScreenshot(virDomainPtr dom,
9258                      virStreamPtr st,
9259                      unsigned int screen,
9260                      unsigned int flags)
9261 {
9262     VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
9263     IConsole *console = NULL;
9264     vboxIID iid = VBOX_IID_INITIALIZER;
9265     IMachine *machine = NULL;
9266     nsresult rc;
9267     char *tmp;
9268     int tmp_fd = -1;
9269     unsigned int max_screen;
9270
9271     virCheckFlags(0, NULL);
9272
9273     vboxIIDFromUUID(&iid, dom->uuid);
9274     rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
9275     if (NS_FAILED(rc)) {
9276         virReportError(VIR_ERR_NO_DOMAIN, "%s",
9277                        _("no domain with matching uuid"));
9278         return NULL;
9279     }
9280
9281     rc = machine->vtbl->GetMonitorCount(machine, &max_screen);
9282     if (NS_FAILED(rc)) {
9283         virReportError(VIR_ERR_OPERATION_FAILED, "%s",
9284                        _("unable to get monitor count"));
9285         VBOX_RELEASE(machine);
9286         return NULL;
9287     }
9288
9289     if (screen >= max_screen) {
9290         virReportError(VIR_ERR_INVALID_ARG,
9291                        _("screen ID higher than monitor "
9292                          "count (%d)"), max_screen);
9293         VBOX_RELEASE(machine);
9294         return NULL;
9295     }
9296
9297     if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
9298         VBOX_RELEASE(machine);
9299         return NULL;
9300     }
9301
9302     if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
9303         virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
9304         VIR_FREE(tmp);
9305         VBOX_RELEASE(machine);
9306         return NULL;
9307     }
9308
9309
9310     rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
9311     if (NS_SUCCEEDED(rc)) {
9312         rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
9313         if (NS_SUCCEEDED(rc) && console) {
9314             IDisplay *display = NULL;
9315
9316             console->vtbl->GetDisplay(console, &display);
9317
9318             if (display) {
9319                 PRUint32 width, height, bitsPerPixel;
9320                 PRUint32 screenDataSize;
9321                 PRUint8 *screenData;
9322 # if VBOX_API_VERSION >= 4003000
9323                 PRInt32 xOrigin, yOrigin;
9324 # endif
9325
9326                 rc = display->vtbl->GetScreenResolution(display, screen,
9327                                                         &width, &height,
9328 # if VBOX_API_VERSION < 4003000
9329                                                         &bitsPerPixel);
9330 # else
9331                                                         &bitsPerPixel,
9332                                                         &xOrigin, &yOrigin);
9333 # endif
9334
9335                 if (NS_FAILED(rc) || !width || !height) {
9336                     virReportError(VIR_ERR_OPERATION_FAILED, "%s",
9337                                    _("unable to get screen resolution"));
9338                     goto endjob;
9339                 }
9340
9341                 rc = display->vtbl->TakeScreenShotPNGToArray(display, screen,
9342                                                              width, height,
9343                                                              &screenDataSize,
9344                                                              &screenData);
9345                 if (NS_FAILED(rc)) {
9346                     virReportError(VIR_ERR_OPERATION_FAILED, "%s",
9347                                    _("failed to take screenshot"));
9348                     goto endjob;
9349                 }
9350
9351                 if (safewrite(tmp_fd, (char *) screenData,
9352                               screenDataSize) < 0) {
9353                     virReportSystemError(errno, _("unable to write data "
9354                                                   "to '%s'"), tmp);
9355                     goto endjob;
9356                 }
9357
9358                 if (VIR_CLOSE(tmp_fd) < 0) {
9359                     virReportSystemError(errno, _("unable to close %s"), tmp);
9360                     goto endjob;
9361                 }
9362
9363                 if (VIR_STRDUP(ret, "image/png") < 0)
9364                     goto endjob;
9365
9366                 if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
9367                     virReportError(VIR_ERR_OPERATION_FAILED, "%s",
9368                                    _("unable to open stream"));
9369                     VIR_FREE(ret);
9370                 }
9371  endjob:
9372                 VIR_FREE(screenData);
9373                 VBOX_RELEASE(display);
9374             }
9375             VBOX_RELEASE(console);
9376         }
9377         VBOX_SESSION_CLOSE();
9378     }
9379
9380     VIR_FORCE_CLOSE(tmp_fd);
9381     unlink(tmp);
9382     VIR_FREE(tmp);
9383     VBOX_RELEASE(machine);
9384     vboxIIDUnalloc(&iid);
9385     return ret;
9386 }
9387 #endif /* VBOX_API_VERSION >= 4000000 */
9388
9389
9390 #define MATCH(FLAG) (flags & (FLAG))
9391 static int
9392 vboxConnectListAllDomains(virConnectPtr conn,
9393                           virDomainPtr **domains,
9394                           unsigned int flags)
9395 {
9396     VBOX_OBJECT_CHECK(conn, int, -1);
9397     vboxArray machines = VBOX_ARRAY_INITIALIZER;
9398     char      *machineNameUtf8  = NULL;
9399     PRUnichar *machineNameUtf16 = NULL;
9400     unsigned char uuid[VIR_UUID_BUFLEN];
9401     vboxIID iid = VBOX_IID_INITIALIZER;
9402     PRUint32 state;
9403     nsresult rc;
9404     size_t i;
9405     virDomainPtr dom;
9406     virDomainPtr *doms = NULL;
9407     int count = 0;
9408     bool active;
9409     PRUint32 snapshotCount;
9410
9411     virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
9412
9413     /* filter out flag options that will produce 0 results in vbox driver:
9414      * - managed save: vbox guests don't have managed save images
9415      * - autostart: vbox doesn't support autostarting guests
9416      * - persistance: vbox doesn't support transient guests
9417      */
9418     if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
9419          !MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT)) ||
9420         (MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) &&
9421          !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART)) ||
9422         (MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) &&
9423          !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE))) {
9424         if (domains &&
9425             VIR_ALLOC_N(*domains, 1) < 0)
9426             goto cleanup;
9427
9428         ret = 0;
9429         goto cleanup;
9430     }
9431
9432     rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
9433     if (NS_FAILED(rc)) {
9434         virReportError(VIR_ERR_INTERNAL_ERROR,
9435                        _("Could not get list of domains, rc=%08x"), (unsigned)rc);
9436         goto cleanup;
9437     }
9438
9439     if (domains &&
9440         VIR_ALLOC_N(doms, machines.count + 1) < 0)
9441         goto cleanup;
9442
9443     for (i = 0; i < machines.count; i++) {
9444         IMachine *machine = machines.items[i];
9445
9446         if (machine) {
9447             PRBool isAccessible = PR_FALSE;
9448             machine->vtbl->GetAccessible(machine, &isAccessible);
9449             if (isAccessible) {
9450                 machine->vtbl->GetState(machine, &state);
9451
9452                 if (state >= MachineState_FirstOnline &&
9453                     state <= MachineState_LastOnline)
9454                     active = true;
9455                 else
9456                     active = false;
9457
9458                 /* filter by active state */
9459                 if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
9460                     !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
9461                       (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
9462                     continue;
9463
9464                 /* filter by snapshot existence */
9465                 if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
9466                     rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
9467                     if (NS_FAILED(rc)) {
9468                         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9469                                        _("could not get snapshot count for listed domains"));
9470                         goto cleanup;
9471                     }
9472                     if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) &&
9473                            snapshotCount > 0) ||
9474                           (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) &&
9475                            snapshotCount == 0)))
9476                         continue;
9477                 }
9478
9479                 /* filter by machine state */
9480                 if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) &&
9481                     !((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) &&
9482                        state == MachineState_Running) ||
9483                       (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) &&
9484                        state == MachineState_Paused) ||
9485                       (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) &&
9486                        state == MachineState_PoweredOff) ||
9487                       (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) &&
9488                        (state != MachineState_Running &&
9489                         state != MachineState_Paused &&
9490                         state != MachineState_PoweredOff))))
9491                     continue;
9492
9493                 /* just count the machines */
9494                 if (!doms) {
9495                     count++;
9496                     continue;
9497                 }
9498
9499                 machine->vtbl->GetName(machine, &machineNameUtf16);
9500                 VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
9501                 machine->vtbl->GetId(machine, &iid.value);
9502                 vboxIIDToUUID(&iid, uuid);
9503                 vboxIIDUnalloc(&iid);
9504
9505                 dom = virGetDomain(conn, machineNameUtf8, uuid);
9506
9507                 VBOX_UTF8_FREE(machineNameUtf8);
9508                 VBOX_UTF16_FREE(machineNameUtf16);
9509
9510                 if (!dom)
9511                     goto cleanup;
9512
9513                 if (active)
9514                     dom->id = i + 1;
9515
9516                 doms[count++] = dom;
9517             }
9518         }
9519     }
9520
9521     if (doms) {
9522         /* safe to ignore, new size will be equal or less than
9523          * previous allocation*/
9524         ignore_value(VIR_REALLOC_N(doms, count + 1));
9525         *domains = doms;
9526         doms = NULL;
9527     }
9528
9529     ret = count;
9530
9531  cleanup:
9532     if (doms) {
9533         for (i = 0; i < count; i++) {
9534             if (doms[i])
9535                 virDomainFree(doms[i]);
9536         }
9537     }
9538     VIR_FREE(doms);
9539
9540     vboxArrayRelease(&machines);
9541     return ret;
9542 }
9543 #undef MATCH
9544
9545
9546 static int
9547 vboxNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
9548                 virNodeInfoPtr nodeinfo)
9549 {
9550     return nodeGetInfo(nodeinfo);
9551 }
9552
9553
9554 static int
9555 vboxNodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED,
9556                            unsigned long long *freeMems,
9557                            int startCell,
9558                            int maxCells)
9559 {
9560     return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
9561 }
9562
9563
9564 static unsigned long long
9565 vboxNodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED)
9566 {
9567     return nodeGetFreeMemory();
9568 }
9569
9570
9571 /**
9572  * Function Tables
9573  */
9574
9575 virDriver NAME(Driver) = {
9576     .no = VIR_DRV_VBOX,
9577     .name = "VBOX",
9578     .connectOpen = vboxConnectOpen, /* 0.6.3 */
9579     .connectClose = vboxConnectClose, /* 0.6.3 */
9580     .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */
9581     .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */
9582     .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */
9583     .nodeGetInfo = vboxNodeGetInfo, /* 0.6.3 */
9584     .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */
9585     .connectListDomains = vboxConnectListDomains, /* 0.6.3 */
9586     .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */
9587     .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */
9588     .domainCreateXML = vboxDomainCreateXML, /* 0.6.3 */
9589     .domainLookupByID = vboxDomainLookupByID, /* 0.6.3 */
9590     .domainLookupByUUID = vboxDomainLookupByUUID, /* 0.6.3 */
9591     .domainLookupByName = vboxDomainLookupByName, /* 0.6.3 */
9592     .domainSuspend = vboxDomainSuspend, /* 0.6.3 */
9593     .domainResume = vboxDomainResume, /* 0.6.3 */
9594     .domainShutdown = vboxDomainShutdown, /* 0.6.3 */
9595     .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
9596     .domainReboot = vboxDomainReboot, /* 0.6.3 */
9597     .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
9598     .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
9599     .domainGetOSType = vboxDomainGetOSType, /* 0.6.3 */
9600     .domainSetMemory = vboxDomainSetMemory, /* 0.6.3 */
9601     .domainGetInfo = vboxDomainGetInfo, /* 0.6.3 */
9602     .domainGetState = vboxDomainGetState, /* 0.9.2 */
9603     .domainSave = vboxDomainSave, /* 0.6.3 */
9604     .domainSetVcpus = vboxDomainSetVcpus, /* 0.7.1 */
9605     .domainSetVcpusFlags = vboxDomainSetVcpusFlags, /* 0.8.5 */
9606     .domainGetVcpusFlags = vboxDomainGetVcpusFlags, /* 0.8.5 */
9607     .domainGetMaxVcpus = vboxDomainGetMaxVcpus, /* 0.7.1 */
9608     .domainGetXMLDesc = vboxDomainGetXMLDesc, /* 0.6.3 */
9609     .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */
9610     .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */
9611     .domainCreate = vboxDomainCreate, /* 0.6.3 */
9612     .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */
9613     .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */
9614     .domainUndefine = vboxDomainUndefine, /* 0.6.3 */
9615     .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */
9616     .domainAttachDevice = vboxDomainAttachDevice, /* 0.6.3 */
9617     .domainAttachDeviceFlags = vboxDomainAttachDeviceFlags, /* 0.7.7 */
9618     .domainDetachDevice = vboxDomainDetachDevice, /* 0.6.3 */
9619     .domainDetachDeviceFlags = vboxDomainDetachDeviceFlags, /* 0.7.7 */
9620     .domainUpdateDeviceFlags = vboxDomainUpdateDeviceFlags, /* 0.8.0 */
9621     .nodeGetCellsFreeMemory = vboxNodeGetCellsFreeMemory, /* 0.6.5 */
9622     .nodeGetFreeMemory = vboxNodeGetFreeMemory, /* 0.6.5 */
9623 #if VBOX_API_VERSION >= 4000000
9624     .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */
9625 #endif
9626 #if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
9627     .connectDomainEventRegister = vboxConnectDomainEventRegister, /* 0.7.0 */
9628     .connectDomainEventDeregister = vboxConnectDomainEventDeregister, /* 0.7.0 */
9629 #endif
9630     .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */
9631     .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */
9632     .domainIsActive = vboxDomainIsActive, /* 0.7.3 */
9633     .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */
9634     .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */
9635 #if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
9636     .connectDomainEventRegisterAny = vboxConnectDomainEventRegisterAny, /* 0.8.0 */
9637     .connectDomainEventDeregisterAny = vboxConnectDomainEventDeregisterAny, /* 0.8.0 */
9638 #endif
9639     .domainSnapshotCreateXML = vboxDomainSnapshotCreateXML, /* 0.8.0 */
9640     .domainSnapshotGetXMLDesc = vboxDomainSnapshotGetXMLDesc, /* 0.8.0 */
9641     .domainSnapshotNum = vboxDomainSnapshotNum, /* 0.8.0 */
9642     .domainSnapshotListNames = vboxDomainSnapshotListNames, /* 0.8.0 */
9643     .domainSnapshotLookupByName = vboxDomainSnapshotLookupByName, /* 0.8.0 */
9644     .domainHasCurrentSnapshot = vboxDomainHasCurrentSnapshot, /* 0.8.0 */
9645     .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
9646     .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */
9647     .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */
9648     .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */
9649     .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */
9650     .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */
9651     .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */
9652 };
9653
9654 virNetworkDriver NAME(NetworkDriver) = {
9655     "VBOX",
9656     .networkOpen = vboxNetworkOpen, /* 0.6.4 */
9657     .networkClose = vboxNetworkClose, /* 0.6.4 */
9658     .connectNumOfNetworks = vboxConnectNumOfNetworks, /* 0.6.4 */
9659     .connectListNetworks = vboxConnectListNetworks, /* 0.6.4 */
9660     .connectNumOfDefinedNetworks = vboxConnectNumOfDefinedNetworks, /* 0.6.4 */
9661     .connectListDefinedNetworks = vboxConnectListDefinedNetworks, /* 0.6.4 */
9662     .networkLookupByUUID = vboxNetworkLookupByUUID, /* 0.6.4 */
9663     .networkLookupByName = vboxNetworkLookupByName, /* 0.6.4 */
9664     .networkCreateXML = vboxNetworkCreateXML, /* 0.6.4 */
9665     .networkDefineXML = vboxNetworkDefineXML, /* 0.6.4 */
9666     .networkUndefine = vboxNetworkUndefine, /* 0.6.4 */
9667     .networkCreate = vboxNetworkCreate, /* 0.6.4 */
9668     .networkDestroy = vboxNetworkDestroy, /* 0.6.4 */
9669     .networkGetXMLDesc = vboxNetworkGetXMLDesc, /* 0.6.4 */
9670 };
9671
9672 virStorageDriver NAME(StorageDriver) = {
9673     .name               = "VBOX",
9674     .storageOpen = vboxStorageOpen, /* 0.7.1 */
9675     .storageClose = vboxStorageClose, /* 0.7.1 */
9676     .connectNumOfStoragePools = vboxConnectNumOfStoragePools, /* 0.7.1 */
9677     .connectListStoragePools = vboxConnectListStoragePools, /* 0.7.1 */
9678     .storagePoolLookupByName = vboxStoragePoolLookupByName, /* 0.7.1 */
9679     .storagePoolNumOfVolumes = vboxStoragePoolNumOfVolumes, /* 0.7.1 */
9680     .storagePoolListVolumes = vboxStoragePoolListVolumes, /* 0.7.1 */
9681
9682     .storageVolLookupByName = vboxStorageVolLookupByName, /* 0.7.1 */
9683     .storageVolLookupByKey = vboxStorageVolLookupByKey, /* 0.7.1 */
9684     .storageVolLookupByPath = vboxStorageVolLookupByPath, /* 0.7.1 */
9685     .storageVolCreateXML = vboxStorageVolCreateXML, /* 0.7.1 */
9686     .storageVolDelete = vboxStorageVolDelete, /* 0.7.1 */
9687     .storageVolGetInfo = vboxStorageVolGetInfo, /* 0.7.1 */
9688     .storageVolGetXMLDesc = vboxStorageVolGetXMLDesc, /* 0.7.1 */
9689     .storageVolGetPath = vboxStorageVolGetPath /* 0.7.1 */
9690 };