vbox_tmpl.c 342.5 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.
 */

/*
11
 * Copyright (C) 2010-2014 Red Hat, Inc.
12 13 14 15 16
 * 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
17
 * Foundation and shipped in the "COPYING.LESSER" file with this library.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 * 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
#elif VBOX_API_VERSION == 4002
# include "vbox_CAPI_v4_2.h"
R
Ryota Ozaki 已提交
77 78
#elif VBOX_API_VERSION == 4003
# include "vbox_CAPI_v4_3.h"
79 80
#else
# error "Unsupport VBOX_API_VERSION"
81 82
#endif

83
/* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */
84
#include "vbox_glue.h"
85 86


87
#define VIR_FROM_THIS                   VIR_FROM_VBOX
J
John Ferlan 已提交
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
#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)

112 113 114
#define VBOX_UTF16_TO_UTF8(arg1, arg2)  data->pFuncs->pfnUtf16ToUtf8(arg1, arg2)
#define VBOX_UTF8_TO_UTF16(arg1, arg2)  data->pFuncs->pfnUtf8ToUtf16(arg1, arg2)

115 116
#define VBOX_ADDREF(arg) (arg)->vtbl->nsisupports.AddRef((nsISupports *)(arg))

117 118 119 120 121 122 123
#define VBOX_RELEASE(arg)                                                     \
    do {                                                                      \
        if (arg) {                                                            \
            (arg)->vtbl->nsisupports.Release((nsISupports *)(arg));           \
            (arg) = NULL;                                                     \
        }                                                                     \
    } while (0)
124 125 126 127

#define VBOX_OBJECT_CHECK(conn, type, value) \
vboxGlobalData *data = conn->privateData;\
type ret = value;\
128
if (!data->vboxObj) {\
129 130 131 132 133 134 135
    return ret;\
}

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

#if VBOX_API_VERSION < 3001

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

#else  /* VBOX_API_VERSION >= 3001 */

typedef IMedium IHardDisk;
typedef IMediumAttachment IHardDiskAttachment;
158 159 160 161 162
# 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) \
163
    (object)->vtbl->func(object, arg1)
164
# define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
165 166 167
    (object)->vtbl->func(object, arg1, arg2)

#endif /* VBOX_API_VERSION >= 3001 */
168

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

#define DEBUGUUID(msg, iid) \
{\
182
    VIR_DEBUG(msg ": {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",\
183 184 185 186 187 188 189 190 191 192 193 194 195
          (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]);\
}\

196 197
typedef struct {
    virMutex lock;
198
    unsigned long version;
199 200

    virCapsPtr caps;
201
    virDomainXMLOptionPtr xmlopt;
202 203 204

    IVirtualBox *vboxObj;
    ISession *vboxSession;
205 206 207

    /** Our version specific API table pointer. */
    PCVBOXXPCOM pFuncs;
208 209 210 211 212 213 214

#if VBOX_API_VERSION == 2002

} vboxGlobalData;

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

215
    /* Async event handling */
216
    virObjectEventStatePtr domainEvents;
217 218
    int fdWatch;

219 220
# if VBOX_API_VERSION <= 3002
    /* IVirtualBoxCallback is used in VirtualBox 3.x only */
221
    IVirtualBoxCallback *vboxCallback;
222
# endif /* VBOX_API_VERSION <= 3002 */
223 224 225 226 227 228 229

    nsIEventQueue  *vboxQueue;
    int volatile vboxCallBackRefCount;

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

230 231
} vboxGlobalData;

232 233 234 235 236 237 238 239 240 241
/* 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
 */

242
static vboxGlobalData *g_pVBoxGlobalData = NULL;
243 244

#endif /* !(VBOX_API_VERSION == 2002) */
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 272 273 274 275
#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 */

276 277
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml);
static int vboxDomainCreate(virDomainPtr dom);
278
static int vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags);
279

280 281 282 283 284 285 286 287 288
static void vboxDriverLock(vboxGlobalData *data) {
    virMutexLock(&data->lock);
}

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

#if VBOX_API_VERSION == 2002
289

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

    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];

322
    for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
323 324 325 326
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
327
    ignore_value(virUUIDParse(uuidstrdst, uuid));
328 329
}

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

    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];

361
    for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
362 363 364 365
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
366
    ignore_value(virUUIDParse(uuidstrdst, uuidinterim));
367 368 369
    memcpy(iid, uuidinterim, VIR_UUID_BUFLEN);
}

370
# ifdef WIN32
371

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
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 */
387
}
388

389 390 391 392 393
static void
vboxIIDToUUID_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid, unsigned char *uuid)
{
    nsIDtoChar(uuid, (nsID *)&iid->value);
}
394

395 396 397 398 399
static void
vboxIIDFromUUID_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid,
                           const unsigned char *uuid)
{
    vboxIIDUnalloc_v2_x_WIN32(data, iid);
400

401
    nsIDFromChar((nsID *)&iid->value, uuid);
402 403
}

404 405 406
static bool
vboxIIDIsEqual_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid1, vboxIID_v2_x_WIN32 *iid2)
{
407
    return memcmp(&iid1->value, &iid2->value, sizeof(GUID)) == 0;
408
}
409

410 411 412 413 414 415 416 417
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);

418
    memcpy(&iid->value, &items[idx], sizeof(GUID));
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 446 447 448 449
}

#  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) {
450 451 452
        return;
    }

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
    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;

474
    sa_assert(iid->value);
475
    nsIDFromChar(iid->value, uuid);
476 477
}

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

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

    iid->value = &iid->backing;

492
    memcpy(iid->value, array->items[idx], sizeof(nsID));
493 494 495 496 497 498 499 500 501 502 503 504
}

#  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 */

505
#else /* VBOX_API_VERSION != 2002 */
506

507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
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;
529 530
}

531 532 533 534 535 536 537 538
static void
vboxIIDToUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                   unsigned char *uuid)
{
    char *utf8 = NULL;

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

539
    ignore_value(virUUIDParse(utf8, uuid));
540 541

    data->pFuncs->pfnUtf8Free(utf8);
542 543
}

544 545 546 547 548
static void
vboxIIDFromUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                     const unsigned char *uuid)
{
    char utf8[VIR_UUID_STRING_BUFLEN];
549

550
    vboxIIDUnalloc_v3_x(data, iid);
551

552
    virUUIDFormat(uuid, utf8);
553

554 555
    data->pFuncs->pfnUtf8ToUtf16(utf8, &iid->value);
}
556

557 558 559 560 561 562
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];
563 564

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

572 573
    return memcmp(uuid1, uuid2, VIR_UUID_BUFLEN) == 0;
}
574 575


576 577 578 579 580
static void
vboxIIDFromArrayItem_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                          vboxArray *array, int idx)
{
    vboxIIDUnalloc_v3_x(data, iid);
581

582 583
    iid->value = array->items[idx];
    iid->owner = false;
584 585
}

586 587 588 589 590 591 592 593

# 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)
594

595
# if VBOX_API_VERSION >= 3001
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611

/**
 * 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
 *
 */
612
static char *vboxGenerateMediumName(PRUint32  storageBus,
613 614 615 616 617
                                    PRInt32   deviceInst,
                                    PRInt32   devicePort,
                                    PRInt32   deviceSlot,
                                    PRUint32 *aMaxPortPerInst,
                                    PRUint32 *aMaxSlotPerPort) {
618
    const char *prefix = NULL;
619 620 621 622 623
    char *name  = NULL;
    int   total = 0;
    PRUint32 maxPortPerInst = 0;
    PRUint32 maxSlotPerPort = 0;

624 625
    if (!aMaxPortPerInst ||
        !aMaxSlotPerPort)
626 627
        return NULL;

628 629
    if ((storageBus < StorageBus_IDE) ||
        (storageBus > StorageBus_Floppy))
630 631 632 633 634 635 636 637 638
        return NULL;

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

    if (storageBus == StorageBus_IDE) {
639
        prefix = "hd";
640 641
    } else if ((storageBus == StorageBus_SATA) ||
               (storageBus == StorageBus_SCSI)) {
642
        prefix = "sd";
643
    } else if (storageBus == StorageBus_Floppy) {
644
        prefix = "fd";
645 646
    }

647
    name = virIndexToDiskName(total, prefix);
648

649
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
650
          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
651
          NULLSTR(name), total, storageBus, deviceInst, devicePort,
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 679 680 681 682
          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;

683 684 685 686 687 688
    if (!deviceName ||
        !deviceInst ||
        !devicePort ||
        !deviceSlot ||
        !aMaxPortPerInst ||
        !aMaxSlotPerPort)
689 690
        return false;

691 692
    if ((storageBus < StorageBus_IDE) ||
        (storageBus > StorageBus_Floppy))
693 694 695 696 697 698 699
        return false;

    total = virDiskNameToIndex(deviceName);

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

700 701 702
    if (!maxPortPerInst ||
        !maxSlotPerPort ||
        (total < 0))
703 704 705 706 707 708
        return false;

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

709
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
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 782 783 784 785
          "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;

786 787 788
    if (virStrToLong_i(strUtf8, NULL, 10, &ret) < 0)
        ret = -1;

789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
    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;
}

808
# endif /* VBOX_API_VERSION >= 3001 */
809

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

812 813 814 815 816 817
static PRUnichar *
vboxSocketFormatAddrUtf16(vboxGlobalData *data, virSocketAddrPtr addr)
{
    char *utf8 = NULL;
    PRUnichar *utf16 = NULL;

818
    utf8 = virSocketAddrFormat(addr);
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838

    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);

839
    if (virSocketAddrParse(addr, utf8, AF_UNSPEC) < 0) {
840 841 842 843 844 845 846 847 848 849 850
        goto cleanup;
    }

    result = 0;

cleanup:
    VBOX_UTF8_FREE(utf8);

    return result;
}

851

852 853 854 855 856
static virDomainDefParserConfig vboxDomainDefParserConfig = {
    .macPrefix = { 0x08, 0x00, 0x27 },
};


857
static virDomainXMLOptionPtr
858 859
vboxXMLConfInit(void)
{
860 861
    return virDomainXMLOptionNew(&vboxDomainDefParserConfig,
                                 NULL, NULL);
862 863 864
}


865 866
static virCapsPtr vboxCapsInit(void)
{
867 868 869
    virCapsPtr caps;
    virCapsGuestPtr guest;

870
    if ((caps = virCapabilitiesNew(virArchFromHost(),
871 872 873
                                   0, 0)) == NULL)
        goto no_memory;

874
    if (nodeCapsInitNUMA(caps) < 0)
875 876 877 878
        goto no_memory;

    if ((guest = virCapabilitiesAddGuest(caps,
                                         "hvm",
879
                                         caps->host.arch,
880 881 882 883 884 885 886 887 888 889 890 891 892
                                         NULL,
                                         NULL,
                                         0,
                                         NULL)) == NULL)
        goto no_memory;

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

894 895 896
    return caps;

no_memory:
897
    virObjectUnref(caps);
898 899 900
    return NULL;
}

901 902 903
static int
vboxInitialize(vboxGlobalData *data)
{
904 905 906
    data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION);

    if (data->pFuncs == NULL)
907
        goto cleanup;
908 909 910

#if VBOX_XPCOMC_VERSION == 0x00010000U
    data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
911
#else  /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
912 913
    data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj,
                               ISESSION_IID_STR, &data->vboxSession);
914

915
# if VBOX_API_VERSION == 2002
916 917 918

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

919
# else  /* !(VBOX_API_VERSION == 2002) */
920 921 922 923 924 925 926

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

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

    if (data->vboxQueue == NULL) {
927 928
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("nsIEventQueue object is null"));
929 930 931
        goto cleanup;
    }

932
# endif /* !(VBOX_API_VERSION == 2002) */
933
#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
934 935

    if (data->vboxObj == NULL) {
936 937
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("IVirtualBox object is null"));
938
        goto cleanup;
939 940 941
    }

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

    return 0;

cleanup:
    return -1;
}

953
static int vboxExtractVersion(vboxGlobalData *data) {
954
    int ret = -1;
955 956 957 958 959 960 961 962 963 964
    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;

965
        VBOX_UTF16_TO_UTF8(versionUtf16, &vboxVersion);
966

967
        if (virParseVersionString(vboxVersion, &data->version, false) >= 0)
968 969
            ret = 0;

970 971
        VBOX_UTF8_FREE(vboxVersion);
        VBOX_COM_UNALLOC_MEM(versionUtf16);
972 973 974
    }

    if (ret != 0)
975 976
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not extract VirtualBox version"));
977

978 979 980 981
    return ret;
}

static void vboxUninitialize(vboxGlobalData *data) {
982 983 984
    if (!data)
        return;

985 986
    if (data->pFuncs)
        data->pFuncs->pfnComUninitialize();
987

988
    virObjectUnref(data->caps);
989
    virObjectUnref(data->xmlopt);
990 991 992
#if VBOX_API_VERSION == 2002
    /* No domainEventCallbacks in 2.2.* version */
#else  /* !(VBOX_API_VERSION == 2002) */
993
    virObjectEventStateFree(data->domainEvents);
994
#endif /* !(VBOX_API_VERSION == 2002) */
995 996 997
    VIR_FREE(data);
}

998

999 1000 1001
static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
1002
{
1003
    vboxGlobalData *data = NULL;
1004
    uid_t uid = geteuid();
1005

E
Eric Blake 已提交
1006 1007
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1008 1009 1010
    if (conn->uri == NULL &&
        !(conn->uri = virURIParse(uid ? "vbox:///session" : "vbox:///system")))
        return VIR_DRV_OPEN_ERROR;
1011

1012
    if (conn->uri->scheme == NULL ||
1013
        STRNEQ(conn->uri->scheme, "vbox"))
1014 1015 1016 1017
        return VIR_DRV_OPEN_DECLINED;

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

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

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

1041
    if (VIR_ALLOC(data) < 0)
1042
        return VIR_DRV_OPEN_ERROR;
1043

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

1052 1053 1054 1055 1056 1057
#if VBOX_API_VERSION == 2002

    /* No domainEventCallbacks in 2.2.* version */

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

1058
    if (!(data->domainEvents = virObjectEventStateNew())) {
1059
        vboxUninitialize(data);
1060 1061 1062 1063 1064 1065 1066 1067
        return VIR_DRV_OPEN_ERROR;
    }

    data->conn = conn;
    g_pVBoxGlobalData = data;

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

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

    return VIR_DRV_OPEN_SUCCESS;
}

1074
static int vboxConnectClose(virConnectPtr conn) {
1075
    vboxGlobalData *data = conn->privateData;
E
Eric Blake 已提交
1076
    VIR_DEBUG("%s: in vboxClose", conn->driver->name);
1077 1078 1079 1080 1081 1082 1083

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

    return 0;
}

1084
static int vboxConnectGetVersion(virConnectPtr conn, unsigned long *version) {
1085
    vboxGlobalData *data = conn->privateData;
E
Eric Blake 已提交
1086
    VIR_DEBUG("%s: in vboxGetVersion", conn->driver->name);
1087 1088 1089 1090 1091 1092 1093 1094

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

    return 0;
}

1095 1096 1097 1098 1099 1100 1101

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


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

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

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

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

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

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

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}


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

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

    return ret;
}

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

1156
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1157
    if (NS_FAILED(rc)) {
1158
        virReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
1159 1160
                       _("Could not get list of Domains, rc=%08x"),
                       (unsigned)rc);
1161 1162
        goto cleanup;
    }
1163

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

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

cleanup:
1183
    vboxArrayRelease(&machines);
1184 1185 1186
    return ret;
}

1187
static int vboxConnectNumOfDomains(virConnectPtr conn) {
1188
    VBOX_OBJECT_CHECK(conn, int, -1);
1189
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1190
    PRUint32 state;
1191
    nsresult rc;
1192
    size_t i;
1193

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

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

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

cleanup:
1218
    vboxArrayRelease(&machines);
1219 1220 1221 1222
    return ret;
}

static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml,
1223
                                        unsigned int flags) {
1224 1225 1226 1227 1228 1229 1230 1231
    /* 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.
     */

1232 1233 1234 1235 1236
    virDomainPtr dom;

    virCheckFlags(0, NULL);

    dom = vboxDomainDefineXML(conn, xml);
1237 1238 1239 1240
    if (dom == NULL)
        return NULL;

    if (vboxDomainCreate(dom) < 0) {
1241
        vboxDomainUndefineFlags(dom, 0);
1242
        virObjectUnref(dom);
1243
        return NULL;
1244 1245 1246 1247 1248 1249
    }

    return dom;
}

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

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

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

1273 1274 1275 1276
    if (id < machines.count) {
        IMachine *machine = machines.items[id];

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

1286
                    machine->vtbl->GetName(machine, &machineNameUtf16);
1287
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1288

1289 1290 1291
                    machine->vtbl->GetId(machine, &iid.value);
                    vboxIIDToUUID(&iid, uuid);
                    vboxIIDUnalloc(&iid);
1292 1293 1294 1295 1296 1297 1298

                    /* 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.
                     */

1299
                    ret = virGetDomain(conn, machineNameUtf8, uuid);
1300 1301 1302 1303 1304 1305
                    if (ret)
                        ret->id = id + 1;

                    /* Cleanup all the XPCOM allocated stuff here */
                    VBOX_UTF8_FREE(machineNameUtf8);
                    VBOX_UTF16_FREE(machineNameUtf16);
1306 1307 1308 1309 1310
                }
            }
        }
    }

1311
    vboxArrayRelease(&machines);
1312 1313

    return ret;
1314 1315 1316
}

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

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

1334 1335
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1336
        PRBool isAccessible = PR_FALSE;
1337

1338 1339
        if (!machine)
            continue;
1340

1341 1342
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1343

1344 1345
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
1346
                continue;
1347 1348
            vboxIIDToUUID(&iid, iid_as_uuid);
            vboxIIDUnalloc(&iid);
1349

1350
            if (memcmp(uuid, iid_as_uuid, VIR_UUID_BUFLEN) == 0) {
1351

1352
                PRUint32 state;
1353

1354
                matched = 1;
1355

1356 1357
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1358

1359
                machine->vtbl->GetState(machine, &state);
1360

1361 1362 1363 1364 1365
                /* 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.
                 */
1366

1367
                ret = virGetDomain(conn, machineNameUtf8, iid_as_uuid);
1368 1369 1370
                if (ret &&
                    (state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1371
                    ret->id = i + 1;
1372 1373
            }

1374 1375
            if (matched == 1)
                break;
1376 1377 1378
        }
    }

1379 1380 1381
    /* Do the cleanup and take care you dont leak any memory */
    VBOX_UTF8_FREE(machineNameUtf8);
    VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1382
    vboxArrayRelease(&machines);
1383 1384

    return ret;
1385 1386 1387
}

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

1398
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1399
    if (NS_FAILED(rc)) {
1400 1401
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1402 1403
        return NULL;
    }
1404

1405 1406
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1407
        PRBool isAccessible = PR_FALSE;
1408

1409 1410
        if (!machine)
            continue;
1411

1412 1413
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1414

1415 1416
            machine->vtbl->GetName(machine, &machineNameUtf16);
            VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1417

1418
            if (STREQ(name, machineNameUtf8)) {
1419

1420
                PRUint32 state;
1421

1422
                matched = 1;
1423

1424 1425 1426
                machine->vtbl->GetId(machine, &iid.value);
                vboxIIDToUUID(&iid, uuid);
                vboxIIDUnalloc(&iid);
1427

1428
                machine->vtbl->GetState(machine, &state);
1429

1430 1431 1432 1433 1434
                /* 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.
                 */
1435

1436
                ret = virGetDomain(conn, machineNameUtf8, uuid);
1437 1438 1439
                if (ret &&
                    (state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1440
                    ret->id = i + 1;
1441 1442
            }

J
John Ferlan 已提交
1443 1444
            VBOX_UTF8_FREE(machineNameUtf8);
            VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1445 1446
            if (matched == 1)
                break;
1447 1448 1449
        }
    }

1450
    vboxArrayRelease(&machines);
1451 1452

    return ret;
1453 1454
}

1455 1456

static int vboxDomainIsActive(virDomainPtr dom) {
1457
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1458
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1459
    vboxIID iid = VBOX_IID_INITIALIZER;
1460 1461
    char      *machineNameUtf8  = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1462
    unsigned char uuid[VIR_UUID_BUFLEN];
1463 1464
    size_t i;
    int matched = 0;
1465
    nsresult rc;
1466

1467
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1468
    if (NS_FAILED(rc)) {
1469 1470
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1471 1472
        return ret;
    }
1473

1474 1475
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1476 1477 1478 1479 1480 1481 1482
        PRBool isAccessible = PR_FALSE;

        if (!machine)
            continue;

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

1484 1485
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
1486
                continue;
1487 1488
            vboxIIDToUUID(&iid, uuid);
            vboxIIDUnalloc(&iid);
1489

1490
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
1491

1492
                PRUint32 state;
1493

1494
                matched = 1;
1495

1496 1497
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1498

1499
                machine->vtbl->GetState(machine, &state);
1500

1501 1502
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1503 1504 1505
                    ret = 1;
                else
                    ret = 0;
1506 1507
            }

1508 1509
            if (matched == 1)
                break;
1510 1511 1512
        }
    }

1513 1514 1515
    /* Do the cleanup and take care you dont leak any memory */
    VBOX_UTF8_FREE(machineNameUtf8);
    VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1516
    vboxArrayRelease(&machines);
1517

1518 1519 1520 1521
    return ret;
}


1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533
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)) {
1534 1535
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1536 1537 1538 1539 1540 1541 1542 1543 1544
        goto cleanup;
    }

    ret = 1;

cleanup:
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1545 1546 1547
}


1548
static int vboxDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED) {
1549 1550 1551 1552 1553 1554 1555 1556 1557 1558
    /* 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)) {
1559 1560
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1561 1562 1563 1564 1565 1566 1567 1568 1569
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1570 1571
}

1572
static int vboxDomainSuspend(virDomainPtr dom) {
1573
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1574
    IMachine *machine    = NULL;
1575
    vboxIID iid = VBOX_IID_INITIALIZER;
1576
    IConsole *console    = NULL;
1577
    PRBool isAccessible  = PR_FALSE;
1578
    PRUint32 state;
1579
    nsresult rc;
1580

1581
    vboxIIDFromUUID(&iid, dom->uuid);
1582
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1583
    if (NS_FAILED(rc)) {
1584 1585
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1586 1587
        goto cleanup;
    }
1588

1589 1590
    if (!machine)
        goto cleanup;
1591

1592 1593 1594
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1595

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

cleanup:
1618
    VBOX_RELEASE(machine);
1619
    vboxIIDUnalloc(&iid);
1620 1621 1622 1623
    return ret;
}

static int vboxDomainResume(virDomainPtr dom) {
1624
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1625
    IMachine *machine    = NULL;
1626
    vboxIID iid = VBOX_IID_INITIALIZER;
1627 1628
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1629
    nsresult rc;
1630

1631
    PRBool isAccessible = PR_FALSE;
1632

1633
    vboxIIDFromUUID(&iid, dom->uuid);
1634
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1635
    if (NS_FAILED(rc)) {
1636 1637
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1638 1639
        goto cleanup;
    }
1640

1641 1642
    if (!machine)
        goto cleanup;
1643

1644 1645 1646 1647 1648
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);

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

cleanup:
1670
    VBOX_RELEASE(machine);
1671
    vboxIIDUnalloc(&iid);
1672 1673 1674
    return ret;
}

1675 1676
static int vboxDomainShutdownFlags(virDomainPtr dom,
                                   unsigned int flags) {
1677
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1678
    IMachine *machine    = NULL;
1679
    vboxIID iid = VBOX_IID_INITIALIZER;
1680 1681
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1682 1683
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1684

1685 1686
    virCheckFlags(0, -1);

1687
    vboxIIDFromUUID(&iid, dom->uuid);
1688
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1689
    if (NS_FAILED(rc)) {
1690 1691
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1692 1693
        goto cleanup;
    }
1694

1695 1696
    if (!machine)
        goto cleanup;
1697

1698 1699 1700
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1701

1702
        if (state == MachineState_Paused) {
1703 1704
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine paused, so can't power it down"));
1705 1706
            goto cleanup;
        } else if (state == MachineState_PoweredOff) {
1707 1708
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1709 1710
            goto cleanup;
        }
1711

1712
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1713 1714 1715 1716 1717
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
            console->vtbl->PowerButton(console);
            VBOX_RELEASE(console);
            ret = 0;
1718
        }
1719
        VBOX_SESSION_CLOSE();
1720 1721 1722
    }

cleanup:
1723
    VBOX_RELEASE(machine);
1724
    vboxIIDUnalloc(&iid);
1725 1726 1727
    return ret;
}

1728 1729 1730 1731 1732
static int vboxDomainShutdown(virDomainPtr dom) {
    return vboxDomainShutdownFlags(dom, 0);
}


E
Eric Blake 已提交
1733 1734
static int vboxDomainReboot(virDomainPtr dom, unsigned int flags)
{
1735
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1736
    IMachine *machine    = NULL;
1737
    vboxIID iid = VBOX_IID_INITIALIZER;
1738 1739
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1740 1741
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1742

E
Eric Blake 已提交
1743 1744
    virCheckFlags(0, -1);

1745
    vboxIIDFromUUID(&iid, dom->uuid);
1746
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1747
    if (NS_FAILED(rc)) {
1748 1749
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1750 1751
        goto cleanup;
    }
1752

1753 1754
    if (!machine)
        goto cleanup;
1755

1756 1757 1758
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1759

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

cleanup:
1777
    VBOX_RELEASE(machine);
1778
    vboxIIDUnalloc(&iid);
1779 1780 1781
    return ret;
}

1782 1783 1784 1785
static int
vboxDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
1786
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1787
    IMachine *machine    = NULL;
1788
    vboxIID iid = VBOX_IID_INITIALIZER;
1789 1790
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1791 1792
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1793

1794 1795
    virCheckFlags(0, -1);

1796
    vboxIIDFromUUID(&iid, dom->uuid);
1797
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1798
    if (NS_FAILED(rc)) {
1799 1800
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1801 1802
        goto cleanup;
    }
1803

1804 1805
    if (!machine)
        goto cleanup;
1806

1807 1808 1809
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1810

1811
        if (state == MachineState_PoweredOff) {
1812 1813
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1814 1815
            goto cleanup;
        }
1816

1817
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1818 1819
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
1820 1821

#if VBOX_API_VERSION == 2002
1822
            console->vtbl->PowerDown(console);
1823
#else
1824
            IProgress *progress = NULL;
1825 1826 1827 1828
            console->vtbl->PowerDown(console, &progress);
            if (progress) {
                progress->vtbl->WaitForCompletion(progress, -1);
                VBOX_RELEASE(progress);
1829
            }
1830 1831
#endif
            VBOX_RELEASE(console);
1832
            dom->id = -1;
1833
            ret = 0;
1834
        }
1835
        VBOX_SESSION_CLOSE();
1836 1837 1838
    }

cleanup:
1839
    VBOX_RELEASE(machine);
1840
    vboxIIDUnalloc(&iid);
1841 1842 1843
    return ret;
}

1844 1845 1846 1847 1848 1849
static int
vboxDomainDestroy(virDomainPtr dom)
{
    return vboxDomainDestroyFlags(dom, 0);
}

1850
static char *vboxDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) {
1851 1852 1853 1854 1855
    /* 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 ;)
     */
1856
    char *osType;
1857

1858
    ignore_value(VIR_STRDUP(osType, "hvm"));
1859
    return osType;
1860 1861 1862
}

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

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

1878 1879
    if (!machine)
        goto cleanup;
1880

1881 1882 1883
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1884

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

1891
        rc = VBOX_SESSION_OPEN(iid.value, machine);
1892 1893 1894
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
1895

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

cleanup:
1913
    VBOX_RELEASE(machine);
1914
    vboxIIDUnalloc(&iid);
1915 1916 1917
    return ret;
}

1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928
static virDomainState vboxConvertState(enum MachineState state) {
    switch (state) {
        case MachineState_Running:
            return VIR_DOMAIN_RUNNING;
        case MachineState_Stuck:
            return VIR_DOMAIN_BLOCKED;
        case MachineState_Paused:
            return VIR_DOMAIN_PAUSED;
        case MachineState_Stopping:
            return VIR_DOMAIN_SHUTDOWN;
        case MachineState_PoweredOff:
R
Ryota Ozaki 已提交
1929
        case MachineState_Saved:
1930 1931 1932 1933 1934 1935 1936 1937 1938
            return VIR_DOMAIN_SHUTOFF;
        case MachineState_Aborted:
            return VIR_DOMAIN_CRASHED;
        case MachineState_Null:
        default:
            return VIR_DOMAIN_NOSTATE;
    }
}

1939
static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info) {
1940
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1941
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1942 1943
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1944
    nsresult rc;
1945
    size_t i = 0;
1946

1947
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1948
    if (NS_FAILED(rc)) {
1949 1950
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1951 1952
        goto cleanup;
    }
1953

1954
    info->nrVirtCpu = 0;
1955 1956
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1957
        PRBool isAccessible = PR_FALSE;
1958

1959 1960
        if (!machine)
            continue;
1961

1962 1963
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1964

1965 1966 1967 1968 1969 1970
            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
1971
                * for time being set max_balloon and cur_balloon to same
1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
                * 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;
                }
1989 1990


1991 1992 1993 1994 1995 1996
                machine->vtbl->GetCPUCount(machine, &CPUCount);
                machine->vtbl->GetMemorySize(machine, &memorySize);
                machine->vtbl->GetState(machine, &state);

                info->cpuTime = 0;
                info->nrVirtCpu = CPUCount;
1997 1998
                info->memory = memorySize * 1024;
                info->maxMem = maxMemorySize * 1024;
1999
                info->state = vboxConvertState(state);
2000

2001
                ret = 0;
2002 2003
            }

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

    }

2012
    vboxArrayRelease(&machines);
2013 2014 2015 2016 2017

cleanup:
    return ret;
}

2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034
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)) {
2035 2036
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
2037 2038 2039 2040 2041
        goto cleanup;
    }

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

2042
    *state = vboxConvertState(mstate);
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053

    if (reason)
        *reason = 0;

    ret = 0;

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

2054
static int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED) {
2055
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
2056
    IConsole *console    = NULL;
2057
    vboxIID iid = VBOX_IID_INITIALIZER;
2058
    IMachine *machine = NULL;
2059
    nsresult rc;
2060 2061 2062 2063 2064 2065 2066 2067

    /* 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
     */

2068
    /* Open a Session for the machine */
2069
    vboxIIDFromUUID(&iid, dom->uuid);
2070 2071 2072 2073
#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)) {
2074 2075
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
2076 2077 2078 2079 2080
        return -1;
    }
#endif

    rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
2081 2082 2083 2084
    if (NS_SUCCEEDED(rc)) {
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (NS_SUCCEEDED(rc) && console) {
            IProgress *progress = NULL;
2085

2086
            console->vtbl->SaveState(console, &progress);
2087

2088
            if (progress) {
2089
#if VBOX_API_VERSION == 2002
2090
                nsresult resultCode;
2091
#else
2092
                PRInt32 resultCode;
2093
#endif
2094

2095 2096 2097 2098
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
                if (NS_SUCCEEDED(resultCode)) {
                    ret = 0;
2099
                }
2100
                VBOX_RELEASE(progress);
2101
            }
2102
            VBOX_RELEASE(console);
2103
        }
2104
        VBOX_SESSION_CLOSE();
2105 2106
    }

2107
    DEBUGIID("UUID of machine being saved:", iid.value);
2108

2109
    VBOX_RELEASE(machine);
2110
    vboxIIDUnalloc(&iid);
2111 2112 2113
    return ret;
}

2114 2115 2116 2117
static int
vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
{
2118
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
2119
    IMachine *machine    = NULL;
2120
    vboxIID iid = VBOX_IID_INITIALIZER;
2121
    PRUint32  CPUCount   = nvcpus;
2122
    nsresult rc;
2123

2124
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
2125
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2126 2127 2128
        return -1;
    }

2129
    vboxIIDFromUUID(&iid, dom->uuid);
2130 2131 2132 2133
#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)) {
2134 2135
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
2136 2137 2138 2139 2140
        return -1;
    }
#endif

    rc = VBOX_SESSION_OPEN(iid.value, machine);
2141 2142 2143 2144 2145 2146 2147
    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;
2148
            } else {
2149 2150 2151 2152
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("could not set the number of cpus of the domain "
                                 "to: %u, rc=%08x"),
                               CPUCount, (unsigned)rc);
2153
            }
2154
            VBOX_RELEASE(machine);
2155
        } else {
2156 2157
            virReportError(VIR_ERR_NO_DOMAIN,
                           _("no domain with matching id %d"), dom->id);
2158
        }
2159
    } else {
2160 2161
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("can't open session to the domain with id %d"), dom->id);
2162
    }
2163
    VBOX_SESSION_CLOSE();
2164

2165
    vboxIIDUnalloc(&iid);
2166 2167 2168
    return ret;
}

2169 2170 2171
static int
vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
2172
    return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2173 2174 2175 2176 2177
}

static int
vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
2178 2179
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    ISystemProperties *systemProperties = NULL;
2180 2181
    PRUint32 maxCPUCount = 0;

2182
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
2183
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2184 2185 2186
        return -1;
    }

2187 2188 2189 2190 2191
    /* Currently every domain supports the same number of max cpus
     * as that supported by vbox and thus take it directly from
     * the systemproperties.
     */

2192 2193 2194 2195
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
        VBOX_RELEASE(systemProperties);
2196 2197 2198 2199 2200 2201 2202 2203
    }

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}

2204 2205 2206
static int
vboxDomainGetMaxVcpus(virDomainPtr dom)
{
2207
    return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
2208 2209 2210
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

2211 2212
static void vboxHostDeviceGetXMLDesc(vboxGlobalData *data, virDomainDefPtr def, IMachine *machine)
{
R
Ryota Ozaki 已提交
2213
#if VBOX_API_VERSION < 4003
2214 2215
    IUSBController *USBController = NULL;
    PRBool enabled = PR_FALSE;
R
Ryota Ozaki 已提交
2216 2217 2218
#else
    IUSBDeviceFilters *USBDeviceFilters = NULL;
#endif
2219 2220 2221 2222 2223
    vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER;
    size_t i;
    PRUint32 USBFilterCount = 0;

    def->nhostdevs = 0;
R
Ryota Ozaki 已提交
2224 2225

#if VBOX_API_VERSION < 4003
2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237
    machine->vtbl->GetUSBController(machine, &USBController);

    if (!USBController)
        return;

    USBController->vtbl->GetEnabled(USBController, &enabled);
    if (!enabled)
        goto release_controller;

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

R
Ryota Ozaki 已提交
2238 2239 2240 2241 2242 2243 2244 2245 2246 2247
#else
    machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);

    if (!USBDeviceFilters)
        return;

    vboxArrayGet(&deviceFilters, USBDeviceFilters,
                 USBDeviceFilters->vtbl->GetDeviceFilters);
#endif

2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271
    if (deviceFilters.count <= 0)
        goto release_filters;

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

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

        deviceFilter->vtbl->GetActive(deviceFilter, &active);
        if (active) {
            def->nhostdevs++;
        }
    }

    if (def->nhostdevs == 0)
        goto release_filters;

    /* Alloc mem needed for the filters now */
    if (VIR_ALLOC_N(def->hostdevs, def->nhostdevs) < 0)
        goto release_filters;

2272 2273 2274 2275 2276 2277
    for (i = 0; i < def->nhostdevs; i++) {
        def->hostdevs[i] = virDomainHostdevDefAlloc();
        if (!def->hostdevs[i])
            goto release_hostdevs;
    }

2278
    for (i = 0; i < deviceFilters.count; i++) {
2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320
        PRBool active                  = PR_FALSE;
        IUSBDeviceFilter *deviceFilter = deviceFilters.items[i];
        PRUnichar *vendorIdUtf16       = NULL;
        char *vendorIdUtf8             = NULL;
        unsigned vendorId              = 0;
        PRUnichar *productIdUtf16      = NULL;
        char *productIdUtf8            = NULL;
        unsigned productId             = 0;
        char *endptr                   = NULL;

        deviceFilter->vtbl->GetActive(deviceFilter, &active);
        if (!active)
            continue;

        def->hostdevs[USBFilterCount]->mode =
            VIR_DOMAIN_HOSTDEV_MODE_SUBSYS;
        def->hostdevs[USBFilterCount]->source.subsys.type =
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB;

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

        VBOX_UTF16_TO_UTF8(vendorIdUtf16, &vendorIdUtf8);
        VBOX_UTF16_TO_UTF8(productIdUtf16, &productIdUtf8);

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

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

        VBOX_UTF16_FREE(vendorIdUtf16);
        VBOX_UTF8_FREE(vendorIdUtf8);

        VBOX_UTF16_FREE(productIdUtf16);
        VBOX_UTF8_FREE(productIdUtf8);

        USBFilterCount++;
    }

release_filters:
    vboxArrayRelease(&deviceFilters);
R
Ryota Ozaki 已提交
2321
#if VBOX_API_VERSION < 4003
2322 2323
release_controller:
    VBOX_RELEASE(USBController);
R
Ryota Ozaki 已提交
2324 2325 2326
#else
    VBOX_RELEASE(USBDeviceFilters);
#endif
2327 2328 2329 2330 2331 2332 2333 2334 2335

    return;

release_hostdevs:
    for (i = 0; i < def->nhostdevs; i++)
        virDomainHostdevDefFree(def->hostdevs[i]);
    VIR_FREE(def->hostdevs);

    goto release_filters;
2336 2337
}

2338
static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
2339
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
2340 2341
    virDomainDefPtr def  = NULL;
    IMachine *machine    = NULL;
2342
    vboxIID iid = VBOX_IID_INITIALIZER;
2343
    int gotAllABoutDef   = -1;
2344
    nsresult rc;
2345

2346 2347
    /* Flags checked by virDomainDefFormat */

2348
    if (VIR_ALLOC(def) < 0)
2349 2350
        goto cleanup;

2351
    vboxIIDFromUUID(&iid, dom->uuid);
2352
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
2353
    if (NS_SUCCEEDED(rc)) {
2354
        PRBool accessible = PR_FALSE;
2355

2356 2357
        machine->vtbl->GetAccessible(machine, &accessible);
        if (accessible) {
2358
            size_t i = 0;
2359 2360 2361
            PRBool PAEEnabled                   = PR_FALSE;
            PRBool ACPIEnabled                  = PR_FALSE;
            PRBool IOAPICEnabled                = PR_FALSE;
2362
            PRBool VRDxEnabled                  = PR_FALSE;
2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383
            PRUint32 CPUCount                   = 0;
            PRUint32 memorySize                 = 0;
            PRUint32 netAdpCnt                  = 0;
            PRUint32 netAdpIncCnt               = 0;
            PRUint32 maxMemorySize              = 4 * 1024;
            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 */
2384
            vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
2385
#endif /* VBOX_API_VERSION >= 3001 */
2386 2387 2388 2389 2390
#if VBOX_API_VERSION < 4000
            IVRDPServer *VRDxServer             = NULL;
#else  /* VBOX_API_VERSION >= 4000 */
            IVRDEServer *VRDxServer             = NULL;
#endif /* VBOX_API_VERSION >= 4000 */
2391
            IAudioAdapter *audioAdapter         = NULL;
2392 2393 2394
#if VBOX_API_VERSION >= 4001
            PRUint32 chipsetType                = ChipsetType_Null;
#endif /* VBOX_API_VERSION >= 4001 */
2395
            ISystemProperties *systemProperties = NULL;
2396 2397


2398 2399 2400
            def->virtType = VIR_DOMAIN_VIRT_VBOX;
            def->id = dom->id;
            memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
2401 2402
            if (VIR_STRDUP(def->name, dom->name) < 0)
                goto cleanup;
2403

2404
            machine->vtbl->GetMemorySize(machine, &memorySize);
2405
            def->mem.cur_balloon = memorySize * 1024;
2406

2407 2408 2409 2410
#if VBOX_API_VERSION >= 4001
            machine->vtbl->GetChipsetType(machine, &chipsetType);
#endif /* VBOX_API_VERSION >= 4001 */

2411 2412 2413 2414
            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
2415
#if VBOX_API_VERSION < 4001
2416
                systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt);
2417 2418 2419
#else  /* VBOX_API_VERSION >= 4000 */
                systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType, &netAdpCnt);
#endif /* VBOX_API_VERSION >= 4000 */
2420 2421 2422 2423 2424 2425 2426 2427 2428
                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
             */
2429 2430
            /* def->mem.max_balloon = maxMemorySize * 1024; */
            def->mem.max_balloon = memorySize * 1024;
2431 2432

            machine->vtbl->GetCPUCount(machine, &CPUCount);
E
Eric Blake 已提交
2433
            def->maxvcpus = def->vcpus = CPUCount;
2434 2435 2436

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

2437 2438
            if (VIR_STRDUP(def->os.type, "hvm") < 0)
                goto cleanup;
2439

2440
            def->os.arch = virArchFromHost();
2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463

            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 已提交
2464
                    /* Can VirtualBox really boot from a shared folder? */
2465
                }
2466
            }
2467

2468 2469
#if VBOX_API_VERSION < 3001
            machine->vtbl->GetPAEEnabled(machine, &PAEEnabled);
2470
#elif VBOX_API_VERSION == 3001
2471
            machine->vtbl->GetCpuProperty(machine, CpuPropertyType_PAE, &PAEEnabled);
2472 2473 2474
#elif VBOX_API_VERSION >= 3002
            machine->vtbl->GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled);
#endif
2475 2476
            if (PAEEnabled)
                def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_DOMAIN_FEATURE_STATE_ON;
2477

2478 2479 2480
            machine->vtbl->GetBIOSSettings(machine, &bios);
            if (bios) {
                bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled);
2481 2482
                if (ACPIEnabled)
                    def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_DOMAIN_FEATURE_STATE_ON;
2483

2484
                bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled);
2485 2486
                if (IOAPICEnabled)
                    def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_DOMAIN_FEATURE_STATE_ON;
2487

2488 2489 2490 2491 2492
                VBOX_RELEASE(bios);
            }

            /* Currently VirtualBox always uses locatime
             * so locatime is always true here */
2493
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
2494 2495 2496 2497 2498 2499 2500 2501

            /* 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 */
2502
                        PRUint32 VRAMSize          = 8;
2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514
                        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;
2515
                        def->videos[0]->vram            = VRAMSize * 1024;
2516 2517 2518 2519
                        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;
2520 2521 2522
                        }
                    }
                }
2523
            }
2524

2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535
            /* 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;
2536

2537
                def->ngraphics = 0;
2538

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

2543 2544 2545
                if (valueTypeUtf16) {
                    VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
                    VBOX_UTF16_FREE(valueTypeUtf16);
2546

2547
                    if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
2548 2549 2550
                        PRUnichar *keyDislpayUtf16   = NULL;
                        PRUnichar *valueDisplayUtf16 = NULL;
                        char      *valueDisplayUtf8  = NULL;
2551

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

2556 2557 2558
                        if (valueDisplayUtf16) {
                            VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
                            VBOX_UTF16_FREE(valueDisplayUtf16);
2559

J
John Ferlan 已提交
2560
                            if (strlen(valueDisplayUtf8) <= 0)
2561
                                VBOX_UTF8_FREE(valueDisplayUtf8);
2562
                        }
2563

2564 2565
                        if (STREQ(valueTypeUtf8, "sdl")) {
                            sdlPresent = 1;
2566
                            if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) {
2567 2568 2569 2570 2571 2572
                                /* 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++;
2573
                        }
2574

2575 2576
                        if (STREQ(valueTypeUtf8, "gui")) {
                            guiPresent = 1;
2577
                            if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) {
2578
                                /* just don't go to cleanup yet as it is ok to have
2579 2580
                                 * guiDisplay as NULL and we check it below if it
                                 * exist and then only use it there
2581
                                 */
2582
                            }
2583 2584
                            totalPresent++;
                        }
J
John Ferlan 已提交
2585
                        VBOX_UTF8_FREE(valueDisplayUtf8);
2586 2587
                    }

2588 2589
                    if (STREQ(valueTypeUtf8, "vrdp"))
                        vrdpPresent = 1;
2590

2591 2592
                    VBOX_UTF8_FREE(valueTypeUtf8);
                }
2593

2594 2595 2596 2597 2598 2599 2600
                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++;
                    }
2601

2602 2603 2604 2605 2606 2607 2608 2609
                    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) {
2610
                        const char *tmp;
2611
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
2612
                        tmp = virGetEnvBlockSUID("DISPLAY");
2613 2614 2615 2616
                        if (VIR_STRDUP(def->graphics[def->ngraphics]->data.desktop.display, tmp) < 0) {
                            /* just don't go to cleanup yet as it is ok to have
                             * display as NULL
                             */
2617 2618 2619 2620 2621
                        }
                        totalPresent++;
                        def->ngraphics++;
                    }
                }
2622

2623 2624 2625 2626 2627 2628 2629 2630
#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) {
2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641

                        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;
2642
                            VRDxServer->vtbl->GetPort(VRDxServer, &VRDPport);
2643 2644
                            if (VRDPport) {
                                def->graphics[def->ngraphics]->data.rdp.port = VRDPport;
2645
#elif VBOX_API_VERSION < 4000 /* 3001 <= VBOX_API_VERSION < 4000 */
2646
                            PRUnichar *VRDPport = NULL;
2647
                            VRDxServer->vtbl->GetPorts(VRDxServer, &VRDPport);
2648 2649 2650 2651
                            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);
2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662
#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 */
2663
                            } else {
2664
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
2665
                            }
2666

2667
                            def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;
2668

2669 2670 2671 2672 2673 2674 2675 2676
#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 */
2677 2678 2679
                            if (netAddressUtf16) {
                                VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8);
                                if (STRNEQ(netAddressUtf8, ""))
2680 2681
                                    virDomainGraphicsListenSetAddress(def->graphics[def->ngraphics], 0,
                                                                      netAddressUtf8, -1, true);
2682 2683 2684
                                VBOX_UTF16_FREE(netAddressUtf16);
                                VBOX_UTF8_FREE(netAddressUtf8);
                            }
2685

2686
                            VRDxServer->vtbl->GetAllowMultiConnection(VRDxServer, &allowMultiConnection);
2687
                            if (allowMultiConnection) {
2688
                                def->graphics[def->ngraphics]->data.rdp.multiUser = true;
2689
                            }
2690

2691
                            VRDxServer->vtbl->GetReuseSingleConnection(VRDxServer, &reuseSingleConnection);
2692
                            if (reuseSingleConnection) {
2693
                                def->graphics[def->ngraphics]->data.rdp.replaceUser = true;
2694
                            }
2695

2696
                            def->ngraphics++;
2697
                        } else
2698
                            virReportOOMError();
2699
                    }
2700
                    VBOX_RELEASE(VRDxServer);
2701
                }
2702
            }
2703

2704 2705 2706
#if VBOX_API_VERSION < 3001
            /* dump IDE hdds if present */
            VBOX_UTF8_TO_UTF16(hddBus, &hddBusUtf16);
2707

2708 2709 2710 2711
            def->ndisks = 0;
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 0,  &hardDiskPM);
            if (hardDiskPM)
                def->ndisks++;
2712

2713 2714 2715
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 1,  &hardDiskPS);
            if (hardDiskPS)
                def->ndisks++;
2716

2717 2718 2719
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 1, 1,  &hardDiskSS);
            if (hardDiskSS)
                def->ndisks++;
2720

2721 2722 2723 2724 2725 2726 2727 2728
            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;
2729
                    }
2730
                }
2731
            }
2732

2733 2734 2735 2736
            if (hardDiskPM) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2737

2738 2739
                hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2740

2741
                hardDiskPM->vtbl->GetType(hardDiskPM, &hddType);
2742

2743
                if (hddType == HardDiskType_Immutable)
2744
                    def->disks[hddNum]->readonly = true;
2745 2746
                ignore_value(VIR_STRDUP(def->disks[hddNum]->src, hddlocation));
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hda"));
2747
                hddNum++;
2748

2749 2750 2751 2752
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPM);
            }
2753

2754 2755 2756 2757
            if (hardDiskPS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2758

2759 2760
                hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2761

2762
                hardDiskPS->vtbl->GetType(hardDiskPS, &hddType);
2763

2764
                if (hddType == HardDiskType_Immutable)
2765
                    def->disks[hddNum]->readonly = true;
2766 2767
                ignore_value(VIR_STRDUP(def->disks[hddNum]->src, hddlocation));
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdb"));
2768
                hddNum++;
2769

2770 2771 2772 2773
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPS);
            }
2774

2775 2776 2777 2778
            if (hardDiskSS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2779

2780 2781
                hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2782

2783
                hardDiskSS->vtbl->GetType(hardDiskSS, &hddType);
2784

2785
                if (hddType == HardDiskType_Immutable)
2786
                    def->disks[hddNum]->readonly = true;
J
Ján Tomko 已提交
2787 2788 2789
                ignore_value(VIR_STRDUP(def->disks[hddNum]->src, hddlocation));
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdd"));
                hddNum++;
2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802

                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;
2803
            vboxArrayGet(&mediumAttachments, machine, machine->vtbl->GetMediumAttachments);
2804 2805

            /* get the number of attachments */
2806 2807
            for (i = 0; i < mediumAttachments.count; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2808 2809 2810 2811 2812 2813 2814
                if (imediumattach) {
                    IMedium *medium = NULL;

                    imediumattach->vtbl->GetMedium(imediumattach, &medium);
                    if (medium) {
                        def->ndisks++;
                        VBOX_RELEASE(medium);
2815 2816
                    }
                }
2817
            }
2818

2819 2820 2821 2822 2823 2824
            /* 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) {
                        error = true;
                        break;
2825 2826
                    }
                }
2827 2828 2829 2830 2831 2832 2833 2834
            } else {
                error = true;
            }

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

            /* get the attachment details here */
2835 2836
            for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869
                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;
                }
2870

2871 2872 2873
                medium->vtbl->GetLocation(medium, &mediumLocUtf16);
                VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
                VBOX_UTF16_FREE(mediumLocUtf16);
2874
                ignore_value(VIR_STRDUP(def->disks[diskCount]->src, mediumLocUtf8));
2875 2876 2877 2878 2879 2880 2881 2882
                VBOX_UTF8_FREE(mediumLocUtf8);

                if (!(def->disks[diskCount]->src)) {
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2883

2884 2885 2886 2887 2888 2889 2890 2891 2892 2893
                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;
                }
2894

2895 2896 2897 2898 2899 2900 2901 2902 2903 2904
                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);
2905
                def->disks[diskCount]->dst = vboxGenerateMediumName(storageBus,
2906 2907 2908 2909 2910 2911
                                                                    deviceInst,
                                                                    devicePort,
                                                                    deviceSlot,
                                                                    maxPortPerInst,
                                                                    maxSlotPerPort);
                if (!def->disks[diskCount]->dst) {
2912 2913 2914 2915
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Could not generate medium name for the disk "
                                     "at: controller instance:%u, port:%d, slot:%d"),
                                   deviceInst, devicePort, deviceSlot);
2916 2917 2918 2919 2920
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2921

2922 2923
                medium->vtbl->GetReadOnly(medium, &readOnly);
                if (readOnly == PR_TRUE)
2924
                    def->disks[diskCount]->readonly = true;
2925

2926
                def->disks[diskCount]->type = VIR_DOMAIN_DISK_TYPE_FILE;
2927

2928 2929 2930 2931
                VBOX_RELEASE(medium);
                VBOX_RELEASE(storageController);
                diskCount++;
            }
2932

2933
            vboxArrayRelease(&mediumAttachments);
2934

2935 2936 2937 2938 2939 2940 2941 2942
            /* cleanup on error */
            if (error) {
                for (i = 0; i < def->ndisks; i++) {
                    VIR_FREE(def->disks[i]);
                }
                VIR_FREE(def->disks);
                def->ndisks = 0;
            }
2943

2944
#endif /* VBOX_API_VERSION >= 3001 */
2945

M
Matthias Bolte 已提交
2946 2947 2948 2949 2950 2951 2952 2953 2954
            /* shared folders */
            vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER;

            def->nfss = 0;

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

            if (sharedFolders.count > 0) {
2955
                if (VIR_ALLOC_N(def->fss, sharedFolders.count) < 0)
M
Matthias Bolte 已提交
2956 2957 2958 2959 2960 2961 2962 2963 2964 2965
                    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;

2966
                    if (VIR_ALLOC(def->fss[i]) < 0)
M
Matthias Bolte 已提交
2967 2968 2969 2970 2971 2972
                        goto sharedFoldersCleanup;

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

                    sharedFolder->vtbl->GetHostPath(sharedFolder, &hostPathUtf16);
                    VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath);
2973 2974 2975
                    if (VIR_STRDUP(def->fss[i]->src, hostPath) < 0) {
                        VBOX_UTF8_FREE(hostPath);
                        VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
2976 2977
                        goto sharedFoldersCleanup;
                    }
2978 2979
                    VBOX_UTF8_FREE(hostPath);
                    VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
2980 2981 2982

                    sharedFolder->vtbl->GetName(sharedFolder, &nameUtf16);
                    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
2983 2984 2985
                    if (VIR_STRDUP(def->fss[i]->dst, name) < 0) {
                        VBOX_UTF8_FREE(name);
                        VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
2986 2987
                        goto sharedFoldersCleanup;
                    }
2988 2989
                    VBOX_UTF8_FREE(name);
                    VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000

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

                    ++def->nfss;
                }
            }

sharedFoldersCleanup:
            vboxArrayRelease(&sharedFolders);

3001 3002 3003 3004 3005
            /* dump network cards if present */
            def->nnets = 0;
            /* Get which network cards are enabled */
            for (i = 0; i < netAdpCnt; i++) {
                INetworkAdapter *adapter = NULL;
3006

3007 3008 3009
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
3010

3011 3012 3013 3014
                    adapter->vtbl->GetEnabled(adapter, &enabled);
                    if (enabled) {
                        def->nnets++;
                    }
3015

3016 3017 3018
                    VBOX_RELEASE(adapter);
                }
            }
3019

3020 3021 3022
            /* 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++) {
3023
                    ignore_value(VIR_ALLOC(def->nets[i]));
3024 3025
                }
            }
3026

3027
            /* Now get the details about the network cards here */
3028
            for (i = 0; netAdpIncCnt < def->nnets && i < netAdpCnt; i++) {
3029
                INetworkAdapter *adapter = NULL;
3030

3031 3032 3033
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
3034

3035 3036 3037 3038 3039 3040 3041
                    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};
3042

3043 3044
                        adapter->vtbl->GetAttachmentType(adapter, &attachmentType);
                        if (attachmentType == NetworkAttachmentType_NAT) {
3045

3046
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
3047

3048 3049 3050
                        } else if (attachmentType == NetworkAttachmentType_Bridged) {
                            PRUnichar *hostIntUtf16 = NULL;
                            char *hostInt           = NULL;
3051

3052
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
3053

3054
#if VBOX_API_VERSION < 4001
3055
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
3056 3057 3058
#else /* VBOX_API_VERSION >= 4001 */
                            adapter->vtbl->GetBridgedInterface(adapter, &hostIntUtf16);
#endif /* VBOX_API_VERSION >= 4001 */
3059

3060
                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
3061
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.bridge.brname, hostInt));
3062

3063 3064
                            VBOX_UTF8_FREE(hostInt);
                            VBOX_UTF16_FREE(hostIntUtf16);
3065

3066 3067 3068
                        } else if (attachmentType == NetworkAttachmentType_Internal) {
                            PRUnichar *intNetUtf16 = NULL;
                            char *intNet           = NULL;
3069

3070 3071 3072 3073 3074
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL;

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

                            VBOX_UTF16_TO_UTF8(intNetUtf16, &intNet);
3075
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.internal.name, intNet));
3076 3077 3078 3079 3080 3081 3082 3083 3084 3085

                            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;

3086
#if VBOX_API_VERSION < 4001
3087
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
3088 3089 3090
#else /* VBOX_API_VERSION >= 4001 */
                            adapter->vtbl->GetHostOnlyInterface(adapter, &hostIntUtf16);
#endif /* VBOX_API_VERSION >= 4001 */
3091 3092

                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
3093
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.network.name, hostInt));
3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106

                            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) {
3107
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C970A"));
3108
                        } else if (adapterType == NetworkAdapterType_Am79C973) {
3109
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C973"));
3110
                        } else if (adapterType == NetworkAdapterType_I82540EM) {
3111
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82540EM"));
3112
                        } else if (adapterType == NetworkAdapterType_I82545EM) {
3113
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82545EM"));
3114
                        } else if (adapterType == NetworkAdapterType_I82543GC) {
3115
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82543GC"));
3116 3117
#if VBOX_API_VERSION >= 3001
                        } else if (adapterType == NetworkAdapterType_Virtio) {
3118
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "virtio"));
3119
#endif /* VBOX_API_VERSION >= 3001 */
3120 3121
                        }

3122 3123 3124 3125 3126 3127 3128 3129 3130
                        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 ... */
3131
                        if (virMacAddrParse(macaddr, &def->nets[netAdpIncCnt]->mac) < 0)
3132 3133 3134 3135 3136 3137
                        {}

                        netAdpIncCnt++;

                        VBOX_UTF16_FREE(MACAddressUtf16);
                        VBOX_UTF8_FREE(MACAddress);
3138
                    }
3139 3140

                    VBOX_RELEASE(adapter);
3141
                }
3142
            }
3143

3144
            /* dump sound card if active */
3145

3146 3147 3148
            /* Set def->nsounds to one as VirtualBox currently supports
             * only one sound card
             */
3149

3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176
            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;
                        }
                    } else {
                        def->nsounds = 0;
                    }
                }
                VBOX_RELEASE(audioAdapter);
            }
3177

3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201
#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;
3202
                                def->disks[def->ndisks - 1]->readonly = true;
3203 3204 3205
                                ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->src, location));
                                ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "hdc"));
                                def->ndisks--;
3206
                            } else {
3207
                                def->ndisks--;
3208 3209
                            }
                        } else {
3210
                            def->ndisks--;
3211
                        }
3212 3213 3214 3215

                        VBOX_UTF8_FREE(location);
                        VBOX_UTF16_FREE(locationUtf16);
                        VBOX_MEDIUM_RELEASE(dvdImage);
3216 3217
                    }
                }
3218 3219
                VBOX_RELEASE(dvdDrive);
            }
3220

3221 3222 3223 3224 3225 3226 3227
            /* 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) {
3228 3229
                    PRUint32 state = DriveState_Null;

3230
                    floppyDrive->vtbl->GetState(floppyDrive, &state);
3231
                    if (state == DriveState_ImageMounted) {
3232
                        IFloppyImage *floppyImage = NULL;
3233

3234 3235
                        floppyDrive->vtbl->GetImage(floppyDrive, &floppyImage);
                        if (floppyImage) {
3236 3237 3238
                            PRUnichar *locationUtf16 = NULL;
                            char *location           = NULL;

3239 3240
                            floppyImage->vtbl->imedium.GetLocation((IMedium *)floppyImage, &locationUtf16);
                            VBOX_UTF16_TO_UTF8(locationUtf16, &location);
3241 3242 3243 3244

                            def->ndisks++;
                            if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
                                if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
3245 3246
                                    def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                                    def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC;
3247
                                    def->disks[def->ndisks - 1]->type = VIR_DOMAIN_DISK_TYPE_FILE;
3248
                                    def->disks[def->ndisks - 1]->readonly = false;
3249 3250 3251
                                    ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->src, location));
                                    ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "fda"));
                                    def->ndisks--;
3252 3253 3254 3255 3256 3257 3258
                                } else {
                                    def->ndisks--;
                                }
                            } else {
                                def->ndisks--;
                            }

3259 3260 3261
                            VBOX_UTF8_FREE(location);
                            VBOX_UTF16_FREE(locationUtf16);
                            VBOX_MEDIUM_RELEASE(floppyImage);
3262 3263 3264 3265
                        }
                    }
                }

3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278
                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) {
3279 3280
                    PRBool enabled = PR_FALSE;

3281
                    serialPort->vtbl->GetEnabled(serialPort, &enabled);
3282
                    if (enabled) {
3283
                        def->nserials++;
3284 3285
                    }

3286
                    VBOX_RELEASE(serialPort);
3287
                }
3288
            }
3289

3290 3291 3292
            /* 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++) {
3293
                    ignore_value(VIR_ALLOC(def->serials[i]));
3294 3295
                }
            }
3296

3297
            /* Now get the details about the serial ports here */
3298 3299 3300
            for (i = 0;
                 serialPortIncCount < def->nserials && i < serialPortCount;
                 i++) {
3301
                ISerialPort *serialPort = NULL;
3302

3303 3304 3305
                machine->vtbl->GetSerialPort(machine, i, &serialPort);
                if (serialPort) {
                    PRBool enabled = PR_FALSE;
3306

3307 3308 3309 3310 3311 3312 3313 3314 3315 3316
                    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) {
3317
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
3318
                        } else if (hostMode == PortMode_HostDevice) {
3319
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
3320 3321
#if VBOX_API_VERSION >= 3000
                        } else if (hostMode == PortMode_RawFile) {
3322
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3323 3324
#endif /* VBOX_API_VERSION >= 3000 */
                        } else {
3325
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_NULL;
3326
                        }
3327

3328
                        def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
3329

3330 3331 3332 3333 3334 3335 3336
                        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;
                        }
3337

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

3340 3341
                        if (pathUtf16) {
                            VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3342
                            ignore_value(VIR_STRDUP(def->serials[serialPortIncCount]->source.data.file.path, path));
3343 3344
                        }

3345 3346 3347 3348
                        serialPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
3349 3350
                    }

3351 3352 3353
                    VBOX_RELEASE(serialPort);
                }
            }
3354

3355 3356 3357 3358 3359
            /* dump parallel ports if active */
            def->nparallels = 0;
            /* Get which parallel ports are enabled/active */
            for (i = 0; i < parallelPortCount; i++) {
                IParallelPort *parallelPort = NULL;
3360

3361 3362 3363
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
3364

3365 3366 3367
                    parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                    if (enabled) {
                        def->nparallels++;
3368
                    }
3369 3370

                    VBOX_RELEASE(parallelPort);
3371
                }
3372
            }
3373

3374 3375 3376
            /* 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++) {
3377
                    ignore_value(VIR_ALLOC(def->parallels[i]));
3378
                }
3379
            }
3380

3381
            /* Now get the details about the parallel ports here */
3382 3383 3384 3385
            for (i = 0;
                 parallelPortIncCount < def->nparallels &&
                     i < parallelPortCount;
                 i++) {
3386
                IParallelPort *parallelPort = NULL;
3387

3388 3389 3390
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
3391

3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405
                    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;
                        }
3406

3407
                        def->parallels[parallelPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3408
                        def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
3409

3410
                        parallelPort->vtbl->GetPath(parallelPort, &pathUtf16);
3411

3412
                        VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3413
                        ignore_value(VIR_STRDUP(def->parallels[parallelPortIncCount]->source.data.file.path, path));
3414

3415 3416 3417 3418
                        parallelPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
3419
                    }
3420 3421

                    VBOX_RELEASE(parallelPort);
3422
                }
3423
            }
3424

3425
            /* dump USB devices/filters if active */
3426
            vboxHostDeviceGetXMLDesc(data, def, machine);
3427 3428 3429 3430 3431

            /* all done so set gotAllABoutDef and pass def to virDomainDefFormat
             * to generate XML for it
             */
            gotAllABoutDef = 0;
3432
        }
3433 3434
        VBOX_RELEASE(machine);
        machine = NULL;
3435 3436 3437
    }

    if (gotAllABoutDef == 0)
3438
        ret = virDomainDefFormat(def, flags);
3439 3440

cleanup:
3441
    vboxIIDUnalloc(&iid);
3442 3443 3444 3445
    virDomainDefFree(def);
    return ret;
}

3446
static int vboxConnectListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) {
3447
    VBOX_OBJECT_CHECK(conn, int, -1);
3448
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3449 3450 3451
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    PRUint32 state;
3452
    nsresult rc;
3453
    size_t i, j;
3454

3455
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3456
    if (NS_FAILED(rc)) {
3457 3458 3459
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of Defined Domains, rc=%08x"),
                       (unsigned)rc);
3460 3461
        goto cleanup;
    }
3462

3463 3464
    memset(names, 0, sizeof(names[i]) * maxnames);

3465 3466 3467
    ret = 0;
    for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) {
        IMachine *machine = machines.items[i];
3468 3469 3470 3471 3472 3473

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3474 3475
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3476 3477
                    machine->vtbl->GetName(machine, &machineNameUtf16);
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
3478 3479 3480
                    if (VIR_STRDUP(names[j], machineName) < 0) {
                        VBOX_UTF16_FREE(machineNameUtf16);
                        VBOX_UTF8_FREE(machineName);
3481
                        for (j = 0; j < maxnames; j++)
3482 3483 3484
                            VIR_FREE(names[j]);
                        ret = -1;
                        goto cleanup;
3485
                    }
3486 3487
                    VBOX_UTF16_FREE(machineNameUtf16);
                    VBOX_UTF8_FREE(machineName);
3488
                    j++;
3489
                    ret++;
3490 3491 3492 3493 3494 3495
                }
            }
        }
    }

cleanup:
3496
    vboxArrayRelease(&machines);
3497 3498 3499
    return ret;
}

3500
static int vboxConnectNumOfDefinedDomains(virConnectPtr conn) {
3501
    VBOX_OBJECT_CHECK(conn, int, -1);
3502
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3503
    PRUint32 state       = MachineState_Null;
3504
    nsresult rc;
3505
    size_t i;
3506

3507
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3508
    if (NS_FAILED(rc)) {
3509 3510 3511
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get number of Defined Domains, rc=%08x"),
                       (unsigned)rc);
3512 3513
        goto cleanup;
    }
3514

3515 3516 3517
    ret = 0;
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3518 3519 3520 3521 3522 3523

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3524 3525
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3526
                    ret++;
3527 3528 3529 3530 3531 3532
                }
            }
        }
    }

cleanup:
3533
    vboxArrayRelease(&machines);
3534 3535 3536
    return ret;
}

E
Eric Blake 已提交
3537 3538

static int
3539
vboxStartMachine(virDomainPtr dom, int maxDomID, IMachine *machine,
3540
                 vboxIID *iid ATTRIBUTE_UNUSED /* >= 4.0 */)
E
Eric Blake 已提交
3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566
{
    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);

3567
        if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
E
Eric Blake 已提交
3568 3569 3570 3571 3572 3573 3574 3575 3576 3577

            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 已提交
3578
                if (strlen(valueDisplayUtf8) <= 0)
E
Eric Blake 已提交
3579 3580 3581 3582 3583
                    VBOX_UTF8_FREE(valueDisplayUtf8);
            }

            if (STREQ(valueTypeUtf8, "sdl")) {
                sdlPresent = 1;
3584 3585 3586 3587 3588
                if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) {
                    /* 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
                     */
E
Eric Blake 已提交
3589 3590 3591 3592 3593
                }
            }

            if (STREQ(valueTypeUtf8, "gui")) {
                guiPresent = 1;
3594 3595 3596 3597 3598
                if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) {
                    /* 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
                     */
E
Eric Blake 已提交
3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618
                }
            }
        }

        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 已提交
3619
    VBOX_UTF8_FREE(valueDisplayUtf8);
E
Eric Blake 已提交
3620 3621 3622

    if (guiPresent) {
        if (guiDisplay) {
E
Eric Blake 已提交
3623
            char *displayutf8;
3624
            if (virAsprintf(&displayutf8, "DISPLAY=%s", guiDisplay) >= 0) {
E
Eric Blake 已提交
3625 3626 3627
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3628 3629 3630 3631 3632 3633 3634 3635
            VIR_FREE(guiDisplay);
        }

        VBOX_UTF8_TO_UTF16("gui", &sessionType);
    }

    if (sdlPresent) {
        if (sdlDisplay) {
E
Eric Blake 已提交
3636
            char *displayutf8;
3637
            if (virAsprintf(&displayutf8, "DISPLAY=%s", sdlDisplay) >= 0) {
E
Eric Blake 已提交
3638 3639 3640
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3641 3642 3643 3644 3645 3646 3647 3648 3649 3650
            VIR_FREE(sdlDisplay);
        }

        VBOX_UTF8_TO_UTF16("sdl", &sessionType);
    }

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

3651
#if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
3652 3653
    rc = data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj,
                                                data->vboxSession,
3654
                                                iid->value,
E
Eric Blake 已提交
3655 3656
                                                sessionType,
                                                env,
3657
                                                &progress);
3658 3659 3660 3661 3662
#else /* VBOX_API_VERSION >= 4000 */
    rc = machine->vtbl->LaunchVMProcess(machine, data->vboxSession,
                                        sessionType, env, &progress);
#endif /* VBOX_API_VERSION >= 4000 */

E
Eric Blake 已提交
3663
    if (NS_FAILED(rc)) {
3664 3665
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("OpenRemoteSession/LaunchVMProcess failed, domain can't be started"));
E
Eric Blake 已提交
3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685
        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 */
3686
            dom->id = maxDomID + 1;
E
Eric Blake 已提交
3687 3688 3689 3690 3691 3692
            ret = 0;
        }
    }

    VBOX_RELEASE(progress);

3693
    VBOX_SESSION_CLOSE();
E
Eric Blake 已提交
3694 3695 3696 3697 3698 3699 3700

    VBOX_UTF16_FREE(env);
    VBOX_UTF16_FREE(sessionType);

    return ret;
}

3701
static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags) {
3702
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
3703
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3704
    unsigned char uuid[VIR_UUID_BUFLEN] = {0};
3705
    nsresult rc;
3706
    size_t i = 0;
3707

3708 3709
    virCheckFlags(0, -1);

3710
    if (!dom->name) {
3711 3712
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Error while reading the domain name"));
3713 3714 3715
        goto cleanup;
    }

3716
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3717
    if (NS_FAILED(rc)) {
3718 3719
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
3720 3721
        goto cleanup;
    }
3722

3723 3724
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3725
        PRBool isAccessible = PR_FALSE;
3726

3727 3728
        if (!machine)
            continue;
3729

3730 3731
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
3732
            vboxIID iid = VBOX_IID_INITIALIZER;
3733

3734 3735
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
3736
                continue;
3737
            vboxIIDToUUID(&iid, uuid);
3738

3739
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
3740 3741 3742
                PRUint32 state = MachineState_Null;
                machine->vtbl->GetState(machine, &state);

3743 3744 3745
                if ((state == MachineState_PoweredOff) ||
                    (state == MachineState_Saved) ||
                    (state == MachineState_Aborted)) {
3746
                    ret = vboxStartMachine(dom, i, machine, &iid);
3747
                } else {
3748
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3749 3750 3751
                                   _("machine is not in "
                                     "poweroff|saved|aborted state, so "
                                     "couldn't start it"));
3752
                    ret = -1;
3753 3754
                }
            }
3755
            vboxIIDUnalloc(&iid);
3756 3757
            if (ret != -1)
                break;
3758 3759 3760
        }
    }

3761
    /* Do the cleanup and take care you dont leak any memory */
3762
    vboxArrayRelease(&machines);
3763

3764 3765 3766 3767
cleanup:
    return ret;
}

3768 3769 3770 3771
static int vboxDomainCreate(virDomainPtr dom) {
    return vboxDomainCreateWithFlags(dom, 0);
}

E
Eric Blake 已提交
3772 3773 3774 3775 3776 3777
static void
vboxSetBootDeviceOrder(virDomainDefPtr def, vboxGlobalData *data,
                       IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 maxBootPosition            = 0;
3778
    size_t i = 0;
3779

3780
    VIR_DEBUG("def->os.type             %s", def->os.type);
3781
    VIR_DEBUG("def->os.arch             %s", virArchToString(def->os.arch));
3782
    VIR_DEBUG("def->os.machine          %s", def->os.machine);
3783
    VIR_DEBUG("def->os.nBootDevs        %zu", def->os.nBootDevs);
3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795
    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);
3796

E
Eric Blake 已提交
3797 3798 3799 3800 3801 3802
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxBootPosition(systemProperties,
                                                   &maxBootPosition);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
3803
    }
3804

E
Eric Blake 已提交
3805 3806 3807
    /* Clear the defaults first */
    for (i = 0; i < maxBootPosition; i++) {
        machine->vtbl->SetBootOrder(machine, i+1, DeviceType_Null);
3808
    }
3809

E
Eric Blake 已提交
3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820
    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;
3821
        }
E
Eric Blake 已提交
3822
        machine->vtbl->SetBootOrder(machine, i+1, device);
3823
    }
E
Eric Blake 已提交
3824
}
3825

E
Eric Blake 已提交
3826 3827 3828
static void
vboxAttachDrives(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
3829
    size_t i;
E
Eric Blake 已提交
3830
    nsresult rc;
3831 3832

#if VBOX_API_VERSION < 3001
E
Eric Blake 已提交
3833 3834 3835 3836
    if (def->ndisks == 0)
        return;

    for (i = 0; i < def->ndisks; i++) {
3837 3838 3839 3840 3841 3842 3843
        VIR_DEBUG("disk(%zu) type:       %d", i, def->disks[i]->type);
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
        VIR_DEBUG("disk(%zu) src:        %s", i, def->disks[i]->src);
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
        VIR_DEBUG("disk(%zu) driverName: %s", i, def->disks[i]->driverName);
        VIR_DEBUG("disk(%zu) driverType: %s", i,
3844
                  virStorageFileFormatTypeToString(def->disks[i]->format));
3845 3846
        VIR_DEBUG("disk(%zu) cachemode:  %d", i, def->disks[i]->cachemode);
        VIR_DEBUG("disk(%zu) readonly:   %s", i, (def->disks[i]->readonly
E
Eric Blake 已提交
3847
                                             ? "True" : "False"));
3848
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->shared
E
Eric Blake 已提交
3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860
                                             ? "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
                 */
3861

E
Eric Blake 已提交
3862 3863 3864 3865
                machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                if (dvdDrive) {
                    IDVDImage *dvdImage          = NULL;
                    PRUnichar *dvdfileUtf16      = NULL;
3866 3867
                    vboxIID dvduuid = VBOX_IID_INITIALIZER;
                    vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
3868

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

E
Eric Blake 已提交
3871 3872 3873 3874 3875
                    data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                      dvdfileUtf16, &dvdImage);
                    if (!dvdImage) {
                        data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                          dvdfileUtf16,
3876
                                                          dvdemptyuuid.value,
E
Eric Blake 已提交
3877 3878 3879 3880
                                                          &dvdImage);
                    }
                    if (dvdImage) {
                        rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage,
3881
                                                           &dvduuid.value);
E
Eric Blake 已提交
3882
                        if (NS_FAILED(rc)) {
3883 3884 3885 3886
                            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 已提交
3887
                        } else {
3888
                            rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
E
Eric Blake 已提交
3889
                            if (NS_FAILED(rc)) {
3890 3891 3892
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("could not attach the file to cdrom: %s, rc=%08x"),
                                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
3893
                            } else {
3894
                                DEBUGIID("CD/DVDImage UUID:", dvduuid.value);
3895
                            }
3896
                        }
E
Eric Blake 已提交
3897 3898

                        VBOX_MEDIUM_RELEASE(dvdImage);
3899
                    }
3900
                    vboxIIDUnalloc(&dvduuid);
E
Eric Blake 已提交
3901 3902 3903 3904 3905 3906 3907 3908 3909 3910
                    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;
3911
                vboxIID hdduuid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
3912 3913 3914 3915 3916 3917
                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
                 */
3918

E
Eric Blake 已提交
3919 3920
                VBOX_UTF8_TO_UTF16(def->disks[i]->src, &hddfileUtf16);
                VBOX_UTF8_TO_UTF16("", &hddEmpty);
3921

E
Eric Blake 已提交
3922 3923
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16,
                                                  &hardDisk);
3924

E
Eric Blake 已提交
3925
                if (!hardDisk) {
3926
# if VBOX_API_VERSION == 2002
E
Eric Blake 已提交
3927 3928 3929 3930
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      &hardDisk);
3931
# else
E
Eric Blake 已提交
3932 3933 3934 3935 3936 3937 3938 3939
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      0,
                                                      hddEmpty,
                                                      0,
                                                      hddEmpty,
                                                      &hardDisk);
3940
# endif
E
Eric Blake 已提交
3941
                }
3942

E
Eric Blake 已提交
3943 3944
                if (hardDisk) {
                    rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk,
3945
                                                       &hdduuid.value);
E
Eric Blake 已提交
3946
                    if (NS_FAILED(rc)) {
3947 3948 3949 3950
                        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 已提交
3951 3952 3953 3954
                    } else {
                        if (def->disks[i]->readonly) {
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Immutable);
3955
                            VIR_DEBUG("setting harddisk to readonly");
E
Eric Blake 已提交
3956 3957 3958
                        } else if (!def->disks[i]->readonly) {
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Normal);
3959
                            VIR_DEBUG("setting harddisk type to normal");
E
Eric Blake 已提交
3960 3961 3962
                        }
                        if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
                            if (STREQ(def->disks[i]->dst, "hdc")) {
3963
                                VIR_DEBUG("Not connecting harddisk to hdc as hdc"
E
Eric Blake 已提交
3964
                                       " is taken by CD/DVD Drive");
3965
                            } else {
E
Eric Blake 已提交
3966 3967 3968 3969
                                PRInt32 channel          = 0;
                                PRInt32 device           = 0;
                                PRUnichar *hddcnameUtf16 = NULL;

3970 3971
                                char *hddcname;
                                ignore_value(VIR_STRDUP(hddcname, "IDE"));
E
Eric Blake 已提交
3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983
                                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;
3984
                                }
E
Eric Blake 已提交
3985 3986

                                rc = machine->vtbl->AttachHardDisk(machine,
3987
                                                                   hdduuid.value,
E
Eric Blake 已提交
3988 3989 3990 3991 3992 3993
                                                                   hddcnameUtf16,
                                                                   channel,
                                                                   device);
                                VBOX_UTF16_FREE(hddcnameUtf16);

                                if (NS_FAILED(rc)) {
3994 3995 3996 3997
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file as "
                                                     "harddisk: %s, rc=%08x"),
                                                   def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
3998
                                } else {
3999
                                    DEBUGIID("Attached HDD with UUID", hdduuid.value);
4000 4001 4002
                                }
                            }
                        }
4003
                    }
E
Eric Blake 已提交
4004 4005
                    VBOX_MEDIUM_RELEASE(hardDisk);
                }
4006
                vboxIIDUnalloc(&hdduuid);
E
Eric Blake 已提交
4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020
                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;
4021 4022
                        vboxIID fduuid = VBOX_IID_INITIALIZER;
                        vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
4023

E
Eric Blake 已提交
4024 4025 4026 4027
                        VBOX_UTF8_TO_UTF16(def->disks[i]->src, &fdfileUtf16);
                        rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                  fdfileUtf16,
                                                                  &floppyImage);
4028

E
Eric Blake 已提交
4029 4030 4031
                        if (!floppyImage) {
                            data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                 fdfileUtf16,
4032
                                                                 fdemptyuuid.value,
E
Eric Blake 已提交
4033 4034
                                                                 &floppyImage);
                        }
4035

E
Eric Blake 已提交
4036 4037
                        if (floppyImage) {
                            rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage,
4038
                                                                  &fduuid.value);
E
Eric Blake 已提交
4039
                            if (NS_FAILED(rc)) {
4040 4041 4042 4043
                                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 已提交
4044 4045
                            } else {
                                rc = floppyDrive->vtbl->MountImage(floppyDrive,
4046
                                                                   fduuid.value);
E
Eric Blake 已提交
4047
                                if (NS_FAILED(rc)) {
4048 4049 4050 4051
                                    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 已提交
4052
                                } else {
4053
                                    DEBUGIID("floppyImage UUID", fduuid.value);
4054 4055
                                }
                            }
E
Eric Blake 已提交
4056
                            VBOX_MEDIUM_RELEASE(floppyImage);
4057
                        }
4058
                        vboxIIDUnalloc(&fduuid);
E
Eric Blake 已提交
4059
                        VBOX_UTF16_FREE(fdfileUtf16);
4060
                    }
E
Eric Blake 已提交
4061
                    VBOX_RELEASE(floppyDrive);
4062
                }
E
Eric Blake 已提交
4063
            } else if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
4064
            }
4065
        }
E
Eric Blake 已提交
4066
    }
4067
#else  /* VBOX_API_VERSION >= 3001 */
E
Eric Blake 已提交
4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079
    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 */
4080
    {
E
Eric Blake 已提交
4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115
        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);
    }
4116

E
Eric Blake 已提交
4117
    for (i = 0; i < def->ndisks && !error; i++) {
4118 4119 4120 4121 4122 4123 4124
        VIR_DEBUG("disk(%zu) type:       %d", i, def->disks[i]->type);
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
        VIR_DEBUG("disk(%zu) src:        %s", i, def->disks[i]->src);
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
        VIR_DEBUG("disk(%zu) driverName: %s", i, def->disks[i]->driverName);
        VIR_DEBUG("disk(%zu) driverType: %s", i,
4125
                  virStorageFileFormatTypeToString(def->disks[i]->format));
4126 4127
        VIR_DEBUG("disk(%zu) cachemode:  %d", i, def->disks[i]->cachemode);
        VIR_DEBUG("disk(%zu) readonly:   %s", i, (def->disks[i]->readonly
E
Eric Blake 已提交
4128
                                             ? "True" : "False"));
4129
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->shared
E
Eric Blake 已提交
4130 4131 4132 4133 4134 4135 4136 4137 4138
                                             ? "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;
4139
# if VBOX_API_VERSION >= 4000
4140
            PRUint32   accessMode      = AccessMode_ReadOnly;
4141
# endif
E
Eric Blake 已提交
4142 4143 4144 4145 4146 4147 4148 4149
            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;
4150
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4151 4152
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj,
                                                  mediumFileUtf16, &medium);
4153 4154
# else
                accessMode = AccessMode_ReadWrite;
4155
# endif
E
Eric Blake 已提交
4156 4157
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                deviceType = DeviceType_DVD;
4158
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4159 4160
                data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                  mediumFileUtf16, &medium);
4161 4162
# else
                accessMode = AccessMode_ReadOnly;
4163
# endif
E
Eric Blake 已提交
4164 4165
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                deviceType = DeviceType_Floppy;
4166
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4167 4168
                data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                     mediumFileUtf16, &medium);
4169 4170
# else
                accessMode = AccessMode_ReadWrite;
4171
# endif
E
Eric Blake 已提交
4172 4173 4174 4175
            } else {
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4176

4177
# if VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
4178 4179
            data->vboxObj->vtbl->FindMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, &medium);
4180 4181 4182
# elif VBOX_API_VERSION >= 4002
            data->vboxObj->vtbl->OpenMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, accessMode, PR_FALSE, &medium);
4183 4184
# endif

E
Eric Blake 已提交
4185 4186
            if (!medium) {
                PRUnichar *mediumEmpty = NULL;
4187

E
Eric Blake 已提交
4188
                VBOX_UTF8_TO_UTF16("", &mediumEmpty);
4189

4190
# if VBOX_API_VERSION < 4000
4191
                if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
4192 4193 4194 4195 4196 4197 4198 4199
                    rc = data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                           mediumFileUtf16,
                                                           AccessMode_ReadWrite,
                                                           false,
                                                           mediumEmpty,
                                                           false,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
4200 4201
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_CDROM) {
4202 4203 4204 4205
                    rc = data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                           mediumFileUtf16,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
4206 4207
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
4208 4209 4210 4211 4212 4213
                    rc = data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                              mediumFileUtf16,
                                                              mediumEmpty,
                                                              &medium);
                } else {
                    rc = 0;
4214
                }
4215
# elif VBOX_API_VERSION == 4000
4216 4217 4218 4219
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     &medium);
4220 4221 4222 4223 4224 4225 4226
# elif VBOX_API_VERSION >= 4001
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     false,
                                                     &medium);
# endif /* VBOX_API_VERSION >= 4001 */
4227

E
Eric Blake 已提交
4228 4229
                VBOX_UTF16_FREE(mediumEmpty);
            }
4230

E
Eric Blake 已提交
4231
            if (!medium) {
4232 4233 4234 4235
                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 已提交
4236 4237 4238
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4239

E
Eric Blake 已提交
4240 4241
            rc = medium->vtbl->GetId(medium, &mediumUUID);
            if (NS_FAILED(rc)) {
4242 4243 4244 4245
                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 已提交
4246 4247 4248 4249
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4250

E
Eric Blake 已提交
4251 4252 4253
            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                if (def->disks[i]->readonly) {
                    medium->vtbl->SetType(medium, MediumType_Immutable);
4254
                    VIR_DEBUG("setting harddisk to immutable");
E
Eric Blake 已提交
4255 4256
                } else if (!def->disks[i]->readonly) {
                    medium->vtbl->SetType(medium, MediumType_Normal);
4257
                    VIR_DEBUG("setting harddisk type to normal");
4258
                }
E
Eric Blake 已提交
4259
            }
4260

E
Eric Blake 已提交
4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273
            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;
            }
4274

E
Eric Blake 已提交
4275 4276 4277 4278 4279 4280 4281 4282
            /* get the device details i.e instance, port and slot */
            if (!vboxGetDeviceDetails(def->disks[i]->dst,
                                      maxPortPerInst,
                                      maxSlotPerPort,
                                      storageBus,
                                      &deviceInst,
                                      &devicePort,
                                      &deviceSlot)) {
4283
                virReportError(VIR_ERR_INTERNAL_ERROR,
4284 4285 4286
                               _("can't get the port/slot number of "
                                 "harddisk/dvd/floppy to be attached: "
                                 "%s, rc=%08x"),
4287
                               def->disks[i]->src, (unsigned)rc);
4288 4289 4290
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumUUID);
                VBOX_UTF16_FREE(mediumFileUtf16);
E
Eric Blake 已提交
4291 4292 4293 4294 4295 4296 4297 4298 4299
                continue;
            }

            /* attach the harddisk/dvd/Floppy to the storage controller */
            rc = machine->vtbl->AttachDevice(machine,
                                             storageCtlName,
                                             devicePort,
                                             deviceSlot,
                                             deviceType,
4300
# if VBOX_API_VERSION < 4000
E
Eric Blake 已提交
4301
                                             mediumUUID);
4302 4303 4304
# else /* VBOX_API_VERSION >= 4000 */
                                             medium);
# endif /* VBOX_API_VERSION >= 4000 */
E
Eric Blake 已提交
4305 4306

            if (NS_FAILED(rc)) {
4307
                virReportError(VIR_ERR_INTERNAL_ERROR,
4308 4309
                               _("could not attach the file as "
                                 "harddisk/dvd/floppy: %s, rc=%08x"),
4310
                               def->disks[i]->src, (unsigned)rc);
E
Eric Blake 已提交
4311 4312
            } else {
                DEBUGIID("Attached HDD/DVD/Floppy with UUID", mediumUUID);
4313
            }
E
Eric Blake 已提交
4314 4315 4316 4317 4318

            VBOX_RELEASE(medium);
            VBOX_UTF16_FREE(mediumUUID);
            VBOX_UTF16_FREE(mediumFileUtf16);
            VBOX_UTF16_FREE(storageCtlName);
4319 4320 4321
        }
    }
#endif /* VBOX_API_VERSION >= 3001 */
E
Eric Blake 已提交
4322
}
4323

E
Eric Blake 已提交
4324 4325 4326 4327
static void
vboxAttachSound(virDomainDefPtr def, IMachine *machine)
{
    nsresult rc;
4328

E
Eric Blake 已提交
4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344
    /* 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);
4345
                }
4346
            }
E
Eric Blake 已提交
4347
            VBOX_RELEASE(audioAdapter);
4348
        }
E
Eric Blake 已提交
4349 4350 4351 4352 4353 4354 4355
    }
}

static void
vboxAttachNetwork(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
4356 4357 4358
#if VBOX_API_VERSION >= 4001
    PRUint32 chipsetType                = ChipsetType_Null;
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4359
    PRUint32 networkAdapterCount        = 0;
4360
    size_t i = 0;
E
Eric Blake 已提交
4361

4362 4363 4364 4365
#if VBOX_API_VERSION >= 4001
    machine->vtbl->GetChipsetType(machine, &chipsetType);
#endif /* VBOX_API_VERSION >= 4001 */

E
Eric Blake 已提交
4366 4367
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
4368
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4369 4370
        systemProperties->vtbl->GetNetworkAdapterCount(systemProperties,
                                                       &networkAdapterCount);
4371 4372 4373 4374
#else  /* VBOX_API_VERSION >= 4000 */
        systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType,
                                                      &networkAdapterCount);
#endif /* VBOX_API_VERSION >= 4000 */
E
Eric Blake 已提交
4375 4376 4377 4378
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }

4379
    VIR_DEBUG("Number of Network Cards to be connected: %zu", def->nnets);
4380
    VIR_DEBUG("Number of Network Cards available: %d", networkAdapterCount);
E
Eric Blake 已提交
4381 4382 4383 4384 4385 4386 4387

    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};

4388
        virMacAddrFormat(&def->nets[i]->mac, macaddr);
E
Eric Blake 已提交
4389 4390
        snprintf(macaddrvbox, VIR_MAC_STRING_BUFLEN - 5,
                 "%02X%02X%02X%02X%02X%02X",
4391 4392 4393 4394 4395 4396
                 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 已提交
4397 4398
        macaddrvbox[VIR_MAC_STRING_BUFLEN - 6] = '\0';

4399 4400 4401 4402
        VIR_DEBUG("NIC(%zu): Type:   %d", i, def->nets[i]->type);
        VIR_DEBUG("NIC(%zu): Model:  %s", i, def->nets[i]->model);
        VIR_DEBUG("NIC(%zu): Mac:    %s", i, macaddr);
        VIR_DEBUG("NIC(%zu): ifname: %s", i, def->nets[i]->ifname);
E
Eric Blake 已提交
4403
        if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4404
            VIR_DEBUG("NIC(%zu): name:    %s", i, def->nets[i]->data.network.name);
E
Eric Blake 已提交
4405
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
4406
            VIR_DEBUG("NIC(%zu): name:   %s", i, def->nets[i]->data.internal.name);
E
Eric Blake 已提交
4407
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
4408
            VIR_DEBUG("NIC(%zu): NAT.", i);
E
Eric Blake 已提交
4409
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
4410 4411 4412
            VIR_DEBUG("NIC(%zu): brname: %s", i, def->nets[i]->data.bridge.brname);
            VIR_DEBUG("NIC(%zu): script: %s", i, def->nets[i]->script);
            VIR_DEBUG("NIC(%zu): ipaddr: %s", i, def->nets[i]->data.bridge.ipaddr);
4413 4414
        }

E
Eric Blake 已提交
4415 4416 4417 4418 4419
        machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
        if (adapter) {
            PRUnichar *MACAddress = NULL;

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

E
Eric Blake 已提交
4421
            if (def->nets[i]->model) {
E
Eric Blake 已提交
4422
                if (STRCASEEQ(def->nets[i]->model, "Am79C970A")) {
E
Eric Blake 已提交
4423
                    adapterType = NetworkAdapterType_Am79C970A;
E
Eric Blake 已提交
4424
                } else if (STRCASEEQ(def->nets[i]->model, "Am79C973")) {
E
Eric Blake 已提交
4425
                    adapterType = NetworkAdapterType_Am79C973;
E
Eric Blake 已提交
4426
                } else if (STRCASEEQ(def->nets[i]->model, "82540EM")) {
E
Eric Blake 已提交
4427
                    adapterType = NetworkAdapterType_I82540EM;
E
Eric Blake 已提交
4428
                } else if (STRCASEEQ(def->nets[i]->model, "82545EM")) {
E
Eric Blake 已提交
4429
                    adapterType = NetworkAdapterType_I82545EM;
E
Eric Blake 已提交
4430
                } else if (STRCASEEQ(def->nets[i]->model, "82543GC")) {
E
Eric Blake 已提交
4431
                    adapterType = NetworkAdapterType_I82543GC;
4432
#if VBOX_API_VERSION >= 3001
E
Eric Blake 已提交
4433
                } else if (STRCASEEQ(def->nets[i]->model, "virtio")) {
E
Eric Blake 已提交
4434
                    adapterType = NetworkAdapterType_Virtio;
4435 4436
#endif /* VBOX_API_VERSION >= 3001 */
                }
E
Eric Blake 已提交
4437 4438 4439
            } else {
                adapterType = NetworkAdapterType_Am79C973;
            }
4440

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

E
Eric Blake 已提交
4443 4444 4445
            if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
                PRUnichar *hostInterface = NULL;
                /* Bridged Network */
4446

4447
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4448
                adapter->vtbl->AttachToBridgedInterface(adapter);
4449 4450 4451
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Bridged);
#endif /* VBOX_API_VERSION >= 4001 */
4452

E
Eric Blake 已提交
4453 4454 4455
                if (def->nets[i]->data.bridge.brname) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.bridge.brname,
                                       &hostInterface);
4456
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4457
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4458 4459 4460
#else /* VBOX_API_VERSION >= 4001 */
                    adapter->vtbl->SetBridgedInterface(adapter, hostInterface);
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4461 4462 4463 4464 4465
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
                PRUnichar *internalNetwork = NULL;
                /* Internal Network */
4466

4467
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4468
                adapter->vtbl->AttachToInternalNetwork(adapter);
4469 4470 4471
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Internal);
#endif /* VBOX_API_VERSION >= 4001 */
4472

E
Eric Blake 已提交
4473 4474 4475 4476 4477
                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);
4478
                }
E
Eric Blake 已提交
4479 4480 4481 4482 4483 4484
            } 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)
                 */
4485
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4486
                adapter->vtbl->AttachToHostOnlyInterface(adapter);
4487 4488 4489
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_HostOnly);
#endif /* VBOX_API_VERSION >= 4001 */
4490

E
Eric Blake 已提交
4491 4492 4493
                if (def->nets[i]->data.network.name) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.network.name,
                                       &hostInterface);
4494
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4495
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4496 4497 4498
#else /* VBOX_API_VERSION >= 4001 */
                    adapter->vtbl->SetHostOnlyInterface(adapter, hostInterface);
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4499 4500 4501 4502
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
                /* NAT */
4503
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4504
                adapter->vtbl->AttachToNAT(adapter);
4505 4506 4507
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
#endif /* VBOX_API_VERSION >= 4001 */
E
Eric Blake 已提交
4508 4509 4510 4511
            } else {
                /* else always default to NAT if we don't understand
                 * what option is been passed to us
                 */
4512
#if VBOX_API_VERSION < 4001
E
Eric Blake 已提交
4513
                adapter->vtbl->AttachToNAT(adapter);
4514 4515 4516
#else /* VBOX_API_VERSION >= 4001 */
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
#endif /* VBOX_API_VERSION >= 4001 */
4517
            }
E
Eric Blake 已提交
4518 4519 4520 4521

            VBOX_UTF8_TO_UTF16(macaddrvbox, &MACAddress);
            adapter->vtbl->SetMACAddress(adapter, MACAddress);
            VBOX_UTF16_FREE(MACAddress);
4522
        }
E
Eric Blake 已提交
4523 4524 4525 4526 4527 4528 4529 4530
    }
}

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

E
Eric Blake 已提交
4533 4534 4535 4536 4537 4538 4539
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetSerialPortCount(systemProperties,
                                                   &serialPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4540

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

4546 4547
        VIR_DEBUG("SerialPort(%zu): Type: %d", i, def->serials[i]->source.type);
        VIR_DEBUG("SerialPort(%zu): target.port: %d", i,
E
Eric Blake 已提交
4548
              def->serials[i]->target.port);
4549

E
Eric Blake 已提交
4550 4551 4552
        machine->vtbl->GetSerialPort(machine, i, &serialPort);
        if (serialPort) {
            PRUnichar *pathUtf16 = NULL;
4553

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

4556 4557 4558
            if (def->serials[i]->source.data.file.path) {
                VBOX_UTF8_TO_UTF16(def->serials[i]->source.data.file.path,
                                   &pathUtf16);
E
Eric Blake 已提交
4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573
                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);
4574
                VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4575
                      i, 4, 1016, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4576 4577 4578
            } else if (def->serials[i]->target.port == 1) {
                serialPort->vtbl->SetIRQ(serialPort, 3);
                serialPort->vtbl->SetIOBase(serialPort, 760);
4579
                VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4580
                      i, 3, 760, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4581
            }
4582

4583
            if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV) {
E
Eric Blake 已提交
4584
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostDevice);
4585
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE) {
E
Eric Blake 已提交
4586
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostPipe);
4587
#if VBOX_API_VERSION >= 3000
4588
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE) {
E
Eric Blake 已提交
4589
                serialPort->vtbl->SetHostMode(serialPort, PortMode_RawFile);
4590
#endif /* VBOX_API_VERSION >= 3000 */
E
Eric Blake 已提交
4591 4592 4593 4594
            } else {
                serialPort->vtbl->SetHostMode(serialPort,
                                              PortMode_Disconnected);
            }
4595

E
Eric Blake 已提交
4596
            VBOX_RELEASE(serialPort);
J
John Ferlan 已提交
4597
            VBOX_UTF16_FREE(pathUtf16);
4598
        }
E
Eric Blake 已提交
4599 4600
    }
}
4601

E
Eric Blake 已提交
4602 4603 4604 4605 4606
static void
vboxAttachParallel(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 parallelPortCount          = 0;
4607
    size_t i = 0;
4608

E
Eric Blake 已提交
4609 4610 4611 4612 4613 4614 4615
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetParallelPortCount(systemProperties,
                                                     &parallelPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4616

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

4622 4623
        VIR_DEBUG("ParallelPort(%zu): Type: %d", i, def->parallels[i]->source.type);
        VIR_DEBUG("ParallelPort(%zu): target.port: %d", i,
E
Eric Blake 已提交
4624
              def->parallels[i]->target.port);
4625

E
Eric Blake 已提交
4626 4627 4628
        machine->vtbl->GetParallelPort(machine, i, &parallelPort);
        if (parallelPort) {
            PRUnichar *pathUtf16 = NULL;
4629

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

E
Eric Blake 已提交
4632 4633 4634 4635 4636
            /* 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
             */
4637 4638 4639 4640
            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 已提交
4641 4642 4643 4644
                parallelPort->vtbl->SetPath(parallelPort, pathUtf16);
                if (i == 0) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 7);
                    parallelPort->vtbl->SetIOBase(parallelPort, 888);
4645
                    VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4646
                          i, 7, 888, def->parallels[i]->source.data.file.path);
E
Eric Blake 已提交
4647 4648 4649
                } else if (i == 1) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 5);
                    parallelPort->vtbl->SetIOBase(parallelPort, 632);
4650
                    VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4651
                          i, 5, 632, def->parallels[i]->source.data.file.path);
4652 4653
                }
            }
E
Eric Blake 已提交
4654 4655 4656 4657 4658 4659 4660

            /* 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 已提交
4661
            VBOX_UTF16_FREE(pathUtf16);
4662
        }
E
Eric Blake 已提交
4663 4664 4665 4666 4667 4668 4669 4670
    }
}

static void
vboxAttachVideo(virDomainDefPtr def, IMachine *machine)
{
    if ((def->nvideos == 1) &&
        (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_VBOX)) {
4671 4672
        machine->vtbl->SetVRAMSize(machine,
                                   VIR_DIV_UP(def->videos[0]->vram, 1024));
E
Eric Blake 已提交
4673 4674 4675 4676
        machine->vtbl->SetMonitorCount(machine, def->videos[0]->heads);
        if (def->videos[0]->accel) {
            machine->vtbl->SetAccelerate3DEnabled(machine,
                                                  def->videos[0]->accel->support3d);
4677
#if VBOX_API_VERSION >= 3001
E
Eric Blake 已提交
4678 4679
            machine->vtbl->SetAccelerate2DVideoEnabled(machine,
                                                       def->videos[0]->accel->support2d);
4680
#endif /* VBOX_API_VERSION >= 3001 */
E
Eric Blake 已提交
4681 4682
        } else {
            machine->vtbl->SetAccelerate3DEnabled(machine, 0);
4683
#if VBOX_API_VERSION >= 3001
E
Eric Blake 已提交
4684
            machine->vtbl->SetAccelerate2DVideoEnabled(machine, 0);
4685 4686
#endif /* VBOX_API_VERSION >= 3001 */
        }
E
Eric Blake 已提交
4687 4688
    }
}
4689

E
Eric Blake 已提交
4690 4691 4692 4693 4694 4695 4696 4697
static void
vboxAttachDisplay(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    int vrdpPresent  = 0;
    int sdlPresent   = 0;
    int guiPresent   = 0;
    char *guiDisplay = NULL;
    char *sdlDisplay = NULL;
4698
    size_t i = 0;
4699

E
Eric Blake 已提交
4700
    for (i = 0; i < def->ngraphics; i++) {
4701 4702 4703 4704 4705
#if VBOX_API_VERSION < 4000
        IVRDPServer *VRDxServer = NULL;
#else /* VBOX_API_VERSION >= 4000 */
        IVRDEServer *VRDxServer = NULL;
#endif /* VBOX_API_VERSION >= 4000 */
4706

E
Eric Blake 已提交
4707 4708
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) &&
            (vrdpPresent == 0)) {
4709

E
Eric Blake 已提交
4710
            vrdpPresent = 1;
4711 4712 4713 4714 4715 4716
#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) {
4717 4718 4719
                const char *listenAddr
                    = virDomainGraphicsListenGetAddress(def->graphics[i], 0);

4720
                VRDxServer->vtbl->SetEnabled(VRDxServer, PR_TRUE);
4721
                VIR_DEBUG("VRDP Support turned ON.");
4722 4723

#if VBOX_API_VERSION < 3001
E
Eric Blake 已提交
4724
                if (def->graphics[i]->data.rdp.port) {
4725
                    VRDxServer->vtbl->SetPort(VRDxServer,
E
Eric Blake 已提交
4726
                                              def->graphics[i]->data.rdp.port);
4727
                    VIR_DEBUG("VRDP Port changed to: %d",
E
Eric Blake 已提交
4728 4729 4730 4731 4732
                          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
                     */
4733
                    VRDxServer->vtbl->SetPort(VRDxServer, 0);
4734
                    VIR_DEBUG("VRDP Port changed to default, which is 3389 currently");
E
Eric Blake 已提交
4735
                }
4736
#elif VBOX_API_VERSION < 4000 /* 3001 <= VBOX_API_VERSION < 4000 */
E
Eric Blake 已提交
4737 4738
                PRUnichar *portUtf16 = NULL;
                portUtf16 = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
4739
                VRDxServer->vtbl->SetPorts(VRDxServer, portUtf16);
E
Eric Blake 已提交
4740
                VBOX_UTF16_FREE(portUtf16);
4741 4742 4743 4744 4745 4746 4747 4748 4749 4750
#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 */
4751

E
Eric Blake 已提交
4752
                if (def->graphics[i]->data.rdp.replaceUser) {
4753
                    VRDxServer->vtbl->SetReuseSingleConnection(VRDxServer,
E
Eric Blake 已提交
4754
                                                               PR_TRUE);
4755
                    VIR_DEBUG("VRDP set to reuse single connection");
E
Eric Blake 已提交
4756
                }
4757

E
Eric Blake 已提交
4758
                if (def->graphics[i]->data.rdp.multiUser) {
4759
                    VRDxServer->vtbl->SetAllowMultiConnection(VRDxServer,
E
Eric Blake 已提交
4760
                                                              PR_TRUE);
4761
                    VIR_DEBUG("VRDP set to allow multiple connection");
E
Eric Blake 已提交
4762
                }
4763

4764
                if (listenAddr) {
4765 4766 4767
#if VBOX_API_VERSION >= 4000
                    PRUnichar *netAddressKey = NULL;
#endif
E
Eric Blake 已提交
4768
                    PRUnichar *netAddressUtf16 = NULL;
4769

4770
                    VBOX_UTF8_TO_UTF16(listenAddr, &netAddressUtf16);
4771 4772
#if VBOX_API_VERSION < 4000
                    VRDxServer->vtbl->SetNetAddress(VRDxServer,
E
Eric Blake 已提交
4773
                                                    netAddressUtf16);
4774 4775 4776 4777 4778 4779
#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 */
4780
                    VIR_DEBUG("VRDP listen address is set to: %s",
4781
                              listenAddr);
4782

E
Eric Blake 已提交
4783
                    VBOX_UTF16_FREE(netAddressUtf16);
4784
                }
E
Eric Blake 已提交
4785

4786
                VBOX_RELEASE(VRDxServer);
4787
            }
E
Eric Blake 已提交
4788
        }
4789

E
Eric Blake 已提交
4790 4791 4792
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) &&
            (guiPresent == 0)) {
            guiPresent = 1;
4793 4794 4795 4796 4797
            if (VIR_STRDUP(guiDisplay, def->graphics[i]->data.desktop.display) < 0) {
                /* 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
                 */
4798
            }
E
Eric Blake 已提交
4799
        }
4800

E
Eric Blake 已提交
4801 4802 4803
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) &&
            (sdlPresent == 0)) {
            sdlPresent = 1;
4804 4805 4806 4807 4808
            if (VIR_STRDUP(sdlDisplay, def->graphics[i]->data.sdl.display) < 0) {
                /* 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
                 */
4809
            }
4810
        }
E
Eric Blake 已提交
4811
    }
4812

E
Eric Blake 已提交
4813 4814 4815 4816
    if ((vrdpPresent == 1) && (guiPresent == 0) && (sdlPresent == 0)) {
        /* store extradata key that frontend is set to vrdp */
        PRUnichar *keyTypeUtf16   = NULL;
        PRUnichar *valueTypeUtf16 = NULL;
4817

E
Eric Blake 已提交
4818 4819
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("vrdp", &valueTypeUtf16);
4820

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

E
Eric Blake 已提交
4823 4824
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4825

E
Eric Blake 已提交
4826 4827 4828 4829 4830 4831
    } 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;
4832

E
Eric Blake 已提交
4833 4834
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("sdl", &valueTypeUtf16);
4835

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

E
Eric Blake 已提交
4838 4839
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4840

E
Eric Blake 已提交
4841 4842 4843
        if (sdlDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(sdlDisplay, &valueDisplayUtf16);
4844

E
Eric Blake 已提交
4845 4846
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4847

E
Eric Blake 已提交
4848 4849 4850
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
        }
4851

E
Eric Blake 已提交
4852 4853 4854 4855 4856 4857
    } 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;
4858

E
Eric Blake 已提交
4859 4860
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("gui", &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 (guiDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(guiDisplay, &valueDisplayUtf16);
4870

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

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

E
Eric Blake 已提交
4879 4880 4881
    VIR_FREE(guiDisplay);
    VIR_FREE(sdlDisplay);
}
4882

E
Eric Blake 已提交
4883 4884 4885
static void
vboxAttachUSB(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
R
Ryota Ozaki 已提交
4886
#if VBOX_API_VERSION < 4003
E
Eric Blake 已提交
4887
    IUSBController *USBController = NULL;
R
Ryota Ozaki 已提交
4888 4889 4890
#else
    IUSBDeviceFilters *USBDeviceFilters = NULL;
#endif
4891
    size_t i = 0;
E
Eric Blake 已提交
4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902
    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++) {
R
Ryota Ozaki 已提交
4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918
        if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
            continue;

        if (def->hostdevs[i]->source.subsys.type !=
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            continue;

        if (!def->hostdevs[i]->source.subsys.u.usb.vendor &&
            !def->hostdevs[i]->source.subsys.u.usb.product)
            continue;

        VIR_DEBUG("USB Device detected, VendorId:0x%x, ProductId:0x%x",
                  def->hostdevs[i]->source.subsys.u.usb.vendor,
                  def->hostdevs[i]->source.subsys.u.usb.product);
        isUSB = true;
        break;
E
Eric Blake 已提交
4919 4920
    }

R
Ryota Ozaki 已提交
4921 4922 4923
    if (!isUSB)
        return;

R
Ryota Ozaki 已提交
4924
#if VBOX_API_VERSION < 4003
R
Ryota Ozaki 已提交
4925 4926 4927 4928 4929 4930 4931 4932 4933
    /* First Start the USB Controller and then loop
     * to attach USB Devices to it
     */
    machine->vtbl->GetUSBController(machine, &USBController);

    if (!USBController)
        return;

    USBController->vtbl->SetEnabled(USBController, 1);
R
Ryota Ozaki 已提交
4934
# if VBOX_API_VERSION < 4002
R
Ryota Ozaki 已提交
4935
    USBController->vtbl->SetEnabledEhci(USBController, 1);
R
Ryota Ozaki 已提交
4936
# else
R
Ryota Ozaki 已提交
4937
    USBController->vtbl->SetEnabledEHCI(USBController, 1);
R
Ryota Ozaki 已提交
4938 4939 4940 4941 4942 4943
# endif
#else
    machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);

    if (!USBDeviceFilters)
        return;
4944
#endif
4945

R
Ryota Ozaki 已提交
4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956
    for (i = 0; i < def->nhostdevs; i++) {
        char *filtername           = NULL;
        PRUnichar *filternameUtf16 = NULL;
        IUSBDeviceFilter *filter   = NULL;
        PRUnichar *vendorIdUtf16  = NULL;
        char vendorId[40]         = {0};
        PRUnichar *productIdUtf16 = NULL;
        char productId[40]        = {0};

        if (def->hostdevs[i]->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
            continue;
4957

R
Ryota Ozaki 已提交
4958 4959 4960
        if (def->hostdevs[i]->source.subsys.type !=
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            continue;
4961

R
Ryota Ozaki 已提交
4962 4963 4964 4965 4966 4967
        /* Zero pad for nice alignment when fewer than 9999
         * devices.
         */
        if (virAsprintf(&filtername, "filter%04zu", i) >= 0) {
            VBOX_UTF8_TO_UTF16(filtername, &filternameUtf16);
            VIR_FREE(filtername);
R
Ryota Ozaki 已提交
4968
#if VBOX_API_VERSION < 4003
R
Ryota Ozaki 已提交
4969 4970 4971
            USBController->vtbl->CreateDeviceFilter(USBController,
                                                    filternameUtf16,
                                                    &filter);
R
Ryota Ozaki 已提交
4972 4973 4974 4975 4976
#else
            USBDeviceFilters->vtbl->CreateDeviceFilter(USBDeviceFilters,
                                                       filternameUtf16,
                                                       &filter);
#endif
R
Ryota Ozaki 已提交
4977 4978
        }
        VBOX_UTF16_FREE(filternameUtf16);
E
Eric Blake 已提交
4979

R
Ryota Ozaki 已提交
4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000
        if (!filter)
            continue;

        if (!def->hostdevs[i]->source.subsys.u.usb.vendor &&
            !def->hostdevs[i]->source.subsys.u.usb.product)
            continue;

        if (def->hostdevs[i]->source.subsys.u.usb.vendor) {
            snprintf(vendorId, sizeof(vendorId), "%x",
                     def->hostdevs[i]->source.subsys.u.usb.vendor);
            VBOX_UTF8_TO_UTF16(vendorId, &vendorIdUtf16);
            filter->vtbl->SetVendorId(filter, vendorIdUtf16);
            VBOX_UTF16_FREE(vendorIdUtf16);
        }
        if (def->hostdevs[i]->source.subsys.u.usb.product) {
            snprintf(productId, sizeof(productId), "%x",
                     def->hostdevs[i]->source.subsys.u.usb.product);
            VBOX_UTF8_TO_UTF16(productId, &productIdUtf16);
            filter->vtbl->SetProductId(filter,
                                       productIdUtf16);
            VBOX_UTF16_FREE(productIdUtf16);
E
Eric Blake 已提交
5001
        }
R
Ryota Ozaki 已提交
5002
        filter->vtbl->SetActive(filter, 1);
R
Ryota Ozaki 已提交
5003
#if VBOX_API_VERSION < 4003
R
Ryota Ozaki 已提交
5004 5005 5006
        USBController->vtbl->InsertDeviceFilter(USBController,
                                                i,
                                                filter);
R
Ryota Ozaki 已提交
5007 5008 5009 5010 5011
#else
        USBDeviceFilters->vtbl->InsertDeviceFilter(USBDeviceFilters,
                                                   i,
                                                   filter);
#endif
R
Ryota Ozaki 已提交
5012
        VBOX_RELEASE(filter);
E
Eric Blake 已提交
5013
    }
R
Ryota Ozaki 已提交
5014 5015

#if VBOX_API_VERSION < 4003
R
Ryota Ozaki 已提交
5016
    VBOX_RELEASE(USBController);
R
Ryota Ozaki 已提交
5017 5018 5019
#else
    VBOX_RELEASE(USBDeviceFilters);
#endif
E
Eric Blake 已提交
5020 5021
}

M
Matthias Bolte 已提交
5022 5023 5024
static void
vboxAttachSharedFolder(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
5025
    size_t i;
M
Matthias Bolte 已提交
5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053
    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 已提交
5054 5055 5056 5057
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml) {
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
    IMachine       *machine     = NULL;
    IBIOSSettings  *bios        = NULL;
5058 5059
    vboxIID iid = VBOX_IID_INITIALIZER;
    vboxIID mchiid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
5060 5061
    virDomainDefPtr def         = NULL;
    PRUnichar *machineNameUtf16 = NULL;
5062
#if VBOX_API_VERSION >= 3002 && VBOX_API_VERSION < 4002
E
Eric Blake 已提交
5063 5064 5065
    PRBool override             = PR_FALSE;
#endif
    nsresult rc;
5066 5067 5068 5069 5070 5071 5072 5073
    char uuidstr[VIR_UUID_STRING_BUFLEN];
#if VBOX_API_VERSION >= 4002
    const char *flagsUUIDPrefix = "UUID=";
    const char *flagsForceOverwrite = "forceOverwrite=0";
    const char *flagsSeparator = ",";
    char createFlags[strlen(flagsUUIDPrefix) + VIR_UUID_STRING_BUFLEN + strlen(flagsSeparator) + strlen(flagsForceOverwrite) + 1];
    PRUnichar *createFlagsUtf16 = NULL;
#endif
E
Eric Blake 已提交
5074

5075 5076
    if (!(def = virDomainDefParseString(xml, data->caps, data->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_VBOX,
E
Eric Blake 已提交
5077 5078 5079 5080 5081
                                        VIR_DOMAIN_XML_INACTIVE))) {
        goto cleanup;
    }

    VBOX_UTF8_TO_UTF16(def->name, &machineNameUtf16);
5082
    vboxIIDFromUUID(&iid, def->uuid);
5083 5084
    virUUIDFormat(def->uuid, uuidstr);

E
Eric Blake 已提交
5085 5086 5087 5088 5089
#if VBOX_API_VERSION < 3002
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
5090
                                            iid.value,
E
Eric Blake 已提交
5091
                                            &machine);
5092
#elif VBOX_API_VERSION < 4000 /* 3002 <= VBOX_API_VERSION < 4000 */
E
Eric Blake 已提交
5093 5094 5095 5096
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
5097
                                            iid.value,
E
Eric Blake 已提交
5098 5099
                                            override,
                                            &machine);
5100
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
5101 5102 5103 5104 5105 5106 5107
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            NULL,
                                            machineNameUtf16,
                                            NULL,
                                            iid.value,
                                            override,
                                            &machine);
5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124
#else /* VBOX_API_VERSION >= 4002 */
    snprintf(createFlags, sizeof(createFlags), "%s%s%s%s",
             flagsUUIDPrefix,
             uuidstr,
             flagsSeparator,
             flagsForceOverwrite
            );
    VBOX_UTF8_TO_UTF16(createFlags, &createFlagsUtf16);
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            NULL,
                                            machineNameUtf16,
                                            0,
                                            nsnull,
                                            nsnull,
                                            createFlagsUtf16,
                                            &machine);
#endif /* VBOX_API_VERSION >= 4002 */
E
Eric Blake 已提交
5125 5126 5127
    VBOX_UTF16_FREE(machineNameUtf16);

    if (NS_FAILED(rc)) {
5128 5129
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
5130 5131 5132
        goto cleanup;
    }

5133 5134
    rc = machine->vtbl->SetMemorySize(machine,
                                      VIR_DIV_UP(def->mem.cur_balloon, 1024));
E
Eric Blake 已提交
5135
    if (NS_FAILED(rc)) {
5136 5137 5138 5139
        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 已提交
5140 5141
    }

E
Eric Blake 已提交
5142
    if (def->vcpus != def->maxvcpus) {
5143 5144
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("current vcpu count must equal maximum"));
E
Eric Blake 已提交
5145 5146
    }
    rc = machine->vtbl->SetCPUCount(machine, def->maxvcpus);
E
Eric Blake 已提交
5147
    if (NS_FAILED(rc)) {
5148 5149 5150
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not set the number of virtual CPUs to: %u, rc=%08x"),
                       def->maxvcpus, (unsigned)rc);
E
Eric Blake 已提交
5151 5152 5153
    }

#if VBOX_API_VERSION < 3001
5154 5155 5156
    rc = machine->vtbl->SetPAEEnabled(machine,
                                      def->features[VIR_DOMAIN_FEATURE_PAE] ==
                                      VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5157 5158
#elif VBOX_API_VERSION == 3001
    rc = machine->vtbl->SetCpuProperty(machine, CpuPropertyType_PAE,
5159 5160
                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
                                       VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5161 5162
#elif VBOX_API_VERSION >= 3002
    rc = machine->vtbl->SetCPUProperty(machine, CPUPropertyType_PAE,
5163 5164
                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
                                       VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5165 5166
#endif
    if (NS_FAILED(rc)) {
5167 5168
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not change PAE status to: %s, rc=%08x"),
5169
                       (def->features[VIR_DOMAIN_FEATURE_PAE] == VIR_DOMAIN_FEATURE_STATE_ON)
5170
                       ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
5171 5172 5173 5174
    }

    machine->vtbl->GetBIOSSettings(machine, &bios);
    if (bios) {
5175 5176 5177
        rc = bios->vtbl->SetACPIEnabled(bios,
                                        def->features[VIR_DOMAIN_FEATURE_ACPI] ==
                                        VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5178
        if (NS_FAILED(rc)) {
5179 5180
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change ACPI status to: %s, rc=%08x"),
5181
                           (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_DOMAIN_FEATURE_STATE_ON)
5182
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
5183
        }
5184 5185 5186
        rc = bios->vtbl->SetIOAPICEnabled(bios,
                                          def->features[VIR_DOMAIN_FEATURE_APIC] ==
                                          VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5187
        if (NS_FAILED(rc)) {
5188 5189
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change APIC status to: %s, rc=%08x"),
5190
                           (def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_DOMAIN_FEATURE_STATE_ON)
5191
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
5192
        }
E
Eric Blake 已提交
5193 5194 5195 5196 5197 5198
        VBOX_RELEASE(bios);
    }

    /* Register the machine before attaching other devices to it */
    rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
    if (NS_FAILED(rc)) {
5199 5200
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
5201 5202 5203 5204 5205 5206 5207
        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
     */
5208
    machine->vtbl->GetId(machine, &mchiid.value);
5209
    VBOX_SESSION_OPEN(mchiid.value, machine);
E
Eric Blake 已提交
5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220
    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 已提交
5221
    vboxAttachSharedFolder(def, data, machine);
5222

5223 5224 5225 5226
    /* Save the machine settings made till now and close the
     * session. also free up the mchiid variable used.
     */
    rc = machine->vtbl->SaveSettings(machine);
5227
    VBOX_SESSION_CLOSE();
5228
    vboxIIDUnalloc(&mchiid);
5229

5230 5231
    ret = virGetDomain(conn, def->name, def->uuid);
    VBOX_RELEASE(machine);
5232

5233
    vboxIIDUnalloc(&iid);
5234 5235
    virDomainDefFree(def);

5236
    return ret;
5237 5238

cleanup:
5239
    VBOX_RELEASE(machine);
5240
    vboxIIDUnalloc(&iid);
5241 5242 5243 5244
    virDomainDefFree(def);
    return NULL;
}

5245
static int
5246
vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags)
5247
{
5248
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5249
    IMachine *machine    = NULL;
5250
    vboxIID iid = VBOX_IID_INITIALIZER;
5251
    nsresult rc;
5252 5253 5254
#if VBOX_API_VERSION >= 4000
    vboxArray media = VBOX_ARRAY_INITIALIZER;
#endif
5255 5256 5257 5258
    /* 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);
5259

5260
    vboxIIDFromUUID(&iid, dom->uuid);
5261

5262
#if VBOX_API_VERSION < 4000
5263 5264 5265
    /* 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
5266 5267 5268 5269
     * 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.
5270 5271 5272
     */
    {
        PRUnichar *hddcnameUtf16 = NULL;
5273

5274 5275
        char *hddcname;
        ignore_value(VIR_STRDUP(hddcname, "IDE"));
5276 5277
        VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16);
        VIR_FREE(hddcname);
5278

5279
        /* Open a Session for the machine */
5280
        rc = VBOX_SESSION_OPEN(iid.value, machine);
5281 5282 5283 5284
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {

5285
# if VBOX_API_VERSION < 3001
5286 5287 5288 5289
                /* 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);
5290
# else  /* VBOX_API_VERSION >= 3001 */
5291 5292 5293
                /* get all the controller first, then the attachments and
                 * remove them all so that the machine can be undefined
                 */
5294
                vboxArray storageControllers = VBOX_ARRAY_INITIALIZER;
5295
                size_t i = 0, j = 0;
5296

5297 5298
                vboxArrayGet(&storageControllers, machine,
                             machine->vtbl->GetStorageControllers);
5299

5300 5301
                for (i = 0; i < storageControllers.count; i++) {
                    IStorageController *strCtl = storageControllers.items[i];
5302
                    PRUnichar *strCtlName = NULL;
5303
                    vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
5304 5305 5306 5307 5308

                    if (!strCtl)
                        continue;

                    strCtl->vtbl->GetName(strCtl, &strCtlName);
5309 5310 5311
                    vboxArrayGetWithPtrArg(&mediumAttachments, machine,
                                           machine->vtbl->GetMediumAttachmentsOfController,
                                           strCtlName);
5312

5313 5314
                    for (j = 0; j < mediumAttachments.count; j++) {
                        IMediumAttachment *medAtt = mediumAttachments.items[j];
5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330
                        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);
                        }
                    }
5331

5332 5333
                    vboxArrayRelease(&storageControllers);

5334 5335
                    machine->vtbl->RemoveStorageController(machine, strCtlName);
                    VBOX_UTF16_FREE(strCtlName);
5336
                }
5337 5338

                vboxArrayRelease(&storageControllers);
5339
# endif /* VBOX_API_VERSION >= 3001 */
5340 5341

                machine->vtbl->SaveSettings(machine);
5342
            }
5343
            VBOX_SESSION_CLOSE();
5344
        }
5345 5346
        VBOX_UTF16_FREE(hddcnameUtf16);
    }
5347
#endif
5348

5349
#if VBOX_API_VERSION < 4000
5350
    rc = data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, iid.value, &machine);
5351 5352 5353
#else /* VBOX_API_VERSION >= 4000 */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
5354 5355
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5356 5357 5358 5359 5360 5361 5362 5363 5364 5365
        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 */
5366
    DEBUGIID("UUID of machine being undefined", iid.value);
5367

5368 5369
    if (NS_SUCCEEDED(rc)) {
#if VBOX_API_VERSION < 4000
5370
        machine->vtbl->DeleteSettings(machine);
5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384
#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);

R
Ryota Ozaki 已提交
5385
#  if VBOX_API_VERSION < 4003
5386
        ((IMachine_Delete)machine->vtbl->Delete)(machine, &safeArray, &progress);
R
Ryota Ozaki 已提交
5387 5388 5389
#  else
        ((IMachine_Delete)machine->vtbl->DeleteConfig)(machine, &safeArray, &progress);
#  endif
5390
# else
5391 5392 5393
        /* 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 };
R
Ryota Ozaki 已提交
5394
#  if VBOX_API_VERSION < 4003
5395
        machine->vtbl->Delete(machine, 0, array, &progress);
R
Ryota Ozaki 已提交
5396 5397 5398
#  else
        machine->vtbl->DeleteConfig(machine, 0, array, &progress);
#  endif
5399 5400 5401 5402 5403 5404
# endif
        if (progress != NULL) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
#endif /* VBOX_API_VERSION >= 4000 */
5405 5406
        ret = 0;
    } else {
5407 5408
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not delete the domain, rc=%08x"), (unsigned)rc);
5409 5410
    }

5411 5412 5413
#if VBOX_API_VERSION >= 4000
    vboxArrayUnalloc(&media);
#endif
5414
    vboxIIDUnalloc(&iid);
5415
    VBOX_RELEASE(machine);
5416 5417 5418 5419

    return ret;
}

5420 5421 5422 5423 5424 5425
static int
vboxDomainUndefine(virDomainPtr dom)
{
    return vboxDomainUndefineFlags(dom, 0);
}

5426 5427 5428
static int vboxDomainAttachDeviceImpl(virDomainPtr dom,
                                      const char *xml,
                                      int mediaChangeOnly ATTRIBUTE_UNUSED) {
5429
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5430
    IMachine *machine    = NULL;
5431
    vboxIID iid = VBOX_IID_INITIALIZER;
5432 5433 5434
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5435
    nsresult rc;
5436

5437
    if (VIR_ALLOC(def) < 0)
5438 5439
        return ret;

5440
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
5441 5442
        goto cleanup;

5443 5444
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5445
    if (dev == NULL)
5446 5447
        goto cleanup;

5448
    vboxIIDFromUUID(&iid, dom->uuid);
5449
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5450
    if (NS_FAILED(rc)) {
5451 5452
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5453 5454
        goto cleanup;
    }
5455

5456 5457
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5458

5459 5460
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5461
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5462
        } else {
5463
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5464 5465 5466 5467 5468 5469 5470
        }
        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) {
5471 5472
                        if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                            dev->data.disk->src != NULL) {
5473 5474 5475 5476 5477 5478 5479 5480 5481
                            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;
5482 5483
                                vboxIID dvduuid = VBOX_IID_INITIALIZER;
                                vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
5484

5485
                                VBOX_UTF8_TO_UTF16(dev->data.disk->src, &dvdfileUtf16);
5486

5487 5488
                                data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
                                if (!dvdImage) {
5489
                                    data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage);
5490 5491
                                }
                                if (dvdImage) {
5492
                                    rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value);
5493
                                    if (NS_FAILED(rc)) {
5494 5495 5496 5497
                                        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);
5498 5499 5500
                                    } else {
                                        /* unmount the previous mounted image */
                                        dvdDrive->vtbl->Unmount(dvdDrive);
5501
                                        rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
5502
                                        if (NS_FAILED(rc)) {
5503 5504 5505
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("could not attach the file to cdrom: %s, rc=%08x"),
                                                           dev->data.disk->src, (unsigned)rc);
5506
                                        } else {
5507
                                            ret = 0;
5508
                                            DEBUGIID("CD/DVD Image UUID:", dvduuid.value);
5509 5510
                                        }
                                    }
5511 5512

                                    VBOX_MEDIUM_RELEASE(dvdImage);
5513
                                }
5514
                                vboxIIDUnalloc(&dvduuid);
5515 5516
                                VBOX_UTF16_FREE(dvdfileUtf16);
                                VBOX_RELEASE(dvdDrive);
5517
                            }
5518 5519 5520
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
5521 5522
                        if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_FILE &&
                            dev->data.disk->src != NULL) {
5523 5524 5525 5526 5527 5528 5529
                            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;
5530 5531
                                    vboxIID fduuid = VBOX_IID_INITIALIZER;
                                    vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
5532 5533 5534 5535 5536 5537 5538 5539
                                    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,
5540
                                                                             fdemptyuuid.value,
5541 5542
                                                                             &floppyImage);
                                    }
5543

5544
                                    if (floppyImage) {
5545
                                        rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value);
5546
                                        if (NS_FAILED(rc)) {
5547 5548 5549 5550
                                            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);
5551
                                        } else {
5552
                                            rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value);
5553
                                            if (NS_FAILED(rc)) {
5554 5555 5556
                                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                                               _("could not attach the file to floppy drive: %s, rc=%08x"),
                                                               dev->data.disk->src, (unsigned)rc);
5557
                                            } else {
5558
                                                ret = 0;
5559
                                                DEBUGIID("attached floppy, UUID:", fduuid.value);
5560 5561
                                            }
                                        }
5562
                                        VBOX_MEDIUM_RELEASE(floppyImage);
5563
                                    }
5564
                                    vboxIIDUnalloc(&fduuid);
5565
                                    VBOX_UTF16_FREE(fdfileUtf16);
5566
                                }
5567
                                VBOX_RELEASE(floppyDrive);
5568
                            }
5569
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5570
                        }
5571 5572 5573 5574 5575 5576 5577
                    }
#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) {
5578 5579
                        }
                    }
M
Matthias Bolte 已提交
5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598
                } 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)) {
5599 5600 5601
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not attach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5602 5603 5604 5605 5606 5607
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
                    VBOX_UTF16_FREE(hostPathUtf16);
5608
                }
5609 5610
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5611
            }
5612
            VBOX_SESSION_CLOSE();
5613 5614 5615 5616
        }
    }

cleanup:
5617
    vboxIIDUnalloc(&iid);
5618 5619 5620 5621 5622
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5623 5624 5625 5626
static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml) {
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

5627 5628 5629 5630 5631 5632
static int
vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5633
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5634 5635
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5636 5637 5638
        return -1;
    }

5639 5640 5641 5642 5643
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags) {
5644 5645 5646
    virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
                  VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
5647

5648
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5649 5650
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5651 5652 5653 5654
        return -1;
    }

    return vboxDomainAttachDeviceImpl(dom, xml, 1);
5655 5656
}

5657
static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml) {
5658
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5659
    IMachine *machine    = NULL;
5660
    vboxIID iid = VBOX_IID_INITIALIZER;
5661 5662 5663
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5664
    nsresult rc;
5665

5666
    if (VIR_ALLOC(def) < 0)
5667 5668
        return ret;

5669
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
5670 5671
        goto cleanup;

5672 5673
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5674
    if (dev == NULL)
5675 5676
        goto cleanup;

5677
    vboxIIDFromUUID(&iid, dom->uuid);
5678
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5679
    if (NS_FAILED(rc)) {
5680 5681
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5682 5683
        goto cleanup;
    }
5684

5685 5686
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5687

5688 5689
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5690
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5691
        } else {
5692
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5693
        }
5694

5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710
        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)) {
5711 5712 5713
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not de-attach the mounted ISO, rc=%08x"),
                                                   (unsigned)rc);
5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730
                                } 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);
5731
                                    if (NS_FAILED(rc)) {
5732 5733 5734 5735
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("could not attach the file "
                                                         "to floppy drive, rc=%08x"),
                                                       (unsigned)rc);
5736 5737 5738
                                    } else {
                                        ret = 0;
                                    }
5739 5740 5741 5742 5743
                                } 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;
5744
                                }
5745
                                VBOX_RELEASE(floppyDrive);
5746
                            }
5747
                        } else if (dev->data.disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5748
                        }
5749 5750 5751 5752 5753 5754 5755
                    }
#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) {
5756 5757
                        }
                    }
M
Matthias Bolte 已提交
5758 5759 5760 5761 5762 5763 5764 5765 5766
                } 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)) {
5767 5768 5769
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not detach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5770 5771 5772 5773 5774
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
5775
                }
5776 5777
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5778
            }
5779
            VBOX_SESSION_CLOSE();
5780 5781 5782 5783
        }
    }

cleanup:
5784
    vboxIIDUnalloc(&iid);
5785 5786 5787 5788 5789
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5790 5791 5792 5793 5794 5795
static int
vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5796
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5797 5798
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5799 5800 5801 5802 5803 5804
        return -1;
    }

    return vboxDomainDetachDevice(dom, xml);
}

J
Jiri Denemark 已提交
5805 5806 5807 5808 5809
static int
vboxDomainSnapshotGetAll(virDomainPtr dom,
                         IMachine *machine,
                         ISnapshot ***snapshots)
{
5810
    vboxIID empty = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5811 5812 5813 5814 5815 5816 5817 5818
    ISnapshot **list = NULL;
    PRUint32 count;
    nsresult rc;
    unsigned int next;
    unsigned int top;

    rc = machine->vtbl->GetSnapshotCount(machine, &count);
    if (NS_FAILED(rc)) {
5819 5820 5821
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5822 5823 5824 5825 5826 5827
        goto error;
    }

    if (count == 0)
        goto out;

5828
    if (VIR_ALLOC_N(list, count) < 0)
J
Jiri Denemark 已提交
5829 5830
        goto error;

5831
#if VBOX_API_VERSION < 4000
5832
    rc = machine->vtbl->GetSnapshot(machine, empty.value, list);
5833 5834 5835
#else /* VBOX_API_VERSION >= 4000 */
    rc = machine->vtbl->FindSnapshot(machine, empty.value, list);
#endif /* VBOX_API_VERSION >= 4000 */
J
Jiri Denemark 已提交
5836
    if (NS_FAILED(rc) || !list[0]) {
5837 5838 5839
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get root snapshot for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5840 5841 5842 5843 5844 5845
        goto error;
    }

    /* BFS walk through snapshot tree */
    top = 1;
    for (next = 0; next < count; next++) {
5846
        vboxArray children = VBOX_ARRAY_INITIALIZER;
5847
        size_t i;
J
Jiri Denemark 已提交
5848 5849

        if (!list[next]) {
5850 5851
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected number of snapshots < %u"), count);
J
Jiri Denemark 已提交
5852 5853 5854
            goto error;
        }

5855 5856
        rc = vboxArrayGet(&children, list[next],
                               list[next]->vtbl->GetChildren);
J
Jiri Denemark 已提交
5857
        if (NS_FAILED(rc)) {
5858 5859
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get children snapshots"));
J
Jiri Denemark 已提交
5860 5861
            goto error;
        }
5862 5863 5864
        for (i = 0; i < children.count; i++) {
            ISnapshot *child = children.items[i];
            if (!child)
J
Jiri Denemark 已提交
5865 5866
                continue;
            if (top == count) {
5867 5868
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected number of snapshots > %u"), count);
5869
                vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5870 5871
                goto error;
            }
5872 5873
            VBOX_ADDREF(child);
            list[top++] = child;
J
Jiri Denemark 已提交
5874
        }
5875
        vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901
    }

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;
5902
    size_t i;
J
Jiri Denemark 已提交
5903 5904 5905 5906 5907 5908 5909 5910 5911 5912

    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) {
5913 5914
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927
            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) {
5928 5929 5930
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s has no snapshots with name %s"),
                       dom->name, name);
J
Jiri Denemark 已提交
5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947
        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,
5948
                            unsigned int flags)
J
Jiri Denemark 已提交
5949 5950 5951
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
    virDomainSnapshotDefPtr def = NULL;
5952
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966
    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

5967 5968
    /* VBox has no snapshot metadata, so this flag is trivial.  */
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
5969

5970
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps,
5971
                                                data->xmlopt, 0, 0)))
J
Jiri Denemark 已提交
5972 5973
        goto cleanup;

5974
    if (def->ndisks) {
5975 5976
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk snapshots not supported yet"));
5977 5978 5979
        goto cleanup;
    }

5980
    vboxIIDFromUUID(&domiid, dom->uuid);
5981
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
5982
    if (NS_FAILED(rc)) {
5983 5984
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
5985 5986 5987 5988 5989
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
5990 5991
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
5992 5993 5994 5995 5996
        goto cleanup;
    }

    if ((state >= MachineState_FirstOnline)
        && (state <= MachineState_LastOnline)) {
5997
        rc = VBOX_SESSION_OPEN_EXISTING(domiid.value, machine);
J
Jiri Denemark 已提交
5998
    } else {
5999
        rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6000
    }
6001

J
Jiri Denemark 已提交
6002 6003 6004
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6005 6006 6007
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026
        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) {
6027 6028
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6029 6030 6031 6032 6033 6034
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6035 6036
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6037 6038 6039 6040 6041
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6042 6043
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
J
Jiri Denemark 已提交
6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054
                  dom->name);
        goto cleanup;
    }

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

cleanup:
    VBOX_RELEASE(progress);
    VBOX_UTF16_FREE(description);
    VBOX_UTF16_FREE(name);
    VBOX_RELEASE(console);
6055
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
6056
    VBOX_RELEASE(machine);
6057
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6058 6059 6060 6061 6062
    virDomainSnapshotDefFree(def);
    return ret;
}

static char *
6063 6064
vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                             unsigned int flags)
J
Jiri Denemark 已提交
6065 6066 6067
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
6068
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079
    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];

6080 6081
    virCheckFlags(0, NULL);

6082
    vboxIIDFromUUID(&domiid, dom->uuid);
6083
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6084
    if (NS_FAILED(rc)) {
6085 6086
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6087 6088 6089 6090 6091 6092
        goto cleanup;
    }

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

6093
    if (VIR_ALLOC(def) < 0)
6094
        goto cleanup;
6095 6096
    if (VIR_STRDUP(def->name, snapshot->name) < 0)
        goto cleanup;
J
Jiri Denemark 已提交
6097 6098 6099

    rc = snap->vtbl->GetDescription(snap, &str16);
    if (NS_FAILED(rc)) {
6100 6101 6102
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get description of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6103 6104 6105 6106 6107
        goto cleanup;
    }
    if (str16) {
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
6108 6109 6110 6111
        if (VIR_STRDUP(def->description, str8) < 0) {
            VBOX_UTF8_FREE(str8);
            goto cleanup;
        }
J
Jiri Denemark 已提交
6112 6113 6114 6115 6116
        VBOX_UTF8_FREE(str8);
    }

    rc = snap->vtbl->GetTimeStamp(snap, &timestamp);
    if (NS_FAILED(rc)) {
6117 6118 6119
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get creation time of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6120 6121 6122 6123 6124 6125 6126
        goto cleanup;
    }
    /* timestamp is in milliseconds while creationTime in seconds */
    def->creationTime = timestamp / 1000;

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
6127 6128 6129
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6130 6131 6132 6133 6134
        goto cleanup;
    }
    if (parent) {
        rc = parent->vtbl->GetName(parent, &str16);
        if (NS_FAILED(rc) || !str16) {
6135 6136 6137
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get name of parent of snapshot %s"),
                           snapshot->name);
J
Jiri Denemark 已提交
6138 6139 6140 6141
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
6142 6143
        if (VIR_STRDUP(def->parent, str8) < 0) {
            VBOX_UTF8_FREE(str8);
6144
            goto cleanup;
6145 6146
        }
        VBOX_UTF8_FREE(str8);
J
Jiri Denemark 已提交
6147 6148 6149 6150
    }

    rc = snap->vtbl->GetOnline(snap, &online);
    if (NS_FAILED(rc)) {
6151 6152 6153
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6154 6155 6156 6157 6158 6159 6160 6161
        goto cleanup;
    }
    if (online)
        def->state = VIR_DOMAIN_RUNNING;
    else
        def->state = VIR_DOMAIN_SHUTOFF;

    virUUIDFormat(dom->uuid, uuidstr);
6162
    ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0);
J
Jiri Denemark 已提交
6163 6164 6165 6166 6167 6168

cleanup:
    virDomainSnapshotDefFree(def);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
6169
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6170 6171 6172 6173 6174
    return ret;
}

static int
vboxDomainSnapshotNum(virDomainPtr dom,
6175
                      unsigned int flags)
J
Jiri Denemark 已提交
6176 6177
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6178
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6179 6180 6181 6182
    IMachine *machine = NULL;
    nsresult rc;
    PRUint32 snapshotCount;

6183 6184
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6185

6186
    vboxIIDFromUUID(&iid, dom->uuid);
6187
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6188
    if (NS_FAILED(rc)) {
6189 6190
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6191 6192 6193
        goto cleanup;
    }

6194 6195 6196 6197 6198 6199
    /* VBox snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

J
Jiri Denemark 已提交
6200 6201
    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
    if (NS_FAILED(rc)) {
6202 6203 6204
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6205 6206 6207
        goto cleanup;
    }

6208 6209 6210 6211 6212
    /* VBox has at most one root snapshot.  */
    if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS))
        ret = 1;
    else
        ret = snapshotCount;
J
Jiri Denemark 已提交
6213 6214 6215

cleanup:
    VBOX_RELEASE(machine);
6216
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6217 6218 6219 6220 6221 6222 6223
    return ret;
}

static int
vboxDomainSnapshotListNames(virDomainPtr dom,
                            char **names,
                            int nameslen,
6224
                            unsigned int flags)
J
Jiri Denemark 已提交
6225 6226
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6227
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6228 6229 6230 6231
    IMachine *machine = NULL;
    nsresult rc;
    ISnapshot **snapshots = NULL;
    int count = 0;
6232
    size_t i;
J
Jiri Denemark 已提交
6233

6234 6235
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6236

6237
    vboxIIDFromUUID(&iid, dom->uuid);
6238
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6239
    if (NS_FAILED(rc)) {
6240 6241
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6242 6243 6244
        goto cleanup;
    }

6245 6246 6247 6248 6249
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

6250 6251 6252
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) {
        vboxIID empty = VBOX_IID_INITIALIZER;

6253
        if (VIR_ALLOC_N(snapshots, 1) < 0)
6254 6255 6256 6257 6258 6259 6260
            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]) {
6261 6262 6263
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get root snapshot for domain %s"),
                           dom->name);
6264 6265 6266 6267 6268 6269 6270
            goto cleanup;
        }
        count = 1;
    } else {
        if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
            goto cleanup;
    }
J
Jiri Denemark 已提交
6271 6272 6273 6274 6275 6276 6277 6278 6279 6280

    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) {
6281 6282
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
6283 6284 6285 6286
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(nameUtf16, &name);
        VBOX_UTF16_FREE(nameUtf16);
6287 6288
        if (VIR_STRDUP(names[i], name) < 0) {
            VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
6289 6290
            goto cleanup;
        }
6291
        VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305
    }

    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);
6306
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6307 6308 6309 6310 6311 6312
    return ret;
}

static virDomainSnapshotPtr
vboxDomainSnapshotLookupByName(virDomainPtr dom,
                               const char *name,
6313
                               unsigned int flags)
J
Jiri Denemark 已提交
6314 6315
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6316
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6317 6318 6319 6320
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

6321 6322
    virCheckFlags(0, NULL);

6323
    vboxIIDFromUUID(&iid, dom->uuid);
6324
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6325
    if (NS_FAILED(rc)) {
6326 6327
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338
        goto cleanup;
    }

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

    ret = virGetDomainSnapshot(dom, name);

cleanup:
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
6339
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6340 6341 6342 6343 6344
    return ret;
}

static int
vboxDomainHasCurrentSnapshot(virDomainPtr dom,
6345
                             unsigned int flags)
J
Jiri Denemark 已提交
6346 6347
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6348
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6349 6350 6351 6352
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

6353 6354
    virCheckFlags(0, -1);

6355
    vboxIIDFromUUID(&iid, dom->uuid);
6356
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6357
    if (NS_FAILED(rc)) {
6358 6359
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6360 6361 6362 6363 6364
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6365 6366
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
6367 6368 6369 6370 6371 6372 6373 6374 6375 6376
        goto cleanup;
    }

    if (snapshot)
        ret = 1;
    else
        ret = 0;

cleanup:
    VBOX_RELEASE(machine);
6377
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6378 6379 6380
    return ret;
}

6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399
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)) {
6400 6401
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6402 6403 6404 6405 6406 6407 6408 6409
        goto cleanup;
    }

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

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
6410 6411 6412
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
6413 6414 6415
        goto cleanup;
    }
    if (!parent) {
6416 6417 6418
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshot->name);
6419 6420 6421 6422 6423
        goto cleanup;
    }

    rc = parent->vtbl->GetName(parent, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6424 6425 6426
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get name of parent of snapshot %s"),
                       snapshot->name);
6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446
        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 已提交
6447 6448
static virDomainSnapshotPtr
vboxDomainSnapshotCurrent(virDomainPtr dom,
6449
                          unsigned int flags)
J
Jiri Denemark 已提交
6450 6451
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6452
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6453 6454 6455 6456 6457 6458
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

6459 6460
    virCheckFlags(0, NULL);

6461
    vboxIIDFromUUID(&iid, dom->uuid);
6462
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6463
    if (NS_FAILED(rc)) {
6464 6465
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6466 6467 6468 6469 6470
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6471 6472
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
6473 6474 6475 6476
        goto cleanup;
    }

    if (!snapshot) {
6477 6478
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain has no snapshots"));
J
Jiri Denemark 已提交
6479 6480 6481 6482 6483
        goto cleanup;
    }

    rc = snapshot->vtbl->GetName(snapshot, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6484 6485
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
J
Jiri Denemark 已提交
6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501
        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);
6502
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6503 6504 6505
    return ret;
}

6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524
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)) {
6525 6526
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6527 6528 6529 6530 6531 6532 6533 6534
        goto cleanup;
    }

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

    rc = machine->vtbl->GetCurrentSnapshot(machine, &current);
    if (NS_FAILED(rc)) {
6535 6536
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
6537 6538 6539 6540 6541 6542 6543 6544 6545
        goto cleanup;
    }
    if (!current) {
        ret = 0;
        goto cleanup;
    }

    rc = current->vtbl->GetName(current, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6546 6547
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584
        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)) {
6585 6586
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602
        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 已提交
6603 6604 6605 6606 6607 6608 6609
#if VBOX_API_VERSION < 3001
static int
vboxDomainSnapshotRestore(virDomainPtr dom,
                          IMachine *machine,
                          ISnapshot *snapshot)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6610
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6611 6612
    nsresult rc;

6613 6614
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
6615 6616
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
6617 6618 6619
        goto cleanup;
    }

6620
    rc = machine->vtbl->SetCurrentSnapshot(machine, iid.value);
J
Jiri Denemark 已提交
6621
    if (NS_FAILED(rc)) {
6622 6623
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
6624 6625 6626 6627 6628 6629
        goto cleanup;
    }

    ret = 0;

cleanup:
6630
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644
    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;
6645
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6646

6647 6648
    rc = machine->vtbl->GetId(machine, &domiid.value);
    if (NS_FAILED(rc)) {
6649 6650
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain UUID"));
J
Jiri Denemark 已提交
6651 6652 6653 6654 6655
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6656 6657
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6658 6659 6660 6661 6662
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6663 6664
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s is already running"), dom->name);
J
Jiri Denemark 已提交
6665 6666 6667
        goto cleanup;
    }

6668
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6669 6670 6671
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6672 6673 6674
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6675 6676 6677 6678 6679 6680
        goto cleanup;
    }

    rc = console->vtbl->RestoreSnapshot(console, snapshot, &progress);
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
6681 6682
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot restore domain snapshot for running domain"));
J
Jiri Denemark 已提交
6683
        } else {
6684 6685 6686
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not restore snapshot for domain %s"),
                           dom->name);
J
Jiri Denemark 已提交
6687 6688 6689 6690 6691 6692 6693
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6694 6695
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
6696 6697 6698 6699 6700 6701 6702 6703
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(progress);
    VBOX_RELEASE(console);
6704
    VBOX_SESSION_CLOSE();
6705
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6706 6707 6708 6709 6710 6711
    return ret;
}
#endif

static int
vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
6712
                           unsigned int flags)
J
Jiri Denemark 已提交
6713 6714 6715
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6716
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6717 6718 6719 6720 6721 6722 6723
    IMachine *machine = NULL;
    ISnapshot *newSnapshot = NULL;
    ISnapshot *prevSnapshot = NULL;
    PRBool online = PR_FALSE;
    PRUint32 state;
    nsresult rc;

6724 6725
    virCheckFlags(0, -1);

6726
    vboxIIDFromUUID(&domiid, dom->uuid);
6727
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6728
    if (NS_FAILED(rc)) {
6729 6730
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6731 6732 6733 6734 6735 6736 6737 6738 6739
        goto cleanup;
    }

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

    rc = newSnapshot->vtbl->GetOnline(newSnapshot, &online);
    if (NS_FAILED(rc)) {
6740 6741 6742
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6743 6744 6745 6746 6747
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &prevSnapshot);
    if (NS_FAILED(rc)) {
6748 6749 6750
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6751 6752 6753 6754 6755
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6756 6757
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6758 6759 6760 6761 6762
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6763 6764
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot revert snapshot of running domain"));
J
Jiri Denemark 已提交
6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780
        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);
6781
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6782 6783 6784 6785 6786 6787 6788 6789 6790
    return ret;
}

static int
vboxDomainSnapshotDeleteSingle(vboxGlobalData *data,
                               IConsole *console,
                               ISnapshot *snapshot)
{
    IProgress *progress = NULL;
6791
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6792 6793 6794 6795 6796 6797 6798 6799
    int ret = -1;
    nsresult rc;
#if VBOX_API_VERSION == 2002
    nsresult result;
#else
    PRInt32 result;
#endif

6800 6801
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
6802 6803
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
6804 6805 6806 6807
        goto cleanup;
    }

#if VBOX_API_VERSION < 3001
6808
    rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
6809
#else
6810
    rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
6811 6812 6813
#endif
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
6814 6815
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot delete domain snapshot for running domain"));
J
Jiri Denemark 已提交
6816
        } else {
6817 6818
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("could not delete snapshot"));
J
Jiri Denemark 已提交
6819 6820 6821 6822 6823 6824 6825
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6826 6827
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not delete snapshot"));
J
Jiri Denemark 已提交
6828 6829 6830 6831 6832 6833 6834
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(progress);
6835
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6836 6837 6838 6839 6840 6841 6842 6843
    return ret;
}

static int
vboxDomainSnapshotDeleteTree(vboxGlobalData *data,
                             IConsole *console,
                             ISnapshot *snapshot)
{
6844
    vboxArray children = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
6845 6846
    int ret = -1;
    nsresult rc;
6847
    size_t i;
J
Jiri Denemark 已提交
6848

6849
    rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren);
J
Jiri Denemark 已提交
6850
    if (NS_FAILED(rc)) {
6851 6852
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get children snapshots"));
J
Jiri Denemark 已提交
6853 6854 6855
        goto cleanup;
    }

6856 6857 6858
    for (i = 0; i < children.count; i++) {
        if (vboxDomainSnapshotDeleteTree(data, console, children.items[i]))
            goto cleanup;
J
Jiri Denemark 已提交
6859 6860 6861 6862 6863
    }

    ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot);

cleanup:
6864
    vboxArrayRelease(&children);
J
Jiri Denemark 已提交
6865 6866 6867 6868 6869 6870 6871 6872 6873
    return ret;
}

static int
vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                         unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6874
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6875 6876 6877 6878 6879 6880
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    IConsole *console = NULL;
    PRUint32 state;
    nsresult rc;

6881 6882
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
6883

6884
    vboxIIDFromUUID(&domiid, dom->uuid);
6885
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6886
    if (NS_FAILED(rc)) {
6887 6888
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6889 6890 6891 6892 6893 6894 6895 6896 6897
        goto cleanup;
    }

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

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6898 6899
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6900 6901 6902
        goto cleanup;
    }

6903 6904 6905 6906 6907 6908 6909
    /* 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 已提交
6910 6911
    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6912 6913
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot delete snapshots of running domain"));
J
Jiri Denemark 已提交
6914 6915 6916
        goto cleanup;
    }

6917
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6918 6919 6920
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6921 6922 6923
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934
        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);
6935
    vboxIIDUnalloc(&domiid);
6936
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
6937 6938 6939
    return ret;
}

6940
#if VBOX_API_VERSION <= 2002 || VBOX_API_VERSION >= 4000
6941
    /* No Callback support for VirtualBox 2.2.* series */
6942 6943
    /* No Callback support for VirtualBox 4.* series */
#else /* !(VBOX_API_VERSION == 2002 || VBOX_API_VERSION >= 4000) */
6944 6945

/* Functions needed for Callbacks */
6946
static nsresult PR_COM_METHOD
6947
vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
6948 6949
                                 PRUnichar *machineId, PRUint32 state)
{
6950 6951 6952 6953 6954 6955
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

6956
    VIR_DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state);
6957 6958 6959 6960 6961 6962 6963
    DEBUGPRUnichar("machineId", machineId);

    if (machineId) {
        char *machineIdUtf8       = NULL;
        unsigned char uuid[VIR_UUID_BUFLEN];

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
6964
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
6965 6966 6967

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
6968
            virObjectEventPtr ev;
6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998

            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;
            }

6999
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
7000

7001
            if (ev)
7002
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
7003 7004 7005 7006 7007 7008 7009 7010
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

7011
static nsresult PR_COM_METHOD
7012
vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7013 7014
                                PRUnichar *machineId)
{
7015
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7016 7017 7018 7019 7020
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

7021
static nsresult PR_COM_METHOD
7022
vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7023 7024 7025
                                 PRUnichar *machineId, PRUnichar *key,
                                 PRUnichar *value,
                                 PRUnichar **error ATTRIBUTE_UNUSED,
7026
                                 PRBool *allowChange ATTRIBUTE_UNUSED)
7027
{
7028
    VIR_DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false");
7029 7030 7031 7032 7033 7034 7035
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

7036
static nsresult PR_COM_METHOD
7037 7038
vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *machineId,
7039 7040
                              PRUnichar *key, PRUnichar *value)
{
7041
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7042 7043 7044 7045 7046 7047 7048
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

7049
# if VBOX_API_VERSION < 3001
7050
static nsresult PR_COM_METHOD
7051 7052 7053 7054
vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *mediaId,
                              PRUint32 mediaType ATTRIBUTE_UNUSED,
                              PRBool registered ATTRIBUTE_UNUSED)
7055
{
7056 7057
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
    VIR_DEBUG("mediaType: %d", mediaType);
7058 7059 7060 7061
    DEBUGPRUnichar("mediaId", mediaId);

    return NS_OK;
}
7062 7063
# else  /* VBOX_API_VERSION >= 3001 */
# endif /* VBOX_API_VERSION >= 3001 */
7064

7065
static nsresult PR_COM_METHOD
7066
vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7067 7068
                                PRUnichar *machineId, PRBool registered)
{
7069 7070 7071 7072 7073 7074
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

7075
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
7076 7077 7078 7079 7080 7081 7082
    DEBUGPRUnichar("machineId", machineId);

    if (machineId) {
        char *machineIdUtf8       = NULL;
        unsigned char uuid[VIR_UUID_BUFLEN];

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
7083
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
7084 7085 7086

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
7087
            virObjectEventPtr ev;
7088 7089

            /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED
J
Ján Tomko 已提交
7090
             * event because the when the machine is de-registered the call
7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102
             * 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;
            }

7103
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
7104

7105
            if (ev)
7106
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
7107 7108 7109 7110 7111 7112 7113 7114
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

7115
static nsresult PR_COM_METHOD
7116 7117 7118
vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                 PRUnichar *machineId,
                                 PRUint32 state ATTRIBUTE_UNUSED)
7119
{
7120
    VIR_DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state);
7121 7122 7123 7124 7125
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

7126
static nsresult PR_COM_METHOD
7127 7128
vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                            PRUnichar *machineId,
7129 7130
                            PRUnichar *snapshotId)
{
7131
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7132 7133 7134 7135 7136 7137
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

7138
static nsresult PR_COM_METHOD
7139 7140
vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                PRUnichar *machineId,
7141 7142
                                PRUnichar *snapshotId)
{
7143
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7144 7145 7146 7147 7148 7149
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

7150
static nsresult PR_COM_METHOD
7151 7152
vboxCallbackOnSnapshotChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                             PRUnichar *machineId,
7153 7154
                             PRUnichar *snapshotId)
{
7155
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7156 7157 7158 7159 7160 7161
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

7162
static nsresult PR_COM_METHOD
7163
vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7164 7165 7166
                                  PRUnichar *machineId, PRUnichar *name,
                                  PRUnichar *value, PRUnichar *flags)
{
7167
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7168 7169 7170 7171 7172 7173 7174 7175
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("name", name);
    DEBUGPRUnichar("value", value);
    DEBUGPRUnichar("flags", flags);

    return NS_OK;
}

7176
static nsresult PR_COM_METHOD
7177
vboxCallbackAddRef(nsISupports *pThis ATTRIBUTE_UNUSED)
7178
{
7179 7180 7181 7182
    nsresult c;

    c = ++g_pVBoxGlobalData->vboxCallBackRefCount;

7183
    VIR_DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c);
7184 7185 7186 7187

    return c;
}

7188 7189 7190
static nsresult PR_COM_METHOD
vboxCallbackRelease(nsISupports *pThis)
{
7191 7192 7193 7194 7195 7196 7197 7198 7199
    nsresult c;

    c = --g_pVBoxGlobalData->vboxCallBackRefCount;
    if (c == 0) {
        /* delete object */
        VIR_FREE(pThis->vtbl);
        VIR_FREE(pThis);
    }

7200
    VIR_DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c);
7201 7202 7203 7204

    return c;
}

7205 7206 7207
static nsresult PR_COM_METHOD
vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp)
{
7208 7209 7210 7211 7212
    IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis;
    static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID;
    static const nsID isupportIID = NS_ISUPPORTS_IID;

    /* Match UUID for IVirtualBoxCallback class */
7213 7214
    if (memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 ||
        memcmp(iid, &isupportIID, sizeof(nsID)) == 0) {
7215 7216 7217
        g_pVBoxGlobalData->vboxCallBackRefCount++;
        *resultp = that;

7218
        VIR_DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount);
7219 7220 7221 7222 7223

        return NS_OK;
    }


7224
    VIR_DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis);
7225 7226 7227 7228 7229 7230
    DEBUGUUID("The UUID Callback Interface expects", iid);
    DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID);
    return NS_NOINTERFACE;
}


7231
static IVirtualBoxCallback *vboxAllocCallbackObj(void) {
7232 7233
    IVirtualBoxCallback *vboxCallback = NULL;

7234
    /* Allocate, Initialize and return a valid
7235 7236 7237
     * IVirtualBoxCallback object here
     */
    if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) {
7238
        VIR_FREE(vboxCallback);
7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249
        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;
7250
# if VBOX_API_VERSION < 3001
7251
        vboxCallback->vtbl->OnMediaRegistered           = &vboxCallbackOnMediaRegistered;
7252 7253
# else  /* VBOX_API_VERSION >= 3001 */
# endif /* VBOX_API_VERSION >= 3001 */
7254 7255 7256
        vboxCallback->vtbl->OnMachineRegistered         = &vboxCallbackOnMachineRegistered;
        vboxCallback->vtbl->OnSessionStateChange        = &vboxCallbackOnSessionStateChange;
        vboxCallback->vtbl->OnSnapshotTaken             = &vboxCallbackOnSnapshotTaken;
7257
# if VBOX_API_VERSION < 3002
7258
        vboxCallback->vtbl->OnSnapshotDiscarded         = &vboxCallbackOnSnapshotDiscarded;
7259 7260 7261
# else /* VBOX_API_VERSION >= 3002 */
        vboxCallback->vtbl->OnSnapshotDeleted           = &vboxCallbackOnSnapshotDiscarded;
# endif /* VBOX_API_VERSION >= 3002 */
7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286
        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);
    }
}

7287 7288 7289 7290 7291 7292
static int
vboxConnectDomainEventRegister(virConnectPtr conn,
                               virConnectDomainEventCallback callback,
                               void *opaque,
                               virFreeCallback freecb)
{
7293
    VBOX_OBJECT_CHECK(conn, int, -1);
7294
    int vboxRet          = -1;
7295
    nsresult rc;
7296 7297 7298 7299 7300 7301

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

7302
    if (data->vboxCallback == NULL) {
7303
        data->vboxCallback = vboxAllocCallbackObj();
7304 7305 7306 7307
        if (data->vboxCallback != NULL) {
            rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
            if (NS_SUCCEEDED(rc)) {
                vboxRet = 0;
7308 7309
            }
        }
7310 7311 7312
    } else {
        vboxRet = 0;
    }
7313

7314 7315 7316 7317 7318 7319 7320
    /* 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);
7321

7322 7323
            data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL);
        }
7324

7325 7326 7327 7328 7329
        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
             */
7330

7331
            ret = virDomainEventStateRegister(conn, data->domainEvents, NULL,
7332
                                              callback, opaque, freecb);
7333
            VIR_DEBUG("virObjectEventStateRegister (ret = %d) (conn: %p, "
7334
                      "callback: %p, opaque: %p, "
7335
                      "freecb: %p)", ret, conn, callback,
7336
                      opaque, freecb);
7337 7338 7339 7340 7341 7342
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
7343
        return 0;
7344 7345 7346 7347 7348 7349 7350 7351
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

7352 7353 7354 7355
static int
vboxConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback callback)
{
7356
    VBOX_OBJECT_CHECK(conn, int, -1);
7357
    int cnt;
7358 7359 7360 7361 7362 7363

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

7364 7365
    cnt = virDomainEventStateDeregister(conn, data->domainEvents,
                                        callback);
7366

7367 7368 7369
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
7370

7371 7372 7373
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
7374 7375 7376 7377
    }

    vboxDriverUnlock(data);

7378 7379 7380
    if (cnt >= 0)
        ret = 0;

7381 7382 7383
    return ret;
}

7384 7385 7386 7387 7388 7389
static int vboxConnectDomainEventRegisterAny(virConnectPtr conn,
                                             virDomainPtr dom,
                                             int eventID,
                                             virConnectDomainEventGenericCallback callback,
                                             void *opaque,
                                             virFreeCallback freecb) {
7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427
    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
             */

7428
            if (virDomainEventStateRegisterID(conn, data->domainEvents, NULL,
7429 7430
                                              dom, eventID,
                                              callback, opaque, freecb, &ret) < 0)
7431
                ret = -1;
7432
            VIR_DEBUG("virDomainEventStateRegisterID (ret = %d) (conn: %p, "
7433
                      "callback: %p, opaque: %p, "
7434
                      "freecb: %p)", ret, conn, callback,
7435
                      opaque, freecb);
7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
        return ret;
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

7451 7452 7453 7454
static int
vboxConnectDomainEventDeregisterAny(virConnectPtr conn,
                                    int callbackID)
{
7455
    VBOX_OBJECT_CHECK(conn, int, -1);
7456
    int cnt;
7457 7458 7459 7460 7461 7462

    /* Locking has to be there as callbacks are not
     * really fully thread safe
     */
    vboxDriverLock(data);

7463
    cnt = virObjectEventStateDeregisterID(conn, data->domainEvents,
7464
                                          callbackID);
7465

7466 7467 7468
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
7469

7470 7471 7472
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
7473 7474 7475 7476
    }

    vboxDriverUnlock(data);

7477 7478 7479
    if (cnt >= 0)
        ret = 0;

7480 7481 7482
    return ret;
}

7483
#endif /* !(VBOX_API_VERSION == 2002 || VBOX_API_VERSION >= 4000) */
7484

7485 7486 7487 7488 7489
/**
 * The Network Functions here on
 */
static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
7490 7491
                                        unsigned int flags)
{
7492 7493
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
7494 7495
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

7496 7497 7498 7499 7500 7501 7502 7503
    if (STRNEQ(conn->driver->name, "VBOX"))
        goto cleanup;

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
        goto cleanup;

7504
    VIR_DEBUG("network initialized");
7505 7506 7507 7508 7509 7510 7511 7512
    /* conn->networkPrivateData = some network specific data */
    return VIR_DRV_OPEN_SUCCESS;

cleanup:
    return VIR_DRV_OPEN_DECLINED;
}

static int vboxNetworkClose(virConnectPtr conn) {
7513
    VIR_DEBUG("network uninitialized");
7514 7515 7516 7517
    conn->networkPrivateData = NULL;
    return 0;
}

7518
static int vboxConnectNumOfNetworks(virConnectPtr conn) {
7519
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7520
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7521
    size_t i = 0;
7522

7523
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7524

7525 7526 7527 7528
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
7529
            PRUint32 interfaceType = 0;
7530

7531
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7532 7533
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7534

7535
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7536

7537 7538
                if (status == HostNetworkInterfaceStatus_Up)
                    ret++;
7539 7540 7541 7542
            }
        }
    }

7543 7544
    vboxArrayRelease(&networkInterfaces);

7545 7546
    VBOX_RELEASE(host);

7547
    VIR_DEBUG("numActive: %d", ret);
7548
    return ret;
7549 7550
}

7551
static int vboxConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
7552
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7553
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7554
    size_t i = 0;
7555

7556 7557 7558 7559
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7560

7561
        if (networkInterface) {
7562
            PRUint32 interfaceType = 0;
7563

7564
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7565

7566 7567
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7568

7569
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7570

7571 7572 7573
                if (status == HostNetworkInterfaceStatus_Up) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
7574

7575
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7576
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7577

7578
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
7579
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
7580
                        ret++;
7581

7582 7583
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
7584 7585 7586 7587 7588
                }
            }
        }
    }

7589
    vboxArrayRelease(&networkInterfaces);
7590

7591
    VBOX_RELEASE(host);
7592

7593 7594
    return ret;
}
7595

7596
static int vboxConnectNumOfDefinedNetworks(virConnectPtr conn) {
7597
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7598
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7599
    size_t i = 0;
7600

7601
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7602

7603 7604 7605 7606
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
7607
            PRUint32 interfaceType = 0;
7608

7609
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7610 7611
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7612

7613
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7614

7615 7616
                if (status == HostNetworkInterfaceStatus_Down)
                    ret++;
7617 7618 7619 7620
            }
        }
    }

7621 7622
    vboxArrayRelease(&networkInterfaces);

7623 7624
    VBOX_RELEASE(host);

7625
    VIR_DEBUG("numActive: %d", ret);
7626
    return ret;
7627 7628
}

7629
static int vboxConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
7630
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7631
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7632
    size_t i = 0;
7633

7634 7635 7636 7637
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7638

7639
        if (networkInterface) {
7640
            PRUint32 interfaceType = 0;
7641

7642
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7643

7644 7645
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7646

7647
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7648

7649 7650 7651
                if (status == HostNetworkInterfaceStatus_Down) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
7652

7653
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7654
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7655

7656
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
7657
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
7658
                        ret++;
7659

7660 7661
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
7662 7663 7664 7665 7666
                }
            }
        }
    }

7667
    vboxArrayRelease(&networkInterfaces);
7668 7669 7670 7671

    VBOX_RELEASE(host);

    return ret;
7672 7673
}

7674 7675 7676
static virNetworkPtr
vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
7677
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
7678
    vboxIID iid = VBOX_IID_INITIALIZER;
7679

7680
    vboxIIDFromUUID(&iid, uuid);
7681

7682 7683 7684
    /* TODO: "internal" networks are just strings and
     * thus can't do much with them
     */
7685
    IHostNetworkInterface *networkInterface = NULL;
7686

7687
    host->vtbl->FindHostNetworkInterfaceById(host, iid.value, &networkInterface);
7688 7689
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7690

7691
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7692

7693 7694 7695
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            char *nameUtf8       = NULL;
            PRUnichar *nameUtf16 = NULL;
7696

7697 7698
            networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
            VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7699

7700
            ret = virGetNetwork(conn, nameUtf8, uuid);
7701

7702
            VIR_DEBUG("Network Name: %s", nameUtf8);
7703
            DEBUGIID("Network UUID", iid.value);
7704

7705 7706
            VBOX_UTF8_FREE(nameUtf8);
            VBOX_UTF16_FREE(nameUtf16);
7707
        }
7708 7709

        VBOX_RELEASE(networkInterface);
7710 7711
    }

7712 7713
    VBOX_RELEASE(host);

7714
    vboxIIDUnalloc(&iid);
7715 7716 7717 7718
    return ret;
}

static virNetworkPtr vboxNetworkLookupByName(virConnectPtr conn, const char *name) {
7719 7720 7721
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *nameUtf16                    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7722

7723
    VBOX_UTF8_TO_UTF16(name, &nameUtf16);
7724

7725
    host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface);
7726

7727 7728
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7729

7730
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7731

7732 7733
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            unsigned char uuid[VIR_UUID_BUFLEN];
7734
            vboxIID iid = VBOX_IID_INITIALIZER;
7735

7736 7737
            networkInterface->vtbl->GetId(networkInterface, &iid.value);
            vboxIIDToUUID(&iid, uuid);
7738
            ret = virGetNetwork(conn, name, uuid);
7739
            VIR_DEBUG("Network Name: %s", name);
7740

7741 7742
            DEBUGIID("Network UUID", iid.value);
            vboxIIDUnalloc(&iid);
7743
        }
7744 7745

        VBOX_RELEASE(networkInterface);
7746 7747
    }

7748 7749 7750
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(host);

7751 7752 7753
    return ret;
}

7754
static virNetworkPtr vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start) {
7755 7756 7757 7758
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    char      *networkInterfaceNameUtf8     = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7759
    nsresult rc;
7760

7761
    virNetworkDefPtr def = virNetworkDefParseString(xml);
7762 7763
    virNetworkIpDefPtr ipdef;
    virSocketAddr netmask;
7764

7765
    if ((!def) ||
7766
        (def->forward.type != VIR_NETWORK_FORWARD_NONE) ||
7767
        (def->nips == 0 || !def->ips))
7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778
        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)
7779
        goto cleanup;
7780

7781 7782 7783 7784 7785 7786
    /* 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.
     */
7787

7788
#if VBOX_API_VERSION == 2002
7789
    if (STREQ(def->name, "vboxnet0")) {
7790
        PRUint32 interfaceType = 0;
7791

7792 7793
        VBOX_UTF8_TO_UTF16(def->name, &networkInterfaceNameUtf16);
        host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7794

7795 7796 7797 7798 7799 7800
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
        if (interfaceType != HostNetworkInterfaceType_HostOnly) {
            VBOX_RELEASE(networkInterface);
            networkInterface = NULL;
        }
    }
7801
#else /* VBOX_API_VERSION != 2002 */
7802 7803 7804 7805
    {
        IProgress *progress = NULL;
        host->vtbl->CreateHostOnlyNetworkInterface(host, &networkInterface,
                                                   &progress);
7806

7807 7808 7809 7810
        if (progress) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
7811
    }
7812
#endif /* VBOX_API_VERSION != 2002 */
7813

7814 7815 7816 7817
    if (networkInterface) {
        unsigned char uuid[VIR_UUID_BUFLEN];
        char      *networkNameUtf8  = NULL;
        PRUnichar *networkNameUtf16 = NULL;
7818
        vboxIID vboxnetiid = VBOX_IID_INITIALIZER;
7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829

        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);
                goto cleanup;
            }
        }
7830

E
Eric Blake 已提交
7831
        VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
7832

7833 7834 7835
        /* Currently support only one dhcp server per network
         * with contigious address space from start to end
         */
7836
        if ((ipdef->nranges >= 1) &&
7837 7838
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
7839 7840 7841 7842 7843 7844 7845 7846 7847 7848
            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);
7849
                VIR_DEBUG("couldn't find dhcp server so creating one");
7850 7851 7852 7853 7854 7855 7856 7857
            }
            if (dhcpServer) {
                PRUnichar *ipAddressUtf16     = NULL;
                PRUnichar *networkMaskUtf16   = NULL;
                PRUnichar *fromIPAddressUtf16 = NULL;
                PRUnichar *toIPAddressUtf16   = NULL;
                PRUnichar *trunkTypeUtf16     = NULL;

7858 7859 7860 7861
                ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
                networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
                fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
                toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
7862 7863 7864 7865 7866 7867 7868 7869 7870 7871

                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;
                }
7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896

                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);
            }
        }
7897

7898
        if ((ipdef->nhosts >= 1) &&
7899
            VIR_SOCKET_ADDR_VALID(&ipdef->hosts[0].ip)) {
7900 7901
            PRUnichar *ipAddressUtf16   = NULL;
            PRUnichar *networkMaskUtf16 = NULL;
7902

7903 7904
            ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip);
            networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
7905 7906 7907 7908 7909 7910

            if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) {
                VBOX_UTF16_FREE(ipAddressUtf16);
                VBOX_UTF16_FREE(networkMaskUtf16);
                goto cleanup;
            }
7911

7912 7913 7914 7915
            /* 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
             */
7916
#if VBOX_API_VERSION < 4002
7917 7918 7919
            networkInterface->vtbl->EnableStaticIpConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
7920 7921 7922 7923 7924
#else
            networkInterface->vtbl->EnableStaticIPConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
#endif
7925

7926 7927 7928
            VBOX_UTF16_FREE(ipAddressUtf16);
            VBOX_UTF16_FREE(networkMaskUtf16);
        } else {
7929
#if VBOX_API_VERSION < 4002
7930 7931
            networkInterface->vtbl->EnableDynamicIpConfig(networkInterface);
            networkInterface->vtbl->DhcpRediscover(networkInterface);
7932 7933 7934 7935
#else
            networkInterface->vtbl->EnableDynamicIPConfig(networkInterface);
            networkInterface->vtbl->DHCPRediscover(networkInterface);
#endif
7936
        }
7937

7938 7939 7940 7941 7942
        rc = networkInterface->vtbl->GetId(networkInterface, &vboxnetiid.value);
        if (NS_SUCCEEDED(rc)) {
            vboxIIDToUUID(&vboxnetiid, uuid);
            DEBUGIID("Real Network UUID", vboxnetiid.value);
            vboxIIDUnalloc(&vboxnetiid);
7943
            ret = virGetNetwork(conn, networkInterfaceNameUtf8, uuid);
7944
        }
7945 7946 7947 7948

        VIR_FREE(networkNameUtf8);
        VBOX_UTF16_FREE(networkNameUtf16);
        VBOX_RELEASE(networkInterface);
7949 7950
    }

7951 7952 7953 7954
    VBOX_UTF8_FREE(networkInterfaceNameUtf8);
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

7955 7956 7957 7958 7959
cleanup:
    virNetworkDefFree(def);
    return ret;
}

7960 7961 7962 7963 7964 7965 7966 7967
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);
}

7968
static int vboxNetworkUndefineDestroy(virNetworkPtr network, bool removeinterface) {
7969
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
7970
    char *networkNameUtf8 = NULL;
7971 7972
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7973 7974 7975 7976 7977 7978 7979 7980 7981

    /* 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
     */

7982
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
7983 7984
        goto cleanup;

7985
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
7986

7987
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7988

7989 7990
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7991

7992
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7993

7994 7995 7996
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
7997

7998
#if VBOX_API_VERSION != 2002
7999 8000 8001
            if (removeinterface) {
                PRUnichar *iidUtf16 = NULL;
                IProgress *progress = NULL;
8002

8003
                networkInterface->vtbl->GetId(networkInterface, &iidUtf16);
8004

8005
                if (iidUtf16) {
8006
# if VBOX_API_VERSION == 3000
8007 8008 8009
                    IHostNetworkInterface *netInt = NULL;
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &netInt, &progress);
                    VBOX_RELEASE(netInt);
8010
# else  /* VBOX_API_VERSION > 3000 */
8011
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &progress);
8012
# endif /* VBOX_API_VERSION > 3000 */
8013 8014
                    VBOX_UTF16_FREE(iidUtf16);
                }
8015

8016 8017 8018 8019 8020
                if (progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
                }
            }
8021 8022
#endif /* VBOX_API_VERSION != 2002 */

E
Eric Blake 已提交
8023
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8024 8025 8026 8027 8028 8029 8030 8031 8032 8033

            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);
8034 8035
            }

8036 8037
            VBOX_UTF16_FREE(networkNameUtf16);

8038
        }
8039
        VBOX_RELEASE(networkInterface);
8040 8041
    }

8042 8043 8044
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8045 8046 8047 8048 8049 8050 8051
    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

8052 8053 8054 8055
static int vboxNetworkUndefine(virNetworkPtr network) {
    return vboxNetworkUndefineDestroy(network, true);
}

8056
static int vboxNetworkCreate(virNetworkPtr network) {
8057
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
8058
    char *networkNameUtf8 = NULL;
8059 8060
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
8061 8062 8063 8064 8065 8066 8067 8068

    /* 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
     */

8069
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
8070 8071
        goto cleanup;

8072
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8073

8074
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8075

8076 8077
    if (networkInterface) {
        PRUint32 interfaceType = 0;
8078

8079
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8080

8081 8082 8083
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
8084 8085


E
Eric Blake 已提交
8086
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8087

8088 8089 8090 8091 8092
            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (dhcpServer) {
                PRUnichar *trunkTypeUtf16 = NULL;
8093

8094
                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);
8095

8096
                VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);
8097

8098 8099 8100 8101
                dhcpServer->vtbl->Start(dhcpServer,
                                        networkNameUtf16,
                                        networkInterfaceNameUtf16,
                                        trunkTypeUtf16);
8102

8103 8104
                VBOX_UTF16_FREE(trunkTypeUtf16);
                VBOX_RELEASE(dhcpServer);
8105 8106
            }

8107
            VBOX_UTF16_FREE(networkNameUtf16);
8108
        }
8109 8110

        VBOX_RELEASE(networkInterface);
8111 8112
    }

8113 8114 8115
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8116 8117 8118 8119 8120 8121 8122 8123
    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

static int vboxNetworkDestroy(virNetworkPtr network) {
8124
    return vboxNetworkUndefineDestroy(network, false);
8125 8126
}

8127
static char *vboxNetworkGetXMLDesc(virNetworkPtr network,
E
Eric Blake 已提交
8128 8129
                                   unsigned int flags)
{
8130
    VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
8131
    virNetworkDefPtr def  = NULL;
8132
    virNetworkIpDefPtr ipdef = NULL;
8133
    char *networkNameUtf8 = NULL;
8134 8135
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
8136

E
Eric Blake 已提交
8137 8138
    virCheckFlags(0, NULL);

8139
    if (VIR_ALLOC(def) < 0)
8140
        goto cleanup;
8141
    if (VIR_ALLOC(ipdef) < 0)
8142 8143 8144
        goto cleanup;
    def->ips = ipdef;
    def->nips = 1;
8145

8146
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
8147 8148
        goto cleanup;

8149
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8150

8151
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8152

8153 8154
    if (networkInterface) {
        PRUint32 interfaceType = 0;
8155

8156
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8157

8158
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
J
Ján Tomko 已提交
8159
            if (VIR_STRDUP(def->name, network->name) >= 0) {
8160 8161
                PRUnichar *networkNameUtf16 = NULL;
                IDHCPServer *dhcpServer     = NULL;
8162
                vboxIID vboxnet0IID = VBOX_IID_INITIALIZER;
8163

8164 8165
                networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID.value);
                vboxIIDToUUID(&vboxnet0IID, def->uuid);
8166

E
Eric Blake 已提交
8167
                VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8168

8169
                def->forward.type = VIR_NETWORK_FORWARD_NONE;
8170

8171 8172 8173 8174
                data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                 networkNameUtf16,
                                                                 &dhcpServer);
                if (dhcpServer) {
8175
                    ipdef->nranges = 1;
8176
                    if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >=0) {
8177 8178 8179 8180
                        PRUnichar *ipAddressUtf16     = NULL;
                        PRUnichar *networkMaskUtf16   = NULL;
                        PRUnichar *fromIPAddressUtf16 = NULL;
                        PRUnichar *toIPAddressUtf16   = NULL;
8181
                        bool errorOccurred = false;
8182

8183 8184 8185 8186 8187 8188 8189
                        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
                         */
8190
                        if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8191
                                                     &ipdef->address) < 0 ||
8192
                            vboxSocketParseAddrUtf16(data, networkMaskUtf16,
8193
                                                     &ipdef->netmask) < 0 ||
8194
                            vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
8195
                                                     &ipdef->ranges[0].start) < 0 ||
8196
                            vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
8197
                                                     &ipdef->ranges[0].end) < 0) {
8198 8199
                            errorOccurred = true;
                        }
8200 8201 8202 8203 8204

                        VBOX_UTF16_FREE(ipAddressUtf16);
                        VBOX_UTF16_FREE(networkMaskUtf16);
                        VBOX_UTF16_FREE(fromIPAddressUtf16);
                        VBOX_UTF16_FREE(toIPAddressUtf16);
8205 8206 8207 8208

                        if (errorOccurred) {
                            goto cleanup;
                        }
8209
                    } else {
8210
                        ipdef->nranges = 0;
8211
                    }
8212

8213
                    ipdef->nhosts = 1;
8214
                    if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >=0) {
8215
                        if (VIR_STRDUP(ipdef->hosts[0].name, network->name) < 0) {
8216 8217
                            VIR_FREE(ipdef->hosts);
                            ipdef->nhosts = 0;
8218
                        } else {
8219 8220
                            PRUnichar *macAddressUtf16 = NULL;
                            PRUnichar *ipAddressUtf16  = NULL;
8221
                            bool errorOccurred = false;
8222

8223
                            networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
8224 8225
                            networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

8226
                            VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac);
8227 8228

                            if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8229
                                                         &ipdef->hosts[0].ip) < 0) {
8230 8231
                                errorOccurred = true;
                            }
8232

8233 8234
                            VBOX_UTF16_FREE(macAddressUtf16);
                            VBOX_UTF16_FREE(ipAddressUtf16);
8235 8236 8237 8238

                            if (errorOccurred) {
                                goto cleanup;
                            }
8239 8240
                        }
                    } else {
8241
                        ipdef->nhosts = 0;
8242
                    }
8243 8244 8245 8246 8247

                    VBOX_RELEASE(dhcpServer);
                } else {
                    PRUnichar *networkMaskUtf16 = NULL;
                    PRUnichar *ipAddressUtf16   = NULL;
8248
                    bool errorOccurred = false;
8249 8250 8251 8252

                    networkInterface->vtbl->GetNetworkMask(networkInterface, &networkMaskUtf16);
                    networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

8253
                    if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
8254
                                                 &ipdef->netmask) < 0 ||
8255
                        vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8256
                                                 &ipdef->address) < 0) {
8257 8258
                        errorOccurred = true;
                    }
8259 8260 8261

                    VBOX_UTF16_FREE(networkMaskUtf16);
                    VBOX_UTF16_FREE(ipAddressUtf16);
8262 8263 8264 8265

                    if (errorOccurred) {
                        goto cleanup;
                    }
8266 8267
                }

8268 8269
                DEBUGIID("Network UUID", vboxnet0IID.value);
                vboxIIDUnalloc(&vboxnet0IID);
8270
                VBOX_UTF16_FREE(networkNameUtf16);
8271 8272
            }
        }
8273 8274

        VBOX_RELEASE(networkInterface);
8275 8276
    }

8277 8278 8279
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8280
    ret = virNetworkDefFormat(def, 0);
8281 8282

cleanup:
8283
    virNetworkDefFree(def);
8284 8285 8286 8287
    VIR_FREE(networkNameUtf8);
    return ret;
}

8288 8289 8290 8291
/**
 * The Storage Functions here on
 */

8292 8293 8294
static virDrvOpenStatus vboxStorageOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
8295
{
8296 8297
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
8298 8299
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

8300
    if (STRNEQ(conn->driver->name, "VBOX"))
8301
        return VIR_DRV_OPEN_DECLINED;
8302 8303 8304 8305

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
8306
        return VIR_DRV_OPEN_ERROR;
8307

8308
    VIR_DEBUG("vbox storage initialized");
8309 8310 8311 8312
    /* conn->storagePrivateData = some storage specific data */
    return VIR_DRV_OPEN_SUCCESS;
}

8313
static int vboxStorageClose(virConnectPtr conn) {
8314
    VIR_DEBUG("vbox storage uninitialized");
8315 8316 8317 8318
    conn->storagePrivateData = NULL;
    return 0;
}

8319
static int vboxConnectNumOfStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED) {
8320 8321 8322 8323 8324 8325 8326 8327

    /** Currently only one pool supported, the default one
     * given by ISystemProperties::defaultHardDiskFolder()
     */

    return 1;
}

8328 8329
static int vboxConnectListStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
                                       char **const names, int nnames) {
8330 8331
    int numActive = 0;

8332 8333 8334
    if (nnames == 1 &&
        VIR_STRDUP(names[numActive], "default-pool") > 0)
        numActive++;
8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348
    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";

8349
        ignore_value(virUUIDParse(uuidstr, uuid));
8350

8351
        ret = virGetStoragePool(conn, name, uuid, NULL, NULL);
8352 8353 8354 8355 8356 8357
    }

    return ret;
}

static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool) {
8358
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
8359
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8360 8361
    PRUint32 hardDiskAccessible = 0;
    nsresult rc;
8362
    size_t i;
8363

8364
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8365
    if (NS_SUCCEEDED(rc)) {
8366 8367
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8368 8369
            if (hardDisk) {
                PRUint32 hddstate;
8370

8371 8372 8373
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible)
                    hardDiskAccessible++;
8374 8375
            }
        }
8376 8377 8378 8379

        vboxArrayRelease(&hardDisks);

        ret = hardDiskAccessible;
8380
    } else {
8381
        ret = -1;
8382 8383 8384
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get number of volumes in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
8385 8386
    }

8387
    return ret;
8388 8389 8390
}

static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) {
8391
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
8392
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8393 8394
    PRUint32 numActive     = 0;
    nsresult rc;
8395
    size_t i;
8396

8397
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8398
    if (NS_SUCCEEDED(rc)) {
8399 8400
        for (i = 0; i < hardDisks.count && numActive < nnames; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8401

8402 8403 8404 8405
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
8406

8407 8408 8409
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8410

8411 8412
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
8413

8414
                    if (nameUtf8) {
8415
                        VIR_DEBUG("nnames[%d]: %s", numActive, nameUtf8);
8416
                        if (VIR_STRDUP(names[numActive], nameUtf8) > 0)
8417 8418 8419
                            numActive++;

                        VBOX_UTF8_FREE(nameUtf8);
8420 8421 8422 8423
                    }
                }
            }
        }
8424 8425 8426 8427

        vboxArrayRelease(&hardDisks);

        ret = numActive;
8428
    } else {
8429
        ret = -1;
8430 8431 8432
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get the volume list in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
8433 8434
    }

8435
    return ret;
8436 8437 8438
}

static virStorageVolPtr vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name) {
8439
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8440
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8441
    nsresult rc;
8442
    size_t i;
8443

8444
    if (!name)
8445
        return ret;
8446

8447
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8448
    if (NS_SUCCEEDED(rc)) {
8449 8450
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8451

8452 8453 8454 8455
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
8456

8457 8458 8459
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8460

8461 8462 8463 8464
                    if (nameUtf16) {
                        VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                        VBOX_UTF16_FREE(nameUtf16);
                    }
8465

8466
                    if (nameUtf8 && STREQ(nameUtf8, name)) {
8467 8468 8469
                        vboxIID hddIID = VBOX_IID_INITIALIZER;
                        unsigned char uuid[VIR_UUID_BUFLEN];
                        char key[VIR_UUID_STRING_BUFLEN] = "";
8470

8471 8472 8473 8474
                        rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                        if (NS_SUCCEEDED(rc)) {
                            vboxIIDToUUID(&hddIID, uuid);
                            virUUIDFormat(uuid, key);
8475

8476 8477
                            ret = virGetStorageVol(pool->conn, pool->name, name, key,
                                                   NULL, NULL);
8478

8479 8480 8481 8482
                            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);
8483 8484
                        }

8485
                        vboxIIDUnalloc(&hddIID);
8486 8487
                        VBOX_UTF8_FREE(nameUtf8);
                        break;
8488
                    }
8489

J
John Ferlan 已提交
8490
                    VBOX_UTF8_FREE(nameUtf8);
8491 8492 8493
                }
            }
        }
8494

8495
        vboxArrayRelease(&hardDisks);
8496 8497 8498 8499 8500 8501
    }

    return ret;
}

static virStorageVolPtr vboxStorageVolLookupByKey(virConnectPtr conn, const char *key) {
8502
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
8503 8504
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
8505 8506 8507
    IHardDisk *hardDisk  = NULL;
    nsresult rc;

8508 8509 8510
    if (!key)
        return ret;

8511
    if (virUUIDParse(key, uuid) < 0) {
8512 8513
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), key);
8514
        return NULL;
8515 8516
    }

8517
    vboxIIDFromUUID(&hddIID, uuid);
8518
#if VBOX_API_VERSION < 4000
8519
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8520
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
8521 8522
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8523 8524 8525 8526
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8527
#endif /* VBOX_API_VERSION >= 4000 */
8528 8529
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8530

8531 8532 8533 8534
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
8535

8536 8537
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
            VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
8538

8539
            if (hddNameUtf8) {
8540
                if (vboxConnectNumOfStoragePools(conn) == 1) {
8541 8542
                    ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                           NULL, NULL);
8543
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
8544 8545 8546 8547
                } else {
                    /* TODO: currently only one default pool and thus
                     * nothing here, change it when pools are supported
                     */
8548 8549
                }

8550 8551
                VIR_DEBUG("Storage Volume Name: %s", key);
                VIR_DEBUG("Storage Volume key : %s", hddNameUtf8);
8552 8553 8554

                VBOX_UTF8_FREE(hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
8555 8556
            }
        }
8557 8558

        VBOX_MEDIUM_RELEASE(hardDisk);
8559 8560
    }

8561
    vboxIIDUnalloc(&hddIID);
8562 8563 8564 8565
    return ret;
}

static virStorageVolPtr vboxStorageVolLookupByPath(virConnectPtr conn, const char *path) {
8566
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
8567 8568 8569 8570
    PRUnichar *hddPathUtf16 = NULL;
    IHardDisk *hardDisk     = NULL;
    nsresult rc;

8571 8572
    if (!path)
        return ret;
8573

8574
    VBOX_UTF8_TO_UTF16(path, &hddPathUtf16);
8575

8576 8577
    if (!hddPathUtf16)
        return ret;
8578

8579
#if VBOX_API_VERSION < 4000
8580
    rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk);
8581
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
8582 8583
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, &hardDisk);
8584 8585 8586 8587
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8588
#endif /* VBOX_API_VERSION >= 4000 */
8589 8590
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8591

8592 8593 8594 8595
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
8596

8597
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
8598

8599 8600 8601 8602
            if (hddNameUtf16) {
                VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
            }
8603

8604 8605 8606 8607
            if (hddNameUtf8) {
                vboxIID hddIID = VBOX_IID_INITIALIZER;
                unsigned char uuid[VIR_UUID_BUFLEN];
                char key[VIR_UUID_STRING_BUFLEN] = "";
8608

8609 8610 8611 8612
                rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                if (NS_SUCCEEDED(rc)) {
                    vboxIIDToUUID(&hddIID, uuid);
                    virUUIDFormat(uuid, key);
8613

8614 8615 8616
                    /* TODO: currently only one default pool and thus
                     * the check below, change it when pools are supported
                     */
8617
                    if (vboxConnectNumOfStoragePools(conn) == 1)
8618 8619
                        ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                               NULL, NULL);
8620

8621 8622 8623
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
                    VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8);
                    VIR_DEBUG("Storage Volume key : %s", key);
8624
                }
8625

8626
                vboxIIDUnalloc(&hddIID);
8627 8628
            }

J
John Ferlan 已提交
8629
            VBOX_UTF8_FREE(hddNameUtf8);
8630
        }
8631 8632

        VBOX_MEDIUM_RELEASE(hardDisk);
8633 8634
    }

8635 8636
    VBOX_UTF16_FREE(hddPathUtf16);

8637 8638 8639 8640 8641
    return ret;
}

static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
                                                const char *xml,
E
Eric Blake 已提交
8642 8643
                                                unsigned int flags)
{
8644
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8645
    virStorageVolDefPtr  def  = NULL;
8646 8647
    PRUnichar *hddFormatUtf16 = NULL;
    PRUnichar *hddNameUtf16   = NULL;
8648 8649 8650
    virStoragePoolDef poolDef;
    nsresult rc;

E
Eric Blake 已提交
8651 8652
    virCheckFlags(0, NULL);

8653 8654 8655 8656 8657 8658 8659 8660
    /* 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;

8661
    if ((def = virStorageVolDefParseString(&poolDef, xml)) == NULL)
8662 8663
        goto cleanup;

8664 8665
    if (!def->name ||
        (def->type != VIR_STORAGE_VOL_FILE))
8666
        goto cleanup;
8667

8668 8669 8670 8671 8672 8673
    /* 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
     */
8674

8675 8676 8677 8678 8679 8680 8681
    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);
    }
8682

8683
    VBOX_UTF8_TO_UTF16(def->name, &hddNameUtf16);
8684

8685 8686
    if (hddFormatUtf16 && hddNameUtf16) {
        IHardDisk *hardDisk = NULL;
8687

8688 8689 8690
        rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk);
        if (NS_SUCCEEDED(rc)) {
            IProgress *progress    = NULL;
8691
            PRUint64   logicalSize = VIR_DIV_UP(def->capacity, 1024 * 1024);
8692
            PRUint32   variant     = HardDiskVariant_Standard;
8693

8694 8695
            if (def->capacity == def->allocation)
                variant = HardDiskVariant_Fixed;
8696

R
Ryota Ozaki 已提交
8697
#if VBOX_API_VERSION < 4003
8698
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress);
R
Ryota Ozaki 已提交
8699 8700 8701
#else
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, 1, &variant, &progress);
#endif
8702
            if (NS_SUCCEEDED(rc) && progress) {
8703
#if VBOX_API_VERSION == 2002
8704
                nsresult resultCode;
8705
#else
8706
                PRInt32  resultCode;
8707 8708
#endif

8709 8710
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
8711

8712
                if (NS_SUCCEEDED(resultCode)) {
8713 8714 8715
                    vboxIID hddIID = VBOX_IID_INITIALIZER;
                    unsigned char uuid[VIR_UUID_BUFLEN];
                    char key[VIR_UUID_STRING_BUFLEN] = "";
8716

8717
                    rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
8718
                    if (NS_SUCCEEDED(rc)) {
8719 8720
                        vboxIIDToUUID(&hddIID, uuid);
                        virUUIDFormat(uuid, key);
8721

8722 8723
                        ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
                                               NULL, NULL);
8724
                    }
8725 8726

                    vboxIIDUnalloc(&hddIID);
8727 8728
                }

8729
                VBOX_RELEASE(progress);
8730
            }
8731
        }
8732 8733
    }

8734 8735 8736
    VBOX_UTF16_FREE(hddFormatUtf16);
    VBOX_UTF16_FREE(hddNameUtf16);

8737 8738 8739 8740 8741 8742
cleanup:
    virStorageVolDefFree(def);
    return ret;
}

static int vboxStorageVolDelete(virStorageVolPtr vol,
E
Eric Blake 已提交
8743 8744
                                unsigned int flags)
{
8745
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
8746 8747
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
8748 8749 8750
    IHardDisk *hardDisk  = NULL;
    int deregister = 0;
    nsresult rc;
8751 8752
    size_t i = 0;
    size_t j = 0;
8753

E
Eric Blake 已提交
8754 8755
    virCheckFlags(0, -1);

8756
    if (virUUIDParse(vol->key, uuid) < 0) {
8757 8758
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
8759 8760
        return -1;
    }
8761

8762
    vboxIIDFromUUID(&hddIID, uuid);
8763
#if VBOX_API_VERSION < 4000
8764
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8765
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
8766 8767
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8768 8769 8770 8771
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8772
#endif /* VBOX_API_VERSION >= 4000 */
8773 8774
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8775

8776 8777 8778
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUint32  machineIdsSize = 0;
8779 8780 8781 8782 8783 8784 8785
            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 */
8786

8787 8788 8789 8790 8791 8792 8793
#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 已提交
8794
             * we divide the size of the SafeArray by two, to compensate for
8795 8796 8797 8798
             * this workaround in VirtualBox */
            machineIds.count /= 2;
#endif /* VBOX_API_VERSION >= 2002 */

8799
            machineIdsSize = machineIds.count;
8800

8801
            for (i = 0; i < machineIds.count; i++) {
8802
                IMachine *machine = NULL;
8803 8804 8805
                vboxIID machineId = VBOX_IID_INITIALIZER;

                vboxIIDFromArrayItem(&machineId, &machineIds, i);
8806

8807 8808 8809
#if VBOX_API_VERSION >= 4000
                rc = VBOX_OBJECT_GET_MACHINE(machineId.value, &machine);
                if (NS_FAILED(rc)) {
8810 8811
                    virReportError(VIR_ERR_NO_DOMAIN, "%s",
                                   _("no domain with matching uuid"));
8812 8813 8814 8815 8816 8817
                    break;
                }
#endif

                rc = VBOX_SESSION_OPEN(machineId.value, machine);

8818
                if (NS_SUCCEEDED(rc)) {
8819

8820 8821
                    rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                    if (NS_SUCCEEDED(rc)) {
8822
                        vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER;
8823 8824

#if VBOX_API_VERSION < 3001
8825 8826
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetHardDiskAttachments);
8827
#else  /* VBOX_API_VERSION >= 3001 */
8828 8829
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetMediumAttachments);
8830
#endif /* VBOX_API_VERSION >= 3001 */
8831 8832
                        for (j = 0; j < hddAttachments.count; j++) {
                            IHardDiskAttachment *hddAttachment = hddAttachments.items[j];
8833 8834 8835 8836 8837 8838 8839 8840 8841 8842

                            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) {
8843
                                    vboxIID iid = VBOX_IID_INITIALIZER;
8844

8845 8846
                                    rc = VBOX_MEDIUM_FUNC_ARG1(hdd, GetId, &iid.value);
                                    if (NS_SUCCEEDED(rc)) {
8847

8848 8849
                                            DEBUGIID("HardDisk (to delete) UUID", hddIID.value);
                                            DEBUGIID("HardDisk (currently processing) UUID", iid.value);
8850

8851
                                        if (vboxIIDIsEqual(&hddIID, &iid)) {
8852 8853 8854 8855
                                            PRUnichar *controller = NULL;
                                            PRInt32    port       = 0;
                                            PRInt32    device     = 0;

8856
                                            DEBUGIID("Found HardDisk to delete, UUID", hddIID.value);
8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868

                                            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);
8869
                                                VIR_DEBUG("saving machine settings");
8870
                                            }
8871

8872 8873
                                            if (NS_SUCCEEDED(rc)) {
                                                deregister++;
8874
                                                VIR_DEBUG("deregistering hdd:%d", deregister);
8875
                                            }
8876

J
John Ferlan 已提交
8877
                                            VBOX_UTF16_FREE(controller);
8878
                                        }
8879
                                        vboxIIDUnalloc(&iid);
8880
                                    }
8881
                                    VBOX_MEDIUM_RELEASE(hdd);
8882 8883 8884
                                }
                            }
                        }
8885
                        vboxArrayRelease(&hddAttachments);
8886
                        VBOX_RELEASE(machine);
8887
                    }
8888
                    VBOX_SESSION_CLOSE();
8889
                }
8890 8891

                vboxIIDUnalloc(&machineId);
8892
            }
8893

8894
            vboxArrayUnalloc(&machineIds);
8895

8896 8897
            if (machineIdsSize == 0 || machineIdsSize == deregister) {
                IProgress *progress = NULL;
8898

8899
                rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress);
8900

8901 8902 8903
                if (NS_SUCCEEDED(rc) && progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
8904
                    DEBUGIID("HardDisk deleted, UUID", hddIID.value);
8905
                    ret = 0;
8906 8907 8908
                }
            }
        }
8909 8910

        VBOX_MEDIUM_RELEASE(hardDisk);
8911 8912
    }

8913
    vboxIIDUnalloc(&hddIID);
8914

8915 8916 8917 8918
    return ret;
}

static int vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info) {
8919
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
8920
    IHardDisk *hardDisk  = NULL;
8921 8922
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
8923 8924
    nsresult rc;

8925
    if (!info)
8926
        return ret;
8927

8928
    if (virUUIDParse(vol->key, uuid) < 0) {
8929 8930
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
8931
        return ret;
8932
    }
8933

8934
    vboxIIDFromUUID(&hddIID, uuid);
8935
#if VBOX_API_VERSION < 4000
8936
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8937
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
8938 8939
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8940 8941 8942 8943
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8944
#endif /* VBOX_API_VERSION >= 4000 */
8945 8946
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8947

8948 8949
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
8950
#if VBOX_API_VERSION < 4000
8951 8952
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
8953 8954 8955 8956
#else /* VBOX_API_VERSION >= 4000 */
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
#endif /* VBOX_API_VERSION >= 4000 */
8957

8958
            info->type = VIR_STORAGE_VOL_FILE;
8959

8960
            hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
8961
#if VBOX_API_VERSION < 4000
8962
            info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
8963 8964 8965
#else /* VBOX_API_VERSION >= 4000 */
            info->capacity = hddLogicalSize;
#endif /* VBOX_API_VERSION >= 4000 */
8966

8967 8968
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            info->allocation = hddActualSize;
8969

8970
            ret = 0;
8971

8972 8973 8974 8975
            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);
8976
        }
8977 8978

        VBOX_MEDIUM_RELEASE(hardDisk);
8979 8980
    }

8981
    vboxIIDUnalloc(&hddIID);
8982

8983 8984 8985
    return ret;
}

E
Eric Blake 已提交
8986 8987
static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
{
8988
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
8989
    IHardDisk *hardDisk  = NULL;
8990 8991
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
8992 8993 8994 8995 8996
    virStoragePoolDef pool;
    virStorageVolDef def;
    int defOk = 0;
    nsresult rc;

E
Eric Blake 已提交
8997 8998
    virCheckFlags(0, NULL);

8999 9000 9001
    memset(&pool, 0, sizeof(pool));
    memset(&def, 0, sizeof(def));

9002
    if (virUUIDParse(vol->key, uuid) < 0) {
9003 9004
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
9005
        return ret;
9006
    }
9007

9008
    vboxIIDFromUUID(&hddIID, uuid);
9009
#if VBOX_API_VERSION < 4000
9010
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9011
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
9012 9013
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
9014 9015 9016 9017
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
9018
#endif /* VBOX_API_VERSION >= 4000 */
9019 9020 9021 9022 9023 9024
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;

        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) {
            PRUnichar *hddFormatUtf16 = NULL;
9025
#if VBOX_API_VERSION < 4000
9026 9027
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
9028 9029 9030 9031
#else /* VBOX_API_VERSION >= 4000 */
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
#endif /* VBOX_API_VERSION >= 4000 */
9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042

            /* 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);
9043 9044
            if (NS_SUCCEEDED(rc) && defOk) {
#if VBOX_API_VERSION < 4000
9045
                def.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
9046 9047 9048 9049
#else /* VBOX_API_VERSION >= 4000 */
                def.capacity = hddLogicalSize;
#endif /* VBOX_API_VERSION >= 4000 */
            } else
9050 9051 9052 9053 9054 9055 9056 9057
                defOk = 0;

            rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            if (NS_SUCCEEDED(rc) && defOk)
                def.allocation = hddActualSize;
            else
                defOk = 0;

9058
            if (VIR_STRDUP(def.name, vol->name) < 0)
9059 9060
                defOk = 0;

9061
            if (VIR_STRDUP(def.key, vol->key) < 0)
9062 9063 9064 9065 9066 9067 9068 9069 9070
                defOk = 0;

            rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16);
            if (NS_SUCCEEDED(rc) && defOk) {
                char *hddFormatUtf8 = NULL;

                VBOX_UTF16_TO_UTF8(hddFormatUtf16, &hddFormatUtf8);
                if (hddFormatUtf8) {

9071
                    VIR_DEBUG("Storage Volume Format: %s", hddFormatUtf8);
9072 9073 9074 9075 9076

                    if (STRCASEEQ("vmdk", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VMDK;
                    else if (STRCASEEQ("vhd", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VPC;
9077
                    else
9078
                        def.target.format = VIR_STORAGE_FILE_RAW;
9079

9080 9081 9082
                    /* TODO: need to add vdi to enum virStorageFileFormat {}
                     * and then add it here
                     */
9083

9084
                    VBOX_UTF8_FREE(hddFormatUtf8);
9085 9086
                }

9087 9088 9089
                VBOX_UTF16_FREE(hddFormatUtf16);
            } else {
                defOk = 0;
9090 9091
            }
        }
9092 9093

        VBOX_MEDIUM_RELEASE(hardDisk);
9094 9095
    }

9096
    vboxIIDUnalloc(&hddIID);
9097

9098
    if (defOk)
9099
        ret = virStorageVolDefFormat(&pool, &def);
9100 9101 9102 9103 9104

    return ret;
}

static char *vboxStorageVolGetPath(virStorageVolPtr vol) {
9105
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
9106
    IHardDisk *hardDisk  = NULL;
9107 9108
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
9109 9110
    nsresult rc;

9111
    if (virUUIDParse(vol->key, uuid) < 0) {
9112 9113
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
9114
        return ret;
9115
    }
9116

9117
    vboxIIDFromUUID(&hddIID, uuid);
9118
#if VBOX_API_VERSION < 4000
9119
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9120
#elif VBOX_API_VERSION >= 4000 && VBOX_API_VERSION < 4002
9121 9122
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
9123 9124 9125 9126
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
9127
#endif /* VBOX_API_VERSION >= 4000 */
9128 9129
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
9130

9131 9132 9133 9134
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddLocationUtf16 = NULL;
            char      *hddLocationUtf8  = NULL;
9135

9136
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetLocation, &hddLocationUtf16);
9137

9138 9139
            VBOX_UTF16_TO_UTF8(hddLocationUtf16, &hddLocationUtf8);
            if (hddLocationUtf8) {
9140

9141
                ignore_value(VIR_STRDUP(ret, hddLocationUtf8));
9142

9143 9144 9145
                VIR_DEBUG("Storage Volume Name: %s", vol->name);
                VIR_DEBUG("Storage Volume Path: %s", hddLocationUtf8);
                VIR_DEBUG("Storage Volume Pool: %s", vol->pool);
9146

9147
                VBOX_UTF8_FREE(hddLocationUtf8);
9148 9149
            }

9150
            VBOX_UTF16_FREE(hddLocationUtf16);
9151
        }
9152 9153

        VBOX_MEDIUM_RELEASE(hardDisk);
9154 9155
    }

9156
    vboxIIDUnalloc(&hddIID);
9157

9158 9159
    return ret;
}
9160

9161
#if VBOX_API_VERSION >= 4000
9162 9163 9164 9165
static char *
vboxDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
9166
                     unsigned int flags)
9167 9168 9169 9170 9171 9172 9173 9174 9175 9176
{
    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 已提交
9177 9178
    virCheckFlags(0, NULL);

9179 9180 9181
    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
9182 9183
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
9184 9185 9186 9187 9188
        return NULL;
    }

    rc = machine->vtbl->GetMonitorCount(machine, &max_screen);
    if (NS_FAILED(rc)) {
9189 9190
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to get monitor count"));
9191 9192 9193 9194 9195
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (screen >= max_screen) {
9196 9197 9198
        virReportError(VIR_ERR_INVALID_ARG,
                       _("screen ID higher than monitor "
                         "count (%d)"), max_screen);
9199 9200 9201 9202 9203 9204 9205 9206 9207
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
        VBOX_RELEASE(machine);
        return NULL;
    }

9208 9209
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227
        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;
R
Ryota Ozaki 已提交
9228 9229 9230
# if VBOX_API_VERSION >= 4003
                PRInt32 xOrigin, yOrigin;
# endif
9231 9232 9233

                rc = display->vtbl->GetScreenResolution(display, screen,
                                                        &width, &height,
R
Ryota Ozaki 已提交
9234
# if VBOX_API_VERSION < 4003
9235
                                                        &bitsPerPixel);
R
Ryota Ozaki 已提交
9236 9237 9238 9239
# else
                                                        &bitsPerPixel,
                                                        &xOrigin, &yOrigin);
# endif
9240 9241

                if (NS_FAILED(rc) || !width || !height) {
9242 9243
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to get screen resolution"));
9244 9245 9246 9247 9248 9249 9250 9251
                    goto endjob;
                }

                rc = display->vtbl->TakeScreenShotPNGToArray(display, screen,
                                                             width, height,
                                                             &screenDataSize,
                                                             &screenData);
                if (NS_FAILED(rc)) {
9252 9253
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("failed to take screenshot"));
9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268
                    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;
                }

9269 9270 9271
                if (VIR_STRDUP(ret, "image/png") < 0)
                    goto endjob;

E
Eric Blake 已提交
9272
                if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
9273 9274
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to open stream"));
9275
                    VIR_FREE(ret);
9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286
                }
endjob:
                VIR_FREE(screenData);
                VBOX_RELEASE(display);
            }
            VBOX_RELEASE(console);
        }
        VBOX_SESSION_CLOSE();
    }

    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
9287
    unlink(tmp);
9288 9289 9290 9291 9292
    VIR_FREE(tmp);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}
9293
#endif /* VBOX_API_VERSION >= 4000 */
9294

9295 9296 9297

#define MATCH(FLAG) (flags & (FLAG))
static int
9298 9299 9300
vboxConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
9301 9302 9303 9304 9305 9306 9307 9308 9309
{
    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;
9310
    size_t i;
9311 9312 9313 9314 9315 9316
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    int count = 0;
    bool active;
    PRUint32 snapshotCount;

O
Osier Yang 已提交
9317
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331

    /* 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)
9332
            goto cleanup;
9333 9334 9335 9336 9337 9338 9339

        ret = 0;
        goto cleanup;
    }

    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
    if (NS_FAILED(rc)) {
9340 9341
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of domains, rc=%08x"), (unsigned)rc);
9342 9343 9344 9345 9346
        goto cleanup;
    }

    if (domains &&
        VIR_ALLOC_N(doms, machines.count + 1) < 0)
9347
        goto cleanup;
9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364

    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 已提交
9365
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
9366 9367 9368 9369 9370
                    !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
                    continue;

                /* filter by snapshot existence */
O
Osier Yang 已提交
9371
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
9372 9373
                    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
                    if (NS_FAILED(rc)) {
9374
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9375
                                       _("could not get snapshot count for listed domains"));
9376 9377 9378 9379 9380 9381 9382 9383 9384 9385
                        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 已提交
9386
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) &&
9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451
                    !((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;
}
#undef MATCH


9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475
static int
vboxNodeGetInfo(virConnectPtr conn ATTRIBUTE_UNUSED,
                virNodeInfoPtr nodeinfo)
{
    return nodeGetInfo(nodeinfo);
}


static int
vboxNodeGetCellsFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED,
                           unsigned long long *freeMems,
                           int startCell,
                           int maxCells)
{
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}


static unsigned long long
vboxNodeGetFreeMemory(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return nodeGetFreeMemory();
}

9476

9477 9478 9479 9480
/**
 * Function Tables
 */

9481
virDriver NAME(Driver) = {
9482 9483
    .no = VIR_DRV_VBOX,
    .name = "VBOX",
9484 9485 9486
    .connectOpen = vboxConnectOpen, /* 0.6.3 */
    .connectClose = vboxConnectClose, /* 0.6.3 */
    .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */
9487
    .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */
9488
    .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */
9489
    .nodeGetInfo = vboxNodeGetInfo, /* 0.6.3 */
9490 9491 9492 9493
    .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */
    .connectListDomains = vboxConnectListDomains, /* 0.6.3 */
    .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */
    .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */
9494 9495 9496 9497 9498 9499 9500
    .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 */
9501
    .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
9502 9503
    .domainReboot = vboxDomainReboot, /* 0.6.3 */
    .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
9504
    .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
9505 9506 9507 9508 9509 9510 9511 9512 9513 9514
    .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 */
9515 9516
    .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */
    .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */
9517 9518 9519 9520
    .domainCreate = vboxDomainCreate, /* 0.6.3 */
    .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */
    .domainUndefine = vboxDomainUndefine, /* 0.6.3 */
9521
    .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */
9522 9523 9524 9525 9526
    .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 */
9527 9528
    .nodeGetCellsFreeMemory = vboxNodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = vboxNodeGetFreeMemory, /* 0.6.5 */
9529
#if VBOX_API_VERSION >= 4000
9530
    .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */
9531
#endif
9532
#if VBOX_API_VERSION > 2002 && VBOX_API_VERSION < 4000
9533 9534
    .connectDomainEventRegister = vboxConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = vboxConnectDomainEventDeregister, /* 0.7.0 */
9535
#endif
9536 9537
    .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */
9538 9539 9540
    .domainIsActive = vboxDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */
9541
#if VBOX_API_VERSION > 2002 && VBOX_API_VERSION < 4000
9542 9543
    .connectDomainEventRegisterAny = vboxConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = vboxConnectDomainEventDeregisterAny, /* 0.8.0 */
9544
#endif
9545 9546 9547 9548 9549 9550
    .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 */
9551
    .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
9552
    .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */
9553 9554
    .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */
9555 9556
    .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */
9557
    .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */
9558
};
9559 9560 9561

virNetworkDriver NAME(NetworkDriver) = {
    "VBOX",
9562 9563
    .networkOpen = vboxNetworkOpen, /* 0.6.4 */
    .networkClose = vboxNetworkClose, /* 0.6.4 */
9564 9565 9566 9567
    .connectNumOfNetworks = vboxConnectNumOfNetworks, /* 0.6.4 */
    .connectListNetworks = vboxConnectListNetworks, /* 0.6.4 */
    .connectNumOfDefinedNetworks = vboxConnectNumOfDefinedNetworks, /* 0.6.4 */
    .connectListDefinedNetworks = vboxConnectListDefinedNetworks, /* 0.6.4 */
9568 9569 9570 9571 9572 9573 9574 9575
    .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 */
9576
};
9577 9578 9579

virStorageDriver NAME(StorageDriver) = {
    .name               = "VBOX",
9580 9581
    .storageOpen = vboxStorageOpen, /* 0.7.1 */
    .storageClose = vboxStorageClose, /* 0.7.1 */
9582 9583
    .connectNumOfStoragePools = vboxConnectNumOfStoragePools, /* 0.7.1 */
    .connectListStoragePools = vboxConnectListStoragePools, /* 0.7.1 */
9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595
    .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 */
9596
};