vbox_tmpl.c 342.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/** @file vbox_tmpl.c
 * Template File to support multiple versions of VirtualBox
 * at runtime :).
 *
 * IMPORTANT:
 * Please dont include this file in the src/Makefile.am, it
 * is automatically include by other files.
 */

/*
J
John Ferlan 已提交
11
 * Copyright (C) 2010-2013 Red Hat, Inc.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 * Copyright (C) 2008-2009 Sun Microsystems, Inc.
 *
 * This file is part of a free software library; you can redistribute
 * it and/or modify it under the terms of the GNU Lesser General
 * Public License version 2.1 as published by the Free Software
 * Foundation and shipped in the "COPYING" file with this library.
 * The library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY of any kind.
 *
 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if
 * any license choice other than GPL or LGPL is available it will
 * apply instead, Sun elects to use only the Lesser General Public
 * License version 2.1 (LGPLv2) at this time for any software where
 * a choice of LGPL license versions is made available with the
 * language indicating that LGPLv2 or any later version may be used,
 * or where a choice of which version of the LGPL is applied is
 * otherwise unspecified.
 *
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 USA or visit http://www.sun.com if you need
 * additional information or have any questions.
 */

#include <config.h>

37
#include <unistd.h>
38 39 40
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
41 42 43 44

#include "internal.h"
#include "datatypes.h"
#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"
E
Eric Blake 已提交
57
#include "virfile.h"
58
#include "fdstream.h"
M
Martin Kletzander 已提交
59
#include "viruri.h"
60
#include "virstring.h"
61 62 63 64

/* This one changes from version to version. */
#if VBOX_API_VERSION == 2002
# include "vbox_CAPI_v2_2.h"
65 66
#elif VBOX_API_VERSION == 3000
# include "vbox_CAPI_v3_0.h"
67 68
#elif VBOX_API_VERSION == 3001
# include "vbox_CAPI_v3_1.h"
69 70
#elif VBOX_API_VERSION == 3002
# include "vbox_CAPI_v3_2.h"
71 72
#elif VBOX_API_VERSION == 4000
# include "vbox_CAPI_v4_0.h"
73 74
#elif VBOX_API_VERSION == 4001
# include "vbox_CAPI_v4_1.h"
75 76
#else
# error "Unsupport VBOX_API_VERSION"
77 78
#endif

79
/* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */
80
#include "vbox_glue.h"
81 82


83
#define VIR_FROM_THIS                   VIR_FROM_VBOX
J
John Ferlan 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
#define VBOX_UTF16_FREE(arg)                                            \
    do {                                                                \
        if (arg) {                                                      \
            data->pFuncs->pfnUtf16Free(arg);                            \
            (arg) = NULL;                                               \
        }                                                               \
    } while (0)

#define VBOX_UTF8_FREE(arg)                                             \
    do {                                                                \
        if (arg) {                                                      \
            data->pFuncs->pfnUtf8Free(arg);                             \
            (arg) = NULL;                                               \
        }                                                               \
    } while (0)

#define VBOX_COM_UNALLOC_MEM(arg)                                       \
    do {                                                                \
        if (arg) {                                                      \
            data->pFuncs->pfnComUnallocMem(arg);                        \
            (arg) = NULL;                                               \
        }                                                               \
    } while (0)

108 109 110
#define VBOX_UTF16_TO_UTF8(arg1, arg2)  data->pFuncs->pfnUtf16ToUtf8(arg1, arg2)
#define VBOX_UTF8_TO_UTF16(arg1, arg2)  data->pFuncs->pfnUtf8ToUtf16(arg1, arg2)

111 112
#define VBOX_ADDREF(arg) (arg)->vtbl->nsisupports.AddRef((nsISupports *)(arg))

113 114 115 116 117 118 119
#define VBOX_RELEASE(arg)                                                     \
    do {                                                                      \
        if (arg) {                                                            \
            (arg)->vtbl->nsisupports.Release((nsISupports *)(arg));           \
            (arg) = NULL;                                                     \
        }                                                                     \
    } while (0)
120 121 122 123

#define VBOX_OBJECT_CHECK(conn, type, value) \
vboxGlobalData *data = conn->privateData;\
type ret = value;\
124
if (!data->vboxObj) {\
125 126 127 128 129 130 131
    return ret;\
}

#define VBOX_OBJECT_HOST_CHECK(conn, type, value) \
vboxGlobalData *data = conn->privateData;\
type ret = value;\
IHost *host = NULL;\
132
if (!data->vboxObj) {\
133 134 135 136 137 138 139 140 141
    return ret;\
}\
data->vboxObj->vtbl->GetHost(data->vboxObj, &host);\
if (!host) {\
    return ret;\
}

#if VBOX_API_VERSION < 3001

142
# define VBOX_MEDIUM_RELEASE(arg) \
143
if (arg)\
144
    (arg)->vtbl->imedium.nsisupports.Release((nsISupports *)(arg))
145
# define VBOX_MEDIUM_FUNC_ARG1(object, func, arg1) \
146
    (object)->vtbl->imedium.func((IMedium *)(object), arg1)
147
# define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
148 149 150 151 152 153
    (object)->vtbl->imedium.func((IMedium *)(object), arg1, arg2)

#else  /* VBOX_API_VERSION >= 3001 */

typedef IMedium IHardDisk;
typedef IMediumAttachment IHardDiskAttachment;
154 155 156 157 158
# define MediaState_Inaccessible     MediumState_Inaccessible
# define HardDiskVariant_Standard    MediumVariant_Standard
# define HardDiskVariant_Fixed       MediumVariant_Fixed
# define VBOX_MEDIUM_RELEASE(arg) VBOX_RELEASE(arg)
# define VBOX_MEDIUM_FUNC_ARG1(object, func, arg1) \
159
    (object)->vtbl->func(object, arg1)
160
# define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
161 162 163
    (object)->vtbl->func(object, arg1, arg2)

#endif /* VBOX_API_VERSION >= 3001 */
164

165 166 167 168 169 170
#define DEBUGPRUnichar(msg, strUtf16) \
if (strUtf16) {\
    char *strUtf8 = NULL;\
\
    g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);\
    if (strUtf8) {\
171
        VIR_DEBUG("%s: %s", msg, strUtf8);\
172 173 174 175 176 177
        g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);\
    }\
}

#define DEBUGUUID(msg, iid) \
{\
178
    VIR_DEBUG(msg ": {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",\
179 180 181 182 183 184 185 186 187 188 189 190 191
          (unsigned)(iid)->m0,\
          (unsigned)(iid)->m1,\
          (unsigned)(iid)->m2,\
          (unsigned)(iid)->m3[0],\
          (unsigned)(iid)->m3[1],\
          (unsigned)(iid)->m3[2],\
          (unsigned)(iid)->m3[3],\
          (unsigned)(iid)->m3[4],\
          (unsigned)(iid)->m3[5],\
          (unsigned)(iid)->m3[6],\
          (unsigned)(iid)->m3[7]);\
}\

192 193
typedef struct {
    virMutex lock;
194
    unsigned long version;
195 196

    virCapsPtr caps;
197
    virDomainXMLOptionPtr xmlopt;
198 199 200

    IVirtualBox *vboxObj;
    ISession *vboxSession;
201 202 203

    /** Our version specific API table pointer. */
    PCVBOXXPCOM pFuncs;
204 205 206 207 208 209 210

#if VBOX_API_VERSION == 2002

} vboxGlobalData;

#else /* !(VBOX_API_VERSION == 2002) */

211 212
    /* Async event handling */
    virDomainEventStatePtr domainEvents;
213 214
    int fdWatch;

215 216
# if VBOX_API_VERSION <= 3002
    /* IVirtualBoxCallback is used in VirtualBox 3.x only */
217
    IVirtualBoxCallback *vboxCallback;
218
# endif /* VBOX_API_VERSION <= 3002 */
219 220 221 222 223 224 225

    nsIEventQueue  *vboxQueue;
    int volatile vboxCallBackRefCount;

    /* pointer back to the connection */
    virConnectPtr conn;

226 227
} vboxGlobalData;

228 229 230 231 232 233 234 235 236 237
/* g_pVBoxGlobalData has to be global variable,
 * there is no other way to make the callbacks
 * work other then having g_pVBoxGlobalData as
 * global, because the functions namely AddRef,
 * Release, etc consider it as global and you
 * can't change the function definition as it
 * is XPCOM nsISupport::* function and it expects
 * them that way
 */

238
static vboxGlobalData *g_pVBoxGlobalData = NULL;
239 240

#endif /* !(VBOX_API_VERSION == 2002) */
241

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
#if VBOX_API_VERSION < 4000

# define VBOX_OBJECT_GET_MACHINE(/* in */ iid_value, /* out */ machine) \
    data->vboxObj->vtbl->GetMachine(data->vboxObj, iid_value, machine)

# define VBOX_SESSION_OPEN(/* in */ iid_value, /* unused */ machine) \
    data->vboxObj->vtbl->OpenSession(data->vboxObj, data->vboxSession, iid_value)

# define VBOX_SESSION_OPEN_EXISTING(/* in */ iid_value, /* unused */ machine) \
    data->vboxObj->vtbl->OpenExistingSession(data->vboxObj, data->vboxSession, iid_value)

# define VBOX_SESSION_CLOSE() \
    data->vboxSession->vtbl->Close(data->vboxSession)

#else /* VBOX_API_VERSION >= 4000 */

# define VBOX_OBJECT_GET_MACHINE(/* in */ iid_value, /* out */ machine) \
    data->vboxObj->vtbl->FindMachine(data->vboxObj, iid_value, machine)

# define VBOX_SESSION_OPEN(/* unused */ iid_value, /* in */ machine) \
    machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Write)

# define VBOX_SESSION_OPEN_EXISTING(/* unused */ iid_value, /* in */ machine) \
    machine->vtbl->LockMachine(machine, data->vboxSession, LockType_Shared)

# define VBOX_SESSION_CLOSE() \
    data->vboxSession->vtbl->UnlockMachine(data->vboxSession)

#endif /* VBOX_API_VERSION >= 4000 */

272 273
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml);
static int vboxDomainCreate(virDomainPtr dom);
274
static int vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags);
275

276 277 278 279 280 281 282 283 284
static void vboxDriverLock(vboxGlobalData *data) {
    virMutexLock(&data->lock);
}

static void vboxDriverUnlock(vboxGlobalData *data) {
    virMutexUnlock(&data->lock);
}

#if VBOX_API_VERSION == 2002
285

286
static void nsIDtoChar(unsigned char *uuid, const nsID *iid) {
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
    int i;

    memcpy(uuidinterim, iid, VIR_UUID_BUFLEN);
    virUUIDFormat(uuidinterim, uuidstrsrc);

    uuidstrdst[0]  = uuidstrsrc[6];
    uuidstrdst[1]  = uuidstrsrc[7];
    uuidstrdst[2]  = uuidstrsrc[4];
    uuidstrdst[3]  = uuidstrsrc[5];
    uuidstrdst[4]  = uuidstrsrc[2];
    uuidstrdst[5]  = uuidstrsrc[3];
    uuidstrdst[6]  = uuidstrsrc[0];
    uuidstrdst[7]  = uuidstrsrc[1];

    uuidstrdst[8]  = uuidstrsrc[8];

    uuidstrdst[9]  = uuidstrsrc[11];
    uuidstrdst[10] = uuidstrsrc[12];
    uuidstrdst[11] = uuidstrsrc[9];
    uuidstrdst[12] = uuidstrsrc[10];

    uuidstrdst[13] = uuidstrsrc[13];

    uuidstrdst[14] = uuidstrsrc[16];
    uuidstrdst[15] = uuidstrsrc[17];
    uuidstrdst[16] = uuidstrsrc[14];
    uuidstrdst[17] = uuidstrsrc[15];

318
    for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
319 320 321 322
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
323
    ignore_value(virUUIDParse(uuidstrdst, uuid));
324 325
}

326
static void nsIDFromChar(nsID *iid, const unsigned char *uuid) {
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
    int i;

    virUUIDFormat(uuid, uuidstrsrc);

    uuidstrdst[0]  = uuidstrsrc[6];
    uuidstrdst[1]  = uuidstrsrc[7];
    uuidstrdst[2]  = uuidstrsrc[4];
    uuidstrdst[3]  = uuidstrsrc[5];
    uuidstrdst[4]  = uuidstrsrc[2];
    uuidstrdst[5]  = uuidstrsrc[3];
    uuidstrdst[6]  = uuidstrsrc[0];
    uuidstrdst[7]  = uuidstrsrc[1];

    uuidstrdst[8]  = uuidstrsrc[8];

    uuidstrdst[9]  = uuidstrsrc[11];
    uuidstrdst[10] = uuidstrsrc[12];
    uuidstrdst[11] = uuidstrsrc[9];
    uuidstrdst[12] = uuidstrsrc[10];

    uuidstrdst[13] = uuidstrsrc[13];

    uuidstrdst[14] = uuidstrsrc[16];
    uuidstrdst[15] = uuidstrsrc[17];
    uuidstrdst[16] = uuidstrsrc[14];
    uuidstrdst[17] = uuidstrsrc[15];

357
    for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
358 359 360 361
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
362
    ignore_value(virUUIDParse(uuidstrdst, uuidinterim));
363 364 365
    memcpy(iid, uuidinterim, VIR_UUID_BUFLEN);
}

366
# ifdef WIN32
367

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
typedef struct _vboxIID_v2_x_WIN32 vboxIID;
typedef struct _vboxIID_v2_x_WIN32 vboxIID_v2_x_WIN32;

struct _vboxIID_v2_x_WIN32 {
    /* IID is represented by a GUID value. */
    GUID value;
};

#  define VBOX_IID_INITIALIZER { { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } }

static void
vboxIIDUnalloc_v2_x_WIN32(vboxGlobalData *data ATTRIBUTE_UNUSED,
                          vboxIID_v2_x_WIN32 *iid ATTRIBUTE_UNUSED)
{
    /* Nothing to free */
383
}
384

385 386 387 388 389
static void
vboxIIDToUUID_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid, unsigned char *uuid)
{
    nsIDtoChar(uuid, (nsID *)&iid->value);
}
390

391 392 393 394 395
static void
vboxIIDFromUUID_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid,
                           const unsigned char *uuid)
{
    vboxIIDUnalloc_v2_x_WIN32(data, iid);
396

397
    nsIDFromChar((nsID *)&iid->value, uuid);
398 399
}

400 401 402
static bool
vboxIIDIsEqual_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid1, vboxIID_v2_x_WIN32 *iid2)
{
403
    return memcmp(&iid1->value, &iid2->value, sizeof(GUID)) == 0;
404
}
405

406 407 408 409 410 411 412 413
static void
vboxIIDFromArrayItem_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid,
                                vboxArray *array, int idx)
{
    GUID *items = (GUID *)array->items;

    vboxIIDUnalloc_v2_x_WIN32(data, iid);

414
    memcpy(&iid->value, &items[idx], sizeof(GUID));
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
}

#  define vboxIIDUnalloc(iid) vboxIIDUnalloc_v2_x_WIN32(data, iid)
#  define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v2_x_WIN32(iid, uuid)
#  define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v2_x_WIN32(data, iid, uuid)
#  define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v2_x_WIN32(iid1, iid2)
#  define vboxIIDFromArrayItem(iid, array, idx) \
    vboxIIDFromArrayItem_v2_x_WIN32(data, iid, array, idx)
#  define DEBUGIID(msg, iid) DEBUGUUID(msg, (nsID *)&(iid))

# else /* !WIN32 */

typedef struct _vboxIID_v2_x vboxIID;
typedef struct _vboxIID_v2_x vboxIID_v2_x;

struct _vboxIID_v2_x {
    /* IID is represented by a pointer to a nsID. */
    nsID *value;

    /* backing is used in cases where we need to create or copy an IID.
     * We cannot allocate memory that can be freed by ComUnallocMem.
     * Therefore, we use this stack allocated nsID instead. */
    nsID backing;
};

#  define VBOX_IID_INITIALIZER { NULL, { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0 } } }

static void
vboxIIDUnalloc_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid)
{
    if (iid->value == NULL) {
446 447 448
        return;
    }

449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
    if (iid->value != &iid->backing) {
        data->pFuncs->pfnComUnallocMem(iid->value);
    }

    iid->value = NULL;
}

static void
vboxIIDToUUID_v2_x(vboxIID_v2_x *iid, unsigned char *uuid)
{
    nsIDtoChar(uuid, iid->value);
}

static void
vboxIIDFromUUID_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid,
                     const unsigned char *uuid)
{
    vboxIIDUnalloc_v2_x(data, iid);

    iid->value = &iid->backing;

470
    sa_assert(iid->value);
471
    nsIDFromChar(iid->value, uuid);
472 473
}

474 475 476
static bool
vboxIIDIsEqual_v2_x(vboxIID_v2_x *iid1, vboxIID_v2_x *iid2)
{
477
    return memcmp(iid1->value, iid2->value, sizeof(nsID)) == 0;
478 479 480 481 482 483 484 485 486 487
}

static void
vboxIIDFromArrayItem_v2_x(vboxGlobalData *data, vboxIID_v2_x *iid,
                          vboxArray *array, int idx)
{
    vboxIIDUnalloc_v2_x(data, iid);

    iid->value = &iid->backing;

488
    memcpy(iid->value, array->items[idx], sizeof(nsID));
489 490 491 492 493 494 495 496 497 498 499 500
}

#  define vboxIIDUnalloc(iid) vboxIIDUnalloc_v2_x(data, iid)
#  define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v2_x(iid, uuid)
#  define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v2_x(data, iid, uuid)
#  define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v2_x(iid1, iid2)
#  define vboxIIDFromArrayItem(iid, array, idx) \
    vboxIIDFromArrayItem_v2_x(data, iid, array, idx)
#  define DEBUGIID(msg, iid) DEBUGUUID(msg, iid)

# endif /* !WIN32 */

501
#else /* VBOX_API_VERSION != 2002 */
502

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
typedef struct _vboxIID_v3_x vboxIID;
typedef struct _vboxIID_v3_x vboxIID_v3_x;

struct _vboxIID_v3_x {
    /* IID is represented by a UTF-16 encoded UUID in string form. */
    PRUnichar *value;

    /* owner indicates if we own the value and need to free it. */
    bool owner;
};

# define VBOX_IID_INITIALIZER { NULL, true }

static void
vboxIIDUnalloc_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid)
{
    if (iid->value != NULL && iid->owner) {
        data->pFuncs->pfnUtf16Free(iid->value);
    }

    iid->value = NULL;
    iid->owner = true;
525 526
}

527 528 529 530 531 532 533 534
static void
vboxIIDToUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                   unsigned char *uuid)
{
    char *utf8 = NULL;

    data->pFuncs->pfnUtf16ToUtf8(iid->value, &utf8);

535
    ignore_value(virUUIDParse(utf8, uuid));
536 537

    data->pFuncs->pfnUtf8Free(utf8);
538 539
}

540 541 542 543 544
static void
vboxIIDFromUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                     const unsigned char *uuid)
{
    char utf8[VIR_UUID_STRING_BUFLEN];
545

546
    vboxIIDUnalloc_v3_x(data, iid);
547

548
    virUUIDFormat(uuid, utf8);
549

550 551
    data->pFuncs->pfnUtf8ToUtf16(utf8, &iid->value);
}
552

553 554 555 556 557 558
static bool
vboxIIDIsEqual_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid1,
                    vboxIID_v3_x *iid2)
{
    unsigned char uuid1[VIR_UUID_BUFLEN];
    unsigned char uuid2[VIR_UUID_BUFLEN];
559 560

    /* Note: we can't directly compare the utf8 strings here
E
Eric Blake 已提交
561
     * cause the two UUID's may have separators as space or '-'
562 563
     * or mixture of both and we don't want to fail here by
     * using direct string comparison. Here virUUIDParse() takes
564 565 566
     * care of these cases. */
    vboxIIDToUUID_v3_x(data, iid1, uuid1);
    vboxIIDToUUID_v3_x(data, iid2, uuid2);
567

568 569
    return memcmp(uuid1, uuid2, VIR_UUID_BUFLEN) == 0;
}
570 571


572 573 574 575 576
static void
vboxIIDFromArrayItem_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                          vboxArray *array, int idx)
{
    vboxIIDUnalloc_v3_x(data, iid);
577

578 579
    iid->value = array->items[idx];
    iid->owner = false;
580 581
}

582 583 584 585 586 587 588 589

# define vboxIIDUnalloc(iid) vboxIIDUnalloc_v3_x(data, iid)
# define vboxIIDToUUID(iid, uuid) vboxIIDToUUID_v3_x(data, iid, uuid)
# define vboxIIDFromUUID(iid, uuid) vboxIIDFromUUID_v3_x(data, iid, uuid)
# define vboxIIDIsEqual(iid1, iid2) vboxIIDIsEqual_v3_x(data, iid1, iid2)
# define vboxIIDFromArrayItem(iid, array, idx) \
    vboxIIDFromArrayItem_v3_x(data, iid, array, idx)
# define DEBUGIID(msg, strUtf16) DEBUGPRUnichar(msg, strUtf16)
590

591
# if VBOX_API_VERSION >= 3001
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607

/**
 * function to generate the name for medium,
 * for e.g: hda, sda, etc
 *
 * @returns     null terminated string with device name or NULL
 *              for failures
 * @param       conn            Input Connection Pointer
 * @param       storageBus      Input storage bus type
 * @param       deviceInst      Input device instance number
 * @param       devicePort      Input port number
 * @param       deviceSlot      Input slot number
 * @param       aMaxPortPerInst Input array of max port per device instance
 * @param       aMaxSlotPerPort Input array of max slot per device port
 *
 */
608
static char *vboxGenerateMediumName(PRUint32  storageBus,
609 610 611 612 613
                                    PRInt32   deviceInst,
                                    PRInt32   devicePort,
                                    PRInt32   deviceSlot,
                                    PRUint32 *aMaxPortPerInst,
                                    PRUint32 *aMaxSlotPerPort) {
614
    const char *prefix = NULL;
615 616 617 618 619
    char *name  = NULL;
    int   total = 0;
    PRUint32 maxPortPerInst = 0;
    PRUint32 maxSlotPerPort = 0;

620 621
    if (!aMaxPortPerInst ||
        !aMaxSlotPerPort)
622 623
        return NULL;

624 625
    if ((storageBus < StorageBus_IDE) ||
        (storageBus > StorageBus_Floppy))
626 627 628 629 630 631 632 633 634
        return NULL;

    maxPortPerInst = aMaxPortPerInst[storageBus];
    maxSlotPerPort = aMaxSlotPerPort[storageBus];
    total =   (deviceInst * maxPortPerInst * maxSlotPerPort)
            + (devicePort * maxSlotPerPort)
            + deviceSlot;

    if (storageBus == StorageBus_IDE) {
635
        prefix = "hd";
636 637
    } else if ((storageBus == StorageBus_SATA) ||
               (storageBus == StorageBus_SCSI)) {
638
        prefix = "sd";
639
    } else if (storageBus == StorageBus_Floppy) {
640
        prefix = "fd";
641 642
    }

643
    name = virIndexToDiskName(total, prefix);
644

645
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
646
          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
647
          NULLSTR(name), total, storageBus, deviceInst, devicePort,
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678
          deviceSlot, maxPortPerInst, maxSlotPerPort);
    return name;
}

/**
 * function to get the StorageBus, Port number
 * and Device number for the given devicename
 * e.g: hda has StorageBus = IDE, port = 0,
 *      device = 0
 *
 * @returns     true on Success, false on failure.
 * @param       deviceName      Input device name
 * @param       aMaxPortPerInst Input array of max port per device instance
 * @param       aMaxSlotPerPort Input array of max slot per device port
 * @param       storageBus      Input storage bus type
 * @param       deviceInst      Output device instance number
 * @param       devicePort      Output port number
 * @param       deviceSlot      Output slot number
 *
 */
static bool vboxGetDeviceDetails(const char *deviceName,
                                 PRUint32   *aMaxPortPerInst,
                                 PRUint32   *aMaxSlotPerPort,
                                 PRUint32    storageBus,
                                 PRInt32    *deviceInst,
                                 PRInt32    *devicePort,
                                 PRInt32    *deviceSlot) {
    int total = 0;
    PRUint32 maxPortPerInst = 0;
    PRUint32 maxSlotPerPort = 0;

679 680 681 682 683 684
    if (!deviceName ||
        !deviceInst ||
        !devicePort ||
        !deviceSlot ||
        !aMaxPortPerInst ||
        !aMaxSlotPerPort)
685 686
        return false;

687 688
    if ((storageBus < StorageBus_IDE) ||
        (storageBus > StorageBus_Floppy))
689 690 691 692 693 694 695
        return false;

    total = virDiskNameToIndex(deviceName);

    maxPortPerInst = aMaxPortPerInst[storageBus];
    maxSlotPerPort = aMaxSlotPerPort[storageBus];

696 697 698
    if (!maxPortPerInst ||
        !maxSlotPerPort ||
        (total < 0))
699 700 701 702 703 704
        return false;

    *deviceInst = total / (maxPortPerInst * maxSlotPerPort);
    *devicePort = (total % (maxPortPerInst * maxSlotPerPort)) / maxSlotPerPort;
    *deviceSlot = (total % (maxPortPerInst * maxSlotPerPort)) % maxSlotPerPort;

705
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
          deviceName, total, storageBus, *deviceInst, *devicePort,
          *deviceSlot, maxPortPerInst, maxSlotPerPort);

    return true;
}

/**
 * function to get the values for max port per
 * instance and max slots per port for the devices
 *
 * @returns     true on Success, false on failure.
 * @param       vbox            Input IVirtualBox pointer
 * @param       maxPortPerInst  Output array of max port per instance
 * @param       maxSlotPerPort  Output array of max slot per port
 *
 */

static bool vboxGetMaxPortSlotValues(IVirtualBox *vbox,
                                     PRUint32 *maxPortPerInst,
                                     PRUint32 *maxSlotPerPort) {
    ISystemProperties *sysProps = NULL;

    if (!vbox)
        return false;

    vbox->vtbl->GetSystemProperties(vbox, &sysProps);

    if (!sysProps)
        return false;

    sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
                                                 StorageBus_IDE,
                                                 &maxPortPerInst[StorageBus_IDE]);
    sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
                                                 StorageBus_SATA,
                                                 &maxPortPerInst[StorageBus_SATA]);
    sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
                                                 StorageBus_SCSI,
                                                 &maxPortPerInst[StorageBus_SCSI]);
    sysProps->vtbl->GetMaxPortCountForStorageBus(sysProps,
                                                 StorageBus_Floppy,
                                                 &maxPortPerInst[StorageBus_Floppy]);

    sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
                                                      StorageBus_IDE,
                                                      &maxSlotPerPort[StorageBus_IDE]);
    sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
                                                      StorageBus_SATA,
                                                      &maxSlotPerPort[StorageBus_SATA]);
    sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
                                                      StorageBus_SCSI,
                                                      &maxSlotPerPort[StorageBus_SCSI]);
    sysProps->vtbl->GetMaxDevicesPerPortForStorageBus(sysProps,
                                                      StorageBus_Floppy,
                                                      &maxSlotPerPort[StorageBus_Floppy]);

    VBOX_RELEASE(sysProps);

    return true;
}

/**
 * Converts Utf-16 string to int
 */
static int PRUnicharToInt(PRUnichar *strUtf16) {
    char *strUtf8 = NULL;
    int ret = 0;

    if (!strUtf16)
        return -1;

    g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);
    if (!strUtf8)
        return -1;

782 783 784
    if (virStrToLong_i(strUtf8, NULL, 10, &ret) < 0)
        ret = -1;

785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
    g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);

    return ret;
}

/**
 * Converts int to Utf-16 string
 */
static PRUnichar *PRUnicharFromInt(int n) {
    PRUnichar *strUtf16 = NULL;
    char s[24];

    snprintf(s, sizeof(s), "%d", n);

    g_pVBoxGlobalData->pFuncs->pfnUtf8ToUtf16(s, &strUtf16);

    return strUtf16;
}

804
# endif /* VBOX_API_VERSION >= 3001 */
805

806 807
#endif /* !(VBOX_API_VERSION == 2002) */

808 809 810 811 812 813
static PRUnichar *
vboxSocketFormatAddrUtf16(vboxGlobalData *data, virSocketAddrPtr addr)
{
    char *utf8 = NULL;
    PRUnichar *utf16 = NULL;

814
    utf8 = virSocketAddrFormat(addr);
815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834

    if (utf8 == NULL) {
        return NULL;
    }

    VBOX_UTF8_TO_UTF16(utf8, &utf16);
    VIR_FREE(utf8);

    return utf16;
}

static int
vboxSocketParseAddrUtf16(vboxGlobalData *data, const PRUnichar *utf16,
                         virSocketAddrPtr addr)
{
    int result = -1;
    char *utf8 = NULL;

    VBOX_UTF16_TO_UTF8(utf16, &utf8);

835
    if (virSocketAddrParse(addr, utf8, AF_UNSPEC) < 0) {
836 837 838 839 840 841 842 843 844 845 846
        goto cleanup;
    }

    result = 0;

cleanup:
    VBOX_UTF8_FREE(utf8);

    return result;
}

847

848 849 850 851 852
static virDomainDefParserConfig vboxDomainDefParserConfig = {
    .macPrefix = { 0x08, 0x00, 0x27 },
};


853
static virDomainXMLOptionPtr
854 855
vboxXMLConfInit(void)
{
856 857
    return virDomainXMLOptionNew(&vboxDomainDefParserConfig,
                                 NULL, NULL);
858 859 860
}


861 862
static virCapsPtr vboxCapsInit(void)
{
863 864 865
    virCapsPtr caps;
    virCapsGuestPtr guest;

866
    if ((caps = virCapabilitiesNew(virArchFromHost(),
867 868 869
                                   0, 0)) == NULL)
        goto no_memory;

870
    if (nodeCapsInitNUMA(caps) < 0)
871 872 873 874
        goto no_memory;

    if ((guest = virCapabilitiesAddGuest(caps,
                                         "hvm",
875
                                         caps->host.arch,
876 877 878 879 880 881 882 883 884 885 886 887 888
                                         NULL,
                                         NULL,
                                         0,
                                         NULL)) == NULL)
        goto no_memory;

    if (virCapabilitiesAddGuestDomain(guest,
                                      "vbox",
                                      NULL,
                                      NULL,
                                      0,
                                      NULL) == NULL)
        goto no_memory;
889

890 891 892
    return caps;

no_memory:
893
    virObjectUnref(caps);
894 895 896
    return NULL;
}

897 898 899
static int
vboxInitialize(vboxGlobalData *data)
{
900 901 902
    data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION);

    if (data->pFuncs == NULL)
903
        goto cleanup;
904 905 906

#if VBOX_XPCOMC_VERSION == 0x00010000U
    data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
907
#else  /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
908 909
    data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj,
                               ISESSION_IID_STR, &data->vboxSession);
910

911
# if VBOX_API_VERSION == 2002
912 913 914

    /* No event queue functionality in 2.2.* as of now */

915
# else  /* !(VBOX_API_VERSION == 2002) */
916 917 918 919 920 921 922

    /* Initial the fWatch needed for Event Callbacks */
    data->fdWatch = -1;

    data->pFuncs->pfnGetEventQueue(&data->vboxQueue);

    if (data->vboxQueue == NULL) {
923 924
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("nsIEventQueue object is null"));
925 926 927
        goto cleanup;
    }

928
# endif /* !(VBOX_API_VERSION == 2002) */
929
#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
930 931

    if (data->vboxObj == NULL) {
932 933
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("IVirtualBox object is null"));
934
        goto cleanup;
935 936 937
    }

    if (data->vboxSession == NULL) {
938 939
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("ISession object is null"));
940 941
        goto cleanup;
    }
942 943 944 945 946 947 948

    return 0;

cleanup:
    return -1;
}

949
static int vboxExtractVersion(vboxGlobalData *data) {
950
    int ret = -1;
951 952 953 954 955 956 957 958 959 960
    PRUnichar *versionUtf16 = NULL;
    nsresult rc;

    if (data->version > 0)
        return 0;

    rc = data->vboxObj->vtbl->GetVersion(data->vboxObj, &versionUtf16);
    if (NS_SUCCEEDED(rc)) {
        char *vboxVersion = NULL;

961
        VBOX_UTF16_TO_UTF8(versionUtf16, &vboxVersion);
962

963
        if (virParseVersionString(vboxVersion, &data->version, false) >= 0)
964 965
            ret = 0;

966 967
        VBOX_UTF8_FREE(vboxVersion);
        VBOX_COM_UNALLOC_MEM(versionUtf16);
968 969 970
    }

    if (ret != 0)
971 972
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not extract VirtualBox version"));
973

974 975 976 977
    return ret;
}

static void vboxUninitialize(vboxGlobalData *data) {
978 979 980
    if (!data)
        return;

981 982
    if (data->pFuncs)
        data->pFuncs->pfnComUninitialize();
983

984
    virObjectUnref(data->caps);
985
    virObjectUnref(data->xmlopt);
986 987 988
#if VBOX_API_VERSION == 2002
    /* No domainEventCallbacks in 2.2.* version */
#else  /* !(VBOX_API_VERSION == 2002) */
989
    virDomainEventStateFree(data->domainEvents);
990
#endif /* !(VBOX_API_VERSION == 2002) */
991 992 993
    VIR_FREE(data);
}

994

995 996 997
static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
998
{
999
    vboxGlobalData *data = NULL;
1000 1001
    uid_t uid = getuid();

E
Eric Blake 已提交
1002 1003
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1004 1005 1006
    if (conn->uri == NULL &&
        !(conn->uri = virURIParse(uid ? "vbox:///session" : "vbox:///system")))
        return VIR_DRV_OPEN_ERROR;
1007

1008
    if (conn->uri->scheme == NULL ||
1009
        STRNEQ(conn->uri->scheme, "vbox"))
1010 1011 1012 1013
        return VIR_DRV_OPEN_DECLINED;

    /* Leave for remote driver */
    if (conn->uri->server != NULL)
1014 1015
        return VIR_DRV_OPEN_DECLINED;

1016
    if (conn->uri->path == NULL || STREQ(conn->uri->path, "")) {
1017 1018
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no VirtualBox driver path specified (try vbox:///session)"));
1019 1020 1021
        return VIR_DRV_OPEN_ERROR;
    }

1022
    if (uid != 0) {
1023
        if (STRNEQ(conn->uri->path, "/session")) {
1024 1025
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown driver path '%s' specified (try vbox:///session)"), conn->uri->path);
1026 1027
            return VIR_DRV_OPEN_ERROR;
        }
1028
    } else { /* root */
1029 1030
        if (STRNEQ(conn->uri->path, "/system") &&
            STRNEQ(conn->uri->path, "/session")) {
1031 1032
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown driver path '%s' specified (try vbox:///system)"), conn->uri->path);
1033 1034
            return VIR_DRV_OPEN_ERROR;
        }
1035 1036 1037
    }

    if (VIR_ALLOC(data) < 0) {
1038
        virReportOOMError();
1039
        return VIR_DRV_OPEN_ERROR;
1040 1041
    }

1042
    if (!(data->caps = vboxCapsInit()) ||
1043
        vboxInitialize(data) < 0 ||
1044
        vboxExtractVersion(data) < 0 ||
1045
        !(data->xmlopt = vboxXMLConfInit())) {
1046 1047 1048
        vboxUninitialize(data);
        return VIR_DRV_OPEN_ERROR;
    }
1049

1050 1051 1052 1053 1054 1055
#if VBOX_API_VERSION == 2002

    /* No domainEventCallbacks in 2.2.* version */

#else  /* !(VBOX_API_VERSION == 2002) */

1056
    if (!(data->domainEvents = virDomainEventStateNew())) {
1057
        vboxUninitialize(data);
1058 1059 1060 1061 1062 1063 1064 1065
        return VIR_DRV_OPEN_ERROR;
    }

    data->conn = conn;
    g_pVBoxGlobalData = data;

#endif /* !(VBOX_API_VERSION == 2002) */

1066
    conn->privateData = data;
1067
    VIR_DEBUG("in vboxOpen");
1068 1069 1070 1071

    return VIR_DRV_OPEN_SUCCESS;
}

1072
static int vboxConnectClose(virConnectPtr conn) {
1073
    vboxGlobalData *data = conn->privateData;
1074
    VIR_DEBUG("%s: in vboxClose",conn->driver->name);
1075 1076 1077 1078 1079 1080 1081

    vboxUninitialize(data);
    conn->privateData = NULL;

    return 0;
}

1082
static int vboxConnectGetVersion(virConnectPtr conn, unsigned long *version) {
1083
    vboxGlobalData *data = conn->privateData;
1084
    VIR_DEBUG("%s: in vboxGetVersion",conn->driver->name);
1085 1086 1087 1088 1089 1090 1091 1092

    vboxDriverLock(data);
    *version = data->version;
    vboxDriverUnlock(data);

    return 0;
}

1093 1094 1095 1096 1097 1098 1099

static char *vboxConnectGetHostname(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return virGetHostname();
}


1100
static int vboxConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED) {
1101 1102 1103 1104
    /* Driver is using local, non-network based transport */
    return 1;
}

1105
static int vboxConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED) {
1106 1107 1108 1109
    /* No encryption is needed, or used on the local transport*/
    return 0;
}

1110
static int vboxConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1111 1112 1113 1114
{
    return 1;
}

1115
static int vboxConnectGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED) {
1116
    VBOX_OBJECT_CHECK(conn, int, -1);
1117 1118 1119 1120 1121
    PRUint32 maxCPUCount = 0;

    /* VirtualBox Supports only hvm and thus the type passed to it
     * has no meaning, setting it to ATTRIBUTE_UNUSED
     */
1122
    ISystemProperties *systemProperties = NULL;
1123

1124 1125 1126 1127
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
        VBOX_RELEASE(systemProperties);
1128 1129 1130 1131 1132 1133 1134 1135 1136
    }

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}


1137
static char *vboxConnectGetCapabilities(virConnectPtr conn) {
1138
    VBOX_OBJECT_CHECK(conn, char *, NULL);
1139 1140 1141 1142 1143 1144 1145 1146

    vboxDriverLock(data);
    ret = virCapabilitiesFormatXML(data->caps);
    vboxDriverUnlock(data);

    return ret;
}

1147
static int vboxConnectListDomains(virConnectPtr conn, int *ids, int nids) {
1148
    VBOX_OBJECT_CHECK(conn, int, -1);
1149
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1150
    PRUint32 state;
1151
    nsresult rc;
1152 1153
    int i, j;

1154
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1155
    if (NS_FAILED(rc)) {
1156 1157
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of Domains, rc=%08x"),(unsigned)rc);
1158 1159
        goto cleanup;
    }
1160

1161 1162 1163
    ret = 0;
    for (i = 0, j = 0; (i < machines.count) && (j < nids); ++i) {
        IMachine *machine = machines.items[i];
1164 1165 1166 1167 1168 1169

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
1170 1171
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline)) {
1172 1173
                    ret++;
                    ids[j++] = i + 1;
1174 1175 1176 1177 1178 1179
                }
            }
        }
    }

cleanup:
1180
    vboxArrayRelease(&machines);
1181 1182 1183
    return ret;
}

1184
static int vboxConnectNumOfDomains(virConnectPtr conn) {
1185
    VBOX_OBJECT_CHECK(conn, int, -1);
1186
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1187
    PRUint32 state;
1188
    nsresult rc;
1189 1190
    int i;

1191
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1192
    if (NS_FAILED(rc)) {
1193 1194
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get number of Domains, rc=%08x"), (unsigned)rc);
1195 1196
        goto cleanup;
    }
1197

1198 1199 1200
    ret = 0;
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1201 1202 1203 1204 1205 1206

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
1207 1208
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1209
                    ret++;
1210 1211 1212 1213 1214
            }
        }
    }

cleanup:
1215
    vboxArrayRelease(&machines);
1216 1217 1218 1219
    return ret;
}

static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml,
1220
                                        unsigned int flags) {
1221 1222 1223 1224 1225 1226 1227 1228
    /* VirtualBox currently doesn't have support for running
     * virtual machines without actually defining them and thus
     * for time being just define new machine and start it.
     *
     * TODO: After the appropriate API's are added in VirtualBox
     * change this behaviour to the expected one.
     */

1229 1230 1231 1232 1233
    virDomainPtr dom;

    virCheckFlags(0, NULL);

    dom = vboxDomainDefineXML(conn, xml);
1234 1235 1236 1237
    if (dom == NULL)
        return NULL;

    if (vboxDomainCreate(dom) < 0) {
1238
        vboxDomainUndefineFlags(dom, 0);
1239
        virObjectUnref(dom);
1240
        return NULL;
1241 1242 1243 1244 1245 1246
    }

    return dom;
}

static virDomainPtr vboxDomainLookupByID(virConnectPtr conn, int id) {
1247
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1248
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1249 1250
    vboxIID iid = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
1251
    PRUint32 state;
1252
    nsresult rc;
1253

1254 1255 1256
    /* Internal vbox IDs start from 0, the public libvirt ID
     * starts from 1, so refuse id==0, and adjust the rest*/
    if (id == 0) {
1257 1258
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), id);
1259 1260 1261 1262
        return NULL;
    }
    id = id - 1;

1263
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1264
    if (NS_FAILED(rc)) {
1265 1266
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1267 1268
        return NULL;
    }
1269

1270 1271 1272 1273
    if (id < machines.count) {
        IMachine *machine = machines.items[id];

        if (machine) {
1274
            PRBool isAccessible = PR_FALSE;
1275
            machine->vtbl->GetAccessible(machine, &isAccessible);
1276
            if (isAccessible) {
1277
                machine->vtbl->GetState(machine, &state);
1278 1279
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline)) {
1280 1281
                    PRUnichar *machineNameUtf16 = NULL;
                    char      *machineNameUtf8  = NULL;
1282

1283
                    machine->vtbl->GetName(machine, &machineNameUtf16);
1284
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1285

1286 1287 1288
                    machine->vtbl->GetId(machine, &iid.value);
                    vboxIIDToUUID(&iid, uuid);
                    vboxIIDUnalloc(&iid);
1289 1290 1291 1292 1293 1294 1295

                    /* get a new domain pointer from virGetDomain, if it fails
                     * then no need to assign the id, else assign the id, cause
                     * it is -1 by default. rest is taken care by virGetDomain
                     * itself, so need not worry.
                     */

1296
                    ret = virGetDomain(conn, machineNameUtf8, uuid);
1297 1298 1299 1300 1301 1302
                    if (ret)
                        ret->id = id + 1;

                    /* Cleanup all the XPCOM allocated stuff here */
                    VBOX_UTF8_FREE(machineNameUtf8);
                    VBOX_UTF16_FREE(machineNameUtf16);
1303 1304 1305 1306 1307
                }
            }
        }
    }

1308
    vboxArrayRelease(&machines);
1309 1310

    return ret;
1311 1312 1313
}

static virDomainPtr vboxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid) {
1314
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1315
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1316
    vboxIID iid = VBOX_IID_INITIALIZER;
1317
    char      *machineNameUtf8  = NULL;
1318
    PRUnichar *machineNameUtf16 = NULL;
1319
    unsigned char iid_as_uuid[VIR_UUID_BUFLEN];
1320
    int i, matched = 0;
1321
    nsresult rc;
1322

1323
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1324
    if (NS_FAILED(rc)) {
1325 1326
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1327 1328
        return NULL;
    }
1329

1330 1331
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1332
        PRBool isAccessible = PR_FALSE;
1333

1334 1335
        if (!machine)
            continue;
1336

1337 1338
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1339

1340 1341
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
1342
                continue;
1343 1344
            vboxIIDToUUID(&iid, iid_as_uuid);
            vboxIIDUnalloc(&iid);
1345

1346
            if (memcmp(uuid, iid_as_uuid, VIR_UUID_BUFLEN) == 0) {
1347

1348
                PRUint32 state;
1349

1350
                matched = 1;
1351

1352 1353
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1354

1355
                machine->vtbl->GetState(machine, &state);
1356

1357 1358 1359 1360 1361
                /* get a new domain pointer from virGetDomain, if it fails
                 * then no need to assign the id, else assign the id, cause
                 * it is -1 by default. rest is taken care by virGetDomain
                 * itself, so need not worry.
                 */
1362

1363
                ret = virGetDomain(conn, machineNameUtf8, iid_as_uuid);
1364 1365 1366
                if (ret &&
                    (state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1367
                    ret->id = i + 1;
1368 1369
            }

1370 1371
            if (matched == 1)
                break;
1372 1373 1374
        }
    }

1375 1376 1377
    /* Do the cleanup and take care you dont leak any memory */
    VBOX_UTF8_FREE(machineNameUtf8);
    VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1378
    vboxArrayRelease(&machines);
1379 1380

    return ret;
1381 1382 1383
}

static virDomainPtr vboxDomainLookupByName(virConnectPtr conn, const char *name) {
1384
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1385
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1386
    vboxIID iid = VBOX_IID_INITIALIZER;
1387
    char      *machineNameUtf8  = NULL;
1388
    PRUnichar *machineNameUtf16 = NULL;
1389
    unsigned char uuid[VIR_UUID_BUFLEN];
1390
    int i, matched = 0;
1391
    nsresult rc;
1392

1393
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1394
    if (NS_FAILED(rc)) {
1395 1396
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1397 1398
        return NULL;
    }
1399

1400 1401
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1402
        PRBool isAccessible = PR_FALSE;
1403

1404 1405
        if (!machine)
            continue;
1406

1407 1408
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1409

1410 1411
            machine->vtbl->GetName(machine, &machineNameUtf16);
            VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1412

1413
            if (STREQ(name, machineNameUtf8)) {
1414

1415
                PRUint32 state;
1416

1417
                matched = 1;
1418

1419 1420 1421
                machine->vtbl->GetId(machine, &iid.value);
                vboxIIDToUUID(&iid, uuid);
                vboxIIDUnalloc(&iid);
1422

1423
                machine->vtbl->GetState(machine, &state);
1424

1425 1426 1427 1428 1429
                /* get a new domain pointer from virGetDomain, if it fails
                 * then no need to assign the id, else assign the id, cause
                 * it is -1 by default. rest is taken care by virGetDomain
                 * itself, so need not worry.
                 */
1430

1431
                ret = virGetDomain(conn, machineNameUtf8, uuid);
1432 1433 1434
                if (ret &&
                    (state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1435
                    ret->id = i + 1;
1436 1437
            }

J
John Ferlan 已提交
1438 1439
            VBOX_UTF8_FREE(machineNameUtf8);
            VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1440 1441
            if (matched == 1)
                break;
1442 1443 1444
        }
    }

1445
    vboxArrayRelease(&machines);
1446 1447

    return ret;
1448 1449
}

1450 1451

static int vboxDomainIsActive(virDomainPtr dom) {
1452
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1453
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1454
    vboxIID iid = VBOX_IID_INITIALIZER;
1455 1456
    char      *machineNameUtf8  = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1457
    unsigned char uuid[VIR_UUID_BUFLEN];
1458
    int i, matched = 0;
1459
    nsresult rc;
1460

1461
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1462
    if (NS_FAILED(rc)) {
1463 1464
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1465 1466
        return ret;
    }
1467

1468 1469
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1470 1471 1472 1473 1474 1475 1476
        PRBool isAccessible = PR_FALSE;

        if (!machine)
            continue;

        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1477

1478 1479
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
1480
                continue;
1481 1482
            vboxIIDToUUID(&iid, uuid);
            vboxIIDUnalloc(&iid);
1483

1484
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
1485

1486
                PRUint32 state;
1487

1488
                matched = 1;
1489

1490 1491
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1492

1493
                machine->vtbl->GetState(machine, &state);
1494

1495 1496
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1497 1498 1499
                    ret = 1;
                else
                    ret = 0;
1500 1501
            }

1502 1503
            if (matched == 1)
                break;
1504 1505 1506
        }
    }

1507 1508 1509
    /* Do the cleanup and take care you dont leak any memory */
    VBOX_UTF8_FREE(machineNameUtf8);
    VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1510
    vboxArrayRelease(&machines);
1511

1512 1513 1514 1515
    return ret;
}


1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
static int vboxDomainIsPersistent(virDomainPtr dom ATTRIBUTE_UNUSED)
{
    /* All domains are persistent.  However, we do want to check for
     * existence. */
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    nsresult rc;

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
1528 1529
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1530 1531 1532 1533 1534 1535 1536 1537 1538
        goto cleanup;
    }

    ret = 1;

cleanup:
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1539 1540 1541
}


1542
static int vboxDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED) {
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552
    /* VBox domains never have a persistent state that differs from
     * current state.  However, we do want to check for existence.  */
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    nsresult rc;

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
1553 1554
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1555 1556 1557 1558 1559 1560 1561 1562 1563
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1564 1565
}

1566
static int vboxDomainSuspend(virDomainPtr dom) {
1567
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1568
    IMachine *machine    = NULL;
1569
    vboxIID iid = VBOX_IID_INITIALIZER;
1570
    IConsole *console    = NULL;
1571
    PRBool isAccessible  = PR_FALSE;
1572
    PRUint32 state;
1573
    nsresult rc;
1574

1575
    vboxIIDFromUUID(&iid, dom->uuid);
1576
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1577
    if (NS_FAILED(rc)) {
1578 1579
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1580 1581
        goto cleanup;
    }
1582

1583 1584
    if (!machine)
        goto cleanup;
1585

1586 1587 1588
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1589

1590
        if (state == MachineState_Running) {
1591 1592
            /* set state pause */
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1593 1594 1595 1596 1597
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Pause(console);
                VBOX_RELEASE(console);
                ret = 0;
1598
            } else {
1599 1600
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("error while suspending the domain"));
1601 1602
                goto cleanup;
            }
1603
            VBOX_SESSION_CLOSE();
1604
        } else {
1605 1606
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not in running state to suspend it"));
1607
            goto cleanup;
1608 1609 1610 1611
        }
    }

cleanup:
1612
    VBOX_RELEASE(machine);
1613
    vboxIIDUnalloc(&iid);
1614 1615 1616 1617
    return ret;
}

static int vboxDomainResume(virDomainPtr dom) {
1618
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1619
    IMachine *machine    = NULL;
1620
    vboxIID iid = VBOX_IID_INITIALIZER;
1621 1622
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1623
    nsresult rc;
1624

1625
    PRBool isAccessible = PR_FALSE;
1626

1627
    vboxIIDFromUUID(&iid, dom->uuid);
1628
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1629
    if (NS_FAILED(rc)) {
1630 1631
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1632 1633
        goto cleanup;
    }
1634

1635 1636
    if (!machine)
        goto cleanup;
1637

1638 1639 1640 1641 1642
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);

        if (state == MachineState_Paused) {
1643 1644
            /* resume the machine here */
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1645 1646 1647 1648 1649
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Resume(console);
                VBOX_RELEASE(console);
                ret = 0;
1650
            } else {
1651 1652
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("error while resuming the domain"));
1653 1654
                goto cleanup;
            }
1655
            VBOX_SESSION_CLOSE();
1656
        } else {
1657 1658
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not paused, so can't resume it"));
1659
            goto cleanup;
1660 1661 1662 1663
        }
    }

cleanup:
1664
    VBOX_RELEASE(machine);
1665
    vboxIIDUnalloc(&iid);
1666 1667 1668
    return ret;
}

1669 1670
static int vboxDomainShutdownFlags(virDomainPtr dom,
                                   unsigned int flags) {
1671
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1672
    IMachine *machine    = NULL;
1673
    vboxIID iid = VBOX_IID_INITIALIZER;
1674 1675
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1676 1677
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1678

1679 1680
    virCheckFlags(0, -1);

1681
    vboxIIDFromUUID(&iid, dom->uuid);
1682
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1683
    if (NS_FAILED(rc)) {
1684 1685
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1686 1687
        goto cleanup;
    }
1688

1689 1690
    if (!machine)
        goto cleanup;
1691

1692 1693 1694
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1695

1696
        if (state == MachineState_Paused) {
1697 1698
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine paused, so can't power it down"));
1699 1700
            goto cleanup;
        } else if (state == MachineState_PoweredOff) {
1701 1702
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1703 1704
            goto cleanup;
        }
1705

1706
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1707 1708 1709 1710 1711
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
            console->vtbl->PowerButton(console);
            VBOX_RELEASE(console);
            ret = 0;
1712
        }
1713
        VBOX_SESSION_CLOSE();
1714 1715 1716
    }

cleanup:
1717
    VBOX_RELEASE(machine);
1718
    vboxIIDUnalloc(&iid);
1719 1720 1721
    return ret;
}

1722 1723 1724 1725 1726
static int vboxDomainShutdown(virDomainPtr dom) {
    return vboxDomainShutdownFlags(dom, 0);
}


E
Eric Blake 已提交
1727 1728
static int vboxDomainReboot(virDomainPtr dom, unsigned int flags)
{
1729
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1730
    IMachine *machine    = NULL;
1731
    vboxIID iid = VBOX_IID_INITIALIZER;
1732 1733
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1734 1735
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1736

E
Eric Blake 已提交
1737 1738
    virCheckFlags(0, -1);

1739
    vboxIIDFromUUID(&iid, dom->uuid);
1740
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1741
    if (NS_FAILED(rc)) {
1742 1743
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1744 1745
        goto cleanup;
    }
1746

1747 1748
    if (!machine)
        goto cleanup;
1749

1750 1751 1752
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1753

1754
        if (state == MachineState_Running) {
1755
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1756 1757 1758 1759 1760
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Reset(console);
                VBOX_RELEASE(console);
                ret = 0;
1761
            }
1762
            VBOX_SESSION_CLOSE();
1763
        } else {
1764 1765
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not running, so can't reboot it"));
1766
            goto cleanup;
1767 1768 1769 1770
        }
    }

cleanup:
1771
    VBOX_RELEASE(machine);
1772
    vboxIIDUnalloc(&iid);
1773 1774 1775
    return ret;
}

1776 1777 1778 1779
static int
vboxDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
1780
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1781
    IMachine *machine    = NULL;
1782
    vboxIID iid = VBOX_IID_INITIALIZER;
1783 1784
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1785 1786
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1787

1788 1789
    virCheckFlags(0, -1);

1790
    vboxIIDFromUUID(&iid, dom->uuid);
1791
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1792
    if (NS_FAILED(rc)) {
1793 1794
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1795 1796
        goto cleanup;
    }
1797

1798 1799
    if (!machine)
        goto cleanup;
1800

1801 1802 1803
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1804

1805
        if (state == MachineState_PoweredOff) {
1806 1807
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1808 1809
            goto cleanup;
        }
1810

1811
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1812 1813
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
1814 1815

#if VBOX_API_VERSION == 2002
1816
            console->vtbl->PowerDown(console);
1817
#else
1818
            IProgress *progress = NULL;
1819 1820 1821 1822
            console->vtbl->PowerDown(console, &progress);
            if (progress) {
                progress->vtbl->WaitForCompletion(progress, -1);
                VBOX_RELEASE(progress);
1823
            }
1824 1825
#endif
            VBOX_RELEASE(console);
1826
            dom->id = -1;
1827
            ret = 0;
1828
        }
1829
        VBOX_SESSION_CLOSE();
1830 1831 1832
    }

cleanup:
1833
    VBOX_RELEASE(machine);
1834
    vboxIIDUnalloc(&iid);
1835 1836 1837
    return ret;
}

1838 1839 1840 1841 1842 1843
static int
vboxDomainDestroy(virDomainPtr dom)
{
    return vboxDomainDestroyFlags(dom, 0);
}

1844
static char *vboxDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) {
1845 1846 1847 1848 1849
    /* Returning "hvm" always as suggested on list, cause
     * this functions seems to be badly named and it
     * is supposed to pass the ABI name and not the domain
     * operating system driver as I had imagined ;)
     */
1850 1851 1852
    char *osType = strdup("hvm");

    if (osType == NULL)
1853
        virReportOOMError();
1854 1855

    return osType;
1856 1857 1858
}

static int vboxDomainSetMemory(virDomainPtr dom, unsigned long memory) {
1859
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1860
    IMachine *machine    = NULL;
1861
    vboxIID iid = VBOX_IID_INITIALIZER;
1862
    PRUint32 state       = MachineState_Null;
1863 1864
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1865

1866
    vboxIIDFromUUID(&iid, dom->uuid);
1867
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1868
    if (NS_FAILED(rc)) {
1869 1870
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1871 1872
        goto cleanup;
    }
1873

1874 1875
    if (!machine)
        goto cleanup;
1876

1877 1878 1879
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1880

1881
        if (state != MachineState_PoweredOff) {
1882 1883
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("memory size can't be changed unless domain is powered down"));
1884 1885
            goto cleanup;
        }
1886

1887
        rc = VBOX_SESSION_OPEN(iid.value, machine);
1888 1889 1890
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
1891

1892 1893
                rc = machine->vtbl->SetMemorySize(machine,
                                                  VIR_DIV_UP(memory, 1024));
1894 1895 1896 1897
                if (NS_SUCCEEDED(rc)) {
                    machine->vtbl->SaveSettings(machine);
                    ret = 0;
                } else {
1898 1899 1900 1901
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("could not set the memory size of the "
                                     "domain to: %lu Kb, rc=%08x"),
                                   memory, (unsigned)rc);
1902 1903
                }
            }
1904
            VBOX_SESSION_CLOSE();
1905 1906 1907 1908
        }
    }

cleanup:
1909
    VBOX_RELEASE(machine);
1910
    vboxIIDUnalloc(&iid);
1911 1912 1913 1914
    return ret;
}

static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) {
1915
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1916
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1917 1918
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1919 1920
    nsresult rc;
    int i = 0;
1921

1922
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1923
    if (NS_FAILED(rc)) {
1924 1925
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1926 1927
        goto cleanup;
    }
1928

1929
    info->nrVirtCpu = 0;
1930 1931
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1932
        PRBool isAccessible = PR_FALSE;
1933

1934 1935
        if (!machine)
            continue;
1936

1937 1938
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1939

1940 1941 1942 1943 1944 1945
            machine->vtbl->GetName(machine, &machineNameUtf16);
            VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);

            if (STREQ(dom->name, machineName)) {
                /* Get the Machine State (also match it with
                * virDomainState). Get the Machine memory and
1946
                * for time being set max_balloon and cur_balloon to same
1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963
                * Also since there is no direct way of checking
                * the cputime required (one condition being the
                * VM is remote), return zero for cputime. Get the
                * number of CPU.
                */
                PRUint32 CPUCount   = 0;
                PRUint32 memorySize = 0;
                PRUint32 state      = MachineState_Null;
                PRUint32 maxMemorySize = 4 * 1024;
                ISystemProperties *systemProperties = NULL;

                data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
                if (systemProperties) {
                    systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                    VBOX_RELEASE(systemProperties);
                    systemProperties = NULL;
                }
1964 1965


1966 1967 1968 1969 1970 1971
                machine->vtbl->GetCPUCount(machine, &CPUCount);
                machine->vtbl->GetMemorySize(machine, &memorySize);
                machine->vtbl->GetState(machine, &state);

                info->cpuTime = 0;
                info->nrVirtCpu = CPUCount;
1972 1973
                info->memory = memorySize * 1024;
                info->maxMem = maxMemorySize * 1024;
1974
                switch (state) {
1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996
                    case MachineState_Running:
                        info->state = VIR_DOMAIN_RUNNING;
                        break;
                    case MachineState_Stuck:
                        info->state = VIR_DOMAIN_BLOCKED;
                        break;
                    case MachineState_Paused:
                        info->state = VIR_DOMAIN_PAUSED;
                        break;
                    case MachineState_Stopping:
                        info->state = VIR_DOMAIN_SHUTDOWN;
                        break;
                    case MachineState_PoweredOff:
                        info->state = VIR_DOMAIN_SHUTOFF;
                        break;
                    case MachineState_Aborted:
                        info->state = VIR_DOMAIN_CRASHED;
                        break;
                    case MachineState_Null:
                    default:
                        info->state = VIR_DOMAIN_NOSTATE;
                        break;
1997 1998
                }

1999
                ret = 0;
2000 2001
            }

J
John Ferlan 已提交
2002 2003
            VBOX_UTF8_FREE(machineName);
            VBOX_COM_UNALLOC_MEM(machineNameUtf16);
2004 2005
            if (info->nrVirtCpu)
                break;
2006 2007 2008 2009
        }

    }

2010
    vboxArrayRelease(&machines);
2011 2012 2013 2014 2015

cleanup:
    return ret;
}

2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032
static int
vboxDomainGetState(virDomainPtr dom,
                   int *state,
                   int *reason,
                   unsigned int flags)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID domiid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    PRUint32 mstate = MachineState_Null;
    nsresult rc;

    virCheckFlags(0, -1);

    vboxIIDFromUUID(&domiid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
    if (NS_FAILED(rc)) {
2033 2034
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074
        goto cleanup;
    }

    machine->vtbl->GetState(machine, &mstate);

    switch (mstate) {
    case MachineState_Running:
        *state = VIR_DOMAIN_RUNNING;
        break;
    case MachineState_Stuck:
        *state = VIR_DOMAIN_BLOCKED;
        break;
    case MachineState_Paused:
        *state = VIR_DOMAIN_PAUSED;
        break;
    case MachineState_Stopping:
        *state = VIR_DOMAIN_SHUTDOWN;
        break;
    case MachineState_PoweredOff:
        *state = VIR_DOMAIN_SHUTOFF;
        break;
    case MachineState_Aborted:
        *state = VIR_DOMAIN_CRASHED;
        break;
    case MachineState_Null:
    default:
        *state = VIR_DOMAIN_NOSTATE;
        break;
    }

    if (reason)
        *reason = 0;

    ret = 0;

cleanup:
    vboxIIDUnalloc(&domiid);
    return ret;
}

2075
static int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED) {
2076
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
2077
    IConsole *console    = NULL;
2078
    vboxIID iid = VBOX_IID_INITIALIZER;
2079
    IMachine *machine = NULL;
2080
    nsresult rc;
2081 2082 2083 2084 2085 2086 2087 2088

    /* VirtualBox currently doesn't support saving to a file
     * at a location other then the machine folder and thus
     * setting path to ATTRIBUTE_UNUSED for now, will change
     * this behaviour once get the VirtualBox API in right
     * shape to do this
     */

2089
    /* Open a Session for the machine */
2090
    vboxIIDFromUUID(&iid, dom->uuid);
2091 2092 2093 2094
#if VBOX_API_VERSION >= 4000
    /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
2095 2096
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
2097 2098 2099 2100 2101
        return -1;
    }
#endif

    rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
2102 2103 2104 2105
    if (NS_SUCCEEDED(rc)) {
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (NS_SUCCEEDED(rc) && console) {
            IProgress *progress = NULL;
2106

2107
            console->vtbl->SaveState(console, &progress);
2108

2109
            if (progress) {
2110
#if VBOX_API_VERSION == 2002
2111
                nsresult resultCode;
2112
#else
2113
                PRInt32 resultCode;
2114
#endif
2115

2116 2117 2118 2119
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
                if (NS_SUCCEEDED(resultCode)) {
                    ret = 0;
2120
                }
2121
                VBOX_RELEASE(progress);
2122
            }
2123
            VBOX_RELEASE(console);
2124
        }
2125
        VBOX_SESSION_CLOSE();
2126 2127
    }

2128
    DEBUGIID("UUID of machine being saved:", iid.value);
2129

2130
    VBOX_RELEASE(machine);
2131
    vboxIIDUnalloc(&iid);
2132 2133 2134
    return ret;
}

2135 2136 2137 2138
static int
vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
{
2139
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
2140
    IMachine *machine    = NULL;
2141
    vboxIID iid = VBOX_IID_INITIALIZER;
2142
    PRUint32  CPUCount   = nvcpus;
2143
    nsresult rc;
2144

2145
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
2146
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2147 2148 2149
        return -1;
    }

2150
    vboxIIDFromUUID(&iid, dom->uuid);
2151 2152 2153 2154
#if VBOX_API_VERSION >= 4000
    /* Get machine for the call to VBOX_SESSION_OPEN */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
2155 2156
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
2157 2158 2159 2160 2161
        return -1;
    }
#endif

    rc = VBOX_SESSION_OPEN(iid.value, machine);
2162 2163 2164 2165 2166 2167 2168
    if (NS_SUCCEEDED(rc)) {
        data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
        if (machine) {
            rc = machine->vtbl->SetCPUCount(machine, CPUCount);
            if (NS_SUCCEEDED(rc)) {
                machine->vtbl->SaveSettings(machine);
                ret = 0;
2169
            } else {
2170 2171 2172 2173
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("could not set the number of cpus of the domain "
                                 "to: %u, rc=%08x"),
                               CPUCount, (unsigned)rc);
2174
            }
2175
            VBOX_RELEASE(machine);
2176
        } else {
2177 2178
            virReportError(VIR_ERR_NO_DOMAIN,
                           _("no domain with matching id %d"), dom->id);
2179
        }
2180
    } else {
2181 2182
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("can't open session to the domain with id %d"), dom->id);
2183
    }
2184
    VBOX_SESSION_CLOSE();
2185

2186
    vboxIIDUnalloc(&iid);
2187 2188 2189
    return ret;
}

2190 2191 2192
static int
vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
2193
    return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2194 2195 2196 2197 2198
}

static int
vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
2199 2200
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    ISystemProperties *systemProperties = NULL;
2201 2202
    PRUint32 maxCPUCount = 0;

2203
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
2204
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2205 2206 2207
        return -1;
    }

2208 2209 2210 2211 2212
    /* Currently every domain supports the same number of max cpus
     * as that supported by vbox and thus take it directly from
     * the systemproperties.
     */

2213 2214 2215 2216
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
        VBOX_RELEASE(systemProperties);
2217 2218 2219 2220 2221 2222 2223 2224
    }

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}

2225 2226 2227
static int
vboxDomainGetMaxVcpus(virDomainPtr dom)
{
2228
    return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
2229 2230 2231
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

2232
static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
2233
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
2234 2235
    virDomainDefPtr def  = NULL;
    IMachine *machine    = NULL;
2236
    vboxIID iid = VBOX_IID_INITIALIZER;
2237
    int gotAllABoutDef   = -1;
2238
    nsresult rc;
2239
    char *tmp;
2240

2241 2242
    /* Flags checked by virDomainDefFormat */

2243
    if (VIR_ALLOC(def) < 0) {
2244
        virReportOOMError();
2245 2246 2247
        goto cleanup;
    }

2248
    vboxIIDFromUUID(&iid, dom->uuid);
2249
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
2250
    if (NS_SUCCEEDED(rc)) {
2251
        PRBool accessible = PR_FALSE;
2252

2253 2254 2255 2256 2257 2258
        machine->vtbl->GetAccessible(machine, &accessible);
        if (accessible) {
            int i = 0;
            PRBool PAEEnabled                   = PR_FALSE;
            PRBool ACPIEnabled                  = PR_FALSE;
            PRBool IOAPICEnabled                = PR_FALSE;
2259
            PRBool VRDxEnabled                  = PR_FALSE;
2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281
            PRUint32 CPUCount                   = 0;
            PRUint32 memorySize                 = 0;
            PRUint32 netAdpCnt                  = 0;
            PRUint32 netAdpIncCnt               = 0;
            PRUint32 maxMemorySize              = 4 * 1024;
            PRUint32 USBFilterCount             = 0;
            PRUint32 maxBootPosition            = 0;
            PRUint32 serialPortCount            = 0;
            PRUint32 serialPortIncCount         = 0;
            PRUint32 parallelPortCount          = 0;
            PRUint32 parallelPortIncCount       = 0;
            IBIOSSettings *bios                 = NULL;
#if VBOX_API_VERSION < 3001
            PRInt32       hddNum                = 0;
            IDVDDrive    *dvdDrive              = NULL;
            IHardDisk    *hardDiskPM            = NULL;
            IHardDisk    *hardDiskPS            = NULL;
            IHardDisk    *hardDiskSS            = NULL;
            const char   *hddBus                = "IDE";
            PRUnichar    *hddBusUtf16           = NULL;
            IFloppyDrive *floppyDrive           = NULL;
#else  /* VBOX_API_VERSION >= 3001 */
2282
            vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
2283
#endif /* VBOX_API_VERSION >= 3001 */
2284 2285 2286 2287 2288
#if VBOX_API_VERSION < 4000
            IVRDPServer *VRDxServer             = NULL;
#else  /* VBOX_API_VERSION >= 4000 */
            IVRDEServer *VRDxServer             = NULL;
#endif /* VBOX_API_VERSION >= 4000 */
2289 2290
            IAudioAdapter *audioAdapter         = NULL;
            IUSBController *USBController       = NULL;
2291 2292 2293
#if VBOX_API_VERSION >= 4001
            PRUint32 chipsetType                = ChipsetType_Null;
#endif /* VBOX_API_VERSION >= 4001 */
2294
            ISystemProperties *systemProperties = NULL;
2295 2296


2297 2298 2299 2300
            def->virtType = VIR_DOMAIN_VIRT_VBOX;
            def->id = dom->id;
            memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
            def->name = strdup(dom->name);
2301

2302
            machine->vtbl->GetMemorySize(machine, &memorySize);
2303
            def->mem.cur_balloon = memorySize * 1024;
2304

2305 2306 2307 2308
#if VBOX_API_VERSION >= 4001
            machine->vtbl->GetChipsetType(machine, &chipsetType);
#endif /* VBOX_API_VERSION >= 4001 */

2309 2310 2311 2312
            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
2313
#if VBOX_API_VERSION < 4001
2314
                systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt);
2315 2316 2317
#else  /* VBOX_API_VERSION >= 4000 */
                systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType, &netAdpCnt);
#endif /* VBOX_API_VERSION >= 4000 */
2318 2319 2320 2321 2322 2323 2324 2325 2326
                systemProperties->vtbl->GetSerialPortCount(systemProperties, &serialPortCount);
                systemProperties->vtbl->GetParallelPortCount(systemProperties, &parallelPortCount);
                VBOX_RELEASE(systemProperties);
                systemProperties = NULL;
            }
            /* Currently setting memory and maxMemory as same, cause
             * the notation here seems to be inconsistent while
             * reading and while dumping xml
             */
2327 2328
            /* def->mem.max_balloon = maxMemorySize * 1024; */
            def->mem.max_balloon = memorySize * 1024;
2329 2330

            machine->vtbl->GetCPUCount(machine, &CPUCount);
E
Eric Blake 已提交
2331
            def->maxvcpus = def->vcpus = CPUCount;
2332 2333 2334 2335

            /* Skip cpumasklen, cpumask, onReboot, onPoweroff, onCrash */

            def->os.type = strdup("hvm");
2336

2337
            def->os.arch = virArchFromHost();
2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360

            def->os.nBootDevs = 0;
            for (i = 0; (i < VIR_DOMAIN_BOOT_LAST) && (i < maxBootPosition); i++) {
                PRUint32 device = DeviceType_Null;

                machine->vtbl->GetBootOrder(machine, i+1, &device);

                if (device == DeviceType_Floppy) {
                    def->os.bootDevs[i] = VIR_DOMAIN_BOOT_FLOPPY;
                    def->os.nBootDevs++;
                } else if (device == DeviceType_DVD) {
                    def->os.bootDevs[i] = VIR_DOMAIN_BOOT_CDROM;
                    def->os.nBootDevs++;
                } else if (device == DeviceType_HardDisk) {
                    def->os.bootDevs[i] = VIR_DOMAIN_BOOT_DISK;
                    def->os.nBootDevs++;
                } else if (device == DeviceType_Network) {
                    def->os.bootDevs[i] = VIR_DOMAIN_BOOT_NET;
                    def->os.nBootDevs++;
                } else if (device == DeviceType_USB) {
                    /* Not supported by libvirt yet */
                } else if (device == DeviceType_SharedFolder) {
                    /* Not supported by libvirt yet */
M
Matthias Bolte 已提交
2361
                    /* Can VirtualBox really boot from a shared folder? */
2362
                }
2363
            }
2364

2365 2366 2367
            def->features = 0;
#if VBOX_API_VERSION < 3001
            machine->vtbl->GetPAEEnabled(machine, &PAEEnabled);
2368
#elif VBOX_API_VERSION == 3001
2369
            machine->vtbl->GetCpuProperty(machine, CpuPropertyType_PAE, &PAEEnabled);
2370 2371 2372
#elif VBOX_API_VERSION >= 3002
            machine->vtbl->GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled);
#endif
2373 2374 2375
            if (PAEEnabled) {
                def->features = def->features | (1 << VIR_DOMAIN_FEATURE_PAE);
            }
2376

2377 2378 2379 2380 2381 2382
            machine->vtbl->GetBIOSSettings(machine, &bios);
            if (bios) {
                bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled);
                if (ACPIEnabled) {
                    def->features = def->features | (1 << VIR_DOMAIN_FEATURE_ACPI);
                }
2383

2384 2385 2386
                bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled);
                if (IOAPICEnabled) {
                    def->features = def->features | (1 << VIR_DOMAIN_FEATURE_APIC);
2387 2388
                }

2389 2390 2391 2392 2393
                VBOX_RELEASE(bios);
            }

            /* Currently VirtualBox always uses locatime
             * so locatime is always true here */
2394
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
2395 2396 2397 2398 2399 2400 2401 2402

            /* dump video options vram/2d/3d/directx/etc. */
            {
                /* Currently supports only one graphics card */
                def->nvideos = 1;
                if (VIR_ALLOC_N(def->videos, def->nvideos) >= 0) {
                    if (VIR_ALLOC(def->videos[0]) >= 0) {
                        /* the default is: vram is 8MB, One monitor, 3dAccel Off */
2403
                        PRUint32 VRAMSize          = 8;
2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415
                        PRUint32 monitorCount      = 1;
                        PRBool accelerate3DEnabled = PR_FALSE;
                        PRBool accelerate2DEnabled = PR_FALSE;

                        machine->vtbl->GetVRAMSize(machine, &VRAMSize);
                        machine->vtbl->GetMonitorCount(machine, &monitorCount);
                        machine->vtbl->GetAccelerate3DEnabled(machine, &accelerate3DEnabled);
#if VBOX_API_VERSION >= 3001
                        machine->vtbl->GetAccelerate2DVideoEnabled(machine, &accelerate2DEnabled);
#endif /* VBOX_API_VERSION >= 3001 */

                        def->videos[0]->type            = VIR_DOMAIN_VIDEO_TYPE_VBOX;
2416
                        def->videos[0]->vram            = VRAMSize * 1024;
2417 2418 2419 2420
                        def->videos[0]->heads           = monitorCount;
                        if (VIR_ALLOC(def->videos[0]->accel) >= 0) {
                            def->videos[0]->accel->support3d = accelerate3DEnabled;
                            def->videos[0]->accel->support2d = accelerate2DEnabled;
2421
                        } else
2422
                            virReportOOMError();
2423
                    } else
2424
                        virReportOOMError();
2425
                } else
2426
                    virReportOOMError();
2427
            }
2428

2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439
            /* dump display options vrdp/gui/sdl */
            {
                int vrdpPresent           = 0;
                int sdlPresent            = 0;
                int guiPresent            = 0;
                int totalPresent          = 0;
                char *guiDisplay          = NULL;
                char *sdlDisplay          = NULL;
                PRUnichar *keyTypeUtf16   = NULL;
                PRUnichar *valueTypeUtf16 = NULL;
                char      *valueTypeUtf8  = NULL;
2440

2441
                def->ngraphics = 0;
2442

2443 2444 2445
                VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
                machine->vtbl->GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16);
                VBOX_UTF16_FREE(keyTypeUtf16);
2446

2447 2448 2449
                if (valueTypeUtf16) {
                    VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
                    VBOX_UTF16_FREE(valueTypeUtf16);
2450

2451
                    if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
2452 2453 2454
                        PRUnichar *keyDislpayUtf16   = NULL;
                        PRUnichar *valueDisplayUtf16 = NULL;
                        char      *valueDisplayUtf8  = NULL;
2455

2456 2457 2458
                        VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
                        machine->vtbl->GetExtraData(machine, keyDislpayUtf16, &valueDisplayUtf16);
                        VBOX_UTF16_FREE(keyDislpayUtf16);
2459

2460 2461 2462
                        if (valueDisplayUtf16) {
                            VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
                            VBOX_UTF16_FREE(valueDisplayUtf16);
2463

J
John Ferlan 已提交
2464
                            if (strlen(valueDisplayUtf8) <= 0)
2465
                                VBOX_UTF8_FREE(valueDisplayUtf8);
2466
                        }
2467

2468 2469 2470 2471 2472
                        if (STREQ(valueTypeUtf8, "sdl")) {
                            sdlPresent = 1;
                            if (valueDisplayUtf8)
                                sdlDisplay = strdup(valueDisplayUtf8);
                            if (sdlDisplay == NULL) {
2473
                                virReportOOMError();
2474 2475 2476 2477 2478 2479
                                /* just don't go to cleanup yet as it is ok to have
                                 * sdlDisplay as NULL and we check it below if it
                                 * exist and then only use it there
                                 */
                            }
                            totalPresent++;
2480
                        }
2481

2482 2483 2484 2485 2486
                        if (STREQ(valueTypeUtf8, "gui")) {
                            guiPresent = 1;
                            if (valueDisplayUtf8)
                                guiDisplay = strdup(valueDisplayUtf8);
                            if (guiDisplay == NULL) {
2487
                                virReportOOMError();
2488
                                /* just don't go to cleanup yet as it is ok to have
2489 2490
                                 * guiDisplay as NULL and we check it below if it
                                 * exist and then only use it there
2491
                                 */
2492
                            }
2493 2494
                            totalPresent++;
                        }
J
John Ferlan 已提交
2495
                        VBOX_UTF8_FREE(valueDisplayUtf8);
2496 2497
                    }

2498 2499
                    if (STREQ(valueTypeUtf8, "vrdp"))
                        vrdpPresent = 1;
2500

2501 2502
                    VBOX_UTF8_FREE(valueTypeUtf8);
                }
2503

2504 2505 2506 2507 2508 2509 2510
                if ((totalPresent > 0) && (VIR_ALLOC_N(def->graphics, totalPresent) >= 0)) {
                    if ((guiPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
                        if (guiDisplay)
                            def->graphics[def->ngraphics]->data.desktop.display = guiDisplay;
                        def->ngraphics++;
                    }
2511

2512 2513 2514 2515 2516 2517 2518 2519 2520
                    if ((sdlPresent) && (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_SDL;
                        if (sdlDisplay)
                            def->graphics[def->ngraphics]->data.sdl.display = sdlDisplay;
                        def->ngraphics++;
                    }
                } else if ((vrdpPresent != 1) && (totalPresent == 0) && (VIR_ALLOC_N(def->graphics, 1) >= 0)) {
                    if (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0) {
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
2521 2522 2523 2524 2525 2526 2527 2528 2529
                        tmp = getenv("DISPLAY");
                        if (tmp != NULL) {
                            def->graphics[def->ngraphics]->data.desktop.display = strdup(tmp);
                            if (def->graphics[def->ngraphics]->data.desktop.display == NULL) {
                                virReportOOMError();
                                /* just don't go to cleanup yet as it is ok to have
                                 * display as NULL
                                 */
                            }
2530 2531 2532 2533 2534
                        }
                        totalPresent++;
                        def->ngraphics++;
                    }
                }
2535

2536 2537 2538 2539 2540 2541 2542 2543
#if VBOX_API_VERSION < 4000
                machine->vtbl->GetVRDPServer(machine, &VRDxServer);
#else  /* VBOX_API_VERSION >= 4000 */
                machine->vtbl->GetVRDEServer(machine, &VRDxServer);
#endif /* VBOX_API_VERSION >= 4000 */
                if (VRDxServer) {
                    VRDxServer->vtbl->GetEnabled(VRDxServer, &VRDxEnabled);
                    if (VRDxEnabled) {
2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554

                        totalPresent++;

                        if ((VIR_REALLOC_N(def->graphics, totalPresent) >= 0) &&
                            (VIR_ALLOC(def->graphics[def->ngraphics]) >= 0)) {
                            PRUnichar *netAddressUtf16   = NULL;
                            char      *netAddressUtf8    = NULL;
                            PRBool allowMultiConnection  = PR_FALSE;
                            PRBool reuseSingleConnection = PR_FALSE;
#if VBOX_API_VERSION < 3001
                            PRUint32 VRDPport = 0;
2555
                            VRDxServer->vtbl->GetPort(VRDxServer, &VRDPport);
2556 2557
                            if (VRDPport) {
                                def->graphics[def->ngraphics]->data.rdp.port = VRDPport;
2558
#elif VBOX_API_VERSION < 4000 /* 3001 <= VBOX_API_VERSION < 4000 */
2559
                            PRUnichar *VRDPport = NULL;
2560
                            VRDxServer->vtbl->GetPorts(VRDxServer, &VRDPport);
2561 2562 2563 2564
                            if (VRDPport) {
                                /* even if vbox supports mutilpe ports, single port for now here */
                                def->graphics[def->ngraphics]->data.rdp.port = PRUnicharToInt(VRDPport);
                                VBOX_UTF16_FREE(VRDPport);
2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575
#else /* VBOX_API_VERSION >= 4000 */
                            PRUnichar *VRDEPortsKey = NULL;
                            PRUnichar *VRDEPortsValue = NULL;
                            VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey);
                            VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDEPortsKey, &VRDEPortsValue);
                            VBOX_UTF16_FREE(VRDEPortsKey);
                            if (VRDEPortsValue) {
                                /* even if vbox supports mutilpe ports, single port for now here */
                                def->graphics[def->ngraphics]->data.rdp.port = PRUnicharToInt(VRDEPortsValue);
                                VBOX_UTF16_FREE(VRDEPortsValue);
#endif /* VBOX_API_VERSION >= 4000 */
2576
                            } else {
2577
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
2578
                            }
2579

2580
                            def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;
2581

2582 2583 2584 2585 2586 2587 2588 2589
#if VBOX_API_VERSION >= 4000
                            PRUnichar *VRDENetAddressKey = NULL;
                            VBOX_UTF8_TO_UTF16("TCP/Address", &VRDENetAddressKey);
                            VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDENetAddressKey, &netAddressUtf16);
                            VBOX_UTF16_FREE(VRDENetAddressKey);
#else /* VBOX_API_VERSION < 4000 */
                            VRDxServer->vtbl->GetNetAddress(VRDxServer, &netAddressUtf16);
#endif /* VBOX_API_VERSION < 4000 */
2590 2591 2592
                            if (netAddressUtf16) {
                                VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8);
                                if (STRNEQ(netAddressUtf8, ""))
2593 2594
                                    virDomainGraphicsListenSetAddress(def->graphics[def->ngraphics], 0,
                                                                      netAddressUtf8, -1, true);
2595 2596 2597
                                VBOX_UTF16_FREE(netAddressUtf16);
                                VBOX_UTF8_FREE(netAddressUtf8);
                            }
2598

2599
                            VRDxServer->vtbl->GetAllowMultiConnection(VRDxServer, &allowMultiConnection);
2600
                            if (allowMultiConnection) {
2601
                                def->graphics[def->ngraphics]->data.rdp.multiUser = true;
2602
                            }
2603

2604
                            VRDxServer->vtbl->GetReuseSingleConnection(VRDxServer, &reuseSingleConnection);
2605
                            if (reuseSingleConnection) {
2606
                                def->graphics[def->ngraphics]->data.rdp.replaceUser = true;
2607
                            }
2608

2609
                            def->ngraphics++;
2610
                        } else
2611
                            virReportOOMError();
2612
                    }
2613
                    VBOX_RELEASE(VRDxServer);
2614
                }
2615
            }
2616

2617 2618 2619
#if VBOX_API_VERSION < 3001
            /* dump IDE hdds if present */
            VBOX_UTF8_TO_UTF16(hddBus, &hddBusUtf16);
2620

2621 2622 2623 2624
            def->ndisks = 0;
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 0,  &hardDiskPM);
            if (hardDiskPM)
                def->ndisks++;
2625

2626 2627 2628
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 1,  &hardDiskPS);
            if (hardDiskPS)
                def->ndisks++;
2629

2630 2631 2632
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 1, 1,  &hardDiskSS);
            if (hardDiskSS)
                def->ndisks++;
2633

2634 2635 2636 2637 2638 2639 2640 2641 2642
            VBOX_UTF16_FREE(hddBusUtf16);

            if ((def->ndisks > 0) && (VIR_ALLOC_N(def->disks, def->ndisks) >= 0)) {
                for (i = 0; i < def->ndisks; i++) {
                    if (VIR_ALLOC(def->disks[i]) >= 0) {
                        def->disks[i]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
                        def->disks[i]->bus = VIR_DOMAIN_DISK_BUS_IDE;
                        def->disks[i]->type = VIR_DOMAIN_DISK_TYPE_FILE;
                    } else
2643
                        virReportOOMError();
2644
                }
2645
            }
2646

2647 2648 2649 2650
            if (hardDiskPM) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2651

2652 2653
                hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2654

2655
                hardDiskPM->vtbl->GetType(hardDiskPM, &hddType);
2656

2657
                if (hddType == HardDiskType_Immutable)
2658
                    def->disks[hddNum]->readonly = true;
2659 2660 2661
                def->disks[hddNum]->src = strdup(hddlocation);
                def->disks[hddNum]->dst = strdup("hda");
                hddNum++;
2662

2663 2664 2665 2666
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPM);
            }
2667

2668 2669 2670 2671
            if (hardDiskPS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2672

2673 2674
                hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2675

2676
                hardDiskPS->vtbl->GetType(hardDiskPS, &hddType);
2677

2678
                if (hddType == HardDiskType_Immutable)
2679
                    def->disks[hddNum]->readonly = true;
2680 2681 2682
                def->disks[hddNum]->src = strdup(hddlocation);
                def->disks[hddNum]->dst = strdup("hdb");
                hddNum++;
2683

2684 2685 2686 2687
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPS);
            }
2688

2689 2690 2691 2692
            if (hardDiskSS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2693

2694 2695
                hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2696

2697
                hardDiskSS->vtbl->GetType(hardDiskSS, &hddType);
2698

2699
                if (hddType == HardDiskType_Immutable)
2700
                    def->disks[hddNum]->readonly = true;
2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716
                def->disks[hddNum]->src = strdup(hddlocation);
                def->disks[hddNum]->dst = strdup("hdd");
                hddNum++;

                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskSS);
            }
#else  /* VBOX_API_VERSION >= 3001 */
            /* dump IDE hdds if present */

            bool error = false;
            int diskCount = 0;
            PRUint32   maxPortPerInst[StorageBus_Floppy + 1] = {};
            PRUint32   maxSlotPerPort[StorageBus_Floppy + 1] = {};
            def->ndisks = 0;
2717
            vboxArrayGet(&mediumAttachments, machine, machine->vtbl->GetMediumAttachments);
2718 2719

            /* get the number of attachments */
2720 2721
            for (i = 0; i < mediumAttachments.count; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2722 2723 2724 2725 2726 2727 2728
                if (imediumattach) {
                    IMedium *medium = NULL;

                    imediumattach->vtbl->GetMedium(imediumattach, &medium);
                    if (medium) {
                        def->ndisks++;
                        VBOX_RELEASE(medium);
2729 2730
                    }
                }
2731
            }
2732

2733 2734 2735 2736
            /* Allocate mem, if fails return error */
            if (VIR_ALLOC_N(def->disks, def->ndisks) >= 0) {
                for (i = 0; i < def->ndisks; i++) {
                    if (VIR_ALLOC(def->disks[i]) < 0) {
2737
                        virReportOOMError();
2738 2739
                        error = true;
                        break;
2740 2741
                    }
                }
2742
            } else {
2743
                virReportOOMError();
2744 2745 2746 2747 2748 2749 2750
                error = true;
            }

            if (!error)
                error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst, maxSlotPerPort);

            /* get the attachment details here */
2751 2752
            for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785
                IStorageController *storageController = NULL;
                PRUnichar *storageControllerName = NULL;
                PRUint32   deviceType     = DeviceType_Null;
                PRUint32   storageBus     = StorageBus_Null;
                PRBool     readOnly       = PR_FALSE;
                IMedium   *medium         = NULL;
                PRUnichar *mediumLocUtf16 = NULL;
                char      *mediumLocUtf8  = NULL;
                PRUint32   deviceInst     = 0;
                PRInt32    devicePort     = 0;
                PRInt32    deviceSlot     = 0;

                if (!imediumattach)
                    continue;

                imediumattach->vtbl->GetMedium(imediumattach, &medium);
                if (!medium)
                    continue;

                imediumattach->vtbl->GetController(imediumattach, &storageControllerName);
                if (!storageControllerName) {
                    VBOX_RELEASE(medium);
                    continue;
                }

                machine->vtbl->GetStorageControllerByName(machine,
                                                          storageControllerName,
                                                          &storageController);
                VBOX_UTF16_FREE(storageControllerName);
                if (!storageController) {
                    VBOX_RELEASE(medium);
                    continue;
                }
2786

2787 2788 2789 2790 2791 2792 2793 2794 2795
                medium->vtbl->GetLocation(medium, &mediumLocUtf16);
                VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
                VBOX_UTF16_FREE(mediumLocUtf16);
                def->disks[diskCount]->src = strdup(mediumLocUtf8);
                VBOX_UTF8_FREE(mediumLocUtf8);

                if (!(def->disks[diskCount]->src)) {
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
2796
                    virReportOOMError();
2797 2798 2799
                    error = true;
                    break;
                }
2800

2801 2802 2803 2804 2805 2806 2807 2808 2809 2810
                storageController->vtbl->GetBus(storageController, &storageBus);
                if (storageBus == StorageBus_IDE) {
                    def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_IDE;
                } else if (storageBus == StorageBus_SATA) {
                    def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SATA;
                } else if (storageBus == StorageBus_SCSI) {
                    def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_SCSI;
                } else if (storageBus == StorageBus_Floppy) {
                    def->disks[diskCount]->bus = VIR_DOMAIN_DISK_BUS_FDC;
                }
2811

2812 2813 2814 2815 2816 2817 2818 2819 2820 2821
                imediumattach->vtbl->GetType(imediumattach, &deviceType);
                if (deviceType == DeviceType_HardDisk)
                    def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_DISK;
                else if (deviceType == DeviceType_Floppy)
                    def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                else if (deviceType == DeviceType_DVD)
                    def->disks[diskCount]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;

                imediumattach->vtbl->GetPort(imediumattach, &devicePort);
                imediumattach->vtbl->GetDevice(imediumattach, &deviceSlot);
2822
                def->disks[diskCount]->dst = vboxGenerateMediumName(storageBus,
2823 2824 2825 2826 2827 2828
                                                                    deviceInst,
                                                                    devicePort,
                                                                    deviceSlot,
                                                                    maxPortPerInst,
                                                                    maxSlotPerPort);
                if (!def->disks[diskCount]->dst) {
2829 2830 2831 2832
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Could not generate medium name for the disk "
                                     "at: controller instance:%u, port:%d, slot:%d"),
                                   deviceInst, devicePort, deviceSlot);
2833 2834 2835 2836 2837
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2838

2839 2840
                medium->vtbl->GetReadOnly(medium, &readOnly);
                if (readOnly == PR_TRUE)
2841
                    def->disks[diskCount]->readonly = true;
2842

2843
                def->disks[diskCount]->type = VIR_DOMAIN_DISK_TYPE_FILE;
2844

2845 2846 2847 2848
                VBOX_RELEASE(medium);
                VBOX_RELEASE(storageController);
                diskCount++;
            }
2849

2850
            vboxArrayRelease(&mediumAttachments);
2851

2852 2853 2854 2855 2856 2857 2858 2859
            /* cleanup on error */
            if (error) {
                for (i = 0; i < def->ndisks; i++) {
                    VIR_FREE(def->disks[i]);
                }
                VIR_FREE(def->disks);
                def->ndisks = 0;
            }
2860

2861
#endif /* VBOX_API_VERSION >= 3001 */
2862

M
Matthias Bolte 已提交
2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923
            /* shared folders */
            vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER;

            def->nfss = 0;

            vboxArrayGet(&sharedFolders, machine,
                         machine->vtbl->GetSharedFolders);

            if (sharedFolders.count > 0) {
                if (VIR_ALLOC_N(def->fss, sharedFolders.count) < 0) {
                    virReportOOMError();
                    goto sharedFoldersCleanup;
                }

                for (i = 0; i < sharedFolders.count; i++) {
                    ISharedFolder *sharedFolder = sharedFolders.items[i];
                    PRUnichar *nameUtf16 = NULL;
                    char *name = NULL;
                    PRUnichar *hostPathUtf16 = NULL;
                    char *hostPath = NULL;
                    PRBool writable = PR_FALSE;

                    if (VIR_ALLOC(def->fss[i]) < 0) {
                        virReportOOMError();
                        goto sharedFoldersCleanup;
                    }

                    def->fss[i]->type = VIR_DOMAIN_FS_TYPE_MOUNT;

                    sharedFolder->vtbl->GetHostPath(sharedFolder, &hostPathUtf16);
                    VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath);
                    def->fss[i]->src = strdup(hostPath);
                    VBOX_UTF8_FREE(hostPath);
                    VBOX_UTF16_FREE(hostPathUtf16);

                    if (def->fss[i]->src == NULL) {
                        virReportOOMError();
                        goto sharedFoldersCleanup;
                    }

                    sharedFolder->vtbl->GetName(sharedFolder, &nameUtf16);
                    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
                    def->fss[i]->dst = strdup(name);
                    VBOX_UTF8_FREE(name);
                    VBOX_UTF16_FREE(nameUtf16);

                    if (def->fss[i]->dst == NULL) {
                        virReportOOMError();
                        goto sharedFoldersCleanup;
                    }

                    sharedFolder->vtbl->GetWritable(sharedFolder, &writable);
                    def->fss[i]->readonly = !writable;

                    ++def->nfss;
                }
            }

sharedFoldersCleanup:
            vboxArrayRelease(&sharedFolders);

2924 2925 2926 2927 2928
            /* dump network cards if present */
            def->nnets = 0;
            /* Get which network cards are enabled */
            for (i = 0; i < netAdpCnt; i++) {
                INetworkAdapter *adapter = NULL;
2929

2930 2931 2932
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
2933

2934 2935 2936 2937
                    adapter->vtbl->GetEnabled(adapter, &enabled);
                    if (enabled) {
                        def->nnets++;
                    }
2938

2939 2940 2941
                    VBOX_RELEASE(adapter);
                }
            }
2942

2943 2944 2945 2946 2947
            /* Allocate memory for the networkcards which are enabled */
            if ((def->nnets > 0) && (VIR_ALLOC_N(def->nets, def->nnets) >= 0)) {
                for (i = 0; i < def->nnets; i++) {
                    if (VIR_ALLOC(def->nets[i]) >= 0) {
                    } else
2948
                        virReportOOMError();
2949 2950
                }
            }
2951

2952 2953 2954
            /* Now get the details about the network cards here */
            for (i = 0;(netAdpIncCnt < def->nnets) && (i < netAdpCnt); i++) {
                INetworkAdapter *adapter = NULL;
2955

2956 2957 2958
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
2959

2960 2961 2962 2963 2964 2965 2966
                    adapter->vtbl->GetEnabled(adapter, &enabled);
                    if (enabled) {
                        PRUint32 attachmentType    = NetworkAttachmentType_Null;
                        PRUint32 adapterType       = NetworkAdapterType_Null;
                        PRUnichar *MACAddressUtf16 = NULL;
                        char *MACAddress           = NULL;
                        char macaddr[VIR_MAC_STRING_BUFLEN] = {0};
2967

2968 2969
                        adapter->vtbl->GetAttachmentType(adapter, &attachmentType);
                        if (attachmentType == NetworkAttachmentType_NAT) {
2970

2971
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
2972

2973 2974 2975
                        } else if (attachmentType == NetworkAttachmentType_Bridged) {
                            PRUnichar *hostIntUtf16 = NULL;
                            char *hostInt           = NULL;
2976

2977
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
2978

2979
#if VBOX_API_VERSION < 4001
2980
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
2981 2982 2983
#else /* VBOX_API_VERSION >= 4001 */
                            adapter->vtbl->GetBridgedInterface(adapter, &hostIntUtf16);
#endif /* VBOX_API_VERSION >= 4001 */
2984

2985 2986
                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
                            def->nets[netAdpIncCnt]->data.bridge.brname = strdup(hostInt);
2987

2988 2989
                            VBOX_UTF8_FREE(hostInt);
                            VBOX_UTF16_FREE(hostIntUtf16);
2990

2991 2992 2993
                        } else if (attachmentType == NetworkAttachmentType_Internal) {
                            PRUnichar *intNetUtf16 = NULL;
                            char *intNet           = NULL;
2994

2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL;

                            adapter->vtbl->GetInternalNetwork(adapter, &intNetUtf16);

                            VBOX_UTF16_TO_UTF8(intNetUtf16, &intNet);
                            def->nets[netAdpIncCnt]->data.internal.name = strdup(intNet);

                            VBOX_UTF8_FREE(intNet);
                            VBOX_UTF16_FREE(intNetUtf16);

                        } else if (attachmentType == NetworkAttachmentType_HostOnly) {
                            PRUnichar *hostIntUtf16 = NULL;
                            char *hostInt           = NULL;

                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_NETWORK;

3011
#if VBOX_API_VERSION < 4001
3012
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
3013 3014 3015
#else /* VBOX_API_VERSION >= 4001 */
                            adapter->vtbl->GetHostOnlyInterface(adapter, &hostIntUtf16);
#endif /* VBOX_API_VERSION >= 4001 */
3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044

                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
                            def->nets[netAdpIncCnt]->data.network.name = strdup(hostInt);

                            VBOX_UTF8_FREE(hostInt);
                            VBOX_UTF16_FREE(hostIntUtf16);

                        } else {
                            /* default to user type i.e. NAT in VirtualBox if this
                             * dump is ever used to create a machine.
                             */
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
                        }

                        adapter->vtbl->GetAdapterType(adapter, &adapterType);
                        if (adapterType == NetworkAdapterType_Am79C970A) {
                            def->nets[netAdpIncCnt]->model = strdup("Am79C970A");
                        } else if (adapterType == NetworkAdapterType_Am79C973) {
                            def->nets[netAdpIncCnt]->model = strdup("Am79C973");
                        } else if (adapterType == NetworkAdapterType_I82540EM) {
                            def->nets[netAdpIncCnt]->model = strdup("82540EM");
                        } else if (adapterType == NetworkAdapterType_I82545EM) {
                            def->nets[netAdpIncCnt]->model = strdup("82545EM");
                        } else if (adapterType == NetworkAdapterType_I82543GC) {
                            def->nets[netAdpIncCnt]->model = strdup("82543GC");
#if VBOX_API_VERSION >= 3001
                        } else if (adapterType == NetworkAdapterType_Virtio) {
                            def->nets[netAdpIncCnt]->model = strdup("virtio");
#endif /* VBOX_API_VERSION >= 3001 */
3045 3046
                        }

3047 3048 3049 3050 3051 3052 3053 3054 3055
                        adapter->vtbl->GetMACAddress(adapter, &MACAddressUtf16);
                        VBOX_UTF16_TO_UTF8(MACAddressUtf16, &MACAddress);
                        snprintf(macaddr, VIR_MAC_STRING_BUFLEN,
                                 "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
                                 MACAddress[0], MACAddress[1], MACAddress[2], MACAddress[3],
                                 MACAddress[4], MACAddress[5], MACAddress[6], MACAddress[7],
                                 MACAddress[8], MACAddress[9], MACAddress[10], MACAddress[11]);

                        /* XXX some real error handling here some day ... */
3056
                        if (virMacAddrParse(macaddr, &def->nets[netAdpIncCnt]->mac) < 0)
3057 3058 3059 3060 3061 3062
                        {}

                        netAdpIncCnt++;

                        VBOX_UTF16_FREE(MACAddressUtf16);
                        VBOX_UTF8_FREE(MACAddress);
3063
                    }
3064 3065

                    VBOX_RELEASE(adapter);
3066
                }
3067
            }
3068

3069
            /* dump sound card if active */
3070

3071 3072 3073
            /* Set def->nsounds to one as VirtualBox currently supports
             * only one sound card
             */
3074

3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094
            machine->vtbl->GetAudioAdapter(machine, &audioAdapter);
            if (audioAdapter) {
                PRBool enabled = PR_FALSE;

                audioAdapter->vtbl->GetEnabled(audioAdapter, &enabled);
                if (enabled) {
                    PRUint32 audioController = AudioControllerType_AC97;

                    def->nsounds = 1;
                    if (VIR_ALLOC_N(def->sounds, def->nsounds) >= 0) {
                        if (VIR_ALLOC(def->sounds[0]) >= 0) {
                            audioAdapter->vtbl->GetAudioController(audioAdapter, &audioController);
                            if (audioController == AudioControllerType_SB16) {
                                def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_SB16;
                            } else if (audioController == AudioControllerType_AC97) {
                                def->sounds[0]->model = VIR_DOMAIN_SOUND_MODEL_AC97;
                            }
                        } else {
                            VIR_FREE(def->sounds);
                            def->nsounds = 0;
3095
                            virReportOOMError();
3096 3097 3098
                        }
                    } else {
                        def->nsounds = 0;
3099
                        virReportOOMError();
3100 3101 3102 3103
                    }
                }
                VBOX_RELEASE(audioAdapter);
            }
3104

3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128
#if VBOX_API_VERSION < 3001
            /* dump CDROM/DVD if the drive is attached and has DVD/CD in it */
            machine->vtbl->GetDVDDrive(machine, &dvdDrive);
            if (dvdDrive) {
                PRUint32 state = DriveState_Null;

                dvdDrive->vtbl->GetState(dvdDrive, &state);
                if (state == DriveState_ImageMounted) {
                    IDVDImage *dvdImage = NULL;

                    dvdDrive->vtbl->GetImage(dvdDrive, &dvdImage);
                    if (dvdImage) {
                        PRUnichar *locationUtf16 = NULL;
                        char *location           = NULL;

                        dvdImage->vtbl->imedium.GetLocation((IMedium *)dvdImage, &locationUtf16);
                        VBOX_UTF16_TO_UTF8(locationUtf16, &location);

                        def->ndisks++;
                        if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
                            if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
                                def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
                                def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_IDE;
                                def->disks[def->ndisks - 1]->type = VIR_DOMAIN_DISK_TYPE_FILE;
3129
                                def->disks[def->ndisks - 1]->readonly = true;
3130 3131
                                def->disks[def->ndisks - 1]->src = strdup(location);
                                def->disks[def->ndisks - 1]->dst = strdup("hdc");
3132
                            } else {
3133
                                def->ndisks--;
3134
                                virReportOOMError();
3135 3136
                            }
                        } else {
3137
                            def->ndisks--;
3138
                            virReportOOMError();
3139
                        }
3140 3141 3142 3143

                        VBOX_UTF8_FREE(location);
                        VBOX_UTF16_FREE(locationUtf16);
                        VBOX_MEDIUM_RELEASE(dvdImage);
3144 3145
                    }
                }
3146 3147
                VBOX_RELEASE(dvdDrive);
            }
3148

3149 3150 3151 3152 3153 3154 3155
            /* dump Floppy if the drive is attached and has floppy in it */
            machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
            if (floppyDrive) {
                PRBool enabled = PR_FALSE;

                floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled);
                if (enabled) {
3156 3157
                    PRUint32 state = DriveState_Null;

3158
                    floppyDrive->vtbl->GetState(floppyDrive, &state);
3159
                    if (state == DriveState_ImageMounted) {
3160
                        IFloppyImage *floppyImage = NULL;
3161

3162 3163
                        floppyDrive->vtbl->GetImage(floppyDrive, &floppyImage);
                        if (floppyImage) {
3164 3165 3166
                            PRUnichar *locationUtf16 = NULL;
                            char *location           = NULL;

3167 3168
                            floppyImage->vtbl->imedium.GetLocation((IMedium *)floppyImage, &locationUtf16);
                            VBOX_UTF16_TO_UTF8(locationUtf16, &location);
3169 3170 3171 3172

                            def->ndisks++;
                            if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
                                if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
3173 3174
                                    def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                                    def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC;
3175
                                    def->disks[def->ndisks - 1]->type = VIR_DOMAIN_DISK_TYPE_FILE;
3176
                                    def->disks[def->ndisks - 1]->readonly = false;
3177
                                    def->disks[def->ndisks - 1]->src = strdup(location);
3178
                                    def->disks[def->ndisks - 1]->dst = strdup("fda");
3179 3180
                                } else {
                                    def->ndisks--;
3181
                                    virReportOOMError();
3182 3183 3184
                                }
                            } else {
                                def->ndisks--;
3185
                                virReportOOMError();
3186 3187
                            }

3188 3189 3190
                            VBOX_UTF8_FREE(location);
                            VBOX_UTF16_FREE(locationUtf16);
                            VBOX_MEDIUM_RELEASE(floppyImage);
3191 3192 3193 3194
                        }
                    }
                }

3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207
                VBOX_RELEASE(floppyDrive);
            }
#else  /* VBOX_API_VERSION >= 3001 */
#endif /* VBOX_API_VERSION >= 3001 */

            /* dump serial port if active */
            def->nserials = 0;
            /* Get which serial ports are enabled/active */
            for (i = 0; i < serialPortCount; i++) {
                ISerialPort *serialPort = NULL;

                machine->vtbl->GetSerialPort(machine, i, &serialPort);
                if (serialPort) {
3208 3209
                    PRBool enabled = PR_FALSE;

3210
                    serialPort->vtbl->GetEnabled(serialPort, &enabled);
3211
                    if (enabled) {
3212
                        def->nserials++;
3213 3214
                    }

3215
                    VBOX_RELEASE(serialPort);
3216
                }
3217
            }
3218

3219 3220 3221 3222 3223
            /* Allocate memory for the serial ports which are enabled */
            if ((def->nserials > 0) && (VIR_ALLOC_N(def->serials, def->nserials) >= 0)) {
                for (i = 0; i < def->nserials; i++) {
                    if (VIR_ALLOC(def->serials[i]) >= 0) {
                    } else
3224
                        virReportOOMError();
3225 3226
                }
            }
3227

3228 3229 3230
            /* Now get the details about the serial ports here */
            for (i = 0;(serialPortIncCount < def->nserials) && (i < serialPortCount); i++) {
                ISerialPort *serialPort = NULL;
3231

3232 3233 3234
                machine->vtbl->GetSerialPort(machine, i, &serialPort);
                if (serialPort) {
                    PRBool enabled = PR_FALSE;
3235

3236 3237 3238 3239 3240 3241 3242 3243 3244 3245
                    serialPort->vtbl->GetEnabled(serialPort, &enabled);
                    if (enabled) {
                        PRUint32 hostMode    = PortMode_Disconnected;
                        PRUint32 IOBase      = 0;
                        PRUint32 IRQ         = 0;
                        PRUnichar *pathUtf16 = NULL;
                        char *path           = NULL;

                        serialPort->vtbl->GetHostMode(serialPort, &hostMode);
                        if (hostMode == PortMode_HostPipe) {
3246
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
3247
                        } else if (hostMode == PortMode_HostDevice) {
3248
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
3249 3250
#if VBOX_API_VERSION >= 3000
                        } else if (hostMode == PortMode_RawFile) {
3251
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3252 3253
#endif /* VBOX_API_VERSION >= 3000 */
                        } else {
3254
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_NULL;
3255
                        }
3256

3257
                        def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
3258

3259 3260 3261 3262 3263 3264 3265
                        serialPort->vtbl->GetIRQ(serialPort, &IRQ);
                        serialPort->vtbl->GetIOBase(serialPort, &IOBase);
                        if ((IRQ == 4) && (IOBase == 1016)) {
                            def->serials[serialPortIncCount]->target.port = 0;
                        } else if ((IRQ == 3) && (IOBase == 760)) {
                            def->serials[serialPortIncCount]->target.port = 1;
                        }
3266

3267
                        serialPort->vtbl->GetPath(serialPort, &pathUtf16);
3268

3269 3270
                        if (pathUtf16) {
                            VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3271
                            def->serials[serialPortIncCount]->source.data.file.path = strdup(path);
3272 3273
                        }

3274 3275 3276 3277
                        serialPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
3278 3279
                    }

3280 3281 3282
                    VBOX_RELEASE(serialPort);
                }
            }
3283

3284 3285 3286 3287 3288
            /* dump parallel ports if active */
            def->nparallels = 0;
            /* Get which parallel ports are enabled/active */
            for (i = 0; i < parallelPortCount; i++) {
                IParallelPort *parallelPort = NULL;
3289

3290 3291 3292
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
3293

3294 3295 3296
                    parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                    if (enabled) {
                        def->nparallels++;
3297
                    }
3298 3299

                    VBOX_RELEASE(parallelPort);
3300
                }
3301
            }
3302

3303 3304 3305 3306 3307
            /* Allocate memory for the parallel ports which are enabled */
            if ((def->nparallels > 0) && (VIR_ALLOC_N(def->parallels, def->nparallels) >= 0)) {
                for (i = 0; i < def->nparallels; i++) {
                    if (VIR_ALLOC(def->parallels[i]) >= 0) {
                    } else
3308
                        virReportOOMError();
3309
                }
3310
            }
3311

3312 3313 3314
            /* Now get the details about the parallel ports here */
            for (i = 0;(parallelPortIncCount < def->nparallels) && (i < parallelPortCount); i++) {
                IParallelPort *parallelPort = NULL;
3315

3316 3317 3318
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
3319

3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333
                    parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                    if (enabled) {
                        PRUint32 IOBase      = 0;
                        PRUint32 IRQ         = 0;
                        PRUnichar *pathUtf16 = NULL;
                        char *path           = NULL;

                        parallelPort->vtbl->GetIRQ(parallelPort, &IRQ);
                        parallelPort->vtbl->GetIOBase(parallelPort, &IOBase);
                        if ((IRQ == 7) && (IOBase == 888)) {
                            def->parallels[parallelPortIncCount]->target.port = 0;
                        } else if ((IRQ == 5) && (IOBase == 632)) {
                            def->parallels[parallelPortIncCount]->target.port = 1;
                        }
3334

3335
                        def->parallels[parallelPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3336
                        def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
3337

3338
                        parallelPort->vtbl->GetPath(parallelPort, &pathUtf16);
3339

3340
                        VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3341
                        def->parallels[parallelPortIncCount]->source.data.file.path = strdup(path);
3342

3343 3344 3345 3346
                        parallelPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
3347
                    }
3348 3349

                    VBOX_RELEASE(parallelPort);
3350
                }
3351
            }
3352

3353 3354 3355 3356 3357
            /* dump USB devices/filters if active */
            def->nhostdevs = 0;
            machine->vtbl->GetUSBController(machine, &USBController);
            if (USBController) {
                PRBool enabled = PR_FALSE;
3358

3359 3360
                USBController->vtbl->GetEnabled(USBController, &enabled);
                if (enabled) {
3361
                    vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER;
3362

3363 3364
                    vboxArrayGet(&deviceFilters, USBController,
                                 USBController->vtbl->GetDeviceFilters);
3365

3366
                    if (deviceFilters.count > 0) {
3367

3368 3369 3370
                        /* check if the filters are active and then only
                         * alloc mem and set def->nhostdevs
                         */
3371

3372
                        for (i = 0; i < deviceFilters.count; i++) {
3373
                            PRBool active = PR_FALSE;
3374
                            IUSBDeviceFilter *deviceFilter = deviceFilters.items[i];
3375

3376
                            deviceFilter->vtbl->GetActive(deviceFilter, &active);
3377 3378
                            if (active) {
                                def->nhostdevs++;
3379
                            }
3380
                        }
3381

3382 3383 3384
                        if (def->nhostdevs > 0) {
                            /* Alloc mem needed for the filters now */
                            if (VIR_ALLOC_N(def->hostdevs, def->nhostdevs) >= 0) {
3385

3386
                                for (i = 0; (USBFilterCount < def->nhostdevs) || (i < deviceFilters.count); i++) {
3387
                                    PRBool active = PR_FALSE;
3388
                                    IUSBDeviceFilter *deviceFilter = deviceFilters.items[i];
3389

3390
                                    deviceFilter->vtbl->GetActive(deviceFilter, &active);
3391 3392 3393 3394 3395 3396 3397 3398 3399
                                    if (active) {
                                        if (VIR_ALLOC(def->hostdevs[USBFilterCount]) >= 0) {
                                            PRUnichar *vendorIdUtf16  = NULL;
                                            char *vendorIdUtf8        = NULL;
                                            unsigned vendorId         = 0;
                                            PRUnichar *productIdUtf16 = NULL;
                                            char *productIdUtf8       = NULL;
                                            unsigned productId        = 0;
                                            char *endptr              = NULL;
3400

3401 3402 3403 3404
                                            def->hostdevs[USBFilterCount]->mode =
                                                VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
                                            def->hostdevs[USBFilterCount]->source.subsys.type =
                                                VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;
3405

3406 3407
                                            deviceFilter->vtbl->GetVendorId(deviceFilter, &vendorIdUtf16);
                                            deviceFilter->vtbl->GetProductId(deviceFilter, &productIdUtf16);
3408

3409 3410
                                            VBOX_UTF16_TO_UTF8(vendorIdUtf16, &vendorIdUtf8);
                                            VBOX_UTF16_TO_UTF8(productIdUtf16, &productIdUtf8);
3411

3412 3413
                                            vendorId  = strtol(vendorIdUtf8, &endptr, 16);
                                            productId = strtol(productIdUtf8, &endptr, 16);
3414

3415 3416
                                            def->hostdevs[USBFilterCount]->source.subsys.u.usb.vendor  = vendorId;
                                            def->hostdevs[USBFilterCount]->source.subsys.u.usb.product = productId;
3417

3418 3419
                                            VBOX_UTF16_FREE(vendorIdUtf16);
                                            VBOX_UTF8_FREE(vendorIdUtf8);
3420

3421 3422
                                            VBOX_UTF16_FREE(productIdUtf16);
                                            VBOX_UTF8_FREE(productIdUtf8);
3423

3424 3425
                                            USBFilterCount++;
                                        } else
3426
                                            virReportOOMError();
3427
                                    }
3428 3429
                                }
                            } else
3430
                                virReportOOMError();
3431 3432 3433
                        }
                    }

3434
                    /* Cleanup */
3435
                    vboxArrayRelease(&deviceFilters);
3436 3437
                }
                VBOX_RELEASE(USBController);
3438
            }
3439 3440 3441 3442 3443

            /* all done so set gotAllABoutDef and pass def to virDomainDefFormat
             * to generate XML for it
             */
            gotAllABoutDef = 0;
3444
        }
3445 3446
        VBOX_RELEASE(machine);
        machine = NULL;
3447 3448 3449
    }

    if (gotAllABoutDef == 0)
3450
        ret = virDomainDefFormat(def, flags);
3451 3452

cleanup:
3453
    vboxIIDUnalloc(&iid);
3454 3455 3456 3457
    virDomainDefFree(def);
    return ret;
}

3458
static int vboxConnectListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) {
3459
    VBOX_OBJECT_CHECK(conn, int, -1);
3460
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3461 3462 3463
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    PRUint32 state;
3464
    nsresult rc;
3465 3466
    int i, j;

3467
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3468
    if (NS_FAILED(rc)) {
3469 3470 3471
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of Defined Domains, rc=%08x"),
                       (unsigned)rc);
3472 3473
        goto cleanup;
    }
3474

3475 3476 3477
    ret = 0;
    for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) {
        IMachine *machine = machines.items[i];
3478 3479 3480 3481 3482 3483

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3484 3485
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3486 3487
                    machine->vtbl->GetName(machine, &machineNameUtf16);
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
3488 3489 3490 3491
                    names[j] = strdup(machineName);
                    VBOX_UTF16_FREE(machineNameUtf16);
                    VBOX_UTF8_FREE(machineName);
                    if (!names[j]) {
3492
                        virReportOOMError();
3493
                        for (; j >= 0 ; j--)
3494 3495 3496
                            VIR_FREE(names[j]);
                        ret = -1;
                        goto cleanup;
3497
                    }
3498
                    j++;
3499
                    ret++;
3500 3501 3502 3503 3504 3505
                }
            }
        }
    }

cleanup:
3506
    vboxArrayRelease(&machines);
3507 3508 3509
    return ret;
}

3510
static int vboxConnectNumOfDefinedDomains(virConnectPtr conn) {
3511
    VBOX_OBJECT_CHECK(conn, int, -1);
3512
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3513
    PRUint32 state       = MachineState_Null;
3514
    nsresult rc;
3515 3516
    int i;

3517
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3518
    if (NS_FAILED(rc)) {
3519 3520 3521
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get number of Defined Domains, rc=%08x"),
                       (unsigned)rc);
3522 3523
        goto cleanup;
    }
3524

3525 3526 3527
    ret = 0;
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3528 3529 3530 3531 3532 3533

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3534 3535
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3536
                    ret++;
3537 3538 3539 3540 3541 3542
                }
            }
        }
    }

cleanup:
3543
    vboxArrayRelease(&machines);
3544 3545 3546
    return ret;
}

E
Eric Blake 已提交
3547 3548

static int
3549 3550
vboxStartMachine(virDomainPtr dom, int i, IMachine *machine,
                 vboxIID *iid ATTRIBUTE_UNUSED /* >= 4.0 */)
E
Eric Blake 已提交
3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    int vrdpPresent              = 0;
    int sdlPresent               = 0;
    int guiPresent               = 0;
    char *guiDisplay             = NULL;
    char *sdlDisplay             = NULL;
    PRUnichar *keyTypeUtf16      = NULL;
    PRUnichar *valueTypeUtf16    = NULL;
    char      *valueTypeUtf8     = NULL;
    PRUnichar *keyDislpayUtf16   = NULL;
    PRUnichar *valueDisplayUtf16 = NULL;
    char      *valueDisplayUtf8  = NULL;
    IProgress *progress          = NULL;
    PRUnichar *env               = NULL;
    PRUnichar *sessionType       = NULL;
    nsresult rc;

    VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
    machine->vtbl->GetExtraData(machine, keyTypeUtf16, &valueTypeUtf16);
    VBOX_UTF16_FREE(keyTypeUtf16);

    if (valueTypeUtf16) {
        VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
        VBOX_UTF16_FREE(valueTypeUtf16);

3577
        if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
E
Eric Blake 已提交
3578 3579 3580 3581 3582 3583 3584 3585 3586 3587

            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            machine->vtbl->GetExtraData(machine, keyDislpayUtf16,
                                        &valueDisplayUtf16);
            VBOX_UTF16_FREE(keyDislpayUtf16);

            if (valueDisplayUtf16) {
                VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
                VBOX_UTF16_FREE(valueDisplayUtf16);

J
John Ferlan 已提交
3588
                if (strlen(valueDisplayUtf8) <= 0)
E
Eric Blake 已提交
3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636
                    VBOX_UTF8_FREE(valueDisplayUtf8);
            }

            if (STREQ(valueTypeUtf8, "sdl")) {
                sdlPresent = 1;
                if (valueDisplayUtf8) {
                    sdlDisplay = strdup(valueDisplayUtf8);
                    if (sdlDisplay == NULL) {
                        virReportOOMError();
                        /* just don't go to cleanup yet as it is ok to have
                         * sdlDisplay as NULL and we check it below if it
                         * exist and then only use it there
                         */
                    }
                }
            }

            if (STREQ(valueTypeUtf8, "gui")) {
                guiPresent = 1;
                if (valueDisplayUtf8) {
                    guiDisplay = strdup(valueDisplayUtf8);
                    if (guiDisplay == NULL) {
                        virReportOOMError();
                        /* just don't go to cleanup yet as it is ok to have
                         * guiDisplay as NULL and we check it below if it
                         * exist and then only use it there
                         */
                    }
                }
            }
        }

        if (STREQ(valueTypeUtf8, "vrdp")) {
            vrdpPresent = 1;
        }

        if (!vrdpPresent && !sdlPresent && !guiPresent) {
            /* if nothing is selected it means either the machine xml
             * file is really old or some values are missing so fallback
             */
            guiPresent = 1;
        }

        VBOX_UTF8_FREE(valueTypeUtf8);

    } else {
        guiPresent = 1;
    }
J
John Ferlan 已提交
3637
    VBOX_UTF8_FREE(valueDisplayUtf8);
E
Eric Blake 已提交
3638 3639 3640

    if (guiPresent) {
        if (guiDisplay) {
E
Eric Blake 已提交
3641 3642 3643 3644 3645 3646 3647
            char *displayutf8;
            if (virAsprintf(&displayutf8, "DISPLAY=%s", guiDisplay) < 0)
                virReportOOMError();
            else {
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3648 3649 3650 3651 3652 3653 3654 3655
            VIR_FREE(guiDisplay);
        }

        VBOX_UTF8_TO_UTF16("gui", &sessionType);
    }

    if (sdlPresent) {
        if (sdlDisplay) {
E
Eric Blake 已提交
3656 3657 3658 3659 3660 3661 3662
            char *displayutf8;
            if (virAsprintf(&displayutf8, "DISPLAY=%s", sdlDisplay) < 0)
                virReportOOMError();
            else {
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3663 3664 3665 3666 3667 3668 3669 3670 3671 3672
            VIR_FREE(sdlDisplay);
        }

        VBOX_UTF8_TO_UTF16("sdl", &sessionType);
    }

    if (vrdpPresent) {
        VBOX_UTF8_TO_UTF16("vrdp", &sessionType);
    }

3673
#if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
3674 3675
    rc = data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj,
                                                data->vboxSession,
3676
                                                iid->value,
E
Eric Blake 已提交
3677 3678
                                                sessionType,
                                                env,
3679
                                                &progress);
3680 3681 3682 3683 3684
#else /* VBOX_API_VERSION >= 4000 */
    rc = machine->vtbl->LaunchVMProcess(machine, data->vboxSession,
                                        sessionType, env, &progress);
#endif /* VBOX_API_VERSION >= 4000 */

E
Eric Blake 已提交
3685
    if (NS_FAILED(rc)) {
3686 3687
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("OpenRemoteSession/LaunchVMProcess failed, domain can't be started"));
E
Eric Blake 已提交
3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714
        ret = -1;
    } else {
        PRBool completed = 0;
#if VBOX_API_VERSION == 2002
        nsresult resultCode;
#else
        PRInt32  resultCode;
#endif
        progress->vtbl->WaitForCompletion(progress, -1);
        rc = progress->vtbl->GetCompleted(progress, &completed);
        if (NS_FAILED(rc)) {
            /* error */
            ret = -1;
        }
        progress->vtbl->GetResultCode(progress, &resultCode);
        if (NS_FAILED(resultCode)) {
            /* error */
            ret = -1;
        } else {
            /* all ok set the domid */
            dom->id = i + 1;
            ret = 0;
        }
    }

    VBOX_RELEASE(progress);

3715
    VBOX_SESSION_CLOSE();
E
Eric Blake 已提交
3716 3717 3718 3719 3720 3721 3722

    VBOX_UTF16_FREE(env);
    VBOX_UTF16_FREE(sessionType);

    return ret;
}

3723
static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags) {
3724
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
3725
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3726
    unsigned char uuid[VIR_UUID_BUFLEN] = {0};
3727 3728
    nsresult rc;
    int i = 0;
3729

3730 3731
    virCheckFlags(0, -1);

3732
    if (!dom->name) {
3733 3734
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Error while reading the domain name"));
3735 3736 3737
        goto cleanup;
    }

3738
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3739
    if (NS_FAILED(rc)) {
3740 3741
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
3742 3743
        goto cleanup;
    }
3744

3745 3746
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3747
        PRBool isAccessible = PR_FALSE;
3748

3749 3750
        if (!machine)
            continue;
3751

3752 3753
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
3754
            vboxIID iid = VBOX_IID_INITIALIZER;
3755

3756 3757
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
3758
                continue;
3759
            vboxIIDToUUID(&iid, uuid);
3760

3761
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
3762 3763 3764
                PRUint32 state = MachineState_Null;
                machine->vtbl->GetState(machine, &state);

3765 3766 3767
                if ((state == MachineState_PoweredOff) ||
                    (state == MachineState_Saved) ||
                    (state == MachineState_Aborted)) {
3768
                    ret = vboxStartMachine(dom, i, machine, &iid);
3769
                } else {
3770
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3771 3772 3773
                                   _("machine is not in "
                                     "poweroff|saved|aborted state, so "
                                     "couldn't start it"));
3774
                    ret = -1;
3775 3776
                }
            }
3777
            vboxIIDUnalloc(&iid);
3778 3779
            if (ret != -1)
                break;
3780 3781 3782
        }
    }

3783
    /* Do the cleanup and take care you dont leak any memory */
3784
    vboxArrayRelease(&machines);
3785

3786 3787 3788 3789
cleanup:
    return ret;
}

3790 3791 3792 3793
static int vboxDomainCreate(virDomainPtr dom) {
    return vboxDomainCreateWithFlags(dom, 0);
}

E
Eric Blake 已提交
3794 3795 3796 3797 3798 3799 3800
static void
vboxSetBootDeviceOrder(virDomainDefPtr def, vboxGlobalData *data,
                       IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 maxBootPosition            = 0;
    int i = 0;
3801

3802
    VIR_DEBUG("def->os.type             %s", def->os.type);
3803
    VIR_DEBUG("def->os.arch             %s", virArchToString(def->os.arch));
3804
    VIR_DEBUG("def->os.machine          %s", def->os.machine);
3805
    VIR_DEBUG("def->os.nBootDevs        %zu", def->os.nBootDevs);
3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817
    VIR_DEBUG("def->os.bootDevs[0]      %d", def->os.bootDevs[0]);
    VIR_DEBUG("def->os.bootDevs[1]      %d", def->os.bootDevs[1]);
    VIR_DEBUG("def->os.bootDevs[2]      %d", def->os.bootDevs[2]);
    VIR_DEBUG("def->os.bootDevs[3]      %d", def->os.bootDevs[3]);
    VIR_DEBUG("def->os.init             %s", def->os.init);
    VIR_DEBUG("def->os.kernel           %s", def->os.kernel);
    VIR_DEBUG("def->os.initrd           %s", def->os.initrd);
    VIR_DEBUG("def->os.cmdline          %s", def->os.cmdline);
    VIR_DEBUG("def->os.root             %s", def->os.root);
    VIR_DEBUG("def->os.loader           %s", def->os.loader);
    VIR_DEBUG("def->os.bootloader       %s", def->os.bootloader);
    VIR_DEBUG("def->os.bootloaderArgs   %s", def->os.bootloaderArgs);
3818

E
Eric Blake 已提交
3819 3820 3821 3822 3823 3824
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxBootPosition(systemProperties,
                                                   &maxBootPosition);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
3825
    }
3826

E
Eric Blake 已提交
3827 3828 3829
    /* Clear the defaults first */
    for (i = 0; i < maxBootPosition; i++) {
        machine->vtbl->SetBootOrder(machine, i+1, DeviceType_Null);
3830
    }
3831

E
Eric Blake 已提交
3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842
    for (i = 0; (i < def->os.nBootDevs) && (i < maxBootPosition); i++) {
        PRUint32 device = DeviceType_Null;

        if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_FLOPPY) {
            device = DeviceType_Floppy;
        } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_CDROM) {
            device = DeviceType_DVD;
        } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_DISK) {
            device = DeviceType_HardDisk;
        } else if (def->os.bootDevs[i] == VIR_DOMAIN_BOOT_NET) {
            device = DeviceType_Network;
3843
        }
E
Eric Blake 已提交
3844
        machine->vtbl->SetBootOrder(machine, i+1, device);
3845
    }
E
Eric Blake 已提交
3846
}
3847

E
Eric Blake 已提交
3848 3849 3850 3851 3852
static void
vboxAttachDrives(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    int i;
    nsresult rc;
3853 3854

#if VBOX_API_VERSION < 3001
E
Eric Blake 已提交
3855 3856 3857 3858
    if (def->ndisks == 0)
        return;

    for (i = 0; i < def->ndisks; i++) {
3859 3860 3861 3862 3863 3864
        VIR_DEBUG("disk(%d) type:       %d", i, def->disks[i]->type);
        VIR_DEBUG("disk(%d) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%d) bus:        %d", i, def->disks[i]->bus);
        VIR_DEBUG("disk(%d) src:        %s", i, def->disks[i]->src);
        VIR_DEBUG("disk(%d) dst:        %s", i, def->disks[i]->dst);
        VIR_DEBUG("disk(%d) driverName: %s", i, def->disks[i]->driverName);
3865 3866
        VIR_DEBUG("disk(%d) driverType: %s", i,
                  virStorageFileFormatTypeToString(def->disks[i]->format));
3867 3868
        VIR_DEBUG("disk(%d) cachemode:  %d", i, def->disks[i]->cachemode);
        VIR_DEBUG("disk(%d) readonly:   %s", i, (def->disks[i]->readonly
E
Eric Blake 已提交
3869
                                             ? "True" : "False"));
3870
        VIR_DEBUG("disk(%d) shared:     %s", i, (def->disks[i]->shared
E
Eric Blake 已提交
3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882
                                             ? "True" : "False"));

        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
            if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                def->disks[i]->src != NULL) {
                IDVDDrive *dvdDrive = NULL;
                /* Currently CDROM/DVD Drive is always IDE
                 * Secondary Master so neglecting the following
                 * parameters:
                 *      def->disks[i]->bus
                 *      def->disks[i]->dst
                 */
3883

E
Eric Blake 已提交
3884 3885 3886 3887
                machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                if (dvdDrive) {
                    IDVDImage *dvdImage          = NULL;
                    PRUnichar *dvdfileUtf16      = NULL;
3888 3889
                    vboxIID dvduuid = VBOX_IID_INITIALIZER;
                    vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
3890

E
Eric Blake 已提交
3891
                    VBOX_UTF8_TO_UTF16(def->disks[i]->src, &dvdfileUtf16);
3892

E
Eric Blake 已提交
3893 3894 3895 3896 3897
                    data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                      dvdfileUtf16, &dvdImage);
                    if (!dvdImage) {
                        data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                          dvdfileUtf16,
3898
                                                          dvdemptyuuid.value,
E
Eric Blake 已提交
3899 3900 3901 3902
                                                          &dvdImage);
                    }
                    if (dvdImage) {
                        rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage,
3903
                                                           &dvduuid.value);
E
Eric Blake 已提交
3904
                        if (NS_FAILED(rc)) {
3905 3906 3907 3908
                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                           _("can't get the uuid of the file to "
                                             "be attached to cdrom: %s, rc=%08x"),
                                           def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
3909
                        } else {
3910
                            rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
E
Eric Blake 已提交
3911
                            if (NS_FAILED(rc)) {
3912 3913 3914
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("could not attach the file to cdrom: %s, rc=%08x"),
                                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
3915
                            } else {
3916
                                DEBUGIID("CD/DVDImage UUID:", dvduuid.value);
3917
                            }
3918
                        }
E
Eric Blake 已提交
3919 3920

                        VBOX_MEDIUM_RELEASE(dvdImage);
3921
                    }
3922
                    vboxIIDUnalloc(&dvduuid);
E
Eric Blake 已提交
3923 3924 3925 3926 3927 3928 3929 3930 3931 3932
                    VBOX_UTF16_FREE(dvdfileUtf16);
                    VBOX_RELEASE(dvdDrive);
                }
            } else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
            if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                def->disks[i]->src != NULL) {
                IHardDisk *hardDisk     = NULL;
                PRUnichar *hddfileUtf16 = NULL;
3933
                vboxIID hdduuid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
3934 3935 3936 3937 3938 3939
                PRUnichar *hddEmpty     = NULL;
                /* Current Limitation: Harddisk can't be connected to
                 * Secondary Master as Secondary Master is always used
                 * for CD/DVD Drive, so don't connect the harddisk if it
                 * is requested to be connected to Secondary master
                 */
3940

E
Eric Blake 已提交
3941 3942
                VBOX_UTF8_TO_UTF16(def->disks[i]->src, &hddfileUtf16);
                VBOX_UTF8_TO_UTF16("", &hddEmpty);
3943

E
Eric Blake 已提交
3944 3945
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16,
                                                  &hardDisk);
3946

E
Eric Blake 已提交
3947
                if (!hardDisk) {
3948
# if VBOX_API_VERSION == 2002
E
Eric Blake 已提交
3949 3950 3951 3952
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      &hardDisk);
3953
# else
E
Eric Blake 已提交
3954 3955 3956 3957 3958 3959 3960 3961
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      0,
                                                      hddEmpty,
                                                      0,
                                                      hddEmpty,
                                                      &hardDisk);
3962
# endif
E
Eric Blake 已提交
3963
                }
3964

E
Eric Blake 已提交
3965 3966
                if (hardDisk) {
                    rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk,
3967
                                                       &hdduuid.value);
E
Eric Blake 已提交
3968
                    if (NS_FAILED(rc)) {
3969 3970 3971 3972
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("can't get the uuid of the file to be "
                                         "attached as harddisk: %s, rc=%08x"),
                                       def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
3973 3974 3975 3976
                    } else {
                        if (def->disks[i]->readonly) {
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Immutable);
3977
                            VIR_DEBUG("setting harddisk to readonly");
E
Eric Blake 已提交
3978 3979 3980
                        } else if (!def->disks[i]->readonly) {
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Normal);
3981
                            VIR_DEBUG("setting harddisk type to normal");
E
Eric Blake 已提交
3982 3983 3984
                        }
                        if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
                            if (STREQ(def->disks[i]->dst, "hdc")) {
3985
                                VIR_DEBUG("Not connecting harddisk to hdc as hdc"
E
Eric Blake 已提交
3986
                                       " is taken by CD/DVD Drive");
3987
                            } else {
E
Eric Blake 已提交
3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004
                                PRInt32 channel          = 0;
                                PRInt32 device           = 0;
                                PRUnichar *hddcnameUtf16 = NULL;

                                char *hddcname = strdup("IDE");
                                VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16);
                                VIR_FREE(hddcname);

                                if (STREQ(def->disks[i]->dst, "hda")) {
                                    channel = 0;
                                    device  = 0;
                                } else if (STREQ(def->disks[i]->dst, "hdb")) {
                                    channel = 0;
                                    device  = 1;
                                } else if (STREQ(def->disks[i]->dst, "hdd")) {
                                    channel = 1;
                                    device  = 1;
4005
                                }
E
Eric Blake 已提交
4006 4007

                                rc = machine->vtbl->AttachHardDisk(machine,
4008
                                                                   hdduuid.value,
E
Eric Blake 已提交
4009 4010 4011 4012 4013 4014
                                                                   hddcnameUtf16,
                                                                   channel,
                                                                   device);
                                VBOX_UTF16_FREE(hddcnameUtf16);

                                if (NS_FAILED(rc)) {
4015 4016 4017 4018
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file as "
                                                     "harddisk: %s, rc=%08x"),
                                                   def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4019
                                } else {
4020
                                    DEBUGIID("Attached HDD with UUID", hdduuid.value);
4021 4022 4023
                                }
                            }
                        }
4024
                    }
E
Eric Blake 已提交
4025 4026
                    VBOX_MEDIUM_RELEASE(hardDisk);
                }
4027
                vboxIIDUnalloc(&hdduuid);
E
Eric Blake 已提交
4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041
                VBOX_UTF16_FREE(hddEmpty);
                VBOX_UTF16_FREE(hddfileUtf16);
            } else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
            if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                def->disks[i]->src != NULL) {
                IFloppyDrive *floppyDrive;
                machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                if (floppyDrive) {
                    rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1);
                    if (NS_SUCCEEDED(rc)) {
                        IFloppyImage *floppyImage   = NULL;
                        PRUnichar *fdfileUtf16      = NULL;
4042 4043
                        vboxIID fduuid = VBOX_IID_INITIALIZER;
                        vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
4044

E
Eric Blake 已提交
4045 4046 4047 4048
                        VBOX_UTF8_TO_UTF16(def->disks[i]->src, &fdfileUtf16);
                        rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                  fdfileUtf16,
                                                                  &floppyImage);
4049

E
Eric Blake 已提交
4050 4051 4052
                        if (!floppyImage) {
                            data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                 fdfileUtf16,
4053
                                                                 fdemptyuuid.value,
E
Eric Blake 已提交
4054 4055
                                                                 &floppyImage);
                        }
4056

E
Eric Blake 已提交
4057 4058
                        if (floppyImage) {
                            rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage,
4059
                                                                  &fduuid.value);
E
Eric Blake 已提交
4060
                            if (NS_FAILED(rc)) {
4061 4062 4063 4064
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("can't get the uuid of the file to "
                                                 "be attached to floppy drive: %s, rc=%08x"),
                                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4065 4066
                            } else {
                                rc = floppyDrive->vtbl->MountImage(floppyDrive,
4067
                                                                   fduuid.value);
E
Eric Blake 已提交
4068
                                if (NS_FAILED(rc)) {
4069 4070 4071 4072
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file to "
                                                     "floppy drive: %s, rc=%08x"),
                                                   def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4073
                                } else {
4074
                                    DEBUGIID("floppyImage UUID", fduuid.value);
4075 4076
                                }
                            }
E
Eric Blake 已提交
4077
                            VBOX_MEDIUM_RELEASE(floppyImage);
4078
                        }
4079
                        vboxIIDUnalloc(&fduuid);
E
Eric Blake 已提交
4080
                        VBOX_UTF16_FREE(fdfileUtf16);
4081
                    }
E
Eric Blake 已提交
4082
                    VBOX_RELEASE(floppyDrive);
4083
                }
E
Eric Blake 已提交
4084
            } else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
4085
            }
4086
        }
E
Eric Blake 已提交
4087
    }
4088
#else  /* VBOX_API_VERSION >= 3001 */
E
Eric Blake 已提交
4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100
    PRUint32 maxPortPerInst[StorageBus_Floppy + 1] = {};
    PRUint32 maxSlotPerPort[StorageBus_Floppy + 1] = {};
    PRUnichar *storageCtlName = NULL;
    bool error = false;

    /* get the max port/slots/etc for the given storage bus */
    error = !vboxGetMaxPortSlotValues(data->vboxObj, maxPortPerInst,
                                      maxSlotPerPort);

    /* add a storage controller for the mediums to be attached */
    /* this needs to change when multiple controller are supported for
     * ver > 3.1 */
4101
    {
E
Eric Blake 已提交
4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136
        IStorageController *storageCtl = NULL;
        PRUnichar *sName = NULL;

        VBOX_UTF8_TO_UTF16("IDE Controller", &sName);
        machine->vtbl->AddStorageController(machine,
                                            sName,
                                            StorageBus_IDE,
                                            &storageCtl);
        VBOX_UTF16_FREE(sName);
        VBOX_RELEASE(storageCtl);

        VBOX_UTF8_TO_UTF16("SATA Controller", &sName);
        machine->vtbl->AddStorageController(machine,
                                            sName,
                                            StorageBus_SATA,
                                            &storageCtl);
        VBOX_UTF16_FREE(sName);
        VBOX_RELEASE(storageCtl);

        VBOX_UTF8_TO_UTF16("SCSI Controller", &sName);
        machine->vtbl->AddStorageController(machine,
                                            sName,
                                            StorageBus_SCSI,
                                            &storageCtl);
        VBOX_UTF16_FREE(sName);
        VBOX_RELEASE(storageCtl);

        VBOX_UTF8_TO_UTF16("Floppy Controller", &sName);
        machine->vtbl->AddStorageController(machine,
                                            sName,
                                            StorageBus_Floppy,
                                            &storageCtl);
        VBOX_UTF16_FREE(sName);
        VBOX_RELEASE(storageCtl);
    }
4137

E
Eric Blake 已提交
4138
    for (i = 0; i < def->ndisks && !error; i++) {
4139 4140 4141 4142 4143 4144
        VIR_DEBUG("disk(%d) type:       %d", i, def->disks[i]->type);
        VIR_DEBUG("disk(%d) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%d) bus:        %d", i, def->disks[i]->bus);
        VIR_DEBUG("disk(%d) src:        %s", i, def->disks[i]->src);
        VIR_DEBUG("disk(%d) dst:        %s", i, def->disks[i]->dst);
        VIR_DEBUG("disk(%d) driverName: %s", i, def->disks[i]->driverName);
4145 4146
        VIR_DEBUG("disk(%d) driverType: %s", i,
                  virStorageFileFormatTypeToString(def->disks[i]->format));
4147 4148
        VIR_DEBUG("disk(%d) cachemode:  %d", i, def->disks[i]->cachemode);
        VIR_DEBUG("disk(%d) readonly:   %s", i, (def->disks[i]->readonly
E
Eric Blake 已提交
4149
                                             ? "True" : "False"));
4150
        VIR_DEBUG("disk(%d) shared:     %s", i, (def->disks[i]->shared
E
Eric Blake 已提交
4151 4152 4153 4154 4155 4156 4157 4158 4159
                                             ? "True" : "False"));

        if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_FILE &&
            def->disks[i]->src != NULL) {
            IMedium   *medium          = NULL;
            PRUnichar *mediumUUID      = NULL;
            PRUnichar *mediumFileUtf16 = NULL;
            PRUint32   storageBus      = StorageBus_Null;
            PRUint32   deviceType      = DeviceType_Null;
4160
# if VBOX_API_VERSION >= 4000
4161
            PRUint32   accessMode      = AccessMode_ReadOnly;
4162
# endif
E
Eric Blake 已提交
4163 4164 4165 4166 4167 4168 4169 4170
            PRInt32    deviceInst      = 0;
            PRInt32    devicePort      = 0;
            PRInt32    deviceSlot      = 0;

            VBOX_UTF8_TO_UTF16(def->disks[i]->src, &mediumFileUtf16);

            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                deviceType = DeviceType_HardDisk;
4171
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4172 4173
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj,
                                                  mediumFileUtf16, &medium);
4174 4175
# else
                accessMode = AccessMode_ReadWrite;
4176
# endif
E
Eric Blake 已提交
4177 4178
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                deviceType = DeviceType_DVD;
4179
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4180 4181
                data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                  mediumFileUtf16, &medium);
4182 4183
# else
                accessMode = AccessMode_ReadOnly;
4184
# endif
E
Eric Blake 已提交
4185 4186
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                deviceType = DeviceType_Floppy;
4187
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4188 4189
                data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                     mediumFileUtf16, &medium);
4190 4191
# else
                accessMode = AccessMode_ReadWrite;
4192
# endif
E
Eric Blake 已提交
4193 4194 4195 4196
            } else {
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4197

4198 4199 4200 4201 4202
# if VBOX_API_VERSION >= 4000
            data->vboxObj->vtbl->FindMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, &medium);
# endif

E
Eric Blake 已提交
4203 4204
            if (!medium) {
                PRUnichar *mediumEmpty = NULL;
4205

E
Eric Blake 已提交
4206
                VBOX_UTF8_TO_UTF16("", &mediumEmpty);
4207

4208
# if VBOX_API_VERSION < 4000
4209
                if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
4210 4211 4212 4213 4214 4215 4216 4217
                    rc = data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                           mediumFileUtf16,
                                                           AccessMode_ReadWrite,
                                                           false,
                                                           mediumEmpty,
                                                           false,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
4218 4219
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_CDROM) {
4220 4221 4222 4223
                    rc = data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                           mediumFileUtf16,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
4224 4225
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
4226 4227 4228 4229 4230 4231
                    rc = data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                              mediumFileUtf16,
                                                              mediumEmpty,
                                                              &medium);
                } else {
                    rc = 0;
4232
                }
4233
# elif VBOX_API_VERSION == 4000
4234 4235 4236 4237
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     &medium);
4238 4239 4240 4241 4242 4243 4244
# elif VBOX_API_VERSION >= 4001
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     false,
                                                     &medium);
# endif /* VBOX_API_VERSION >= 4001 */
4245

E
Eric Blake 已提交
4246 4247
                VBOX_UTF16_FREE(mediumEmpty);
            }
4248

E
Eric Blake 已提交
4249
            if (!medium) {
4250 4251 4252 4253
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to attach the following disk/dvd/floppy "
                                 "to the machine: %s, rc=%08x"),
                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4254 4255 4256
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4257

E
Eric Blake 已提交
4258 4259
            rc = medium->vtbl->GetId(medium, &mediumUUID);
            if (NS_FAILED(rc)) {
4260 4261 4262 4263
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("can't get the uuid of the file to be attached "
                                 "as harddisk/dvd/floppy: %s, rc=%08x"),
                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4264 4265 4266 4267
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4268

E
Eric Blake 已提交
4269 4270 4271
            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                if (def->disks[i]->readonly) {
                    medium->vtbl->SetType(medium, MediumType_Immutable);
4272
                    VIR_DEBUG("setting harddisk to immutable");
E
Eric Blake 已提交
4273 4274
                } else if (!def->disks[i]->readonly) {
                    medium->vtbl->SetType(medium, MediumType_Normal);
4275
                    VIR_DEBUG("setting harddisk type to normal");
4276
                }
E
Eric Blake 已提交
4277
            }
4278

E
Eric Blake 已提交
4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291
            if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
                VBOX_UTF8_TO_UTF16("IDE Controller", &storageCtlName);
                storageBus = StorageBus_IDE;
            } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_SATA) {
                VBOX_UTF8_TO_UTF16("SATA Controller", &storageCtlName);
                storageBus = StorageBus_SATA;
            } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
                VBOX_UTF8_TO_UTF16("SCSI Controller", &storageCtlName);
                storageBus = StorageBus_SCSI;
            } else if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_FDC) {
                VBOX_UTF8_TO_UTF16("Floppy Controller", &storageCtlName);
                storageBus = StorageBus_Floppy;
            }
4292

E
Eric Blake 已提交
4293 4294 4295 4296 4297 4298 4299 4300
            /* get the device details i.e instance, port and slot */
            if (!vboxGetDeviceDetails(def->disks[i]->dst,
                                      maxPortPerInst,
                                      maxSlotPerPort,
                                      storageBus,
                                      &deviceInst,
                                      &devicePort,
                                      &deviceSlot)) {
4301
                virReportError(VIR_ERR_INTERNAL_ERROR,
4302 4303 4304
                               _("can't get the port/slot number of "
                                 "harddisk/dvd/floppy to be attached: "
                                 "%s, rc=%08x"),
4305
                               def->disks[i]->src, (unsigned)rc);
4306 4307 4308
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumUUID);
                VBOX_UTF16_FREE(mediumFileUtf16);
E
Eric Blake 已提交
4309 4310 4311 4312 4313 4314 4315 4316 4317
                continue;
            }

            /* attach the harddisk/dvd/Floppy to the storage controller */
            rc = machine->vtbl->AttachDevice(machine,
                                             storageCtlName,
                                             devicePort,
                                             deviceSlot,
                                             deviceType,
4318
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4319
                                             mediumUUID);
4320 4321 4322
# else /* VBOX_API_VERSION >= 4000 */
                                             medium);
# endif /* VBOX_API_VERSION >= 4000 */
E
Eric Blake 已提交
4323 4324

            if (NS_FAILED(rc)) {
4325
                virReportError(VIR_ERR_INTERNAL_ERROR,
4326 4327
                               _("could not attach the file as "
                                 "harddisk/dvd/floppy: %s, rc=%08x"),
4328
                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4329 4330
            } else {
                DEBUGIID("Attached HDD/DVD/Floppy with UUID", mediumUUID);
4331
            }
E
Eric Blake 已提交
4332 4333 4334 4335 4336

            VBOX_RELEASE(medium);
            VBOX_UTF16_FREE(mediumUUID);
            VBOX_UTF16_FREE(mediumFileUtf16);
            VBOX_UTF16_FREE(storageCtlName);
4337 4338 4339
        }
    }
#endif /* VBOX_API_VERSION >= 3001 */
E
Eric Blake 已提交
4340
}
4341

E
Eric Blake 已提交
4342 4343 4344 4345
static void
vboxAttachSound(virDomainDefPtr def, IMachine *machine)
{
    nsresult rc;
4346

E
Eric Blake 已提交
4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362
    /* Check if def->nsounds is one as VirtualBox currently supports
     * only one sound card
     */
    if (def->nsounds == 1) {
        IAudioAdapter *audioAdapter = NULL;

        machine->vtbl->GetAudioAdapter(machine, &audioAdapter);
        if (audioAdapter) {
            rc = audioAdapter->vtbl->SetEnabled(audioAdapter, 1);
            if (NS_SUCCEEDED(rc)) {
                if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_SB16) {
                    audioAdapter->vtbl->SetAudioController(audioAdapter,
                                                           AudioControllerType_SB16);
                } else if (def->sounds[0]->model == VIR_DOMAIN_SOUND_MODEL_AC97) {
                    audioAdapter->vtbl->SetAudioController(audioAdapter,
                                                           AudioControllerType_AC97);
4363
                }
4364
            }
E
Eric Blake 已提交
4365
            VBOX_RELEASE(audioAdapter);
4366
        }
E
Eric Blake 已提交
4367 4368 4369 4370 4371 4372 4373
    }
}

static void
vboxAttachNetwork(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
4374 4375 4376
#if VBOX_API_VERSION >= 4001
    PRUint32 chipsetType                = ChipsetType_Null;
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4377 4378 4379
    PRUint32 networkAdapterCount        = 0;
    int i = 0;

4380 4381 4382 4383
#if VBOX_API_VERSION >= 4001
    machine->vtbl->GetChipsetType(machine, &chipsetType);
#endif /* VBOX_API_VERSION >= 4001 */

E
Eric Blake 已提交
4384 4385
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
4386
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4387 4388
        systemProperties->vtbl->GetNetworkAdapterCount(systemProperties,
                                                       &networkAdapterCount);
4389 4390 4391 4392
#else  /* VBOX_API_VERSION >= 4000 */
        systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType,
                                                      &networkAdapterCount);
#endif /* VBOX_API_VERSION >= 4000 */
E
Eric Blake 已提交
4393 4394 4395 4396
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }

4397
    VIR_DEBUG("Number of Network Cards to be connected: %zu", def->nnets);
4398
    VIR_DEBUG("Number of Network Cards available: %d", networkAdapterCount);
E
Eric Blake 已提交
4399 4400 4401 4402 4403 4404 4405

    for (i = 0; (i < def->nnets) && (i < networkAdapterCount); i++) {
        INetworkAdapter *adapter = NULL;
        PRUint32 adapterType     = NetworkAdapterType_Null;
        char macaddr[VIR_MAC_STRING_BUFLEN] = {0};
        char macaddrvbox[VIR_MAC_STRING_BUFLEN - 5] = {0};

4406
        virMacAddrFormat(&def->nets[i]->mac, macaddr);
E
Eric Blake 已提交
4407 4408
        snprintf(macaddrvbox, VIR_MAC_STRING_BUFLEN - 5,
                 "%02X%02X%02X%02X%02X%02X",
4409 4410 4411 4412 4413 4414
                 def->nets[i]->mac.addr[0],
                 def->nets[i]->mac.addr[1],
                 def->nets[i]->mac.addr[2],
                 def->nets[i]->mac.addr[3],
                 def->nets[i]->mac.addr[4],
                 def->nets[i]->mac.addr[5]);
E
Eric Blake 已提交
4415 4416
        macaddrvbox[VIR_MAC_STRING_BUFLEN - 6] = '\0';

4417 4418 4419 4420
        VIR_DEBUG("NIC(%d): Type:   %d", i, def->nets[i]->type);
        VIR_DEBUG("NIC(%d): Model:  %s", i, def->nets[i]->model);
        VIR_DEBUG("NIC(%d): Mac:    %s", i, macaddr);
        VIR_DEBUG("NIC(%d): ifname: %s", i, def->nets[i]->ifname);
E
Eric Blake 已提交
4421
        if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4422
            VIR_DEBUG("NIC(%d): name:    %s", i, def->nets[i]->data.network.name);
E
Eric Blake 已提交
4423
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
4424
            VIR_DEBUG("NIC(%d): name:   %s", i, def->nets[i]->data.internal.name);
E
Eric Blake 已提交
4425
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
4426
            VIR_DEBUG("NIC(%d): NAT.", i);
E
Eric Blake 已提交
4427
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
4428
            VIR_DEBUG("NIC(%d): brname: %s", i, def->nets[i]->data.bridge.brname);
4429
            VIR_DEBUG("NIC(%d): script: %s", i, def->nets[i]->script);
4430
            VIR_DEBUG("NIC(%d): ipaddr: %s", i, def->nets[i]->data.bridge.ipaddr);
4431 4432
        }

E
Eric Blake 已提交
4433 4434 4435 4436 4437
        machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
        if (adapter) {
            PRUnichar *MACAddress = NULL;

            adapter->vtbl->SetEnabled(adapter, 1);
4438

E
Eric Blake 已提交
4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449
            if (def->nets[i]->model) {
                if (STRCASEEQ(def->nets[i]->model , "Am79C970A")) {
                    adapterType = NetworkAdapterType_Am79C970A;
                } else if (STRCASEEQ(def->nets[i]->model , "Am79C973")) {
                    adapterType = NetworkAdapterType_Am79C973;
                } else if (STRCASEEQ(def->nets[i]->model , "82540EM")) {
                    adapterType = NetworkAdapterType_I82540EM;
                } else if (STRCASEEQ(def->nets[i]->model , "82545EM")) {
                    adapterType = NetworkAdapterType_I82545EM;
                } else if (STRCASEEQ(def->nets[i]->model , "82543GC")) {
                    adapterType = NetworkAdapterType_I82543GC;
4450
#if VBOX_API_VERSION >= 3001
E
Eric Blake 已提交
4451 4452
                } else if (STRCASEEQ(def->nets[i]->model , "virtio")) {
                    adapterType = NetworkAdapterType_Virtio;
4453 4454
#endif /* VBOX_API_VERSION >= 3001 */
                }
E
Eric Blake 已提交
4455 4456 4457
            } else {
                adapterType = NetworkAdapterType_Am79C973;
            }
4458

E
Eric Blake 已提交
4459
            adapter->vtbl->SetAdapterType(adapter, adapterType);
4460

E
Eric Blake 已提交
4461 4462 4463
            if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
                PRUnichar *hostInterface = NULL;
                /* Bridged Network */
4464

4465
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4466
                adapter->vtbl->AttachToBridgedInterface(adapter);
4467 4468 4469
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Bridged);
#endif /* VBOX_API_VERSION >= 4001 */
4470

E
Eric Blake 已提交
4471 4472 4473
                if (def->nets[i]->data.bridge.brname) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.bridge.brname,
                                       &hostInterface);
4474
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4475
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4476 4477 4478
#else /* VBOX_API_VERSION >= 4001 */
                    adapter->vtbl->SetBridgedInterface(adapter, hostInterface);
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4479 4480 4481 4482 4483
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
                PRUnichar *internalNetwork = NULL;
                /* Internal Network */
4484

4485
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4486
                adapter->vtbl->AttachToInternalNetwork(adapter);
4487 4488 4489
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Internal);
#endif /* VBOX_API_VERSION >= 4001 */
4490

E
Eric Blake 已提交
4491 4492 4493 4494 4495
                if (def->nets[i]->data.internal.name) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.internal.name,
                                       &internalNetwork);
                    adapter->vtbl->SetInternalNetwork(adapter, internalNetwork);
                    VBOX_UTF16_FREE(internalNetwork);
4496
                }
E
Eric Blake 已提交
4497 4498 4499 4500 4501 4502
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
                PRUnichar *hostInterface = NULL;
                /* Host Only Networking (currently only vboxnet0 available
                 * on *nix and mac, on windows you can create and configure
                 * as many as you want)
                 */
4503
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4504
                adapter->vtbl->AttachToHostOnlyInterface(adapter);
4505 4506 4507
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_HostOnly);
#endif /* VBOX_API_VERSION >= 4001 */
4508

E
Eric Blake 已提交
4509 4510 4511
                if (def->nets[i]->data.network.name) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.network.name,
                                       &hostInterface);
4512
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4513
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4514 4515 4516
#else /* VBOX_API_VERSION >= 4001 */
                    adapter->vtbl->SetHostOnlyInterface(adapter, hostInterface);
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4517 4518 4519 4520
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
                /* NAT */
4521
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4522
                adapter->vtbl->AttachToNAT(adapter);
4523 4524 4525
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4526 4527 4528 4529
            } else {
                /* else always default to NAT if we don't understand
                 * what option is been passed to us
                 */
4530
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4531
                adapter->vtbl->AttachToNAT(adapter);
4532 4533 4534
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
#endif /* VBOX_API_VERSION >= 4001 */
4535
            }
E
Eric Blake 已提交
4536 4537 4538 4539

            VBOX_UTF8_TO_UTF16(macaddrvbox, &MACAddress);
            adapter->vtbl->SetMACAddress(adapter, MACAddress);
            VBOX_UTF16_FREE(MACAddress);
4540
        }
E
Eric Blake 已提交
4541 4542 4543 4544 4545 4546 4547 4548 4549
    }
}

static void
vboxAttachSerial(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 serialPortCount            = 0;
    int i = 0;
4550

E
Eric Blake 已提交
4551 4552 4553 4554 4555 4556 4557
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetSerialPortCount(systemProperties,
                                                   &serialPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4558

4559
    VIR_DEBUG("Number of Serial Ports to be connected: %zu", def->nserials);
4560
    VIR_DEBUG("Number of Serial Ports available: %d", serialPortCount);
E
Eric Blake 已提交
4561 4562
    for (i = 0; (i < def->nserials) && (i < serialPortCount); i++) {
        ISerialPort *serialPort = NULL;
4563

4564 4565
        VIR_DEBUG("SerialPort(%d): Type: %d", i, def->serials[i]->source.type);
        VIR_DEBUG("SerialPort(%d): target.port: %d", i,
E
Eric Blake 已提交
4566
              def->serials[i]->target.port);
4567

E
Eric Blake 已提交
4568 4569 4570
        machine->vtbl->GetSerialPort(machine, i, &serialPort);
        if (serialPort) {
            PRUnichar *pathUtf16 = NULL;
4571

E
Eric Blake 已提交
4572
            serialPort->vtbl->SetEnabled(serialPort, 1);
4573

4574 4575 4576
            if (def->serials[i]->source.data.file.path) {
                VBOX_UTF8_TO_UTF16(def->serials[i]->source.data.file.path,
                                   &pathUtf16);
E
Eric Blake 已提交
4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591
                serialPort->vtbl->SetPath(serialPort, pathUtf16);
            }

            /* For now hard code the serial ports to COM1 and COM2,
             * COM1 (Base Addr: 0x3F8 (decimal: 1016), IRQ: 4)
             * COM2 (Base Addr: 0x2F8 (decimal:  760), IRQ: 3)
             * TODO: make this more flexible
             */
            /* TODO: to improve the libvirt XMl handling so
             * that def->serials[i]->target.port shows real port
             * and not always start at 0
             */
            if (def->serials[i]->target.port == 0) {
                serialPort->vtbl->SetIRQ(serialPort, 4);
                serialPort->vtbl->SetIOBase(serialPort, 1016);
4592
                VIR_DEBUG(" serialPort-%d irq: %d, iobase 0x%x, path: %s",
4593
                      i, 4, 1016, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4594 4595 4596
            } else if (def->serials[i]->target.port == 1) {
                serialPort->vtbl->SetIRQ(serialPort, 3);
                serialPort->vtbl->SetIOBase(serialPort, 760);
4597
                VIR_DEBUG(" serialPort-%d irq: %d, iobase 0x%x, path: %s",
4598
                      i, 3, 760, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4599
            }
4600

4601
            if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV) {
E
Eric Blake 已提交
4602
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostDevice);
4603
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE) {
E
Eric Blake 已提交
4604
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostPipe);
4605
#if VBOX_API_VERSION >= 3000
4606
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE) {
E
Eric Blake 已提交
4607
                serialPort->vtbl->SetHostMode(serialPort, PortMode_RawFile);
4608
#endif /* VBOX_API_VERSION >= 3000 */
E
Eric Blake 已提交
4609 4610 4611 4612
            } else {
                serialPort->vtbl->SetHostMode(serialPort,
                                              PortMode_Disconnected);
            }
4613

E
Eric Blake 已提交
4614
            VBOX_RELEASE(serialPort);
J
John Ferlan 已提交
4615
            VBOX_UTF16_FREE(pathUtf16);
4616
        }
E
Eric Blake 已提交
4617 4618
    }
}
4619

E
Eric Blake 已提交
4620 4621 4622 4623 4624 4625
static void
vboxAttachParallel(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 parallelPortCount          = 0;
    int i = 0;
4626

E
Eric Blake 已提交
4627 4628 4629 4630 4631 4632 4633
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetParallelPortCount(systemProperties,
                                                     &parallelPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4634

4635
    VIR_DEBUG("Number of Parallel Ports to be connected: %zu", def->nparallels);
4636
    VIR_DEBUG("Number of Parallel Ports available: %d", parallelPortCount);
E
Eric Blake 已提交
4637 4638
    for (i = 0; (i < def->nparallels) && (i < parallelPortCount); i++) {
        IParallelPort *parallelPort = NULL;
4639

4640 4641
        VIR_DEBUG("ParallelPort(%d): Type: %d", i, def->parallels[i]->source.type);
        VIR_DEBUG("ParallelPort(%d): target.port: %d", i,
E
Eric Blake 已提交
4642
              def->parallels[i]->target.port);
4643

E
Eric Blake 已提交
4644 4645 4646
        machine->vtbl->GetParallelPort(machine, i, &parallelPort);
        if (parallelPort) {
            PRUnichar *pathUtf16 = NULL;
4647

4648
            VBOX_UTF8_TO_UTF16(def->parallels[i]->source.data.file.path, &pathUtf16);
4649

E
Eric Blake 已提交
4650 4651 4652 4653 4654
            /* For now hard code the parallel ports to
             * LPT1 (Base Addr: 0x378 (decimal: 888), IRQ: 7)
             * LPT2 (Base Addr: 0x278 (decimal: 632), IRQ: 5)
             * TODO: make this more flexible
             */
4655 4656 4657 4658
            if ((def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV)  ||
                (def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_PTY)  ||
                (def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE) ||
                (def->parallels[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE)) {
E
Eric Blake 已提交
4659 4660 4661 4662
                parallelPort->vtbl->SetPath(parallelPort, pathUtf16);
                if (i == 0) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 7);
                    parallelPort->vtbl->SetIOBase(parallelPort, 888);
4663
                    VIR_DEBUG(" parallePort-%d irq: %d, iobase 0x%x, path: %s",
4664
                          i, 7, 888, def->parallels[i]->source.data.file.path);
E
Eric Blake 已提交
4665 4666 4667
                } else if (i == 1) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 5);
                    parallelPort->vtbl->SetIOBase(parallelPort, 632);
4668
                    VIR_DEBUG(" parallePort-%d irq: %d, iobase 0x%x, path: %s",
4669
                          i, 5, 632, def->parallels[i]->source.data.file.path);
4670 4671
                }
            }
E
Eric Blake 已提交
4672 4673 4674 4675 4676 4677 4678

            /* like serial port, parallel port can't be enabled unless
             * correct IRQ and IOBase values are specified.
             */
            parallelPort->vtbl->SetEnabled(parallelPort, 1);

            VBOX_RELEASE(parallelPort);
J
John Ferlan 已提交
4679
            VBOX_UTF16_FREE(pathUtf16);
4680
        }
E
Eric Blake 已提交
4681 4682 4683 4684 4685 4686 4687 4688
    }
}

static void
vboxAttachVideo(virDomainDefPtr def, IMachine *machine)
{
    if ((def->nvideos == 1) &&
        (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_VBOX)) {
4689 4690
        machine->vtbl->SetVRAMSize(machine,
                                   VIR_DIV_UP(def->videos[0]->vram, 1024));
E
Eric Blake 已提交
4691 4692 4693 4694
        machine->vtbl->SetMonitorCount(machine, def->videos[0]->heads);
        if (def->videos[0]->accel) {
            machine->vtbl->SetAccelerate3DEnabled(machine,
                                                  def->videos[0]->accel->support3d);
4695
#if VBOX_API_VERSION >= 3001
E
Eric Blake 已提交
4696 4697
            machine->vtbl->SetAccelerate2DVideoEnabled(machine,
                                                       def->videos[0]->accel->support2d);
4698
#endif /* VBOX_API_VERSION >= 3001 */
E
Eric Blake 已提交
4699 4700
        } else {
            machine->vtbl->SetAccelerate3DEnabled(machine, 0);
4701
#if VBOX_API_VERSION >= 3001
E
Eric Blake 已提交
4702
            machine->vtbl->SetAccelerate2DVideoEnabled(machine, 0);
4703 4704
#endif /* VBOX_API_VERSION >= 3001 */
        }
E
Eric Blake 已提交
4705 4706
    }
}
4707

E
Eric Blake 已提交
4708 4709 4710 4711 4712 4713 4714 4715 4716
static void
vboxAttachDisplay(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    int vrdpPresent  = 0;
    int sdlPresent   = 0;
    int guiPresent   = 0;
    char *guiDisplay = NULL;
    char *sdlDisplay = NULL;
    int i = 0;
4717

E
Eric Blake 已提交
4718
    for (i = 0; i < def->ngraphics; i++) {
4719 4720 4721 4722 4723
#if VBOX_API_VERSION < 4000
        IVRDPServer *VRDxServer = NULL;
#else /* VBOX_API_VERSION >= 4000 */
        IVRDEServer *VRDxServer = NULL;
#endif /* VBOX_API_VERSION >= 4000 */
4724

E
Eric Blake 已提交
4725 4726
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) &&
            (vrdpPresent == 0)) {
4727

E
Eric Blake 已提交
4728
            vrdpPresent = 1;
4729 4730 4731 4732 4733 4734
#if VBOX_API_VERSION < 4000
            machine->vtbl->GetVRDPServer(machine, &VRDxServer);
#else /* VBOX_API_VERSION >= 4000 */
            machine->vtbl->GetVRDEServer(machine, &VRDxServer);
#endif /* VBOX_API_VERSION >= 4000 */
            if (VRDxServer) {
4735 4736 4737
                const char *listenAddr
                    = virDomainGraphicsListenGetAddress(def->graphics[i], 0);

4738
                VRDxServer->vtbl->SetEnabled(VRDxServer, PR_TRUE);
4739
                VIR_DEBUG("VRDP Support turned ON.");
4740 4741

#if VBOX_API_VERSION < 3001
E
Eric Blake 已提交
4742
                if (def->graphics[i]->data.rdp.port) {
4743
                    VRDxServer->vtbl->SetPort(VRDxServer,
E
Eric Blake 已提交
4744
                                              def->graphics[i]->data.rdp.port);
4745
                    VIR_DEBUG("VRDP Port changed to: %d",
E
Eric Blake 已提交
4746 4747 4748 4749 4750
                          def->graphics[i]->data.rdp.port);
                } else if (def->graphics[i]->data.rdp.autoport) {
                    /* Setting the port to 0 will reset its value to
                     * the default one which is 3389 currently
                     */
4751
                    VRDxServer->vtbl->SetPort(VRDxServer, 0);
4752
                    VIR_DEBUG("VRDP Port changed to default, which is 3389 currently");
E
Eric Blake 已提交
4753
                }
4754
#elif VBOX_API_VERSION < 4000 /* 3001 <= VBOX_API_VERSION < 4000 */
E
Eric Blake 已提交
4755 4756
                PRUnichar *portUtf16 = NULL;
                portUtf16 = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
4757
                VRDxServer->vtbl->SetPorts(VRDxServer, portUtf16);
E
Eric Blake 已提交
4758
                VBOX_UTF16_FREE(portUtf16);
4759 4760 4761 4762 4763 4764 4765 4766 4767 4768
#else /* VBOX_API_VERSION >= 4000 */
                PRUnichar *VRDEPortsKey = NULL;
                PRUnichar *VRDEPortsValue = NULL;
                VBOX_UTF8_TO_UTF16("TCP/Ports", &VRDEPortsKey);
                VRDEPortsValue = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
                VRDxServer->vtbl->SetVRDEProperty(VRDxServer, VRDEPortsKey,
                                                  VRDEPortsValue);
                VBOX_UTF16_FREE(VRDEPortsKey);
                VBOX_UTF16_FREE(VRDEPortsValue);
#endif /* VBOX_API_VERSION >= 4000 */
4769

E
Eric Blake 已提交
4770
                if (def->graphics[i]->data.rdp.replaceUser) {
4771
                    VRDxServer->vtbl->SetReuseSingleConnection(VRDxServer,
E
Eric Blake 已提交
4772
                                                               PR_TRUE);
4773
                    VIR_DEBUG("VRDP set to reuse single connection");
E
Eric Blake 已提交
4774
                }
4775

E
Eric Blake 已提交
4776
                if (def->graphics[i]->data.rdp.multiUser) {
4777
                    VRDxServer->vtbl->SetAllowMultiConnection(VRDxServer,
E
Eric Blake 已提交
4778
                                                              PR_TRUE);
4779
                    VIR_DEBUG("VRDP set to allow multiple connection");
E
Eric Blake 已提交
4780
                }
4781

4782
                if (listenAddr) {
4783 4784 4785
#if VBOX_API_VERSION >= 4000
                    PRUnichar *netAddressKey = NULL;
#endif
E
Eric Blake 已提交
4786
                    PRUnichar *netAddressUtf16 = NULL;
4787

4788
                    VBOX_UTF8_TO_UTF16(listenAddr, &netAddressUtf16);
4789 4790
#if VBOX_API_VERSION < 4000
                    VRDxServer->vtbl->SetNetAddress(VRDxServer,
E
Eric Blake 已提交
4791
                                                    netAddressUtf16);
4792 4793 4794 4795 4796 4797
#else /* VBOX_API_VERSION >= 4000 */
                    VBOX_UTF8_TO_UTF16("TCP/Address", &netAddressKey);
                    VRDxServer->vtbl->SetVRDEProperty(VRDxServer, netAddressKey,
                                                      netAddressUtf16);
                    VBOX_UTF16_FREE(netAddressKey);
#endif /* VBOX_API_VERSION >= 4000 */
4798
                    VIR_DEBUG("VRDP listen address is set to: %s",
4799
                              listenAddr);
4800

E
Eric Blake 已提交
4801
                    VBOX_UTF16_FREE(netAddressUtf16);
4802
                }
E
Eric Blake 已提交
4803

4804
                VBOX_RELEASE(VRDxServer);
4805
            }
E
Eric Blake 已提交
4806
        }
4807

E
Eric Blake 已提交
4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) &&
            (guiPresent == 0)) {
            guiPresent = 1;
            if (def->graphics[i]->data.desktop.display) {
                guiDisplay = strdup(def->graphics[i]->data.desktop.display);
                if (guiDisplay == NULL) {
                    virReportOOMError();
                    /* just don't go to cleanup yet as it is ok to have
                     * guiDisplay as NULL and we check it below if it
                     * exist and then only use it there
                     */
4819
                }
4820
            }
E
Eric Blake 已提交
4821
        }
4822

E
Eric Blake 已提交
4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) &&
            (sdlPresent == 0)) {
            sdlPresent = 1;
            if (def->graphics[i]->data.sdl.display) {
                sdlDisplay = strdup(def->graphics[i]->data.sdl.display);
                if (sdlDisplay == NULL) {
                    virReportOOMError();
                    /* just don't go to cleanup yet as it is ok to have
                     * sdlDisplay as NULL and we check it below if it
                     * exist and then only use it there
                     */
4834
                }
4835
            }
4836
        }
E
Eric Blake 已提交
4837
    }
4838

E
Eric Blake 已提交
4839 4840 4841 4842
    if ((vrdpPresent == 1) && (guiPresent == 0) && (sdlPresent == 0)) {
        /* store extradata key that frontend is set to vrdp */
        PRUnichar *keyTypeUtf16   = NULL;
        PRUnichar *valueTypeUtf16 = NULL;
4843

E
Eric Blake 已提交
4844 4845
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("vrdp", &valueTypeUtf16);
4846

E
Eric Blake 已提交
4847
        machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
4848

E
Eric Blake 已提交
4849 4850
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4851

E
Eric Blake 已提交
4852 4853 4854 4855 4856 4857
    } else if ((guiPresent == 0) && (sdlPresent == 1)) {
        /* store extradata key that frontend is set to sdl */
        PRUnichar *keyTypeUtf16      = NULL;
        PRUnichar *valueTypeUtf16    = NULL;
        PRUnichar *keyDislpayUtf16   = NULL;
        PRUnichar *valueDisplayUtf16 = NULL;
4858

E
Eric Blake 已提交
4859 4860
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("sdl", &valueTypeUtf16);
4861

E
Eric Blake 已提交
4862
        machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
4863

E
Eric Blake 已提交
4864 4865
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4866

E
Eric Blake 已提交
4867 4868 4869
        if (sdlDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(sdlDisplay, &valueDisplayUtf16);
4870

E
Eric Blake 已提交
4871 4872
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4873

E
Eric Blake 已提交
4874 4875 4876
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
        }
4877

E
Eric Blake 已提交
4878 4879 4880 4881 4882 4883
    } else {
        /* if all are set then default is gui, with vrdp turned on */
        PRUnichar *keyTypeUtf16      = NULL;
        PRUnichar *valueTypeUtf16    = NULL;
        PRUnichar *keyDislpayUtf16   = NULL;
        PRUnichar *valueDisplayUtf16 = NULL;
4884

E
Eric Blake 已提交
4885 4886
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("gui", &valueTypeUtf16);
4887

E
Eric Blake 已提交
4888
        machine->vtbl->SetExtraData(machine, keyTypeUtf16, valueTypeUtf16);
4889

E
Eric Blake 已提交
4890 4891
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4892

E
Eric Blake 已提交
4893 4894 4895
        if (guiDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(guiDisplay, &valueDisplayUtf16);
4896

E
Eric Blake 已提交
4897 4898
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4899

E
Eric Blake 已提交
4900 4901
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
4902
        }
E
Eric Blake 已提交
4903
    }
4904

E
Eric Blake 已提交
4905 4906 4907
    VIR_FREE(guiDisplay);
    VIR_FREE(sdlDisplay);
}
4908

E
Eric Blake 已提交
4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930
static void
vboxAttachUSB(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    IUSBController *USBController = NULL;
    int i = 0;
    bool isUSB = false;

    if (def->nhostdevs == 0)
        return;

    /* Loop through the devices first and see if you
     * have a USB Device, only if you have one then
     * start the USB controller else just proceed as
     * usual
     */
    for (i = 0; i < def->nhostdevs; i++) {
        if (def->hostdevs[i]->mode ==
            VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
            if (def->hostdevs[i]->source.subsys.type ==
                VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
                if (def->hostdevs[i]->source.subsys.u.usb.vendor ||
                    def->hostdevs[i]->source.subsys.u.usb.product) {
4931
                    VIR_DEBUG("USB Device detected, VendorId:0x%x, ProductId:0x%x",
E
Eric Blake 已提交
4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948
                          def->hostdevs[i]->source.subsys.u.usb.vendor,
                          def->hostdevs[i]->source.subsys.u.usb.product);
                    isUSB = true;
                    break;
                }
            }
        }
    }

    if (isUSB) {
        /* First Start the USB Controller and then loop
         * to attach USB Devices to it
         */
        machine->vtbl->GetUSBController(machine, &USBController);
        if (USBController) {
            USBController->vtbl->SetEnabled(USBController, 1);
            USBController->vtbl->SetEnabledEhci(USBController, 1);
4949

4950 4951
            for (i = 0; i < def->nhostdevs; i++) {
                if (def->hostdevs[i]->mode ==
E
Eric Blake 已提交
4952
                    VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
4953
                    if (def->hostdevs[i]->source.subsys.type ==
E
Eric Blake 已提交
4954
                        VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
4955

E
Eric Blake 已提交
4956
                        char *filtername           = NULL;
E
Eric Blake 已提交
4957 4958
                        PRUnichar *filternameUtf16 = NULL;
                        IUSBDeviceFilter *filter   = NULL;
4959

E
Eric Blake 已提交
4960 4961
                        /* Zero pad for nice alignment when fewer than 9999
                         * devices.
E
Eric Blake 已提交
4962
                         */
E
Eric Blake 已提交
4963 4964 4965 4966 4967 4968 4969 4970 4971
                        if (virAsprintf(&filtername, "filter%04d", i) < 0) {
                            virReportOOMError();
                        } else {
                            VBOX_UTF8_TO_UTF16(filtername, &filternameUtf16);
                            VIR_FREE(filtername);
                            USBController->vtbl->CreateDeviceFilter(USBController,
                                                                    filternameUtf16,
                                                                    &filter);
                        }
E
Eric Blake 已提交
4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983
                        VBOX_UTF16_FREE(filternameUtf16);

                        if (filter &&
                            (def->hostdevs[i]->source.subsys.u.usb.vendor ||
                             def->hostdevs[i]->source.subsys.u.usb.product)) {

                            PRUnichar *vendorIdUtf16  = NULL;
                            char vendorId[40]         = {0};
                            PRUnichar *productIdUtf16 = NULL;
                            char productId[40]        = {0};

                            if (def->hostdevs[i]->source.subsys.u.usb.vendor) {
E
Eric Blake 已提交
4984 4985
                                snprintf(vendorId, sizeof(vendorId), "%x",
                                         def->hostdevs[i]->source.subsys.u.usb.vendor);
E
Eric Blake 已提交
4986 4987 4988 4989 4990
                                VBOX_UTF8_TO_UTF16(vendorId, &vendorIdUtf16);
                                filter->vtbl->SetVendorId(filter, vendorIdUtf16);
                                VBOX_UTF16_FREE(vendorIdUtf16);
                            }
                            if (def->hostdevs[i]->source.subsys.u.usb.product) {
E
Eric Blake 已提交
4991 4992
                                snprintf(productId, sizeof(productId), "%x",
                                         def->hostdevs[i]->source.subsys.u.usb.product);
E
Eric Blake 已提交
4993 4994 4995 4996
                                VBOX_UTF8_TO_UTF16(productId, &productIdUtf16);
                                filter->vtbl->SetProductId(filter,
                                                           productIdUtf16);
                                VBOX_UTF16_FREE(productIdUtf16);
4997
                            }
E
Eric Blake 已提交
4998 4999 5000 5001 5002
                            filter->vtbl->SetActive(filter, 1);
                            USBController->vtbl->InsertDeviceFilter(USBController,
                                                                    i,
                                                                    filter);
                            VBOX_RELEASE(filter);
5003
                        }
E
Eric Blake 已提交
5004

5005 5006 5007
                    }
                }
            }
E
Eric Blake 已提交
5008 5009 5010 5011 5012
            VBOX_RELEASE(USBController);
        }
    }
}

M
Matthias Bolte 已提交
5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044
static void
vboxAttachSharedFolder(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    int i;
    PRUnichar *nameUtf16;
    PRUnichar *hostPathUtf16;
    PRBool writable;

    if (def->nfss == 0)
        return;

    for (i = 0; i < def->nfss; i++) {
        if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_MOUNT)
            continue;

        VBOX_UTF8_TO_UTF16(def->fss[i]->dst, &nameUtf16);
        VBOX_UTF8_TO_UTF16(def->fss[i]->src, &hostPathUtf16);
        writable = !def->fss[i]->readonly;

#if VBOX_API_VERSION < 4000
        machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                          writable);
#else /* VBOX_API_VERSION >= 4000 */
        machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                          writable, PR_FALSE);
#endif /* VBOX_API_VERSION >= 4000 */

        VBOX_UTF16_FREE(nameUtf16);
        VBOX_UTF16_FREE(hostPathUtf16);
    }
}

E
Eric Blake 已提交
5045 5046 5047 5048
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml) {
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
    IMachine       *machine     = NULL;
    IBIOSSettings  *bios        = NULL;
5049 5050
    vboxIID iid = VBOX_IID_INITIALIZER;
    vboxIID mchiid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
5051 5052 5053 5054 5055 5056 5057
    virDomainDefPtr def         = NULL;
    PRUnichar *machineNameUtf16 = NULL;
#if VBOX_API_VERSION >= 3002
    PRBool override             = PR_FALSE;
#endif
    nsresult rc;

5058 5059
    if (!(def = virDomainDefParseString(xml, data->caps, data->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_VBOX,
E
Eric Blake 已提交
5060 5061 5062 5063 5064
                                        VIR_DOMAIN_XML_INACTIVE))) {
        goto cleanup;
    }

    VBOX_UTF8_TO_UTF16(def->name, &machineNameUtf16);
5065
    vboxIIDFromUUID(&iid, def->uuid);
E
Eric Blake 已提交
5066 5067 5068 5069 5070
#if VBOX_API_VERSION < 3002
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
5071
                                            iid.value,
E
Eric Blake 已提交
5072
                                            &machine);
5073
#elif VBOX_API_VERSION < 4000 /* 3002 <= VBOX_API_VERSION < 4000 */
E
Eric Blake 已提交
5074 5075 5076 5077
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
5078
                                            iid.value,
E
Eric Blake 已提交
5079 5080
                                            override,
                                            &machine);
5081 5082 5083 5084 5085 5086 5087 5088 5089
#else /* VBOX_API_VERSION >= 4000 */
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            NULL,
                                            machineNameUtf16,
                                            NULL,
                                            iid.value,
                                            override,
                                            &machine);
#endif /* VBOX_API_VERSION >= 4000 */
E
Eric Blake 已提交
5090 5091 5092
    VBOX_UTF16_FREE(machineNameUtf16);

    if (NS_FAILED(rc)) {
5093 5094
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
5095 5096 5097
        goto cleanup;
    }

5098 5099
    rc = machine->vtbl->SetMemorySize(machine,
                                      VIR_DIV_UP(def->mem.cur_balloon, 1024));
E
Eric Blake 已提交
5100
    if (NS_FAILED(rc)) {
5101 5102 5103 5104
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not set the memory size of the domain to: %llu Kb, "
                         "rc=%08x"),
                       def->mem.cur_balloon, (unsigned)rc);
E
Eric Blake 已提交
5105 5106
    }

E
Eric Blake 已提交
5107
    if (def->vcpus != def->maxvcpus) {
5108 5109
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("current vcpu count must equal maximum"));
E
Eric Blake 已提交
5110 5111
    }
    rc = machine->vtbl->SetCPUCount(machine, def->maxvcpus);
E
Eric Blake 已提交
5112
    if (NS_FAILED(rc)) {
5113 5114 5115
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not set the number of virtual CPUs to: %u, rc=%08x"),
                       def->maxvcpus, (unsigned)rc);
E
Eric Blake 已提交
5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130
    }

#if VBOX_API_VERSION < 3001
    rc = machine->vtbl->SetPAEEnabled(machine, (def->features) &
                                      (1 << VIR_DOMAIN_FEATURE_PAE));
#elif VBOX_API_VERSION == 3001
    rc = machine->vtbl->SetCpuProperty(machine, CpuPropertyType_PAE,
                                       (def->features) &
                                       (1 << VIR_DOMAIN_FEATURE_PAE));
#elif VBOX_API_VERSION >= 3002
    rc = machine->vtbl->SetCPUProperty(machine, CPUPropertyType_PAE,
                                       (def->features) &
                                       (1 << VIR_DOMAIN_FEATURE_PAE));
#endif
    if (NS_FAILED(rc)) {
5131 5132 5133 5134
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not change PAE status to: %s, rc=%08x"),
                       ((def->features) & (1 << VIR_DOMAIN_FEATURE_PAE))
                       ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
5135 5136 5137 5138 5139 5140 5141
    }

    machine->vtbl->GetBIOSSettings(machine, &bios);
    if (bios) {
        rc = bios->vtbl->SetACPIEnabled(bios, (def->features) &
                                        (1 << VIR_DOMAIN_FEATURE_ACPI));
        if (NS_FAILED(rc)) {
5142 5143 5144 5145
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change ACPI status to: %s, rc=%08x"),
                           ((def->features) & (1 << VIR_DOMAIN_FEATURE_ACPI))
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
5146 5147 5148 5149
        }
        rc = bios->vtbl->SetIOAPICEnabled(bios, (def->features) &
                                          (1 << VIR_DOMAIN_FEATURE_APIC));
        if (NS_FAILED(rc)) {
5150 5151 5152 5153
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change APIC status to: %s, rc=%08x"),
                           ((def->features) & (1 << VIR_DOMAIN_FEATURE_APIC))
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
5154
        }
E
Eric Blake 已提交
5155 5156 5157 5158 5159 5160
        VBOX_RELEASE(bios);
    }

    /* Register the machine before attaching other devices to it */
    rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
    if (NS_FAILED(rc)) {
5161 5162
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
5163 5164 5165 5166 5167 5168 5169
        goto cleanup;
    }

    /* Get the uuid of the machine, currently it is immutable
     * object so open a session to it and get it back, so that
     * you can make changes to the machine setting
     */
5170
    machine->vtbl->GetId(machine, &mchiid.value);
5171
    VBOX_SESSION_OPEN(mchiid.value, machine);
E
Eric Blake 已提交
5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182
    data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);

    vboxSetBootDeviceOrder(def, data, machine);
    vboxAttachDrives(def, data, machine);
    vboxAttachSound(def, machine);
    vboxAttachNetwork(def, data, machine);
    vboxAttachSerial(def, data, machine);
    vboxAttachParallel(def, data, machine);
    vboxAttachVideo(def, machine);
    vboxAttachDisplay(def, data, machine);
    vboxAttachUSB(def, data, machine);
M
Matthias Bolte 已提交
5183
    vboxAttachSharedFolder(def, data, machine);
5184

5185 5186 5187 5188
    /* Save the machine settings made till now and close the
     * session. also free up the mchiid variable used.
     */
    rc = machine->vtbl->SaveSettings(machine);
5189
    VBOX_SESSION_CLOSE();
5190
    vboxIIDUnalloc(&mchiid);
5191

5192 5193
    ret = virGetDomain(conn, def->name, def->uuid);
    VBOX_RELEASE(machine);
5194

5195
    vboxIIDUnalloc(&iid);
5196 5197
    virDomainDefFree(def);

5198
    return ret;
5199 5200

cleanup:
5201
    VBOX_RELEASE(machine);
5202
    vboxIIDUnalloc(&iid);
5203 5204 5205 5206
    virDomainDefFree(def);
    return NULL;
}

5207
static int
5208
vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags)
5209
{
5210
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5211
    IMachine *machine    = NULL;
5212
    vboxIID iid = VBOX_IID_INITIALIZER;
5213
    nsresult rc;
5214 5215 5216
#if VBOX_API_VERSION >= 4000
    vboxArray media = VBOX_ARRAY_INITIALIZER;
#endif
5217 5218 5219 5220
    /* No managed save, so we explicitly reject
     * VIR_DOMAIN_UNDEFINE_MANAGED_SAVE.  No snapshot metadata for
     * VBox, so we can trivially ignore that flag.  */
    virCheckFlags(VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
5221

5222
    vboxIIDFromUUID(&iid, dom->uuid);
5223

5224
#if VBOX_API_VERSION < 4000
5225 5226 5227
    /* Block for checking if HDD's are attched to VM.
     * considering just IDE bus for now. Also skipped
     * chanel=1 and device=0 (Secondary Master) as currenlty
5228 5229 5230 5231
     * it is allocated to CD/DVD Drive by default.
     *
     * Only do this for VirtualBox 3.x and before. Since
     * VirtualBox 4.0 the Unregister method can do this for use.
5232 5233 5234
     */
    {
        PRUnichar *hddcnameUtf16 = NULL;
5235

5236 5237 5238
        char *hddcname = strdup("IDE");
        VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16);
        VIR_FREE(hddcname);
5239

5240
        /* Open a Session for the machine */
5241
        rc = VBOX_SESSION_OPEN(iid.value, machine);
5242 5243 5244 5245
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {

5246
# if VBOX_API_VERSION < 3001
5247 5248 5249 5250
                /* Disconnect all the drives if present */
                machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 0);
                machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 0, 1);
                machine->vtbl->DetachHardDisk(machine, hddcnameUtf16, 1, 1);
5251
# else  /* VBOX_API_VERSION >= 3001 */
5252 5253 5254
                /* get all the controller first, then the attachments and
                 * remove them all so that the machine can be undefined
                 */
5255
                vboxArray storageControllers = VBOX_ARRAY_INITIALIZER;
5256 5257
                int i = 0, j = 0;

5258 5259
                vboxArrayGet(&storageControllers, machine,
                             machine->vtbl->GetStorageControllers);
5260

5261 5262
                for (i = 0; i < storageControllers.count; i++) {
                    IStorageController *strCtl = storageControllers.items[i];
5263
                    PRUnichar *strCtlName = NULL;
5264
                    vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
5265 5266 5267 5268 5269

                    if (!strCtl)
                        continue;

                    strCtl->vtbl->GetName(strCtl, &strCtlName);
5270 5271 5272
                    vboxArrayGetWithPtrArg(&mediumAttachments, machine,
                                           machine->vtbl->GetMediumAttachmentsOfController,
                                           strCtlName);
5273

5274 5275
                    for (j = 0; j < mediumAttachments.count; j++) {
                        IMediumAttachment *medAtt = mediumAttachments.items[j];
5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291
                        PRInt32 port = ~0U;
                        PRInt32 device = ~0U;

                        if (!medAtt)
                            continue;

                        medAtt->vtbl->GetPort(medAtt, &port);
                        medAtt->vtbl->GetDevice(medAtt, &device);

                        if ((port != ~0U) && (device != ~0U)) {
                            machine->vtbl->DetachDevice(machine,
                                                        strCtlName,
                                                        port,
                                                        device);
                        }
                    }
5292

5293 5294
                    vboxArrayRelease(&storageControllers);

5295 5296
                    machine->vtbl->RemoveStorageController(machine, strCtlName);
                    VBOX_UTF16_FREE(strCtlName);
5297
                }
5298 5299

                vboxArrayRelease(&storageControllers);
5300
# endif /* VBOX_API_VERSION >= 3001 */
5301 5302

                machine->vtbl->SaveSettings(machine);
5303
            }
5304
            VBOX_SESSION_CLOSE();
5305
        }
5306 5307
        VBOX_UTF16_FREE(hddcnameUtf16);
    }
5308
#endif
5309

5310
#if VBOX_API_VERSION < 4000
5311
    rc = data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, iid.value, &machine);
5312 5313 5314
#else /* VBOX_API_VERSION >= 4000 */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
5315 5316
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5317 5318 5319 5320 5321 5322 5323 5324 5325 5326
        return -1;
    }

    /* We're not interested in the array returned by the Unregister method,
     * but in the side effect of unregistering the virtual machine. In order
     * to call the Unregister method correctly we need to use the vboxArray
     * wrapper here. */
    rc = vboxArrayGetWithUintArg(&media, machine, machine->vtbl->Unregister,
                                 CleanupMode_DetachAllReturnNone);
#endif /* VBOX_API_VERSION >= 4000 */
5327
    DEBUGIID("UUID of machine being undefined", iid.value);
5328

5329 5330
    if (NS_SUCCEEDED(rc)) {
#if VBOX_API_VERSION < 4000
5331
        machine->vtbl->DeleteSettings(machine);
5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347
#else /* VBOX_API_VERSION >= 4000 */
        IProgress *progress = NULL;

        /* The IMachine Delete method takes an array of IMedium items to be
         * deleted along with the virtual machine. We just want to pass an
         * empty array. But instead of adding a full vboxArraySetWithReturn to
         * the glue layer (in order to handle the required signature of the
         * Delete method) we use a local solution here. */
# ifdef WIN32
        SAFEARRAY *safeArray = NULL;
        typedef HRESULT __stdcall (*IMachine_Delete)(IMachine *self,
                                                     SAFEARRAY **media,
                                                     IProgress **progress);

        ((IMachine_Delete)machine->vtbl->Delete)(machine, &safeArray, &progress);
# else
5348 5349 5350 5351
        /* XPCOM doesn't like NULL as an array, even when the array size is 0.
         * Instead pass it a dummy array to avoid passing NULL. */
        IMedium *array[] = { NULL };
        machine->vtbl->Delete(machine, 0, array, &progress);
5352 5353 5354 5355 5356 5357
# endif
        if (progress != NULL) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
#endif /* VBOX_API_VERSION >= 4000 */
5358 5359
        ret = 0;
    } else {
5360 5361
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not delete the domain, rc=%08x"), (unsigned)rc);
5362 5363
    }

5364 5365 5366
#if VBOX_API_VERSION >= 4000
    vboxArrayUnalloc(&media);
#endif
5367
    vboxIIDUnalloc(&iid);
5368
    VBOX_RELEASE(machine);
5369 5370 5371 5372

    return ret;
}

5373 5374 5375 5376 5377 5378
static int
vboxDomainUndefine(virDomainPtr dom)
{
    return vboxDomainUndefineFlags(dom, 0);
}

5379 5380 5381
static int vboxDomainAttachDeviceImpl(virDomainPtr dom,
                                      const char *xml,
                                      int mediaChangeOnly ATTRIBUTE_UNUSED) {
5382
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5383
    IMachine *machine    = NULL;
5384
    vboxIID iid = VBOX_IID_INITIALIZER;
5385 5386 5387
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5388
    nsresult rc;
5389 5390

    if (VIR_ALLOC(def) < 0) {
5391
        virReportOOMError();
5392 5393 5394 5395 5396
        return ret;
    }

    def->os.type = strdup("hvm");

5397
    if (def->os.type == NULL) {
5398
        virReportOOMError();
5399 5400 5401
        goto cleanup;
    }

5402 5403
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5404
    if (dev == NULL)
5405 5406
        goto cleanup;

5407
    vboxIIDFromUUID(&iid, dom->uuid);
5408
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5409
    if (NS_FAILED(rc)) {
5410 5411
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5412 5413
        goto cleanup;
    }
5414

5415 5416
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5417

5418 5419
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5420
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5421
        } else {
5422
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5423 5424 5425 5426 5427 5428 5429
        }
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
#if VBOX_API_VERSION < 3001
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
5430 5431
                        if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                            dev->data.disk->src != NULL) {
5432 5433 5434 5435 5436 5437 5438 5439 5440
                            IDVDDrive *dvdDrive = NULL;
                            /* Currently CDROM/DVD Drive is always IDE
                             * Secondary Master so neglecting the following
                             * parameter dev->data.disk->bus
                             */
                            machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                            if (dvdDrive) {
                                IDVDImage *dvdImage          = NULL;
                                PRUnichar *dvdfileUtf16      = NULL;
5441 5442
                                vboxIID dvduuid = VBOX_IID_INITIALIZER;
                                vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
5443

5444
                                VBOX_UTF8_TO_UTF16(dev->data.disk->src, &dvdfileUtf16);
5445

5446 5447
                                data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
                                if (!dvdImage) {
5448
                                    data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage);
5449 5450
                                }
                                if (dvdImage) {
5451
                                    rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value);
5452
                                    if (NS_FAILED(rc)) {
5453 5454 5455 5456
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("can't get the uuid of the file to "
                                                         "be attached to cdrom: %s, rc=%08x"),
                                                       dev->data.disk->src, (unsigned)rc);
5457 5458 5459
                                    } else {
                                        /* unmount the previous mounted image */
                                        dvdDrive->vtbl->Unmount(dvdDrive);
5460
                                        rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
5461
                                        if (NS_FAILED(rc)) {
5462 5463 5464
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("could not attach the file to cdrom: %s, rc=%08x"),
                                                           dev->data.disk->src, (unsigned)rc);
5465
                                        } else {
5466
                                            ret = 0;
5467
                                            DEBUGIID("CD/DVD Image UUID:", dvduuid.value);
5468 5469
                                        }
                                    }
5470 5471

                                    VBOX_MEDIUM_RELEASE(dvdImage);
5472
                                }
5473
                                vboxIIDUnalloc(&dvduuid);
5474 5475
                                VBOX_UTF16_FREE(dvdfileUtf16);
                                VBOX_RELEASE(dvdDrive);
5476
                            }
5477 5478 5479
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
5480 5481
                        if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                            dev->data.disk->src != NULL) {
5482 5483 5484 5485 5486 5487 5488
                            IFloppyDrive *floppyDrive;
                            machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                            if (floppyDrive) {
                                rc = floppyDrive->vtbl->SetEnabled(floppyDrive, 1);
                                if (NS_SUCCEEDED(rc)) {
                                    IFloppyImage *floppyImage   = NULL;
                                    PRUnichar *fdfileUtf16      = NULL;
5489 5490
                                    vboxIID fduuid = VBOX_IID_INITIALIZER;
                                    vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
5491 5492 5493 5494 5495 5496 5497 5498
                                    VBOX_UTF8_TO_UTF16(dev->data.disk->src, &fdfileUtf16);
                                    rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                              fdfileUtf16,
                                                                              &floppyImage);

                                    if (!floppyImage) {
                                        data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                             fdfileUtf16,
5499
                                                                             fdemptyuuid.value,
5500 5501
                                                                             &floppyImage);
                                    }
5502

5503
                                    if (floppyImage) {
5504
                                        rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value);
5505
                                        if (NS_FAILED(rc)) {
5506 5507 5508 5509
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("can't get the uuid of the file to be "
                                                             "attached to floppy drive: %s, rc=%08x"),
                                                           dev->data.disk->src, (unsigned)rc);
5510
                                        } else {
5511
                                            rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value);
5512
                                            if (NS_FAILED(rc)) {
5513 5514 5515
                                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                                               _("could not attach the file to floppy drive: %s, rc=%08x"),
                                                               dev->data.disk->src, (unsigned)rc);
5516
                                            } else {
5517
                                                ret = 0;
5518
                                                DEBUGIID("attached floppy, UUID:", fduuid.value);
5519 5520
                                            }
                                        }
5521
                                        VBOX_MEDIUM_RELEASE(floppyImage);
5522
                                    }
5523
                                    vboxIIDUnalloc(&fduuid);
5524
                                    VBOX_UTF16_FREE(fdfileUtf16);
5525
                                }
5526
                                VBOX_RELEASE(floppyDrive);
5527
                            }
5528
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5529
                        }
5530 5531 5532 5533 5534 5535 5536
                    }
#else  /* VBOX_API_VERSION >= 3001 */
#endif /* VBOX_API_VERSION >= 3001 */
                } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
                } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
                    if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
                        if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
5537 5538
                        }
                    }
M
Matthias Bolte 已提交
5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557
                } else if (dev->type == VIR_DOMAIN_DEVICE_FS &&
                           dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) {
                    PRUnichar *nameUtf16;
                    PRUnichar *hostPathUtf16;
                    PRBool writable;

                    VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16);
                    VBOX_UTF8_TO_UTF16(dev->data.fs->src, &hostPathUtf16);
                    writable = !dev->data.fs->readonly;

#if VBOX_API_VERSION < 4000
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable);
#else /* VBOX_API_VERSION >= 4000 */
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable, PR_FALSE);
#endif /* VBOX_API_VERSION >= 4000 */

                    if (NS_FAILED(rc)) {
5558 5559 5560
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not attach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5561 5562 5563 5564 5565 5566
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
                    VBOX_UTF16_FREE(hostPathUtf16);
5567
                }
5568 5569
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5570
            }
5571
            VBOX_SESSION_CLOSE();
5572 5573 5574 5575
        }
    }

cleanup:
5576
    vboxIIDUnalloc(&iid);
5577 5578 5579 5580 5581
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5582 5583 5584 5585
static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml) {
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

5586 5587 5588 5589 5590 5591
static int
vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5592
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5593 5594
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5595 5596 5597
        return -1;
    }

5598 5599 5600 5601 5602
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags) {
5603 5604 5605
    virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
                  VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
5606

5607
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5608 5609
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5610 5611 5612 5613
        return -1;
    }

    return vboxDomainAttachDeviceImpl(dom, xml, 1);
5614 5615
}

5616
static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml) {
5617
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5618
    IMachine *machine    = NULL;
5619
    vboxIID iid = VBOX_IID_INITIALIZER;
5620 5621 5622
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5623
    nsresult rc;
5624 5625

    if (VIR_ALLOC(def) < 0) {
5626
        virReportOOMError();
5627 5628 5629 5630 5631
        return ret;
    }

    def->os.type = strdup("hvm");

5632
    if (def->os.type == NULL) {
5633
        virReportOOMError();
5634 5635 5636
        goto cleanup;
    }

5637 5638
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5639
    if (dev == NULL)
5640 5641
        goto cleanup;

5642
    vboxIIDFromUUID(&iid, dom->uuid);
5643
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5644
    if (NS_FAILED(rc)) {
5645 5646
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5647 5648
        goto cleanup;
    }
5649

5650 5651
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5652

5653 5654
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5655
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5656
        } else {
5657
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5658
        }
5659

5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
#if VBOX_API_VERSION < 3001
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                        if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                            IDVDDrive *dvdDrive = NULL;
                            /* Currently CDROM/DVD Drive is always IDE
                             * Secondary Master so neglecting the following
                             * parameter dev->data.disk->bus
                             */
                            machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                            if (dvdDrive) {
                                rc = dvdDrive->vtbl->Unmount(dvdDrive);
                                if (NS_FAILED(rc)) {
5676 5677 5678
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not de-attach the mounted ISO, rc=%08x"),
                                                   (unsigned)rc);
5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695
                                } else {
                                    ret = 0;
                                }
                                VBOX_RELEASE(dvdDrive);
                            }
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                        if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE) {
                            IFloppyDrive *floppyDrive;
                            machine->vtbl->GetFloppyDrive(machine, &floppyDrive);
                            if (floppyDrive) {
                                PRBool enabled = PR_FALSE;

                                floppyDrive->vtbl->GetEnabled(floppyDrive, &enabled);
                                if (enabled) {
                                    rc = floppyDrive->vtbl->Unmount(floppyDrive);
5696
                                    if (NS_FAILED(rc)) {
5697 5698 5699 5700
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("could not attach the file "
                                                         "to floppy drive, rc=%08x"),
                                                       (unsigned)rc);
5701 5702 5703
                                    } else {
                                        ret = 0;
                                    }
5704 5705 5706 5707 5708
                                } else {
                                    /* If you are here means floppy drive is already unmounted
                                     * so don't flag error, just say everything is fine and quit
                                     */
                                    ret = 0;
5709
                                }
5710
                                VBOX_RELEASE(floppyDrive);
5711
                            }
5712
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5713
                        }
5714 5715 5716 5717 5718 5719 5720
                    }
#else  /* VBOX_API_VERSION >= 3001 */
#endif /* VBOX_API_VERSION >= 3001 */
                } else if (dev->type == VIR_DOMAIN_DEVICE_NET) {
                } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
                    if (dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
                        if (dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
5721 5722
                        }
                    }
M
Matthias Bolte 已提交
5723 5724 5725 5726 5727 5728 5729 5730 5731
                } else if (dev->type == VIR_DOMAIN_DEVICE_FS &&
                           dev->data.fs->type == VIR_DOMAIN_FS_TYPE_MOUNT) {
                    PRUnichar *nameUtf16;

                    VBOX_UTF8_TO_UTF16(dev->data.fs->dst, &nameUtf16);

                    rc = machine->vtbl->RemoveSharedFolder(machine, nameUtf16);

                    if (NS_FAILED(rc)) {
5732 5733 5734
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not detach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5735 5736 5737 5738 5739
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
5740
                }
5741 5742
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5743
            }
5744
            VBOX_SESSION_CLOSE();
5745 5746 5747 5748
        }
    }

cleanup:
5749
    vboxIIDUnalloc(&iid);
5750 5751 5752 5753 5754
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5755 5756 5757 5758 5759 5760
static int
vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5761
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5762 5763
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5764 5765 5766 5767 5768 5769
        return -1;
    }

    return vboxDomainDetachDevice(dom, xml);
}

J
Jiri Denemark 已提交
5770 5771 5772 5773 5774
static int
vboxDomainSnapshotGetAll(virDomainPtr dom,
                         IMachine *machine,
                         ISnapshot ***snapshots)
{
5775
    vboxIID empty = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5776 5777 5778 5779 5780 5781 5782 5783
    ISnapshot **list = NULL;
    PRUint32 count;
    nsresult rc;
    unsigned int next;
    unsigned int top;

    rc = machine->vtbl->GetSnapshotCount(machine, &count);
    if (NS_FAILED(rc)) {
5784 5785 5786
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797
        goto error;
    }

    if (count == 0)
        goto out;

    if (VIR_ALLOC_N(list, count) < 0) {
        virReportOOMError();
        goto error;
    }

5798
#if VBOX_API_VERSION < 4000
5799
    rc = machine->vtbl->GetSnapshot(machine, empty.value, list);
5800 5801 5802
#else /* VBOX_API_VERSION >= 4000 */
    rc = machine->vtbl->FindSnapshot(machine, empty.value, list);
#endif /* VBOX_API_VERSION >= 4000 */
J
Jiri Denemark 已提交
5803
    if (NS_FAILED(rc) || !list[0]) {
5804 5805 5806
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get root snapshot for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5807 5808 5809 5810 5811 5812
        goto error;
    }

    /* BFS walk through snapshot tree */
    top = 1;
    for (next = 0; next < count; next++) {
5813
        vboxArray children = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
5814 5815 5816
        unsigned int i;

        if (!list[next]) {
5817 5818
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected number of snapshots < %u"), count);
J
Jiri Denemark 已提交
5819 5820 5821
            goto error;
        }

5822 5823
        rc = vboxArrayGet(&children, list[next],
                               list[next]->vtbl->GetChildren);
J
Jiri Denemark 已提交
5824
        if (NS_FAILED(rc)) {
5825 5826
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get children snapshots"));
J
Jiri Denemark 已提交
5827 5828
            goto error;
        }
5829 5830 5831
        for (i = 0; i < children.count; i++) {
            ISnapshot *child = children.items[i];
            if (!child)
J
Jiri Denemark 已提交
5832 5833
                continue;
            if (top == count) {
5834 5835
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected number of snapshots > %u"), count);
5836
                vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5837 5838
                goto error;
            }
5839 5840
            VBOX_ADDREF(child);
            list[top++] = child;
J
Jiri Denemark 已提交
5841
        }
5842
        vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879
    }

out:
    *snapshots = list;
    return count;

error:
    if (list) {
        for (next = 0; next < count; next++)
            VBOX_RELEASE(list[next]);
    }
    VIR_FREE(list);

    return -1;
}

static ISnapshot *
vboxDomainSnapshotGet(vboxGlobalData *data,
                      virDomainPtr dom,
                      IMachine *machine,
                      const char *name)
{
    ISnapshot **snapshots = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;
    int count = 0;
    int i;

    if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
        goto cleanup;

    for (i = 0; i < count; i++) {
        PRUnichar *nameUtf16;
        char *nameUtf8;

        rc = snapshots[i]->vtbl->GetName(snapshots[i], &nameUtf16);
        if (NS_FAILED(rc) || !nameUtf16) {
5880 5881
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
        VBOX_UTF16_FREE(nameUtf16);
        if (STREQ(name, nameUtf8))
            snapshot = snapshots[i];
        VBOX_UTF8_FREE(nameUtf8);

        if (snapshot)
            break;
    }

    if (!snapshot) {
5895 5896 5897
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s has no snapshots with name %s"),
                       dom->name, name);
J
Jiri Denemark 已提交
5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914
        goto cleanup;
    }

cleanup:
    if (count > 0) {
        for (i = 0; i < count; i++) {
            if (snapshots[i] != snapshot)
                VBOX_RELEASE(snapshots[i]);
        }
    }
    VIR_FREE(snapshots);
    return snapshot;
}

static virDomainSnapshotPtr
vboxDomainSnapshotCreateXML(virDomainPtr dom,
                            const char *xmlDesc,
5915
                            unsigned int flags)
J
Jiri Denemark 已提交
5916 5917 5918
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
    virDomainSnapshotDefPtr def = NULL;
5919
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933
    IMachine *machine = NULL;
    IConsole *console = NULL;
    IProgress *progress = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *name = NULL;
    PRUnichar *description = NULL;
    PRUint32 state;
    nsresult rc;
#if VBOX_API_VERSION == 2002
    nsresult result;
#else
    PRInt32 result;
#endif

5934 5935
    /* VBox has no snapshot metadata, so this flag is trivial.  */
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
5936

5937
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps,
5938
                                                data->xmlopt, 0, 0)))
J
Jiri Denemark 已提交
5939 5940
        goto cleanup;

5941
    if (def->ndisks) {
5942 5943
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk snapshots not supported yet"));
5944 5945 5946
        goto cleanup;
    }

5947
    vboxIIDFromUUID(&domiid, dom->uuid);
5948
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
5949
    if (NS_FAILED(rc)) {
5950 5951
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
5952 5953 5954 5955 5956
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
5957 5958
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
5959 5960 5961 5962 5963
        goto cleanup;
    }

    if ((state >= MachineState_FirstOnline)
        && (state <= MachineState_LastOnline)) {
5964
        rc = VBOX_SESSION_OPEN_EXISTING(domiid.value, machine);
J
Jiri Denemark 已提交
5965
    } else {
5966
        rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
5967
    }
5968

J
Jiri Denemark 已提交
5969 5970 5971
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
5972 5973 5974
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993
        goto cleanup;
    }

    VBOX_UTF8_TO_UTF16(def->name, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    if (def->description) {
        VBOX_UTF8_TO_UTF16(def->description, &description);
        if (!description) {
            virReportOOMError();
            goto cleanup;
        }
    }

    rc = console->vtbl->TakeSnapshot(console, name, description, &progress);
    if (NS_FAILED(rc) || !progress) {
5994 5995
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
5996 5997 5998 5999 6000 6001
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6002 6003
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6004 6005 6006 6007 6008
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6009 6010
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
J
Jiri Denemark 已提交
6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021
                  dom->name);
        goto cleanup;
    }

    ret = virGetDomainSnapshot(dom, def->name);

cleanup:
    VBOX_RELEASE(progress);
    VBOX_UTF16_FREE(description);
    VBOX_UTF16_FREE(name);
    VBOX_RELEASE(console);
6022
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
6023
    VBOX_RELEASE(machine);
6024
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6025 6026 6027 6028 6029
    virDomainSnapshotDefFree(def);
    return ret;
}

static char *
6030 6031
vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                             unsigned int flags)
J
Jiri Denemark 已提交
6032 6033 6034
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
6035
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    ISnapshot *parent = NULL;
    nsresult rc;
    virDomainSnapshotDefPtr def = NULL;
    PRUnichar *str16;
    char *str8;
    PRInt64 timestamp;
    PRBool online = PR_FALSE;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

6047 6048
    virCheckFlags(0, NULL);

6049
    vboxIIDFromUUID(&domiid, dom->uuid);
6050
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6051
    if (NS_FAILED(rc)) {
6052 6053
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065
        goto cleanup;
    }

    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

    if (VIR_ALLOC(def) < 0
        || !(def->name = strdup(snapshot->name)))
        goto no_memory;

    rc = snap->vtbl->GetDescription(snap, &str16);
    if (NS_FAILED(rc)) {
6066 6067 6068
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get description of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081
        goto cleanup;
    }
    if (str16) {
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
        def->description = strdup(str8);
        VBOX_UTF8_FREE(str8);
        if (!def->description)
            goto no_memory;
    }

    rc = snap->vtbl->GetTimeStamp(snap, &timestamp);
    if (NS_FAILED(rc)) {
6082 6083 6084
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get creation time of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6085 6086 6087 6088 6089 6090 6091
        goto cleanup;
    }
    /* timestamp is in milliseconds while creationTime in seconds */
    def->creationTime = timestamp / 1000;

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
6092 6093 6094
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6095 6096 6097 6098 6099
        goto cleanup;
    }
    if (parent) {
        rc = parent->vtbl->GetName(parent, &str16);
        if (NS_FAILED(rc) || !str16) {
6100 6101 6102
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get name of parent of snapshot %s"),
                           snapshot->name);
J
Jiri Denemark 已提交
6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
        def->parent = strdup(str8);
        VBOX_UTF8_FREE(str8);
        if (!def->parent)
            goto no_memory;
    }

    rc = snap->vtbl->GetOnline(snap, &online);
    if (NS_FAILED(rc)) {
6115 6116 6117
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6118 6119 6120 6121 6122 6123 6124 6125
        goto cleanup;
    }
    if (online)
        def->state = VIR_DOMAIN_RUNNING;
    else
        def->state = VIR_DOMAIN_SHUTOFF;

    virUUIDFormat(dom->uuid, uuidstr);
6126
    ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0);
J
Jiri Denemark 已提交
6127 6128 6129 6130 6131 6132

cleanup:
    virDomainSnapshotDefFree(def);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
6133
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6134 6135 6136 6137 6138 6139 6140 6141 6142
    return ret;

no_memory:
    virReportOOMError();
    goto cleanup;
}

static int
vboxDomainSnapshotNum(virDomainPtr dom,
6143
                      unsigned int flags)
J
Jiri Denemark 已提交
6144 6145
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6146
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6147 6148 6149 6150
    IMachine *machine = NULL;
    nsresult rc;
    PRUint32 snapshotCount;

6151 6152
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6153

6154
    vboxIIDFromUUID(&iid, dom->uuid);
6155
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6156
    if (NS_FAILED(rc)) {
6157 6158
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6159 6160 6161
        goto cleanup;
    }

6162 6163 6164 6165 6166 6167
    /* VBox snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

J
Jiri Denemark 已提交
6168 6169
    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
    if (NS_FAILED(rc)) {
6170 6171 6172
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6173 6174 6175
        goto cleanup;
    }

6176 6177 6178 6179 6180
    /* VBox has at most one root snapshot.  */
    if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS))
        ret = 1;
    else
        ret = snapshotCount;
J
Jiri Denemark 已提交
6181 6182 6183

cleanup:
    VBOX_RELEASE(machine);
6184
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6185 6186 6187 6188 6189 6190 6191
    return ret;
}

static int
vboxDomainSnapshotListNames(virDomainPtr dom,
                            char **names,
                            int nameslen,
6192
                            unsigned int flags)
J
Jiri Denemark 已提交
6193 6194
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6195
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6196 6197 6198 6199 6200 6201
    IMachine *machine = NULL;
    nsresult rc;
    ISnapshot **snapshots = NULL;
    int count = 0;
    int i;

6202 6203
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6204

6205
    vboxIIDFromUUID(&iid, dom->uuid);
6206
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6207
    if (NS_FAILED(rc)) {
6208 6209
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6210 6211 6212
        goto cleanup;
    }

6213 6214 6215 6216 6217
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) {
        vboxIID empty = VBOX_IID_INITIALIZER;

        if (VIR_ALLOC_N(snapshots, 1) < 0) {
            virReportOOMError();
            goto cleanup;
        }
#if VBOX_API_VERSION < 4000
        rc = machine->vtbl->GetSnapshot(machine, empty.value, snapshots);
#else /* VBOX_API_VERSION >= 4000 */
        rc = machine->vtbl->FindSnapshot(machine, empty.value, snapshots);
#endif /* VBOX_API_VERSION >= 4000 */
        if (NS_FAILED(rc) || !snapshots[0]) {
6231 6232 6233
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get root snapshot for domain %s"),
                           dom->name);
6234 6235 6236 6237 6238 6239 6240
            goto cleanup;
        }
        count = 1;
    } else {
        if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
            goto cleanup;
    }
J
Jiri Denemark 已提交
6241 6242 6243 6244 6245 6246 6247 6248 6249 6250

    for (i = 0; i < nameslen; i++) {
        PRUnichar *nameUtf16;
        char *name;

        if (i >= count)
            break;

        rc = snapshots[i]->vtbl->GetName(snapshots[i], &nameUtf16);
        if (NS_FAILED(rc) || !nameUtf16) {
6251 6252
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(nameUtf16, &name);
        VBOX_UTF16_FREE(nameUtf16);
        names[i] = strdup(name);
        VBOX_UTF8_FREE(name);
        if (!names[i]) {
            virReportOOMError();
            goto cleanup;
        }
    }

    if (count <= nameslen)
        ret = count;
    else
        ret = nameslen;

cleanup:
    if (count > 0) {
        for (i = 0; i < count; i++)
            VBOX_RELEASE(snapshots[i]);
    }
    VIR_FREE(snapshots);
    VBOX_RELEASE(machine);
6277
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6278 6279 6280 6281 6282 6283
    return ret;
}

static virDomainSnapshotPtr
vboxDomainSnapshotLookupByName(virDomainPtr dom,
                               const char *name,
6284
                               unsigned int flags)
J
Jiri Denemark 已提交
6285 6286
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6287
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6288 6289 6290 6291
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

6292 6293
    virCheckFlags(0, NULL);

6294
    vboxIIDFromUUID(&iid, dom->uuid);
6295
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6296
    if (NS_FAILED(rc)) {
6297 6298
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309
        goto cleanup;
    }

    if (!(snapshot = vboxDomainSnapshotGet(data, dom, machine, name)))
        goto cleanup;

    ret = virGetDomainSnapshot(dom, name);

cleanup:
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
6310
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6311 6312 6313 6314 6315
    return ret;
}

static int
vboxDomainHasCurrentSnapshot(virDomainPtr dom,
6316
                             unsigned int flags)
J
Jiri Denemark 已提交
6317 6318
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6319
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6320 6321 6322 6323
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

6324 6325
    virCheckFlags(0, -1);

6326
    vboxIIDFromUUID(&iid, dom->uuid);
6327
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6328
    if (NS_FAILED(rc)) {
6329 6330
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6331 6332 6333 6334 6335
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6336 6337
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
6338 6339 6340 6341 6342 6343 6344 6345 6346 6347
        goto cleanup;
    }

    if (snapshot)
        ret = 1;
    else
        ret = 0;

cleanup:
    VBOX_RELEASE(machine);
6348
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6349 6350 6351
    return ret;
}

6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370
static virDomainSnapshotPtr
vboxDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    ISnapshot *parent = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

    virCheckFlags(0, NULL);

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
6371 6372
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6373 6374 6375 6376 6377 6378 6379 6380
        goto cleanup;
    }

    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
6381 6382 6383
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
6384 6385 6386
        goto cleanup;
    }
    if (!parent) {
6387 6388 6389
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshot->name);
6390 6391 6392 6393 6394
        goto cleanup;
    }

    rc = parent->vtbl->GetName(parent, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6395 6396 6397
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get name of parent of snapshot %s"),
                       snapshot->name);
6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417
        goto cleanup;
    }
    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    ret = virGetDomainSnapshot(dom, name);

cleanup:
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

J
Jiri Denemark 已提交
6418 6419
static virDomainSnapshotPtr
vboxDomainSnapshotCurrent(virDomainPtr dom,
6420
                          unsigned int flags)
J
Jiri Denemark 已提交
6421 6422
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6423
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6424 6425 6426 6427 6428 6429
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

6430 6431
    virCheckFlags(0, NULL);

6432
    vboxIIDFromUUID(&iid, dom->uuid);
6433
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6434
    if (NS_FAILED(rc)) {
6435 6436
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6437 6438 6439 6440 6441
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6442 6443
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
6444 6445 6446 6447
        goto cleanup;
    }

    if (!snapshot) {
6448 6449
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain has no snapshots"));
J
Jiri Denemark 已提交
6450 6451 6452 6453 6454
        goto cleanup;
    }

    rc = snapshot->vtbl->GetName(snapshot, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6455 6456
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
J
Jiri Denemark 已提交
6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472
        goto cleanup;
    }

    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    ret = virGetDomainSnapshot(dom, name);

cleanup:
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
6473
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6474 6475 6476
    return ret;
}

6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495
static int
vboxDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    ISnapshot *current = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

    virCheckFlags(0, -1);

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
6496 6497
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6498 6499 6500 6501 6502 6503 6504 6505
        goto cleanup;
    }

    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

    rc = machine->vtbl->GetCurrentSnapshot(machine, &current);
    if (NS_FAILED(rc)) {
6506 6507
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
6508 6509 6510 6511 6512 6513 6514 6515 6516
        goto cleanup;
    }
    if (!current) {
        ret = 0;
        goto cleanup;
    }

    rc = current->vtbl->GetName(current, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6517 6518
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555
        goto cleanup;
    }

    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
    if (!name) {
        virReportOOMError();
        goto cleanup;
    }

    ret = STREQ(snapshot->name, name);

cleanup:
    VBOX_UTF8_FREE(name);
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(current);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

static int
vboxDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    nsresult rc;

    virCheckFlags(0, -1);

    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
6556 6557
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573
        goto cleanup;
    }

    /* Check that snapshot exists.  If so, there is no metadata.  */
    if (!(snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name)))
        goto cleanup;

    ret = 0;

cleanup:
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}

J
Jiri Denemark 已提交
6574 6575 6576 6577 6578 6579 6580
#if VBOX_API_VERSION < 3001
static int
vboxDomainSnapshotRestore(virDomainPtr dom,
                          IMachine *machine,
                          ISnapshot *snapshot)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6581
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6582 6583
    nsresult rc;

6584 6585
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
6586 6587
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
6588 6589 6590
        goto cleanup;
    }

6591
    rc = machine->vtbl->SetCurrentSnapshot(machine, iid.value);
J
Jiri Denemark 已提交
6592
    if (NS_FAILED(rc)) {
6593 6594
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
6595 6596 6597 6598 6599 6600
        goto cleanup;
    }

    ret = 0;

cleanup:
6601
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615
    return ret;
}
#else
static int
vboxDomainSnapshotRestore(virDomainPtr dom,
                          IMachine *machine,
                          ISnapshot *snapshot)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    IConsole *console = NULL;
    IProgress *progress = NULL;
    PRUint32 state;
    nsresult rc;
    PRInt32 result;
6616
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6617

6618 6619
    rc = machine->vtbl->GetId(machine, &domiid.value);
    if (NS_FAILED(rc)) {
6620 6621
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain UUID"));
J
Jiri Denemark 已提交
6622 6623 6624 6625 6626
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6627 6628
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6629 6630 6631 6632 6633
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6634 6635
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s is already running"), dom->name);
J
Jiri Denemark 已提交
6636 6637 6638
        goto cleanup;
    }

6639
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6640 6641 6642
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6643 6644 6645
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6646 6647 6648 6649 6650 6651
        goto cleanup;
    }

    rc = console->vtbl->RestoreSnapshot(console, snapshot, &progress);
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
6652 6653
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot restore domain snapshot for running domain"));
J
Jiri Denemark 已提交
6654
        } else {
6655 6656 6657
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not restore snapshot for domain %s"),
                           dom->name);
J
Jiri Denemark 已提交
6658 6659 6660 6661 6662 6663 6664
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6665 6666
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
6667 6668 6669 6670 6671 6672 6673 6674
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(progress);
    VBOX_RELEASE(console);
6675
    VBOX_SESSION_CLOSE();
6676
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6677 6678 6679 6680 6681 6682
    return ret;
}
#endif

static int
vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
6683
                           unsigned int flags)
J
Jiri Denemark 已提交
6684 6685 6686
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6687
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6688 6689 6690 6691 6692 6693 6694
    IMachine *machine = NULL;
    ISnapshot *newSnapshot = NULL;
    ISnapshot *prevSnapshot = NULL;
    PRBool online = PR_FALSE;
    PRUint32 state;
    nsresult rc;

6695 6696
    virCheckFlags(0, -1);

6697
    vboxIIDFromUUID(&domiid, dom->uuid);
6698
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6699
    if (NS_FAILED(rc)) {
6700 6701
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6702 6703 6704 6705 6706 6707 6708 6709 6710
        goto cleanup;
    }

    newSnapshot = vboxDomainSnapshotGet(data, dom, machine, snapshot->name);
    if (!newSnapshot)
        goto cleanup;

    rc = newSnapshot->vtbl->GetOnline(newSnapshot, &online);
    if (NS_FAILED(rc)) {
6711 6712 6713
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6714 6715 6716 6717 6718
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &prevSnapshot);
    if (NS_FAILED(rc)) {
6719 6720 6721
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6722 6723 6724 6725 6726
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6727 6728
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6729 6730 6731 6732 6733
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6734 6735
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot revert snapshot of running domain"));
J
Jiri Denemark 已提交
6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751
        goto cleanup;
    }

    if (vboxDomainSnapshotRestore(dom, machine, newSnapshot))
        goto cleanup;

    if (online) {
        ret = vboxDomainCreate(dom);
        if (!ret)
            vboxDomainSnapshotRestore(dom, machine, prevSnapshot);
    } else
        ret = 0;

cleanup:
    VBOX_RELEASE(prevSnapshot);
    VBOX_RELEASE(newSnapshot);
6752
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6753 6754 6755 6756 6757 6758 6759 6760 6761
    return ret;
}

static int
vboxDomainSnapshotDeleteSingle(vboxGlobalData *data,
                               IConsole *console,
                               ISnapshot *snapshot)
{
    IProgress *progress = NULL;
6762
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6763 6764 6765 6766 6767 6768 6769 6770
    int ret = -1;
    nsresult rc;
#if VBOX_API_VERSION == 2002
    nsresult result;
#else
    PRInt32 result;
#endif

6771 6772
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
6773 6774
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
6775 6776 6777 6778
        goto cleanup;
    }

#if VBOX_API_VERSION < 3001
6779
    rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
6780
#else
6781
    rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
6782 6783 6784
#endif
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
6785 6786
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot delete domain snapshot for running domain"));
J
Jiri Denemark 已提交
6787
        } else {
6788 6789
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("could not delete snapshot"));
J
Jiri Denemark 已提交
6790 6791 6792 6793 6794 6795 6796
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6797 6798
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not delete snapshot"));
J
Jiri Denemark 已提交
6799 6800 6801 6802 6803 6804 6805
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(progress);
6806
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6807 6808 6809 6810 6811 6812 6813 6814
    return ret;
}

static int
vboxDomainSnapshotDeleteTree(vboxGlobalData *data,
                             IConsole *console,
                             ISnapshot *snapshot)
{
6815
    vboxArray children = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
6816 6817 6818 6819
    int ret = -1;
    nsresult rc;
    unsigned int i;

6820
    rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren);
J
Jiri Denemark 已提交
6821
    if (NS_FAILED(rc)) {
6822 6823
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get children snapshots"));
J
Jiri Denemark 已提交
6824 6825 6826
        goto cleanup;
    }

6827 6828 6829
    for (i = 0; i < children.count; i++) {
        if (vboxDomainSnapshotDeleteTree(data, console, children.items[i]))
            goto cleanup;
J
Jiri Denemark 已提交
6830 6831 6832 6833 6834
    }

    ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot);

cleanup:
6835
    vboxArrayRelease(&children);
J
Jiri Denemark 已提交
6836 6837 6838 6839 6840 6841 6842 6843 6844
    return ret;
}

static int
vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                         unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6845
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6846 6847 6848 6849 6850 6851
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    IConsole *console = NULL;
    PRUint32 state;
    nsresult rc;

6852 6853
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
6854

6855
    vboxIIDFromUUID(&domiid, dom->uuid);
6856
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6857
    if (NS_FAILED(rc)) {
6858 6859
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6860 6861 6862 6863 6864 6865 6866 6867 6868
        goto cleanup;
    }

    snap = vboxDomainSnapshotGet(data, dom, machine, snapshot->name);
    if (!snap)
        goto cleanup;

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6869 6870
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6871 6872 6873
        goto cleanup;
    }

6874 6875 6876 6877 6878 6879 6880
    /* VBOX snapshots do not require any libvirt metadata, making this
     * flag trivial once we know we have a valid snapshot.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY) {
        ret = 0;
        goto cleanup;
    }

J
Jiri Denemark 已提交
6881 6882
    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6883 6884
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot delete snapshots of running domain"));
J
Jiri Denemark 已提交
6885 6886 6887
        goto cleanup;
    }

6888
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6889 6890 6891
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6892 6893 6894
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905
        goto cleanup;
    }

    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
        ret = vboxDomainSnapshotDeleteTree(data, console, snap);
    else
        ret = vboxDomainSnapshotDeleteSingle(data, console, snap);

cleanup:
    VBOX_RELEASE(console);
    VBOX_RELEASE(snap);
6906
    vboxIIDUnalloc(&domiid);
6907
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
6908 6909 6910
    return ret;
}

6911
#if VBOX_API_VERSION <= 2002 || VBOX_API_VERSION >= 4000
6912
    /* No Callback support for VirtualBox 2.2.* series */
6913 6914
    /* No Callback support for VirtualBox 4.* series */
#else /* !(VBOX_API_VERSION == 2002 || VBOX_API_VERSION >= 4000) */
6915 6916

/* Functions needed for Callbacks */
6917
static nsresult PR_COM_METHOD
6918
vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6919 6920
                                 PRUnichar *machineId, PRUint32 state)
{
6921 6922 6923 6924 6925 6926
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

6927
    VIR_DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state);
6928 6929 6930 6931 6932 6933 6934
    DEBUGPRUnichar("machineId", machineId);

    if (machineId) {
        char *machineIdUtf8       = NULL;
        unsigned char uuid[VIR_UUID_BUFLEN];

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
6935
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
6936 6937 6938

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
6939
            virDomainEventPtr ev;
6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969

            if (state == MachineState_Starting) {
                event  = VIR_DOMAIN_EVENT_STARTED;
                detail = VIR_DOMAIN_EVENT_STARTED_BOOTED;
            } else if (state == MachineState_Restoring) {
                event  = VIR_DOMAIN_EVENT_STARTED;
                detail = VIR_DOMAIN_EVENT_STARTED_RESTORED;
            } else if (state == MachineState_Paused) {
                event  = VIR_DOMAIN_EVENT_SUSPENDED;
                detail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
            } else if (state == MachineState_Running) {
                event  = VIR_DOMAIN_EVENT_RESUMED;
                detail = VIR_DOMAIN_EVENT_RESUMED_UNPAUSED;
            } else if (state == MachineState_PoweredOff) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
            } else if (state == MachineState_Stopping) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_DESTROYED;
            } else if (state == MachineState_Aborted) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_CRASHED;
            } else if (state == MachineState_Saving) {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_SAVED;
            } else {
                event  = VIR_DOMAIN_EVENT_STOPPED;
                detail = VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN;
            }

6970 6971
            ev = virDomainEventNewFromDom(dom, event, detail);

6972 6973
            if (ev)
                virDomainEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
6974 6975 6976 6977 6978 6979 6980 6981
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

6982
static nsresult PR_COM_METHOD
6983
vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6984 6985
                                PRUnichar *machineId)
{
6986
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
6987 6988 6989 6990 6991
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

6992
static nsresult PR_COM_METHOD
6993
vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6994 6995 6996
                                 PRUnichar *machineId, PRUnichar *key,
                                 PRUnichar *value,
                                 PRUnichar **error ATTRIBUTE_UNUSED,
6997
                                 PRBool *allowChange ATTRIBUTE_UNUSED)
6998
{
6999
    VIR_DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false");
7000 7001 7002 7003 7004 7005 7006
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

7007
static nsresult PR_COM_METHOD
7008 7009
vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *machineId,
7010 7011
                              PRUnichar *key, PRUnichar *value)
{
7012
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7013 7014 7015 7016 7017 7018 7019
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

7020
# if VBOX_API_VERSION < 3001
7021
static nsresult PR_COM_METHOD
7022 7023 7024 7025
vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *mediaId,
                              PRUint32 mediaType ATTRIBUTE_UNUSED,
                              PRBool registered ATTRIBUTE_UNUSED)
7026
{
7027 7028
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
    VIR_DEBUG("mediaType: %d", mediaType);
7029 7030 7031 7032
    DEBUGPRUnichar("mediaId", mediaId);

    return NS_OK;
}
7033 7034
# else  /* VBOX_API_VERSION >= 3001 */
# endif /* VBOX_API_VERSION >= 3001 */
7035

7036
static nsresult PR_COM_METHOD
7037
vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7038 7039
                                PRUnichar *machineId, PRBool registered)
{
7040 7041 7042 7043 7044 7045
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

7046
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
7047 7048 7049 7050 7051 7052 7053
    DEBUGPRUnichar("machineId", machineId);

    if (machineId) {
        char *machineIdUtf8       = NULL;
        unsigned char uuid[VIR_UUID_BUFLEN];

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
7054
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
7055 7056 7057

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
7058
            virDomainEventPtr ev;
7059 7060

            /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED
J
Ján Tomko 已提交
7061
             * event because the when the machine is de-registered the call
7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073
             * to vboxDomainLookupByUUID fails and thus we don't get any
             * dom pointer which is necessary (null dom pointer doesn't work)
             * to show the VIR_DOMAIN_EVENT_UNDEFINED event
             */
            if (registered) {
                event  = VIR_DOMAIN_EVENT_DEFINED;
                detail = VIR_DOMAIN_EVENT_DEFINED_ADDED;
            } else {
                event  = VIR_DOMAIN_EVENT_UNDEFINED;
                detail = VIR_DOMAIN_EVENT_UNDEFINED_REMOVED;
            }

7074 7075
            ev = virDomainEventNewFromDom(dom, event, detail);

7076 7077
            if (ev)
                virDomainEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
7078 7079 7080 7081 7082 7083 7084 7085
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

7086
static nsresult PR_COM_METHOD
7087 7088 7089
vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                 PRUnichar *machineId,
                                 PRUint32 state ATTRIBUTE_UNUSED)
7090
{
7091
    VIR_DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state);
7092 7093 7094 7095 7096
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

7097
static nsresult PR_COM_METHOD
7098 7099
vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                            PRUnichar *machineId,
7100 7101
                            PRUnichar *snapshotId)
{
7102
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7103 7104 7105 7106 7107 7108
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

7109
static nsresult PR_COM_METHOD
7110 7111
vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                PRUnichar *machineId,
7112 7113
                                PRUnichar *snapshotId)
{
7114
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7115 7116 7117 7118 7119 7120
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

7121
static nsresult PR_COM_METHOD
7122 7123
vboxCallbackOnSnapshotChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                             PRUnichar *machineId,
7124 7125
                             PRUnichar *snapshotId)
{
7126
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7127 7128 7129 7130 7131 7132
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

7133
static nsresult PR_COM_METHOD
7134
vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7135 7136 7137
                                  PRUnichar *machineId, PRUnichar *name,
                                  PRUnichar *value, PRUnichar *flags)
{
7138
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7139 7140 7141 7142 7143 7144 7145 7146
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("name", name);
    DEBUGPRUnichar("value", value);
    DEBUGPRUnichar("flags", flags);

    return NS_OK;
}

7147
static nsresult PR_COM_METHOD
7148
vboxCallbackAddRef(nsISupports *pThis ATTRIBUTE_UNUSED)
7149
{
7150 7151 7152 7153
    nsresult c;

    c = ++g_pVBoxGlobalData->vboxCallBackRefCount;

7154
    VIR_DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c);
7155 7156 7157 7158

    return c;
}

7159 7160 7161
static nsresult PR_COM_METHOD
vboxCallbackRelease(nsISupports *pThis)
{
7162 7163 7164 7165 7166 7167 7168 7169 7170
    nsresult c;

    c = --g_pVBoxGlobalData->vboxCallBackRefCount;
    if (c == 0) {
        /* delete object */
        VIR_FREE(pThis->vtbl);
        VIR_FREE(pThis);
    }

7171
    VIR_DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c);
7172 7173 7174 7175

    return c;
}

7176 7177 7178
static nsresult PR_COM_METHOD
vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp)
{
7179 7180 7181 7182 7183
    IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis;
    static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID;
    static const nsID isupportIID = NS_ISUPPORTS_IID;

    /* Match UUID for IVirtualBoxCallback class */
7184 7185
    if (memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 ||
        memcmp(iid, &isupportIID, sizeof(nsID)) == 0) {
7186 7187 7188
        g_pVBoxGlobalData->vboxCallBackRefCount++;
        *resultp = that;

7189
        VIR_DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount);
7190 7191 7192 7193 7194

        return NS_OK;
    }


7195
    VIR_DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis);
7196 7197 7198 7199 7200 7201
    DEBUGUUID("The UUID Callback Interface expects", iid);
    DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID);
    return NS_NOINTERFACE;
}


7202
static IVirtualBoxCallback *vboxAllocCallbackObj(void) {
7203 7204
    IVirtualBoxCallback *vboxCallback = NULL;

7205
    /* Allocate, Initialize and return a valid
7206 7207 7208
     * IVirtualBoxCallback object here
     */
    if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) {
7209
        VIR_FREE(vboxCallback);
7210
        virReportOOMError();
7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221
        return NULL;
    }

    {
        vboxCallback->vtbl->nsisupports.AddRef          = &vboxCallbackAddRef;
        vboxCallback->vtbl->nsisupports.Release         = &vboxCallbackRelease;
        vboxCallback->vtbl->nsisupports.QueryInterface  = &vboxCallbackQueryInterface;
        vboxCallback->vtbl->OnMachineStateChange        = &vboxCallbackOnMachineStateChange;
        vboxCallback->vtbl->OnMachineDataChange         = &vboxCallbackOnMachineDataChange;
        vboxCallback->vtbl->OnExtraDataCanChange        = &vboxCallbackOnExtraDataCanChange;
        vboxCallback->vtbl->OnExtraDataChange           = &vboxCallbackOnExtraDataChange;
7222
# if VBOX_API_VERSION < 3001
7223
        vboxCallback->vtbl->OnMediaRegistered           = &vboxCallbackOnMediaRegistered;
7224 7225
# else  /* VBOX_API_VERSION >= 3001 */
# endif /* VBOX_API_VERSION >= 3001 */
7226 7227 7228
        vboxCallback->vtbl->OnMachineRegistered         = &vboxCallbackOnMachineRegistered;
        vboxCallback->vtbl->OnSessionStateChange        = &vboxCallbackOnSessionStateChange;
        vboxCallback->vtbl->OnSnapshotTaken             = &vboxCallbackOnSnapshotTaken;
7229
# if VBOX_API_VERSION < 3002
7230
        vboxCallback->vtbl->OnSnapshotDiscarded         = &vboxCallbackOnSnapshotDiscarded;
7231 7232 7233
# else /* VBOX_API_VERSION >= 3002 */
        vboxCallback->vtbl->OnSnapshotDeleted           = &vboxCallbackOnSnapshotDiscarded;
# endif /* VBOX_API_VERSION >= 3002 */
7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258
        vboxCallback->vtbl->OnSnapshotChange            = &vboxCallbackOnSnapshotChange;
        vboxCallback->vtbl->OnGuestPropertyChange       = &vboxCallbackOnGuestPropertyChange;
        g_pVBoxGlobalData->vboxCallBackRefCount = 1;

    }

    return vboxCallback;
}

static void vboxReadCallback(int watch ATTRIBUTE_UNUSED,
                             int fd,
                             int events ATTRIBUTE_UNUSED,
                             void *opaque ATTRIBUTE_UNUSED) {
    if (fd >= 0) {
        g_pVBoxGlobalData->vboxQueue->vtbl->ProcessPendingEvents(g_pVBoxGlobalData->vboxQueue);
    } else {
        nsresult rc;
        PLEvent *pEvent = NULL;

        rc = g_pVBoxGlobalData->vboxQueue->vtbl->WaitForEvent(g_pVBoxGlobalData->vboxQueue, &pEvent);
        if (NS_SUCCEEDED(rc))
            g_pVBoxGlobalData->vboxQueue->vtbl->HandleEvent(g_pVBoxGlobalData->vboxQueue, pEvent);
    }
}

7259 7260 7261 7262
static int vboxConnectDomainEventRegister(virConnectPtr conn,
                                          virConnectDomainEventCallback callback,
                                          void *opaque,
                                          virFreeCallback freecb) {
7263
    VBOX_OBJECT_CHECK(conn, int, -1);
7264
    int vboxRet          = -1;
7265
    nsresult rc;
7266 7267 7268 7269 7270 7271

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

7272
    if (data->vboxCallback == NULL) {
7273
        data->vboxCallback = vboxAllocCallbackObj();
7274 7275 7276 7277
        if (data->vboxCallback != NULL) {
            rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
            if (NS_SUCCEEDED(rc)) {
                vboxRet = 0;
7278 7279
            }
        }
7280 7281 7282
    } else {
        vboxRet = 0;
    }
7283

7284 7285 7286 7287 7288 7289 7290
    /* Get the vbox file handle and add a event handle to it
     * so that the events can be passed down to the user
     */
    if (vboxRet == 0) {
        if (data->fdWatch < 0) {
            PRInt32 vboxFileHandle;
            vboxFileHandle = data->vboxQueue->vtbl->GetEventQueueSelectFD(data->vboxQueue);
7291

7292 7293
            data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL);
        }
7294

7295 7296 7297 7298 7299
        if (data->fdWatch >= 0) {
            /* Once a callback is registered with virtualbox, use a list
             * to store the callbacks registered with libvirt so that
             * later you can iterate over them
             */
7300

7301 7302
            ret = virDomainEventStateRegister(conn, data->domainEvents,
                                              callback, opaque, freecb);
7303
            VIR_DEBUG("virDomainEventStateRegister (ret = %d) (conn: %p, "
7304
                      "callback: %p, opaque: %p, "
7305
                      "freecb: %p)", ret, conn, callback,
7306
                      opaque, freecb);
7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
        return ret;
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

7322 7323
static int vboxConnectDomainEventDeregister(virConnectPtr conn,
                                            virConnectDomainEventCallback callback) {
7324
    VBOX_OBJECT_CHECK(conn, int, -1);
7325
    int cnt;
7326 7327 7328 7329 7330 7331

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

7332 7333
    cnt = virDomainEventStateDeregister(conn, data->domainEvents,
                                        callback);
7334

7335 7336 7337
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
7338

7339 7340 7341
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
7342 7343 7344 7345 7346 7347 7348
    }

    vboxDriverUnlock(data);

    return ret;
}

7349 7350 7351 7352 7353 7354
static int vboxConnectDomainEventRegisterAny(virConnectPtr conn,
                                             virDomainPtr dom,
                                             int eventID,
                                             virConnectDomainEventGenericCallback callback,
                                             void *opaque,
                                             virFreeCallback freecb) {
7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392
    VBOX_OBJECT_CHECK(conn, int, -1);
    int vboxRet          = -1;
    nsresult rc;

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

    if (data->vboxCallback == NULL) {
        data->vboxCallback = vboxAllocCallbackObj();
        if (data->vboxCallback != NULL) {
            rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
            if (NS_SUCCEEDED(rc)) {
                vboxRet = 0;
            }
        }
    } else {
        vboxRet = 0;
    }

    /* Get the vbox file handle and add a event handle to it
     * so that the events can be passed down to the user
     */
    if (vboxRet == 0) {
        if (data->fdWatch < 0) {
            PRInt32 vboxFileHandle;
            vboxFileHandle = data->vboxQueue->vtbl->GetEventQueueSelectFD(data->vboxQueue);

            data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL);
        }

        if (data->fdWatch >= 0) {
            /* Once a callback is registered with virtualbox, use a list
             * to store the callbacks registered with libvirt so that
             * later you can iterate over them
             */

7393 7394 7395
            if (virDomainEventStateRegisterID(conn, data->domainEvents,
                                              dom, eventID,
                                              callback, opaque, freecb, &ret) < 0)
7396
                ret = -1;
7397
            VIR_DEBUG("virDomainEventStateRegisterID (ret = %d) (conn: %p, "
7398
                      "callback: %p, opaque: %p, "
7399
                      "freecb: %p)", ret, conn, callback,
7400
                      opaque, freecb);
7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
        return ret;
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

7416 7417
static int vboxConnectDomainEventDeregisterAny(virConnectPtr conn,
                                               int callbackID) {
7418
    VBOX_OBJECT_CHECK(conn, int, -1);
7419
    int cnt;
7420 7421 7422 7423 7424 7425

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

7426 7427
    cnt = virDomainEventStateDeregisterID(conn, data->domainEvents,
                                          callbackID);
7428

7429 7430 7431
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
7432

7433 7434 7435
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
7436 7437 7438 7439 7440 7441 7442
    }

    vboxDriverUnlock(data);

    return ret;
}

7443
#endif /* !(VBOX_API_VERSION == 2002 || VBOX_API_VERSION >= 4000) */
7444

7445 7446 7447 7448 7449
/**
 * The Network Functions here on
 */
static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
7450 7451
                                        unsigned int flags)
{
7452 7453
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
7454 7455
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

7456 7457 7458 7459 7460 7461 7462 7463
    if (STRNEQ(conn->driver->name, "VBOX"))
        goto cleanup;

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
        goto cleanup;

7464
    VIR_DEBUG("network initialized");
7465 7466 7467 7468 7469 7470 7471 7472
    /* conn->networkPrivateData = some network specific data */
    return VIR_DRV_OPEN_SUCCESS;

cleanup:
    return VIR_DRV_OPEN_DECLINED;
}

static int vboxNetworkClose(virConnectPtr conn) {
7473
    VIR_DEBUG("network uninitialized");
7474 7475 7476 7477
    conn->networkPrivateData = NULL;
    return 0;
}

7478
static int vboxConnectNumOfNetworks(virConnectPtr conn) {
7479
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7480
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7481
    int i = 0;
7482

7483
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7484

7485 7486 7487 7488
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
7489
            PRUint32 interfaceType = 0;
7490

7491
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7492 7493
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7494

7495
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7496

7497 7498
                if (status == HostNetworkInterfaceStatus_Up)
                    ret++;
7499 7500 7501 7502
            }
        }
    }

7503 7504
    vboxArrayRelease(&networkInterfaces);

7505 7506
    VBOX_RELEASE(host);

7507
    VIR_DEBUG("numActive: %d", ret);
7508
    return ret;
7509 7510
}

7511
static int vboxConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
7512
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7513
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7514
    int i = 0;
7515

7516 7517 7518 7519
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7520

7521
        if (networkInterface) {
7522
            PRUint32 interfaceType = 0;
7523

7524
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7525

7526 7527
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7528

7529
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7530

7531 7532 7533
                if (status == HostNetworkInterfaceStatus_Up) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
7534

7535
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7536
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7537

7538
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
7539 7540
                    names[ret] = strdup(nameUtf8);
                    if (names[ret] == NULL) {
7541
                        virReportOOMError();
7542 7543
                    } else {
                        ret++;
7544 7545
                    }

7546 7547
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
7548 7549 7550 7551 7552
                }
            }
        }
    }

7553
    vboxArrayRelease(&networkInterfaces);
7554

7555
    VBOX_RELEASE(host);
7556

7557 7558
    return ret;
}
7559

7560
static int vboxConnectNumOfDefinedNetworks(virConnectPtr conn) {
7561
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7562
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7563
    int i = 0;
7564

7565
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7566

7567 7568 7569 7570
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
7571
            PRUint32 interfaceType = 0;
7572

7573
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7574 7575
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7576

7577
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7578

7579 7580
                if (status == HostNetworkInterfaceStatus_Down)
                    ret++;
7581 7582 7583 7584
            }
        }
    }

7585 7586
    vboxArrayRelease(&networkInterfaces);

7587 7588
    VBOX_RELEASE(host);

7589
    VIR_DEBUG("numActive: %d", ret);
7590
    return ret;
7591 7592
}

7593
static int vboxConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
7594
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7595
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7596
    int i = 0;
7597

7598 7599 7600 7601
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7602

7603
        if (networkInterface) {
7604
            PRUint32 interfaceType = 0;
7605

7606
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7607

7608 7609
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7610

7611
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7612

7613 7614 7615
                if (status == HostNetworkInterfaceStatus_Down) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
7616

7617
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7618
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7619

7620
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
7621 7622
                    names[ret] = strdup(nameUtf8);
                    if (names[ret] == NULL) {
7623
                        virReportOOMError();
7624 7625
                    } else {
                        ret++;
7626 7627
                    }

7628 7629
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
7630 7631 7632 7633 7634
                }
            }
        }
    }

7635
    vboxArrayRelease(&networkInterfaces);
7636 7637 7638 7639

    VBOX_RELEASE(host);

    return ret;
7640 7641
}

7642 7643 7644
static virNetworkPtr
vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
7645
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
7646
    vboxIID iid = VBOX_IID_INITIALIZER;
7647

7648
    vboxIIDFromUUID(&iid, uuid);
7649

7650 7651 7652
    /* TODO: "internal" networks are just strings and
     * thus can't do much with them
     */
7653
    IHostNetworkInterface *networkInterface = NULL;
7654

7655
    host->vtbl->FindHostNetworkInterfaceById(host, iid.value, &networkInterface);
7656 7657
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7658

7659
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7660

7661 7662 7663
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            char *nameUtf8       = NULL;
            PRUnichar *nameUtf16 = NULL;
7664

7665 7666
            networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
            VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7667

7668
            ret = virGetNetwork(conn, nameUtf8, uuid);
7669

7670
            VIR_DEBUG("Network Name: %s", nameUtf8);
7671
            DEBUGIID("Network UUID", iid.value);
7672

7673 7674
            VBOX_UTF8_FREE(nameUtf8);
            VBOX_UTF16_FREE(nameUtf16);
7675
        }
7676 7677

        VBOX_RELEASE(networkInterface);
7678 7679
    }

7680 7681
    VBOX_RELEASE(host);

7682
    vboxIIDUnalloc(&iid);
7683 7684 7685 7686
    return ret;
}

static virNetworkPtr vboxNetworkLookupByName(virConnectPtr conn, const char *name) {
7687 7688 7689
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *nameUtf16                    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7690

7691
    VBOX_UTF8_TO_UTF16(name, &nameUtf16);
7692

7693
    host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface);
7694

7695 7696
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7697

7698
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7699

7700 7701
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            unsigned char uuid[VIR_UUID_BUFLEN];
7702
            vboxIID iid = VBOX_IID_INITIALIZER;
7703

7704 7705
            networkInterface->vtbl->GetId(networkInterface, &iid.value);
            vboxIIDToUUID(&iid, uuid);
7706
            ret = virGetNetwork(conn, name, uuid);
7707
            VIR_DEBUG("Network Name: %s", name);
7708

7709 7710
            DEBUGIID("Network UUID", iid.value);
            vboxIIDUnalloc(&iid);
7711
        }
7712 7713

        VBOX_RELEASE(networkInterface);
7714 7715
    }

7716 7717 7718
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(host);

7719 7720 7721
    return ret;
}

7722
static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start) {
7723 7724 7725 7726
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    char      *networkInterfaceNameUtf8     = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7727
    nsresult rc;
7728

7729
    virNetworkDefPtr def = virNetworkDefParseString(xml);
7730 7731
    virNetworkIpDefPtr ipdef;
    virSocketAddr netmask;
7732

7733
    if ((!def) ||
7734
        (def->forward.type != VIR_NETWORK_FORWARD_NONE) ||
7735
        (def->nips == 0 || !def->ips))
7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746
        goto cleanup;

    /* Look for the first IPv4 IP address definition and use that.
     * If there weren't any IPv4 addresses, ignore the network (since it's
     * required below to have an IPv4 address)
    */
    ipdef = virNetworkDefGetIpByIndex(def, AF_INET, 0);
    if (!ipdef)
        goto cleanup;

    if (virNetworkIpDefNetmask(ipdef, &netmask) < 0)
7747
        goto cleanup;
7748

7749 7750 7751 7752 7753 7754
    /* the current limitation of hostonly network is that you can't
     * assign a name to it and it defaults to vboxnet*, for e.g:
     * vboxnet0, vboxnet1, etc. Also the UUID is assigned to it
     * automatically depending on the mac address and thus both
     * these paramters are ignored here for now.
     */
7755

7756
#if VBOX_API_VERSION == 2002
7757
    if (STREQ(def->name, "vboxnet0")) {
7758
        PRUint32 interfaceType = 0;
7759

7760 7761
        VBOX_UTF8_TO_UTF16(def->name, &networkInterfaceNameUtf16);
        host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7762

7763 7764 7765 7766 7767 7768
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
        if (interfaceType != HostNetworkInterfaceType_HostOnly) {
            VBOX_RELEASE(networkInterface);
            networkInterface = NULL;
        }
    }
7769
#else /* VBOX_API_VERSION != 2002 */
7770 7771 7772 7773
    {
        IProgress *progress = NULL;
        host->vtbl->CreateHostOnlyNetworkInterface(host, &networkInterface,
                                                   &progress);
7774

7775 7776 7777 7778
        if (progress) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
7779
    }
7780
#endif /* VBOX_API_VERSION != 2002 */
7781

7782 7783 7784 7785
    if (networkInterface) {
        unsigned char uuid[VIR_UUID_BUFLEN];
        char      *networkNameUtf8  = NULL;
        PRUnichar *networkNameUtf16 = NULL;
7786
        vboxIID vboxnetiid = VBOX_IID_INITIALIZER;
7787 7788 7789 7790 7791 7792 7793 7794

        networkInterface->vtbl->GetName(networkInterface, &networkInterfaceNameUtf16);
        if (networkInterfaceNameUtf16) {
            VBOX_UTF16_TO_UTF8(networkInterfaceNameUtf16, &networkInterfaceNameUtf8);

            if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", networkInterfaceNameUtf8) < 0) {
                VBOX_RELEASE(host);
                VBOX_RELEASE(networkInterface);
7795
                virReportOOMError();
7796 7797 7798
                goto cleanup;
            }
        }
7799

7800
        VBOX_UTF8_TO_UTF16(networkNameUtf8 , &networkNameUtf16);
7801

7802 7803 7804
        /* Currently support only one dhcp server per network
         * with contigious address space from start to end
         */
7805
        if ((ipdef->nranges >= 1) &&
7806 7807
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
7808 7809 7810 7811 7812 7813 7814 7815 7816 7817
            IDHCPServer *dhcpServer = NULL;

            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (!dhcpServer) {
                /* create a dhcp server */
                data->vboxObj->vtbl->CreateDHCPServer(data->vboxObj,
                                                      networkNameUtf16,
                                                      &dhcpServer);
7818
                VIR_DEBUG("couldn't find dhcp server so creating one");
7819 7820 7821 7822 7823 7824 7825 7826
            }
            if (dhcpServer) {
                PRUnichar *ipAddressUtf16     = NULL;
                PRUnichar *networkMaskUtf16   = NULL;
                PRUnichar *fromIPAddressUtf16 = NULL;
                PRUnichar *toIPAddressUtf16   = NULL;
                PRUnichar *trunkTypeUtf16     = NULL;

7827 7828 7829 7830
                ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
                networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
                fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
                toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
7831 7832 7833 7834 7835 7836 7837 7838 7839 7840

                if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL ||
                    fromIPAddressUtf16 == NULL || toIPAddressUtf16 == NULL) {
                    VBOX_UTF16_FREE(ipAddressUtf16);
                    VBOX_UTF16_FREE(networkMaskUtf16);
                    VBOX_UTF16_FREE(fromIPAddressUtf16);
                    VBOX_UTF16_FREE(toIPAddressUtf16);
                    VBOX_RELEASE(dhcpServer);
                    goto cleanup;
                }
7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865

                VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);

                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);

                dhcpServer->vtbl->SetConfiguration(dhcpServer,
                                                   ipAddressUtf16,
                                                   networkMaskUtf16,
                                                   fromIPAddressUtf16,
                                                   toIPAddressUtf16);

                if (start)
                    dhcpServer->vtbl->Start(dhcpServer,
                                            networkNameUtf16,
                                            networkInterfaceNameUtf16,
                                            trunkTypeUtf16);

                VBOX_UTF16_FREE(ipAddressUtf16);
                VBOX_UTF16_FREE(networkMaskUtf16);
                VBOX_UTF16_FREE(fromIPAddressUtf16);
                VBOX_UTF16_FREE(toIPAddressUtf16);
                VBOX_UTF16_FREE(trunkTypeUtf16);
                VBOX_RELEASE(dhcpServer);
            }
        }
7866

7867
        if ((ipdef->nhosts >= 1) &&
7868
            VIR_SOCKET_ADDR_VALID(&ipdef->hosts[0].ip)) {
7869 7870
            PRUnichar *ipAddressUtf16   = NULL;
            PRUnichar *networkMaskUtf16 = NULL;
7871

7872 7873
            ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip);
            networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
7874 7875 7876 7877 7878 7879

            if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) {
                VBOX_UTF16_FREE(ipAddressUtf16);
                VBOX_UTF16_FREE(networkMaskUtf16);
                goto cleanup;
            }
7880

7881 7882 7883 7884 7885 7886 7887
            /* Current drawback is that since EnableStaticIpConfig() sets
             * IP and enables the interface so even if the dhcpserver is not
             * started the interface is still up and running
             */
            networkInterface->vtbl->EnableStaticIpConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
7888

7889 7890 7891 7892 7893 7894
            VBOX_UTF16_FREE(ipAddressUtf16);
            VBOX_UTF16_FREE(networkMaskUtf16);
        } else {
            networkInterface->vtbl->EnableDynamicIpConfig(networkInterface);
            networkInterface->vtbl->DhcpRediscover(networkInterface);
        }
7895

7896 7897 7898 7899 7900
        rc = networkInterface->vtbl->GetId(networkInterface, &vboxnetiid.value);
        if (NS_SUCCEEDED(rc)) {
            vboxIIDToUUID(&vboxnetiid, uuid);
            DEBUGIID("Real Network UUID", vboxnetiid.value);
            vboxIIDUnalloc(&vboxnetiid);
7901
            ret = virGetNetwork(conn, networkInterfaceNameUtf8, uuid);
7902
        }
7903 7904 7905 7906

        VIR_FREE(networkNameUtf8);
        VBOX_UTF16_FREE(networkNameUtf16);
        VBOX_RELEASE(networkInterface);
7907 7908
    }

7909 7910 7911 7912
    VBOX_UTF8_FREE(networkInterfaceNameUtf8);
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

7913 7914 7915 7916 7917
cleanup:
    virNetworkDefFree(def);
    return ret;
}

7918 7919 7920 7921 7922 7923 7924 7925
static virNetworkPtr vboxNetworkCreateXML(virConnectPtr conn, const char *xml) {
    return vboxNetworkDefineCreateXML(conn, xml, true);
}

static virNetworkPtr vboxNetworkDefineXML(virConnectPtr conn, const char *xml) {
    return vboxNetworkDefineCreateXML(conn, xml, false);
}

7926
static int vboxNetworkUndefineDestroy(virNetworkPtr network, bool removeinterface) {
7927
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
7928
    char *networkNameUtf8 = NULL;
7929 7930
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7931 7932 7933 7934 7935 7936 7937 7938 7939 7940

    /* Current limitation of the function for VirtualBox 2.2.* is
     * that you can't delete the default hostonly adaptor namely:
     * vboxnet0 and thus all this functions does is remove the
     * dhcp server configuration, but the network can still be used
     * by giving the machine static IP and also it will still
     * show up in the net-list in virsh
     */

    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) {
7941
        virReportOOMError();
7942 7943 7944
        goto cleanup;
    }

7945
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
7946

7947
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7948

7949 7950
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7951

7952
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7953

7954 7955 7956
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
7957

7958
#if VBOX_API_VERSION != 2002
7959 7960 7961
            if (removeinterface) {
                PRUnichar *iidUtf16 = NULL;
                IProgress *progress = NULL;
7962

7963
                networkInterface->vtbl->GetId(networkInterface, &iidUtf16);
7964

7965
                if (iidUtf16) {
7966
# if VBOX_API_VERSION == 3000
7967 7968 7969
                    IHostNetworkInterface *netInt = NULL;
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &netInt, &progress);
                    VBOX_RELEASE(netInt);
7970
# else  /* VBOX_API_VERSION > 3000 */
7971
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &progress);
7972
# endif /* VBOX_API_VERSION > 3000 */
7973 7974
                    VBOX_UTF16_FREE(iidUtf16);
                }
7975

7976 7977 7978 7979 7980
                if (progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
                }
            }
7981 7982
#endif /* VBOX_API_VERSION != 2002 */

7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993
            VBOX_UTF8_TO_UTF16(networkNameUtf8 , &networkNameUtf16);

            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (dhcpServer) {
                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_FALSE);
                dhcpServer->vtbl->Stop(dhcpServer);
                if (removeinterface)
                    data->vboxObj->vtbl->RemoveDHCPServer(data->vboxObj, dhcpServer);
                VBOX_RELEASE(dhcpServer);
7994 7995
            }

7996 7997
            VBOX_UTF16_FREE(networkNameUtf16);

7998
        }
7999
        VBOX_RELEASE(networkInterface);
8000 8001
    }

8002 8003 8004
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8005 8006 8007 8008 8009 8010 8011
    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

8012 8013 8014 8015
static int vboxNetworkUndefine(virNetworkPtr network) {
    return vboxNetworkUndefineDestroy(network, true);
}

8016
static int vboxNetworkCreate(virNetworkPtr network) {
8017
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
8018
    char *networkNameUtf8 = NULL;
8019 8020
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
8021 8022 8023 8024 8025 8026 8027 8028 8029

    /* Current limitation of the function for VirtualBox 2.2.* is
     * that the default hostonly network "vboxnet0" is always active
     * and thus all this functions does is start the dhcp server,
     * but the network can still be used without starting the dhcp
     * server by giving the machine static IP
     */

    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) {
8030
        virReportOOMError();
8031 8032 8033
        goto cleanup;
    }

8034
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8035

8036
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8037

8038 8039
    if (networkInterface) {
        PRUint32 interfaceType = 0;
8040

8041
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8042

8043 8044 8045
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
8046 8047


8048
            VBOX_UTF8_TO_UTF16(networkNameUtf8 , &networkNameUtf16);
8049

8050 8051 8052 8053 8054
            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (dhcpServer) {
                PRUnichar *trunkTypeUtf16 = NULL;
8055

8056
                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);
8057

8058
                VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);
8059

8060 8061 8062 8063
                dhcpServer->vtbl->Start(dhcpServer,
                                        networkNameUtf16,
                                        networkInterfaceNameUtf16,
                                        trunkTypeUtf16);
8064

8065 8066
                VBOX_UTF16_FREE(trunkTypeUtf16);
                VBOX_RELEASE(dhcpServer);
8067 8068
            }

8069
            VBOX_UTF16_FREE(networkNameUtf16);
8070
        }
8071 8072

        VBOX_RELEASE(networkInterface);
8073 8074
    }

8075 8076 8077
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8078 8079 8080 8081 8082 8083 8084 8085
    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

static int vboxNetworkDestroy(virNetworkPtr network) {
8086
    return vboxNetworkUndefineDestroy(network, false);
8087 8088
}

8089
static char *vboxNetworkGetXMLDesc(virNetworkPtr network,
E
Eric Blake 已提交
8090 8091
                                   unsigned int flags)
{
8092
    VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
8093
    virNetworkDefPtr def  = NULL;
8094
    virNetworkIpDefPtr ipdef = NULL;
8095
    char *networkNameUtf8 = NULL;
8096 8097
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
8098

E
Eric Blake 已提交
8099 8100
    virCheckFlags(0, NULL);

8101
    if (VIR_ALLOC(def) < 0) {
8102
        virReportOOMError();
8103 8104
        goto cleanup;
    }
8105 8106 8107 8108 8109 8110
    if (VIR_ALLOC(ipdef) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    def->ips = ipdef;
    def->nips = 1;
8111 8112

    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0) {
8113
        virReportOOMError();
8114 8115 8116
        goto cleanup;
    }

8117
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8118

8119
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8120

8121 8122
    if (networkInterface) {
        PRUint32 interfaceType = 0;
8123

8124
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8125

8126 8127 8128 8129 8130
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            def->name = strdup(network->name);
            if (def->name != NULL) {
                PRUnichar *networkNameUtf16 = NULL;
                IDHCPServer *dhcpServer     = NULL;
8131
                vboxIID vboxnet0IID = VBOX_IID_INITIALIZER;
8132

8133 8134
                networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID.value);
                vboxIIDToUUID(&vboxnet0IID, def->uuid);
8135

8136
                VBOX_UTF8_TO_UTF16(networkNameUtf8 , &networkNameUtf16);
8137

8138
                def->forward.type = VIR_NETWORK_FORWARD_NONE;
8139

8140 8141 8142 8143
                data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                 networkNameUtf16,
                                                                 &dhcpServer);
                if (dhcpServer) {
8144
                    ipdef->nranges = 1;
8145
                    if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >=0) {
8146 8147 8148 8149
                        PRUnichar *ipAddressUtf16     = NULL;
                        PRUnichar *networkMaskUtf16   = NULL;
                        PRUnichar *fromIPAddressUtf16 = NULL;
                        PRUnichar *toIPAddressUtf16   = NULL;
8150
                        bool errorOccurred = false;
8151

8152 8153 8154 8155 8156 8157 8158
                        dhcpServer->vtbl->GetIPAddress(dhcpServer, &ipAddressUtf16);
                        dhcpServer->vtbl->GetNetworkMask(dhcpServer, &networkMaskUtf16);
                        dhcpServer->vtbl->GetLowerIP(dhcpServer, &fromIPAddressUtf16);
                        dhcpServer->vtbl->GetUpperIP(dhcpServer, &toIPAddressUtf16);
                        /* Currently virtualbox supports only one dhcp server per network
                         * with contigious address space from start to end
                         */
8159
                        if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8160
                                                     &ipdef->address) < 0 ||
8161
                            vboxSocketParseAddrUtf16(data, networkMaskUtf16,
8162
                                                     &ipdef->netmask) < 0 ||
8163
                            vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
8164
                                                     &ipdef->ranges[0].start) < 0 ||
8165
                            vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
8166
                                                     &ipdef->ranges[0].end) < 0) {
8167 8168
                            errorOccurred = true;
                        }
8169 8170 8171 8172 8173

                        VBOX_UTF16_FREE(ipAddressUtf16);
                        VBOX_UTF16_FREE(networkMaskUtf16);
                        VBOX_UTF16_FREE(fromIPAddressUtf16);
                        VBOX_UTF16_FREE(toIPAddressUtf16);
8174 8175 8176 8177

                        if (errorOccurred) {
                            goto cleanup;
                        }
8178
                    } else {
8179
                        ipdef->nranges = 0;
8180
                        virReportOOMError();
8181
                    }
8182

8183
                    ipdef->nhosts = 1;
8184
                    if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >=0) {
8185 8186 8187 8188
                        ipdef->hosts[0].name = strdup(network->name);
                        if (ipdef->hosts[0].name == NULL) {
                            VIR_FREE(ipdef->hosts);
                            ipdef->nhosts = 0;
8189
                            virReportOOMError();
8190
                        } else {
8191 8192
                            PRUnichar *macAddressUtf16 = NULL;
                            PRUnichar *ipAddressUtf16  = NULL;
8193
                            bool errorOccurred = false;
8194

8195
                            networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
8196 8197
                            networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

8198
                            VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac);
8199 8200

                            if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8201
                                                         &ipdef->hosts[0].ip) < 0) {
8202 8203
                                errorOccurred = true;
                            }
8204

8205 8206
                            VBOX_UTF16_FREE(macAddressUtf16);
                            VBOX_UTF16_FREE(ipAddressUtf16);
8207 8208 8209 8210

                            if (errorOccurred) {
                                goto cleanup;
                            }
8211 8212
                        }
                    } else {
8213
                        ipdef->nhosts = 0;
8214
                    }
8215 8216 8217 8218 8219

                    VBOX_RELEASE(dhcpServer);
                } else {
                    PRUnichar *networkMaskUtf16 = NULL;
                    PRUnichar *ipAddressUtf16   = NULL;
8220
                    bool errorOccurred = false;
8221 8222 8223 8224

                    networkInterface->vtbl->GetNetworkMask(networkInterface, &networkMaskUtf16);
                    networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

8225
                    if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
8226
                                                 &ipdef->netmask) < 0 ||
8227
                        vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8228
                                                 &ipdef->address) < 0) {
8229 8230
                        errorOccurred = true;
                    }
8231 8232 8233

                    VBOX_UTF16_FREE(networkMaskUtf16);
                    VBOX_UTF16_FREE(ipAddressUtf16);
8234 8235 8236 8237

                    if (errorOccurred) {
                        goto cleanup;
                    }
8238 8239
                }

8240 8241
                DEBUGIID("Network UUID", vboxnet0IID.value);
                vboxIIDUnalloc(&vboxnet0IID);
8242 8243
                VBOX_UTF16_FREE(networkNameUtf16);
            } else {
8244
                virReportOOMError();
8245 8246
            }
        }
8247 8248

        VBOX_RELEASE(networkInterface);
8249 8250
    }

8251 8252 8253
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8254
    ret = virNetworkDefFormat(def, 0);
8255 8256

cleanup:
8257
    virNetworkDefFree(def);
8258 8259 8260 8261
    VIR_FREE(networkNameUtf8);
    return ret;
}

8262 8263 8264 8265
/**
 * The Storage Functions here on
 */

8266 8267 8268
static virDrvOpenStatus vboxStorageOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
8269
{
8270 8271
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
8272 8273
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

8274
    if (STRNEQ(conn->driver->name, "VBOX"))
8275
        return VIR_DRV_OPEN_DECLINED;
8276 8277 8278 8279

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
8280
        return VIR_DRV_OPEN_ERROR;
8281

8282
    VIR_DEBUG("vbox storage initialized");
8283 8284 8285 8286
    /* conn->storagePrivateData = some storage specific data */
    return VIR_DRV_OPEN_SUCCESS;
}

8287
static int vboxStorageClose(virConnectPtr conn) {
8288
    VIR_DEBUG("vbox storage uninitialized");
8289 8290 8291 8292
    conn->storagePrivateData = NULL;
    return 0;
}

8293
static int vboxConnectNumOfStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED) {
8294 8295 8296 8297 8298 8299 8300 8301

    /** Currently only one pool supported, the default one
     * given by ISystemProperties::defaultHardDiskFolder()
     */

    return 1;
}

8302 8303
static int vboxConnectListStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
                                       char **const names, int nnames) {
8304 8305 8306 8307 8308
    int numActive = 0;

    if (nnames == 1) {
        names[numActive] = strdup("default-pool");
        if (names[numActive] == NULL) {
8309
            virReportOOMError();
8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327
        } else {
            numActive++;
        }
    }
    return numActive;
}

static virStoragePoolPtr vboxStoragePoolLookupByName(virConnectPtr conn, const char *name) {
    virStoragePoolPtr ret = NULL;

    /** Current limitation of the function: since
     * the default pool doesn't have UUID just assign
     * one till vbox can handle pools
     */
    if (STREQ("default-pool", name)) {
        unsigned char uuid[VIR_UUID_BUFLEN];
        const char *uuidstr = "1deff1ff-1481-464f-967f-a50fe8936cc4";

8328
        ignore_value(virUUIDParse(uuidstr, uuid));
8329

8330
        ret = virGetStoragePool(conn, name, uuid, NULL, NULL);
8331 8332 8333 8334 8335 8336
    }

    return ret;
}

static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool) {
8337
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
8338
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8339 8340 8341 8342
    PRUint32 hardDiskAccessible = 0;
    nsresult rc;
    int i;

8343
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8344
    if (NS_SUCCEEDED(rc)) {
8345 8346
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8347 8348
            if (hardDisk) {
                PRUint32 hddstate;
8349

8350 8351 8352
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible)
                    hardDiskAccessible++;
8353 8354
            }
        }
8355 8356 8357 8358

        vboxArrayRelease(&hardDisks);

        ret = hardDiskAccessible;
8359
    } else {
8360
        ret = -1;
8361 8362 8363
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get number of volumes in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
8364 8365
    }

8366
    return ret;
8367 8368 8369
}

static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) {
8370
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
8371
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8372 8373 8374 8375
    PRUint32 numActive     = 0;
    nsresult rc;
    int i;

8376
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8377
    if (NS_SUCCEEDED(rc)) {
8378 8379
        for (i = 0; i < hardDisks.count && numActive < nnames; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8380

8381 8382 8383 8384
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
8385

8386 8387 8388
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8389

8390 8391
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
8392

8393
                    if (nameUtf8) {
8394
                        VIR_DEBUG("nnames[%d]: %s", numActive, nameUtf8);
8395 8396
                        names[numActive] = strdup(nameUtf8);
                        if (names[numActive] == NULL) {
8397
                            virReportOOMError();
8398 8399
                        } else {
                            numActive++;
8400
                        }
8401 8402

                        VBOX_UTF8_FREE(nameUtf8);
8403 8404 8405 8406
                    }
                }
            }
        }
8407 8408 8409 8410

        vboxArrayRelease(&hardDisks);

        ret = numActive;
8411
    } else {
8412
        ret = -1;
8413 8414 8415
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get the volume list in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
8416 8417
    }

8418
    return ret;
8419 8420 8421
}

static virStorageVolPtr vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name) {
8422
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8423
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8424 8425 8426
    nsresult rc;
    int i;

8427
    if (!name)
8428
        return ret;
8429

8430
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8431
    if (NS_SUCCEEDED(rc)) {
8432 8433
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8434

8435 8436 8437 8438
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
8439

8440 8441 8442
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8443

8444 8445 8446 8447
                    if (nameUtf16) {
                        VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                        VBOX_UTF16_FREE(nameUtf16);
                    }
8448

8449
                    if (nameUtf8 && STREQ(nameUtf8, name)) {
8450 8451 8452
                        vboxIID hddIID = VBOX_IID_INITIALIZER;
                        unsigned char uuid[VIR_UUID_BUFLEN];
                        char key[VIR_UUID_STRING_BUFLEN] = "";
8453

8454 8455 8456 8457
                        rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                        if (NS_SUCCEEDED(rc)) {
                            vboxIIDToUUID(&hddIID, uuid);
                            virUUIDFormat(uuid, key);
8458

8459 8460
                            ret = virGetStorageVol(pool->conn, pool->name, name, key,
                                                   NULL, NULL);
8461

8462 8463 8464 8465
                            VIR_DEBUG("virStorageVolPtr: %p", ret);
                            VIR_DEBUG("Storage Volume Name: %s", name);
                            VIR_DEBUG("Storage Volume key : %s", key);
                            VIR_DEBUG("Storage Volume Pool: %s", pool->name);
8466 8467
                        }

8468
                        vboxIIDUnalloc(&hddIID);
8469 8470
                        VBOX_UTF8_FREE(nameUtf8);
                        break;
8471
                    }
8472

J
John Ferlan 已提交
8473
                    VBOX_UTF8_FREE(nameUtf8);
8474 8475 8476
                }
            }
        }
8477

8478
        vboxArrayRelease(&hardDisks);
8479 8480 8481 8482 8483 8484
    }

    return ret;
}

static virStorageVolPtr vboxStorageVolLookupByKey(virConnectPtr conn, const char *key) {
8485
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
8486 8487
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
8488 8489 8490
    IHardDisk *hardDisk  = NULL;
    nsresult rc;

8491 8492 8493
    if (!key)
        return ret;

8494
    if (virUUIDParse(key, uuid) < 0) {
8495 8496
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), key);
8497
        return NULL;
8498 8499
    }

8500
    vboxIIDFromUUID(&hddIID, uuid);
8501
#if VBOX_API_VERSION < 4000
8502
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8503 8504 8505 8506
#else /* VBOX_API_VERSION >= 4000 */
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
#endif /* VBOX_API_VERSION >= 4000 */
8507 8508
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8509

8510 8511 8512 8513
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
8514

8515 8516
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
            VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
8517

8518
            if (hddNameUtf8) {
8519
                if (vboxConnectNumOfStoragePools(conn) == 1) {
8520 8521
                    ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                           NULL, NULL);
8522
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
8523 8524 8525 8526
                } else {
                    /* TODO: currently only one default pool and thus
                     * nothing here, change it when pools are supported
                     */
8527 8528
                }

8529 8530
                VIR_DEBUG("Storage Volume Name: %s", key);
                VIR_DEBUG("Storage Volume key : %s", hddNameUtf8);
8531 8532 8533

                VBOX_UTF8_FREE(hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
8534 8535
            }
        }
8536 8537

        VBOX_MEDIUM_RELEASE(hardDisk);
8538 8539
    }

8540
    vboxIIDUnalloc(&hddIID);
8541 8542 8543 8544
    return ret;
}

static virStorageVolPtr vboxStorageVolLookupByPath(virConnectPtr conn, const char *path) {
8545
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
8546 8547 8548 8549
    PRUnichar *hddPathUtf16 = NULL;
    IHardDisk *hardDisk     = NULL;
    nsresult rc;

8550 8551
    if (!path)
        return ret;
8552

8553
    VBOX_UTF8_TO_UTF16(path, &hddPathUtf16);
8554

8555 8556
    if (!hddPathUtf16)
        return ret;
8557

8558
#if VBOX_API_VERSION < 4000
8559
    rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk);
8560 8561 8562 8563
#else /* VBOX_API_VERSION >= 4000 */
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, &hardDisk);
#endif /* VBOX_API_VERSION >= 4000 */
8564 8565
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8566

8567 8568 8569 8570
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
8571

8572
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
8573

8574 8575 8576 8577
            if (hddNameUtf16) {
                VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
            }
8578

8579 8580 8581 8582
            if (hddNameUtf8) {
                vboxIID hddIID = VBOX_IID_INITIALIZER;
                unsigned char uuid[VIR_UUID_BUFLEN];
                char key[VIR_UUID_STRING_BUFLEN] = "";
8583

8584 8585 8586 8587
                rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                if (NS_SUCCEEDED(rc)) {
                    vboxIIDToUUID(&hddIID, uuid);
                    virUUIDFormat(uuid, key);
8588

8589 8590 8591
                    /* TODO: currently only one default pool and thus
                     * the check below, change it when pools are supported
                     */
8592
                    if (vboxConnectNumOfStoragePools(conn) == 1)
8593 8594
                        ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                               NULL, NULL);
8595

8596 8597 8598
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
                    VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8);
                    VIR_DEBUG("Storage Volume key : %s", key);
8599
                }
8600

8601
                vboxIIDUnalloc(&hddIID);
8602 8603
            }

J
John Ferlan 已提交
8604
            VBOX_UTF8_FREE(hddNameUtf8);
8605
        }
8606 8607

        VBOX_MEDIUM_RELEASE(hardDisk);
8608 8609
    }

8610 8611
    VBOX_UTF16_FREE(hddPathUtf16);

8612 8613 8614 8615 8616
    return ret;
}

static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
                                                const char *xml,
E
Eric Blake 已提交
8617 8618
                                                unsigned int flags)
{
8619
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8620
    virStorageVolDefPtr  def  = NULL;
8621 8622
    PRUnichar *hddFormatUtf16 = NULL;
    PRUnichar *hddNameUtf16   = NULL;
8623 8624 8625
    virStoragePoolDef poolDef;
    nsresult rc;

E
Eric Blake 已提交
8626 8627
    virCheckFlags(0, NULL);

8628 8629 8630 8631 8632 8633 8634 8635
    /* since there is currently one default pool now
     * and virStorageVolDefFormat() just checks it type
     * so just assign it for now, change the behaviour
     * when vbox supports pools.
     */
    memset(&poolDef, 0, sizeof(poolDef));
    poolDef.type = VIR_STORAGE_POOL_DIR;

8636
    if ((def = virStorageVolDefParseString(&poolDef, xml)) == NULL)
8637 8638
        goto cleanup;

8639 8640
    if (!def->name ||
        (def->type != VIR_STORAGE_VOL_FILE))
8641
        goto cleanup;
8642

8643 8644 8645 8646 8647 8648
    /* TODO: for now only the vmdk, vpc and vdi type harddisk
     * variants can be created, also since there is no vdi
     * type in enum virStorageFileFormat {} the default
     * will be to create vdi if nothing is specified in
     * def->target.format
     */
8649

8650 8651 8652 8653 8654 8655 8656
    if (def->target.format == VIR_STORAGE_FILE_VMDK) {
        VBOX_UTF8_TO_UTF16("VMDK", &hddFormatUtf16);
    } else if (def->target.format == VIR_STORAGE_FILE_VPC) {
        VBOX_UTF8_TO_UTF16("VHD", &hddFormatUtf16);
    } else {
        VBOX_UTF8_TO_UTF16("VDI", &hddFormatUtf16);
    }
8657

8658
    VBOX_UTF8_TO_UTF16(def->name, &hddNameUtf16);
8659

8660 8661
    if (hddFormatUtf16 && hddNameUtf16) {
        IHardDisk *hardDisk = NULL;
8662

8663 8664 8665
        rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk);
        if (NS_SUCCEEDED(rc)) {
            IProgress *progress    = NULL;
8666
            PRUint64   logicalSize = VIR_DIV_UP(def->capacity, 1024 * 1024);
8667
            PRUint32   variant     = HardDiskVariant_Standard;
8668

8669 8670
            if (def->capacity == def->allocation)
                variant = HardDiskVariant_Fixed;
8671

8672 8673
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress);
            if (NS_SUCCEEDED(rc) && progress) {
8674
#if VBOX_API_VERSION == 2002
8675
                nsresult resultCode;
8676
#else
8677
                PRInt32  resultCode;
8678 8679
#endif

8680 8681
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
8682

8683
                if (NS_SUCCEEDED(resultCode)) {
8684 8685 8686
                    vboxIID hddIID = VBOX_IID_INITIALIZER;
                    unsigned char uuid[VIR_UUID_BUFLEN];
                    char key[VIR_UUID_STRING_BUFLEN] = "";
8687

8688
                    rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
8689
                    if (NS_SUCCEEDED(rc)) {
8690 8691
                        vboxIIDToUUID(&hddIID, uuid);
                        virUUIDFormat(uuid, key);
8692

8693 8694
                        ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
                                               NULL, NULL);
8695
                    }
8696 8697

                    vboxIIDUnalloc(&hddIID);
8698 8699
                }

8700
                VBOX_RELEASE(progress);
8701
            }
8702
        }
8703 8704
    }

8705 8706 8707
    VBOX_UTF16_FREE(hddFormatUtf16);
    VBOX_UTF16_FREE(hddNameUtf16);

8708 8709 8710 8711 8712 8713
cleanup:
    virStorageVolDefFree(def);
    return ret;
}

static int vboxStorageVolDelete(virStorageVolPtr vol,
E
Eric Blake 已提交
8714 8715
                                unsigned int flags)
{
8716
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
8717 8718
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
8719 8720 8721
    IHardDisk *hardDisk  = NULL;
    int deregister = 0;
    nsresult rc;
8722 8723
    int i = 0;
    int j = 0;
8724

E
Eric Blake 已提交
8725 8726
    virCheckFlags(0, -1);

8727
    if (virUUIDParse(vol->key, uuid) < 0) {
8728 8729
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
8730 8731
        return -1;
    }
8732

8733
    vboxIIDFromUUID(&hddIID, uuid);
8734
#if VBOX_API_VERSION < 4000
8735
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8736 8737 8738 8739
#else /* VBOX_API_VERSION >= 4000 */
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
#endif /* VBOX_API_VERSION >= 4000 */
8740 8741
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8742

8743 8744 8745
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUint32  machineIdsSize = 0;
8746 8747 8748 8749 8750 8751 8752
            vboxArray machineIds = VBOX_ARRAY_INITIALIZER;

#if VBOX_API_VERSION < 3001
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->imedium.GetMachineIds);
#else  /* VBOX_API_VERSION >= 3001 */
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->GetMachineIds);
#endif /* VBOX_API_VERSION >= 3001 */
8753

8754 8755 8756 8757 8758 8759 8760
#if VBOX_API_VERSION == 2002 && defined WIN32
            /* VirtualBox 2.2 on Windows represents IIDs as GUIDs and the
             * machineIds array contains direct instances of the GUID struct
             * instead of pointers to the actual struct instances. But there
             * is no 128bit width simple item type for a SafeArray to fit a
             * GUID in. The largest simple type it 64bit width and VirtualBox
             * uses two of this 64bit items to represents one GUID. Therefore,
J
Ján Tomko 已提交
8761
             * we divide the size of the SafeArray by two, to compensate for
8762 8763 8764 8765
             * this workaround in VirtualBox */
            machineIds.count /= 2;
#endif /* VBOX_API_VERSION >= 2002 */

8766
            machineIdsSize = machineIds.count;
8767

8768
            for (i = 0; i < machineIds.count; i++) {
8769
                IMachine *machine = NULL;
8770 8771 8772
                vboxIID machineId = VBOX_IID_INITIALIZER;

                vboxIIDFromArrayItem(&machineId, &machineIds, i);
8773

8774 8775 8776
#if VBOX_API_VERSION >= 4000
                rc = VBOX_OBJECT_GET_MACHINE(machineId.value, &machine);
                if (NS_FAILED(rc)) {
8777 8778
                    virReportError(VIR_ERR_NO_DOMAIN, "%s",
                                   _("no domain with matching uuid"));
8779 8780 8781 8782 8783 8784
                    break;
                }
#endif

                rc = VBOX_SESSION_OPEN(machineId.value, machine);

8785
                if (NS_SUCCEEDED(rc)) {
8786

8787 8788
                    rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                    if (NS_SUCCEEDED(rc)) {
8789
                        vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER;
8790 8791

#if VBOX_API_VERSION < 3001
8792 8793
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetHardDiskAttachments);
8794
#else  /* VBOX_API_VERSION >= 3001 */
8795 8796
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetMediumAttachments);
8797
#endif /* VBOX_API_VERSION >= 3001 */
8798 8799
                        for (j = 0; j < hddAttachments.count; j++) {
                            IHardDiskAttachment *hddAttachment = hddAttachments.items[j];
8800 8801 8802 8803 8804 8805 8806 8807 8808 8809

                            if (hddAttachment) {
                                IHardDisk *hdd = NULL;

#if VBOX_API_VERSION < 3001
                                rc = hddAttachment->vtbl->GetHardDisk(hddAttachment, &hdd);
#else  /* VBOX_API_VERSION >= 3001 */
                                rc = hddAttachment->vtbl->GetMedium(hddAttachment, &hdd);
#endif /* VBOX_API_VERSION >= 3001 */
                                if (NS_SUCCEEDED(rc) && hdd) {
8810
                                    vboxIID iid = VBOX_IID_INITIALIZER;
8811

8812 8813
                                    rc = VBOX_MEDIUM_FUNC_ARG1(hdd, GetId, &iid.value);
                                    if (NS_SUCCEEDED(rc)) {
8814

8815 8816
                                            DEBUGIID("HardDisk (to delete) UUID", hddIID.value);
                                            DEBUGIID("HardDisk (currently processing) UUID", iid.value);
8817

8818
                                        if (vboxIIDIsEqual(&hddIID, &iid)) {
8819 8820 8821 8822
                                            PRUnichar *controller = NULL;
                                            PRInt32    port       = 0;
                                            PRInt32    device     = 0;

8823
                                            DEBUGIID("Found HardDisk to delete, UUID", hddIID.value);
8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835

                                            hddAttachment->vtbl->GetController(hddAttachment, &controller);
                                            hddAttachment->vtbl->GetPort(hddAttachment, &port);
                                            hddAttachment->vtbl->GetDevice(hddAttachment, &device);

#if VBOX_API_VERSION < 3001
                                            rc = machine->vtbl->DetachHardDisk(machine, controller, port, device);
#else  /* VBOX_API_VERSION >= 3001 */
                                            rc = machine->vtbl->DetachDevice(machine, controller, port, device);
#endif /* VBOX_API_VERSION >= 3001 */
                                            if (NS_SUCCEEDED(rc)) {
                                                rc = machine->vtbl->SaveSettings(machine);
8836
                                                VIR_DEBUG("saving machine settings");
8837
                                            }
8838

8839 8840
                                            if (NS_SUCCEEDED(rc)) {
                                                deregister++;
8841
                                                VIR_DEBUG("deregistering hdd:%d", deregister);
8842
                                            }
8843

J
John Ferlan 已提交
8844
                                            VBOX_UTF16_FREE(controller);
8845
                                        }
8846
                                        vboxIIDUnalloc(&iid);
8847
                                    }
8848
                                    VBOX_MEDIUM_RELEASE(hdd);
8849 8850 8851
                                }
                            }
                        }
8852
                        vboxArrayRelease(&hddAttachments);
8853
                        VBOX_RELEASE(machine);
8854
                    }
8855
                    VBOX_SESSION_CLOSE();
8856
                }
8857 8858

                vboxIIDUnalloc(&machineId);
8859
            }
8860

8861
            vboxArrayUnalloc(&machineIds);
8862

8863 8864
            if (machineIdsSize == 0 || machineIdsSize == deregister) {
                IProgress *progress = NULL;
8865

8866
                rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress);
8867

8868 8869 8870
                if (NS_SUCCEEDED(rc) && progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
8871
                    DEBUGIID("HardDisk deleted, UUID", hddIID.value);
8872
                    ret = 0;
8873 8874 8875
                }
            }
        }
8876 8877

        VBOX_MEDIUM_RELEASE(hardDisk);
8878 8879
    }

8880
    vboxIIDUnalloc(&hddIID);
8881

8882 8883 8884 8885
    return ret;
}

static int vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info) {
8886
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
8887
    IHardDisk *hardDisk  = NULL;
8888 8889
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
8890 8891
    nsresult rc;

8892
    if (!info)
8893
        return ret;
8894

8895
    if (virUUIDParse(vol->key, uuid) < 0) {
8896 8897
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
8898
        return ret;
8899
    }
8900

8901
    vboxIIDFromUUID(&hddIID, uuid);
8902
#if VBOX_API_VERSION < 4000
8903
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8904 8905 8906 8907
#else /* VBOX_API_VERSION >= 4000 */
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
#endif /* VBOX_API_VERSION >= 4000 */
8908 8909
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8910

8911 8912
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
8913
#if VBOX_API_VERSION < 4000
8914 8915
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
8916 8917 8918 8919
#else /* VBOX_API_VERSION >= 4000 */
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
#endif /* VBOX_API_VERSION >= 4000 */
8920

8921
            info->type = VIR_STORAGE_VOL_FILE;
8922

8923
            hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
8924
#if VBOX_API_VERSION < 4000
8925
            info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
8926 8927 8928
#else /* VBOX_API_VERSION >= 4000 */
            info->capacity = hddLogicalSize;
#endif /* VBOX_API_VERSION >= 4000 */
8929

8930 8931
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            info->allocation = hddActualSize;
8932

8933
            ret = 0;
8934

8935 8936 8937 8938
            VIR_DEBUG("Storage Volume Name: %s", vol->name);
            VIR_DEBUG("Storage Volume Type: %s", info->type == VIR_STORAGE_VOL_BLOCK ? "Block" : "File");
            VIR_DEBUG("Storage Volume Capacity: %llu", info->capacity);
            VIR_DEBUG("Storage Volume Allocation: %llu", info->allocation);
8939
        }
8940 8941

        VBOX_MEDIUM_RELEASE(hardDisk);
8942 8943
    }

8944
    vboxIIDUnalloc(&hddIID);
8945

8946 8947 8948
    return ret;
}

E
Eric Blake 已提交
8949 8950
static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
{
8951
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
8952
    IHardDisk *hardDisk  = NULL;
8953 8954
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
8955 8956 8957 8958 8959
    virStoragePoolDef pool;
    virStorageVolDef def;
    int defOk = 0;
    nsresult rc;

E
Eric Blake 已提交
8960 8961
    virCheckFlags(0, NULL);

8962 8963 8964
    memset(&pool, 0, sizeof(pool));
    memset(&def, 0, sizeof(def));

8965
    if (virUUIDParse(vol->key, uuid) < 0) {
8966 8967
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
8968
        return ret;
8969
    }
8970

8971
    vboxIIDFromUUID(&hddIID, uuid);
8972
#if VBOX_API_VERSION < 4000
8973
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8974 8975 8976 8977
#else /* VBOX_API_VERSION >= 4000 */
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
#endif /* VBOX_API_VERSION >= 4000 */
8978 8979 8980 8981 8982 8983
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;

        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) {
            PRUnichar *hddFormatUtf16 = NULL;
8984
#if VBOX_API_VERSION < 4000
8985 8986
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
8987 8988 8989 8990
#else /* VBOX_API_VERSION >= 4000 */
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
#endif /* VBOX_API_VERSION >= 4000 */
8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001

            /* since there is currently one default pool now
             * and virStorageVolDefFormat() just checks it type
             * so just assign it for now, change the behaviour
             * when vbox supports pools.
             */
            pool.type = VIR_STORAGE_POOL_DIR;
            def.type = VIR_STORAGE_VOL_FILE;
            defOk = 1;

            rc = hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
9002 9003
            if (NS_SUCCEEDED(rc) && defOk) {
#if VBOX_API_VERSION < 4000
9004
                def.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
9005 9006 9007 9008
#else /* VBOX_API_VERSION >= 4000 */
                def.capacity = hddLogicalSize;
#endif /* VBOX_API_VERSION >= 4000 */
            } else
9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031
                defOk = 0;

            rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            if (NS_SUCCEEDED(rc) && defOk)
                def.allocation = hddActualSize;
            else
                defOk = 0;

            def.name = strdup(vol->name);
            if (!(def.name && defOk))
                defOk = 0;

            def.key = strdup(vol->key);
            if (!(def.key && defOk))
                defOk = 0;

            rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16);
            if (NS_SUCCEEDED(rc) && defOk) {
                char *hddFormatUtf8 = NULL;

                VBOX_UTF16_TO_UTF8(hddFormatUtf16, &hddFormatUtf8);
                if (hddFormatUtf8) {

9032
                    VIR_DEBUG("Storage Volume Format: %s", hddFormatUtf8);
9033 9034 9035 9036 9037

                    if (STRCASEEQ("vmdk", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VMDK;
                    else if (STRCASEEQ("vhd", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VPC;
9038
                    else
9039
                        def.target.format = VIR_STORAGE_FILE_RAW;
9040

9041 9042 9043
                    /* TODO: need to add vdi to enum virStorageFileFormat {}
                     * and then add it here
                     */
9044

9045
                    VBOX_UTF8_FREE(hddFormatUtf8);
9046 9047
                }

9048 9049 9050
                VBOX_UTF16_FREE(hddFormatUtf16);
            } else {
                defOk = 0;
9051 9052
            }
        }
9053 9054

        VBOX_MEDIUM_RELEASE(hardDisk);
9055 9056
    }

9057
    vboxIIDUnalloc(&hddIID);
9058

9059
    if (defOk)
9060
        ret = virStorageVolDefFormat(&pool, &def);
9061 9062 9063 9064 9065

    return ret;
}

static char *vboxStorageVolGetPath(virStorageVolPtr vol) {
9066
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
9067
    IHardDisk *hardDisk  = NULL;
9068 9069
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
9070 9071
    nsresult rc;

9072
    if (virUUIDParse(vol->key, uuid) < 0) {
9073 9074
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
9075
        return ret;
9076
    }
9077

9078
    vboxIIDFromUUID(&hddIID, uuid);
9079
#if VBOX_API_VERSION < 4000
9080
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9081 9082 9083 9084
#else /* VBOX_API_VERSION >= 4000 */
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
#endif /* VBOX_API_VERSION >= 4000 */
9085 9086
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
9087

9088 9089 9090 9091
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddLocationUtf16 = NULL;
            char      *hddLocationUtf8  = NULL;
9092

9093
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetLocation, &hddLocationUtf16);
9094

9095 9096
            VBOX_UTF16_TO_UTF8(hddLocationUtf16, &hddLocationUtf8);
            if (hddLocationUtf8) {
9097

9098 9099
                ret = strdup(hddLocationUtf8);
                if (!ret)
9100
                    virReportOOMError();
9101

9102 9103 9104
                VIR_DEBUG("Storage Volume Name: %s", vol->name);
                VIR_DEBUG("Storage Volume Path: %s", hddLocationUtf8);
                VIR_DEBUG("Storage Volume Pool: %s", vol->pool);
9105

9106
                VBOX_UTF8_FREE(hddLocationUtf8);
9107 9108
            }

9109
            VBOX_UTF16_FREE(hddLocationUtf16);
9110
        }
9111 9112

        VBOX_MEDIUM_RELEASE(hardDisk);
9113 9114
    }

9115
    vboxIIDUnalloc(&hddIID);
9116

9117 9118
    return ret;
}
9119

9120
#if VBOX_API_VERSION >= 4000
9121 9122 9123 9124
static char *
vboxDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
9125
                     unsigned int flags)
9126 9127 9128 9129 9130 9131 9132 9133 9134 9135
{
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
    IConsole *console = NULL;
    vboxIID iid = VBOX_IID_INITIALIZER;
    IMachine *machine = NULL;
    nsresult rc;
    char *tmp;
    int tmp_fd = -1;
    unsigned int max_screen;

E
Eric Blake 已提交
9136 9137
    virCheckFlags(0, NULL);

9138 9139 9140
    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
9141 9142
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
9143 9144 9145 9146 9147
        return NULL;
    }

    rc = machine->vtbl->GetMonitorCount(machine, &max_screen);
    if (NS_FAILED(rc)) {
9148 9149
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to get monitor count"));
9150 9151 9152 9153 9154
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (screen >= max_screen) {
9155 9156 9157
        virReportError(VIR_ERR_INVALID_ARG,
                       _("screen ID higher than monitor "
                         "count (%d)"), max_screen);
9158 9159 9160 9161 9162 9163 9164 9165 9166 9167
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
        virReportOOMError();
        VBOX_RELEASE(machine);
        return NULL;
    }

9168 9169
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193
        VIR_FREE(tmp);
        VBOX_RELEASE(machine);
        return NULL;
    }


    rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
    if (NS_SUCCEEDED(rc)) {
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (NS_SUCCEEDED(rc) && console) {
            IDisplay *display = NULL;

            console->vtbl->GetDisplay(console, &display);

            if (display) {
                PRUint32 width, height, bitsPerPixel;
                PRUint32 screenDataSize;
                PRUint8 *screenData;

                rc = display->vtbl->GetScreenResolution(display, screen,
                                                        &width, &height,
                                                        &bitsPerPixel);

                if (NS_FAILED(rc) || !width || !height) {
9194 9195
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to get screen resolution"));
9196 9197 9198 9199 9200 9201 9202 9203
                    goto endjob;
                }

                rc = display->vtbl->TakeScreenShotPNGToArray(display, screen,
                                                             width, height,
                                                             &screenDataSize,
                                                             &screenData);
                if (NS_FAILED(rc)) {
9204 9205
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("failed to take screenshot"));
9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220
                    goto endjob;
                }

                if (safewrite(tmp_fd, (char *) screenData,
                              screenDataSize) < 0) {
                    virReportSystemError(errno, _("unable to write data "
                                                  "to '%s'"), tmp);
                    goto endjob;
                }

                if (VIR_CLOSE(tmp_fd) < 0) {
                    virReportSystemError(errno, _("unable to close %s"), tmp);
                    goto endjob;
                }

E
Eric Blake 已提交
9221
                if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
9222 9223
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to open stream"));
9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238
                    goto endjob;
                }

                ret = strdup("image/png");

endjob:
                VIR_FREE(screenData);
                VBOX_RELEASE(display);
            }
            VBOX_RELEASE(console);
        }
        VBOX_SESSION_CLOSE();
    }

    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
9239
    unlink(tmp);
9240 9241 9242 9243 9244
    VIR_FREE(tmp);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}
9245
#endif /* VBOX_API_VERSION >= 4000 */
9246

9247 9248 9249

#define MATCH(FLAG) (flags & (FLAG))
static int
9250 9251 9252
vboxConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268
{
    VBOX_OBJECT_CHECK(conn, int, -1);
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
    char      *machineNameUtf8  = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID iid = VBOX_IID_INITIALIZER;
    PRUint32 state;
    nsresult rc;
    int i;
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    int count = 0;
    bool active;
    PRUint32 snapshotCount;

O
Osier Yang 已提交
9269
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291

    /* filter out flag options that will produce 0 results in vbox driver:
     * - managed save: vbox guests don't have managed save images
     * - autostart: vbox doesn't support autostarting guests
     * - persistance: vbox doesn't support transient guests
     */
    if ((MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) &&
         !MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT)) ||
        (MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) &&
         !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART)) ||
        (MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) &&
         !MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE))) {
        if (domains &&
            VIR_ALLOC_N(*domains, 1) < 0)
            goto no_memory;

        ret = 0;
        goto cleanup;
    }

    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
    if (NS_FAILED(rc)) {
9292 9293
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of domains, rc=%08x"), (unsigned)rc);
9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316
        goto cleanup;
    }

    if (domains &&
        VIR_ALLOC_N(doms, machines.count + 1) < 0)
        goto no_memory;

    for (i = 0; i < machines.count; i++) {
        IMachine *machine = machines.items[i];

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);

                if (state >= MachineState_FirstOnline &&
                    state <= MachineState_LastOnline)
                    active = true;
                else
                    active = false;

                /* filter by active state */
O
Osier Yang 已提交
9317
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
9318 9319 9320 9321 9322
                    !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
                    continue;

                /* filter by snapshot existence */
O
Osier Yang 已提交
9323
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
9324 9325
                    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
                    if (NS_FAILED(rc)) {
9326
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9327
                                       _("could not get snapshot count for listed domains"));
9328 9329 9330 9331 9332 9333 9334 9335 9336 9337
                        goto cleanup;
                    }
                    if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) &&
                           snapshotCount > 0) ||
                          (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) &&
                           snapshotCount == 0)))
                        continue;
                }

                /* filter by machine state */
O
Osier Yang 已提交
9338
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) &&
9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408
                    !((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) &&
                       state == MachineState_Running) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) &&
                       state == MachineState_Paused) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) &&
                       state == MachineState_PoweredOff) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) &&
                       (state != MachineState_Running &&
                        state != MachineState_Paused &&
                        state != MachineState_PoweredOff))))
                    continue;

                /* just count the machines */
                if (!doms) {
                    count++;
                    continue;
                }

                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
                machine->vtbl->GetId(machine, &iid.value);
                vboxIIDToUUID(&iid, uuid);
                vboxIIDUnalloc(&iid);

                dom = virGetDomain(conn, machineNameUtf8, uuid);

                VBOX_UTF8_FREE(machineNameUtf8);
                VBOX_UTF16_FREE(machineNameUtf16);

                if (!dom)
                    goto cleanup;

                if (active)
                    dom->id = i + 1;

                doms[count++] = dom;
            }
        }
    }

    if (doms) {
        /* safe to ignore, new size will be equal or less than
         * previous allocation*/
        ignore_value(VIR_REALLOC_N(doms, count + 1));
        *domains = doms;
        doms = NULL;
    }

    ret = count;

cleanup:
    if (doms) {
        for (i = 0; i < count; i++) {
            if (doms[i])
                virDomainFree(doms[i]);
        }
    }
    VIR_FREE(doms);

    vboxArrayRelease(&machines);
    return ret;

no_memory:
    virReportOOMError();
    goto cleanup;
}
#undef MATCH



9409 9410 9411 9412
/**
 * Function Tables
 */

9413
virDriver NAME(Driver) = {
9414 9415
    .no = VIR_DRV_VBOX,
    .name = "VBOX",
9416 9417 9418
    .connectOpen = vboxConnectOpen, /* 0.6.3 */
    .connectClose = vboxConnectClose, /* 0.6.3 */
    .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */
9419
    .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */
9420
    .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */
9421
    .nodeGetInfo = nodeGetInfo, /* 0.6.3 */
9422 9423 9424 9425
    .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */
    .connectListDomains = vboxConnectListDomains, /* 0.6.3 */
    .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */
    .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */
9426 9427 9428 9429 9430 9431 9432
    .domainCreateXML = vboxDomainCreateXML, /* 0.6.3 */
    .domainLookupByID = vboxDomainLookupByID, /* 0.6.3 */
    .domainLookupByUUID = vboxDomainLookupByUUID, /* 0.6.3 */
    .domainLookupByName = vboxDomainLookupByName, /* 0.6.3 */
    .domainSuspend = vboxDomainSuspend, /* 0.6.3 */
    .domainResume = vboxDomainResume, /* 0.6.3 */
    .domainShutdown = vboxDomainShutdown, /* 0.6.3 */
9433
    .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
9434 9435
    .domainReboot = vboxDomainReboot, /* 0.6.3 */
    .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
9436
    .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
9437 9438 9439 9440 9441 9442 9443 9444 9445 9446
    .domainGetOSType = vboxDomainGetOSType, /* 0.6.3 */
    .domainSetMemory = vboxDomainSetMemory, /* 0.6.3 */
    .domainGetInfo = vboxDomainGetInfo, /* 0.6.3 */
    .domainGetState = vboxDomainGetState, /* 0.9.2 */
    .domainSave = vboxDomainSave, /* 0.6.3 */
    .domainSetVcpus = vboxDomainSetVcpus, /* 0.7.1 */
    .domainSetVcpusFlags = vboxDomainSetVcpusFlags, /* 0.8.5 */
    .domainGetVcpusFlags = vboxDomainGetVcpusFlags, /* 0.8.5 */
    .domainGetMaxVcpus = vboxDomainGetMaxVcpus, /* 0.7.1 */
    .domainGetXMLDesc = vboxDomainGetXMLDesc, /* 0.6.3 */
9447 9448
    .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */
    .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */
9449 9450 9451 9452
    .domainCreate = vboxDomainCreate, /* 0.6.3 */
    .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */
    .domainUndefine = vboxDomainUndefine, /* 0.6.3 */
9453
    .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */
9454 9455 9456 9457 9458 9459 9460
    .domainAttachDevice = vboxDomainAttachDevice, /* 0.6.3 */
    .domainAttachDeviceFlags = vboxDomainAttachDeviceFlags, /* 0.7.7 */
    .domainDetachDevice = vboxDomainDetachDevice, /* 0.6.3 */
    .domainDetachDeviceFlags = vboxDomainDetachDeviceFlags, /* 0.7.7 */
    .domainUpdateDeviceFlags = vboxDomainUpdateDeviceFlags, /* 0.8.0 */
    .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.6.5 */
9461
#if VBOX_API_VERSION >= 4000
9462
    .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */
9463
#endif
9464
#if VBOX_API_VERSION > 2002 && VBOX_API_VERSION < 4000
9465 9466
    .connectDomainEventRegister = vboxConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = vboxConnectDomainEventDeregister, /* 0.7.0 */
9467
#endif
9468 9469
    .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */
9470 9471 9472
    .domainIsActive = vboxDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */
9473
#if VBOX_API_VERSION > 2002 && VBOX_API_VERSION < 4000
9474 9475
    .connectDomainEventRegisterAny = vboxConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = vboxConnectDomainEventDeregisterAny, /* 0.8.0 */
9476
#endif
9477 9478 9479 9480 9481 9482
    .domainSnapshotCreateXML = vboxDomainSnapshotCreateXML, /* 0.8.0 */
    .domainSnapshotGetXMLDesc = vboxDomainSnapshotGetXMLDesc, /* 0.8.0 */
    .domainSnapshotNum = vboxDomainSnapshotNum, /* 0.8.0 */
    .domainSnapshotListNames = vboxDomainSnapshotListNames, /* 0.8.0 */
    .domainSnapshotLookupByName = vboxDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = vboxDomainHasCurrentSnapshot, /* 0.8.0 */
9483
    .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
9484
    .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */
9485 9486
    .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */
9487 9488
    .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */
9489
    .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */
9490
};
9491 9492 9493

virNetworkDriver NAME(NetworkDriver) = {
    "VBOX",
9494 9495
    .networkOpen = vboxNetworkOpen, /* 0.6.4 */
    .networkClose = vboxNetworkClose, /* 0.6.4 */
9496 9497 9498 9499
    .connectNumOfNetworks = vboxConnectNumOfNetworks, /* 0.6.4 */
    .connectListNetworks = vboxConnectListNetworks, /* 0.6.4 */
    .connectNumOfDefinedNetworks = vboxConnectNumOfDefinedNetworks, /* 0.6.4 */
    .connectListDefinedNetworks = vboxConnectListDefinedNetworks, /* 0.6.4 */
9500 9501 9502 9503 9504 9505 9506 9507
    .networkLookupByUUID = vboxNetworkLookupByUUID, /* 0.6.4 */
    .networkLookupByName = vboxNetworkLookupByName, /* 0.6.4 */
    .networkCreateXML = vboxNetworkCreateXML, /* 0.6.4 */
    .networkDefineXML = vboxNetworkDefineXML, /* 0.6.4 */
    .networkUndefine = vboxNetworkUndefine, /* 0.6.4 */
    .networkCreate = vboxNetworkCreate, /* 0.6.4 */
    .networkDestroy = vboxNetworkDestroy, /* 0.6.4 */
    .networkGetXMLDesc = vboxNetworkGetXMLDesc, /* 0.6.4 */
9508
};
9509 9510 9511

virStorageDriver NAME(StorageDriver) = {
    .name               = "VBOX",
9512 9513
    .storageOpen = vboxStorageOpen, /* 0.7.1 */
    .storageClose = vboxStorageClose, /* 0.7.1 */
9514 9515
    .connectNumOfStoragePools = vboxConnectNumOfStoragePools, /* 0.7.1 */
    .connectListStoragePools = vboxConnectListStoragePools, /* 0.7.1 */
9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527
    .storagePoolLookupByName = vboxStoragePoolLookupByName, /* 0.7.1 */
    .storagePoolNumOfVolumes = vboxStoragePoolNumOfVolumes, /* 0.7.1 */
    .storagePoolListVolumes = vboxStoragePoolListVolumes, /* 0.7.1 */

    .storageVolLookupByName = vboxStorageVolLookupByName, /* 0.7.1 */
    .storageVolLookupByKey = vboxStorageVolLookupByKey, /* 0.7.1 */
    .storageVolLookupByPath = vboxStorageVolLookupByPath, /* 0.7.1 */
    .storageVolCreateXML = vboxStorageVolCreateXML, /* 0.7.1 */
    .storageVolDelete = vboxStorageVolDelete, /* 0.7.1 */
    .storageVolGetInfo = vboxStorageVolGetInfo, /* 0.7.1 */
    .storageVolGetXMLDesc = vboxStorageVolGetXMLDesc, /* 0.7.1 */
    .storageVolGetPath = vboxStorageVolGetPath /* 0.7.1 */
9528
};