vbox_tmpl.c 344.1 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

/* This one changes from version to version. */
63
#if VBOX_API_VERSION == 2002000
64
# include "vbox_CAPI_v2_2.h"
65
#elif VBOX_API_VERSION == 3000000
66
# include "vbox_CAPI_v3_0.h"
67
#elif VBOX_API_VERSION == 3001000
68
# include "vbox_CAPI_v3_1.h"
69
#elif VBOX_API_VERSION == 3002000
70
# include "vbox_CAPI_v3_2.h"
71
#elif VBOX_API_VERSION == 4000000
72
# include "vbox_CAPI_v4_0.h"
73
#elif VBOX_API_VERSION == 4001000
74
# include "vbox_CAPI_v4_1.h"
75
#elif VBOX_API_VERSION == 4002000
76
# include "vbox_CAPI_v4_2.h"
77 78 79
#elif VBOX_API_VERSION == 4002020
# include "vbox_CAPI_v4_2_20.h"
#elif VBOX_API_VERSION == 4003000
R
Ryota Ozaki 已提交
80
# include "vbox_CAPI_v4_3.h"
81 82
#elif VBOX_API_VERSION == 4003004
# include "vbox_CAPI_v4_3_4.h"
83 84
#else
# error "Unsupport VBOX_API_VERSION"
85 86
#endif

87
/* Include this *last* or we'll get the wrong vbox_CAPI_*.h. */
88
#include "vbox_glue.h"
89 90


91
#define VIR_FROM_THIS                   VIR_FROM_VBOX
92 93 94

VIR_LOG_INIT("vbox.vbox_tmpl");

J
John Ferlan 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
#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)

119 120 121
#define VBOX_UTF16_TO_UTF8(arg1, arg2)  data->pFuncs->pfnUtf16ToUtf8(arg1, arg2)
#define VBOX_UTF8_TO_UTF16(arg1, arg2)  data->pFuncs->pfnUtf8ToUtf16(arg1, arg2)

122 123
#define VBOX_ADDREF(arg) (arg)->vtbl->nsisupports.AddRef((nsISupports *)(arg))

124 125 126 127 128 129 130
#define VBOX_RELEASE(arg)                                                     \
    do {                                                                      \
        if (arg) {                                                            \
            (arg)->vtbl->nsisupports.Release((nsISupports *)(arg));           \
            (arg) = NULL;                                                     \
        }                                                                     \
    } while (0)
131 132 133 134

#define VBOX_OBJECT_CHECK(conn, type, value) \
vboxGlobalData *data = conn->privateData;\
type ret = value;\
135
if (!data->vboxObj) {\
136 137 138 139 140 141 142
    return ret;\
}

#define VBOX_OBJECT_HOST_CHECK(conn, type, value) \
vboxGlobalData *data = conn->privateData;\
type ret = value;\
IHost *host = NULL;\
143
if (!data->vboxObj) {\
144 145 146 147 148 149 150
    return ret;\
}\
data->vboxObj->vtbl->GetHost(data->vboxObj, &host);\
if (!host) {\
    return ret;\
}

151
#if VBOX_API_VERSION < 3001000
152

153
# define VBOX_MEDIUM_RELEASE(arg) \
154
if (arg)\
155
    (arg)->vtbl->imedium.nsisupports.Release((nsISupports *)(arg))
156
# define VBOX_MEDIUM_FUNC_ARG1(object, func, arg1) \
157
    (object)->vtbl->imedium.func((IMedium *)(object), arg1)
158
# define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
159 160
    (object)->vtbl->imedium.func((IMedium *)(object), arg1, arg2)

161
#else  /* VBOX_API_VERSION >= 3001000 */
162 163 164

typedef IMedium IHardDisk;
typedef IMediumAttachment IHardDiskAttachment;
165 166 167 168 169
# 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) \
170
    (object)->vtbl->func(object, arg1)
171
# define VBOX_MEDIUM_FUNC_ARG2(object, func, arg1, arg2) \
172 173
    (object)->vtbl->func(object, arg1, arg2)

174
#endif /* VBOX_API_VERSION >= 3001000 */
175

176 177 178 179 180 181
#define DEBUGPRUnichar(msg, strUtf16) \
if (strUtf16) {\
    char *strUtf8 = NULL;\
\
    g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(strUtf16, &strUtf8);\
    if (strUtf8) {\
182
        VIR_DEBUG("%s: %s", msg, strUtf8);\
183 184 185 186 187 188
        g_pVBoxGlobalData->pFuncs->pfnUtf8Free(strUtf8);\
    }\
}

#define DEBUGUUID(msg, iid) \
{\
189
    VIR_DEBUG(msg ": {%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",\
190 191 192 193 194 195 196 197 198 199 200 201 202
          (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]);\
}\

203 204
typedef struct {
    virMutex lock;
205
    unsigned long version;
206 207

    virCapsPtr caps;
208
    virDomainXMLOptionPtr xmlopt;
209 210 211

    IVirtualBox *vboxObj;
    ISession *vboxSession;
212 213 214

    /** Our version specific API table pointer. */
    PCVBOXXPCOM pFuncs;
215

216
#if VBOX_API_VERSION == 2002000
217 218 219

} vboxGlobalData;

220
#else /* !(VBOX_API_VERSION == 2002000) */
221

222
    /* Async event handling */
223
    virObjectEventStatePtr domainEvents;
224 225
    int fdWatch;

226
# if VBOX_API_VERSION <= 3002000
227
    /* IVirtualBoxCallback is used in VirtualBox 3.x only */
228
    IVirtualBoxCallback *vboxCallback;
229
# endif /* VBOX_API_VERSION <= 3002000 */
230 231 232 233 234 235 236

    nsIEventQueue  *vboxQueue;
    int volatile vboxCallBackRefCount;

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

237 238
} vboxGlobalData;

239 240 241 242 243 244 245 246 247 248
/* 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
 */

249
static vboxGlobalData *g_pVBoxGlobalData = NULL;
250

251
#endif /* !(VBOX_API_VERSION == 2002000) */
252

253
#if VBOX_API_VERSION < 4000000
254 255 256 257 258 259 260 261 262 263 264 265 266

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

267
#else /* VBOX_API_VERSION >= 4000000 */
268 269 270 271 272 273 274 275 276 277 278 279 280

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

281
#endif /* VBOX_API_VERSION >= 4000000 */
282

283 284
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml);
static int vboxDomainCreate(virDomainPtr dom);
285
static int vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags);
286

287 288
static void vboxDriverLock(vboxGlobalData *data)
{
289 290 291
    virMutexLock(&data->lock);
}

292 293
static void vboxDriverUnlock(vboxGlobalData *data)
{
294 295 296
    virMutexUnlock(&data->lock);
}

297
#if VBOX_API_VERSION == 2002000
298

299 300
static void nsIDtoChar(unsigned char *uuid, const nsID *iid)
{
301 302 303
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
304
    size_t i;
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331

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

332
    for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
333 334 335 336
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
337
    ignore_value(virUUIDParse(uuidstrdst, uuid));
338 339
}

340 341
static void nsIDFromChar(nsID *iid, const unsigned char *uuid)
{
342 343 344
    char uuidstrsrc[VIR_UUID_STRING_BUFLEN];
    char uuidstrdst[VIR_UUID_STRING_BUFLEN];
    unsigned char uuidinterim[VIR_UUID_BUFLEN];
345
    size_t i;
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371

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

372
    for (i = 18; i < VIR_UUID_STRING_BUFLEN; i++) {
373 374 375 376
        uuidstrdst[i] = uuidstrsrc[i];
    }

    uuidstrdst[VIR_UUID_STRING_BUFLEN-1] = '\0';
377
    ignore_value(virUUIDParse(uuidstrdst, uuidinterim));
378 379 380
    memcpy(iid, uuidinterim, VIR_UUID_BUFLEN);
}

381
# ifdef WIN32
382

383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
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 */
398
}
399

400 401 402 403 404
static void
vboxIIDToUUID_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid, unsigned char *uuid)
{
    nsIDtoChar(uuid, (nsID *)&iid->value);
}
405

406 407 408 409 410
static void
vboxIIDFromUUID_v2_x_WIN32(vboxGlobalData *data, vboxIID_v2_x_WIN32 *iid,
                           const unsigned char *uuid)
{
    vboxIIDUnalloc_v2_x_WIN32(data, iid);
411

412
    nsIDFromChar((nsID *)&iid->value, uuid);
413 414
}

415 416 417
static bool
vboxIIDIsEqual_v2_x_WIN32(vboxIID_v2_x_WIN32 *iid1, vboxIID_v2_x_WIN32 *iid2)
{
418
    return memcmp(&iid1->value, &iid2->value, sizeof(GUID)) == 0;
419
}
420

421 422 423 424 425 426 427 428
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);

429
    memcpy(&iid->value, &items[idx], sizeof(GUID));
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
}

#  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) {
461 462 463
        return;
    }

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
    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;

485
    sa_assert(iid->value);
486
    nsIDFromChar(iid->value, uuid);
487 488
}

489 490 491
static bool
vboxIIDIsEqual_v2_x(vboxIID_v2_x *iid1, vboxIID_v2_x *iid2)
{
492
    return memcmp(iid1->value, iid2->value, sizeof(nsID)) == 0;
493 494 495 496 497 498 499 500 501 502
}

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

    iid->value = &iid->backing;

503
    memcpy(iid->value, array->items[idx], sizeof(nsID));
504 505 506 507 508 509 510 511 512 513 514 515
}

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

516
#else /* VBOX_API_VERSION != 2002000 */
517

518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
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;
540 541
}

542 543 544 545 546 547 548 549
static void
vboxIIDToUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                   unsigned char *uuid)
{
    char *utf8 = NULL;

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

550
    ignore_value(virUUIDParse(utf8, uuid));
551 552

    data->pFuncs->pfnUtf8Free(utf8);
553 554
}

555 556 557 558 559
static void
vboxIIDFromUUID_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                     const unsigned char *uuid)
{
    char utf8[VIR_UUID_STRING_BUFLEN];
560

561
    vboxIIDUnalloc_v3_x(data, iid);
562

563
    virUUIDFormat(uuid, utf8);
564

565 566
    data->pFuncs->pfnUtf8ToUtf16(utf8, &iid->value);
}
567

568 569 570 571 572 573
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];
574 575

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

583 584
    return memcmp(uuid1, uuid2, VIR_UUID_BUFLEN) == 0;
}
585 586


587 588 589 590 591
static void
vboxIIDFromArrayItem_v3_x(vboxGlobalData *data, vboxIID_v3_x *iid,
                          vboxArray *array, int idx)
{
    vboxIIDUnalloc_v3_x(data, iid);
592

593 594
    iid->value = array->items[idx];
    iid->owner = false;
595 596
}

597 598 599 600 601 602 603 604

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

606
# if VBOX_API_VERSION >= 3001000
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622

/**
 * 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
 *
 */
623
static char *vboxGenerateMediumName(PRUint32  storageBus,
624 625 626 627
                                    PRInt32   deviceInst,
                                    PRInt32   devicePort,
                                    PRInt32   deviceSlot,
                                    PRUint32 *aMaxPortPerInst,
628 629
                                    PRUint32 *aMaxSlotPerPort)
{
630
    const char *prefix = NULL;
631 632 633 634 635
    char *name  = NULL;
    int   total = 0;
    PRUint32 maxPortPerInst = 0;
    PRUint32 maxSlotPerPort = 0;

636 637
    if (!aMaxPortPerInst ||
        !aMaxSlotPerPort)
638 639
        return NULL;

640 641
    if ((storageBus < StorageBus_IDE) ||
        (storageBus > StorageBus_Floppy))
642 643 644 645 646 647 648 649 650
        return NULL;

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

    if (storageBus == StorageBus_IDE) {
651
        prefix = "hd";
652 653
    } else if ((storageBus == StorageBus_SATA) ||
               (storageBus == StorageBus_SCSI)) {
654
        prefix = "sd";
655
    } else if (storageBus == StorageBus_Floppy) {
656
        prefix = "fd";
657 658
    }

659
    name = virIndexToDiskName(total, prefix);
660

661
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
662
          "devicePort=%d deviceSlot=%d, maxPortPerInst=%u maxSlotPerPort=%u",
663
          NULLSTR(name), total, storageBus, deviceInst, devicePort,
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
          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;

695 696 697 698 699 700
    if (!deviceName ||
        !deviceInst ||
        !devicePort ||
        !deviceSlot ||
        !aMaxPortPerInst ||
        !aMaxSlotPerPort)
701 702
        return false;

703 704
    if ((storageBus < StorageBus_IDE) ||
        (storageBus > StorageBus_Floppy))
705 706 707 708 709 710 711
        return false;

    total = virDiskNameToIndex(deviceName);

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

712 713 714
    if (!maxPortPerInst ||
        !maxSlotPerPort ||
        (total < 0))
715 716 717 718 719 720
        return false;

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

721
    VIR_DEBUG("name=%s, total=%d, storageBus=%u, deviceInst=%d, "
722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741
          "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,
742 743
                                     PRUint32 *maxSlotPerPort)
{
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 786 787
    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
 */
788 789
static int PRUnicharToInt(PRUnichar *strUtf16)
{
790 791 792 793 794 795 796 797 798 799
    char *strUtf8 = NULL;
    int ret = 0;

    if (!strUtf16)
        return -1;

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

800 801 802
    if (virStrToLong_i(strUtf8, NULL, 10, &ret) < 0)
        ret = -1;

803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
    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;
}

822
# endif /* VBOX_API_VERSION >= 3001000 */
823

824
#endif /* !(VBOX_API_VERSION == 2002000) */
825

826 827 828 829 830 831
static PRUnichar *
vboxSocketFormatAddrUtf16(vboxGlobalData *data, virSocketAddrPtr addr)
{
    char *utf8 = NULL;
    PRUnichar *utf16 = NULL;

832
    utf8 = virSocketAddrFormat(addr);
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852

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

853
    if (virSocketAddrParse(addr, utf8, AF_UNSPEC) < 0) {
854 855 856 857 858 859 860 861 862 863 864
        goto cleanup;
    }

    result = 0;

cleanup:
    VBOX_UTF8_FREE(utf8);

    return result;
}

865

866 867 868 869 870
static virDomainDefParserConfig vboxDomainDefParserConfig = {
    .macPrefix = { 0x08, 0x00, 0x27 },
};


871
static virDomainXMLOptionPtr
872 873
vboxXMLConfInit(void)
{
874 875
    return virDomainXMLOptionNew(&vboxDomainDefParserConfig,
                                 NULL, NULL);
876 877 878
}


879 880
static virCapsPtr vboxCapsInit(void)
{
881 882 883
    virCapsPtr caps;
    virCapsGuestPtr guest;

884
    if ((caps = virCapabilitiesNew(virArchFromHost(),
885 886 887
                                   0, 0)) == NULL)
        goto no_memory;

888
    if (nodeCapsInitNUMA(caps) < 0)
889 890 891 892
        goto no_memory;

    if ((guest = virCapabilitiesAddGuest(caps,
                                         "hvm",
893
                                         caps->host.arch,
894 895 896 897 898 899 900 901 902 903 904 905 906
                                         NULL,
                                         NULL,
                                         0,
                                         NULL)) == NULL)
        goto no_memory;

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

908 909 910
    return caps;

no_memory:
911
    virObjectUnref(caps);
912 913 914
    return NULL;
}

915 916 917
static int
vboxInitialize(vboxGlobalData *data)
{
918 919 920
    data->pFuncs = g_pfnGetFunctions(VBOX_XPCOMC_VERSION);

    if (data->pFuncs == NULL)
921
        goto cleanup;
922 923 924

#if VBOX_XPCOMC_VERSION == 0x00010000U
    data->pFuncs->pfnComInitialize(&data->vboxObj, &data->vboxSession);
925
#else  /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
926 927
    data->pFuncs->pfnComInitialize(IVIRTUALBOX_IID_STR, &data->vboxObj,
                               ISESSION_IID_STR, &data->vboxSession);
928

929
# if VBOX_API_VERSION == 2002000
930 931 932

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

933
# else  /* !(VBOX_API_VERSION == 2002000) */
934 935 936 937 938 939 940

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

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

    if (data->vboxQueue == NULL) {
941 942
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("nsIEventQueue object is null"));
943 944 945
        goto cleanup;
    }

946
# endif /* !(VBOX_API_VERSION == 2002000) */
947
#endif /* !(VBOX_XPCOMC_VERSION == 0x00010000U) */
948 949

    if (data->vboxObj == NULL) {
950 951
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("IVirtualBox object is null"));
952
        goto cleanup;
953 954 955
    }

    if (data->vboxSession == NULL) {
956 957
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("ISession object is null"));
958 959
        goto cleanup;
    }
960 961 962 963 964 965 966

    return 0;

cleanup:
    return -1;
}

967 968
static int vboxExtractVersion(vboxGlobalData *data)
{
969
    int ret = -1;
970 971 972 973 974 975 976 977 978 979
    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;

980
        VBOX_UTF16_TO_UTF8(versionUtf16, &vboxVersion);
981

982
        if (virParseVersionString(vboxVersion, &data->version, false) >= 0)
983 984
            ret = 0;

985 986
        VBOX_UTF8_FREE(vboxVersion);
        VBOX_COM_UNALLOC_MEM(versionUtf16);
987 988 989
    }

    if (ret != 0)
990 991
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Could not extract VirtualBox version"));
992

993 994 995
    return ret;
}

996 997
static void vboxUninitialize(vboxGlobalData *data)
{
998 999 1000
    if (!data)
        return;

1001 1002
    if (data->pFuncs)
        data->pFuncs->pfnComUninitialize();
1003

1004
    virObjectUnref(data->caps);
1005
    virObjectUnref(data->xmlopt);
1006
#if VBOX_API_VERSION == 2002000
1007
    /* No domainEventCallbacks in 2.2.* version */
1008
#else  /* !(VBOX_API_VERSION == 2002000) */
1009
    virObjectEventStateFree(data->domainEvents);
1010
#endif /* !(VBOX_API_VERSION == 2002000) */
1011 1012 1013
    VIR_FREE(data);
}

1014

1015 1016 1017
static virDrvOpenStatus vboxConnectOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
1018
{
1019
    vboxGlobalData *data = NULL;
1020
    uid_t uid = geteuid();
1021

E
Eric Blake 已提交
1022 1023
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1024 1025 1026
    if (conn->uri == NULL &&
        !(conn->uri = virURIParse(uid ? "vbox:///session" : "vbox:///system")))
        return VIR_DRV_OPEN_ERROR;
1027

1028
    if (conn->uri->scheme == NULL ||
1029
        STRNEQ(conn->uri->scheme, "vbox"))
1030 1031 1032 1033
        return VIR_DRV_OPEN_DECLINED;

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

1036
    if (conn->uri->path == NULL || STREQ(conn->uri->path, "")) {
1037 1038
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("no VirtualBox driver path specified (try vbox:///session)"));
1039 1040 1041
        return VIR_DRV_OPEN_ERROR;
    }

1042
    if (uid != 0) {
1043
        if (STRNEQ(conn->uri->path, "/session")) {
1044 1045
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown driver path '%s' specified (try vbox:///session)"), conn->uri->path);
1046 1047
            return VIR_DRV_OPEN_ERROR;
        }
1048
    } else { /* root */
1049 1050
        if (STRNEQ(conn->uri->path, "/system") &&
            STRNEQ(conn->uri->path, "/session")) {
1051 1052
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown driver path '%s' specified (try vbox:///system)"), conn->uri->path);
1053 1054
            return VIR_DRV_OPEN_ERROR;
        }
1055 1056
    }

1057
    if (VIR_ALLOC(data) < 0)
1058
        return VIR_DRV_OPEN_ERROR;
1059

1060
    if (!(data->caps = vboxCapsInit()) ||
1061
        vboxInitialize(data) < 0 ||
1062
        vboxExtractVersion(data) < 0 ||
1063
        !(data->xmlopt = vboxXMLConfInit())) {
1064 1065 1066
        vboxUninitialize(data);
        return VIR_DRV_OPEN_ERROR;
    }
1067

1068
#if VBOX_API_VERSION == 2002000
1069 1070 1071

    /* No domainEventCallbacks in 2.2.* version */

1072
#else  /* !(VBOX_API_VERSION == 2002000) */
1073

1074
    if (!(data->domainEvents = virObjectEventStateNew())) {
1075
        vboxUninitialize(data);
1076 1077 1078 1079 1080 1081
        return VIR_DRV_OPEN_ERROR;
    }

    data->conn = conn;
    g_pVBoxGlobalData = data;

1082
#endif /* !(VBOX_API_VERSION == 2002000) */
1083

1084
    conn->privateData = data;
1085
    VIR_DEBUG("in vboxOpen");
1086 1087 1088 1089

    return VIR_DRV_OPEN_SUCCESS;
}

1090 1091
static int vboxConnectClose(virConnectPtr conn)
{
1092
    vboxGlobalData *data = conn->privateData;
E
Eric Blake 已提交
1093
    VIR_DEBUG("%s: in vboxClose", conn->driver->name);
1094 1095 1096 1097 1098 1099 1100

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

    return 0;
}

1101 1102
static int vboxConnectGetVersion(virConnectPtr conn, unsigned long *version)
{
1103
    vboxGlobalData *data = conn->privateData;
E
Eric Blake 已提交
1104
    VIR_DEBUG("%s: in vboxGetVersion", conn->driver->name);
1105 1106 1107 1108 1109 1110 1111 1112

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

    return 0;
}

1113 1114 1115 1116 1117 1118 1119

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


1120 1121
static int vboxConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
1122 1123 1124 1125
    /* Driver is using local, non-network based transport */
    return 1;
}

1126 1127
static int vboxConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
1128 1129 1130 1131
    /* No encryption is needed, or used on the local transport*/
    return 0;
}

1132
static int vboxConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1133 1134 1135 1136
{
    return 1;
}

1137 1138 1139
static int
vboxConnectGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED)
{
1140
    VBOX_OBJECT_CHECK(conn, int, -1);
1141 1142 1143 1144 1145
    PRUint32 maxCPUCount = 0;

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

1148 1149 1150 1151
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
        VBOX_RELEASE(systemProperties);
1152 1153 1154 1155 1156 1157 1158 1159 1160
    }

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}


1161
static char *vboxConnectGetCapabilities(virConnectPtr conn) {
1162
    VBOX_OBJECT_CHECK(conn, char *, NULL);
1163 1164 1165 1166 1167 1168 1169 1170

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

    return ret;
}

1171 1172
static int vboxConnectListDomains(virConnectPtr conn, int *ids, int nids)
{
1173
    VBOX_OBJECT_CHECK(conn, int, -1);
1174
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1175
    PRUint32 state;
1176
    nsresult rc;
1177
    size_t i, j;
1178

1179
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1180
    if (NS_FAILED(rc)) {
1181
        virReportError(VIR_ERR_INTERNAL_ERROR,
E
Eric Blake 已提交
1182 1183
                       _("Could not get list of Domains, rc=%08x"),
                       (unsigned)rc);
1184 1185
        goto cleanup;
    }
1186

1187 1188 1189
    ret = 0;
    for (i = 0, j = 0; (i < machines.count) && (j < nids); ++i) {
        IMachine *machine = machines.items[i];
1190 1191 1192 1193 1194 1195

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
1196 1197
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline)) {
1198 1199
                    ret++;
                    ids[j++] = i + 1;
1200 1201 1202 1203 1204 1205
                }
            }
        }
    }

cleanup:
1206
    vboxArrayRelease(&machines);
1207 1208 1209
    return ret;
}

1210 1211
static int vboxConnectNumOfDomains(virConnectPtr conn)
{
1212
    VBOX_OBJECT_CHECK(conn, int, -1);
1213
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1214
    PRUint32 state;
1215
    nsresult rc;
1216
    size_t i;
1217

1218
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1219
    if (NS_FAILED(rc)) {
1220 1221
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get number of Domains, rc=%08x"), (unsigned)rc);
1222 1223
        goto cleanup;
    }
1224

1225 1226 1227
    ret = 0;
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1228 1229 1230 1231 1232 1233

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
1234 1235
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1236
                    ret++;
1237 1238 1239 1240 1241
            }
        }
    }

cleanup:
1242
    vboxArrayRelease(&machines);
1243 1244 1245 1246
    return ret;
}

static virDomainPtr vboxDomainCreateXML(virConnectPtr conn, const char *xml,
1247 1248
                                        unsigned int flags)
{
1249 1250 1251 1252 1253 1254 1255 1256
    /* 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.
     */

1257 1258 1259 1260 1261
    virDomainPtr dom;

    virCheckFlags(0, NULL);

    dom = vboxDomainDefineXML(conn, xml);
1262 1263 1264 1265
    if (dom == NULL)
        return NULL;

    if (vboxDomainCreate(dom) < 0) {
1266
        vboxDomainUndefineFlags(dom, 0);
1267
        virObjectUnref(dom);
1268
        return NULL;
1269 1270 1271 1272 1273
    }

    return dom;
}

1274 1275
static virDomainPtr vboxDomainLookupByID(virConnectPtr conn, int id)
{
1276
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1277
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1278 1279
    vboxIID iid = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
1280
    PRUint32 state;
1281
    nsresult rc;
1282

1283
    /* Internal vbox IDs start from 0, the public libvirt ID
1284
     * starts from 1, so refuse id == 0, and adjust the rest*/
1285
    if (id == 0) {
1286 1287
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), id);
1288 1289 1290 1291
        return NULL;
    }
    id = id - 1;

1292
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1293
    if (NS_FAILED(rc)) {
1294 1295
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1296 1297
        return NULL;
    }
1298

1299 1300 1301 1302
    if (id < machines.count) {
        IMachine *machine = machines.items[id];

        if (machine) {
1303
            PRBool isAccessible = PR_FALSE;
1304
            machine->vtbl->GetAccessible(machine, &isAccessible);
1305
            if (isAccessible) {
1306
                machine->vtbl->GetState(machine, &state);
1307 1308
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline)) {
1309 1310
                    PRUnichar *machineNameUtf16 = NULL;
                    char      *machineNameUtf8  = NULL;
1311

1312
                    machine->vtbl->GetName(machine, &machineNameUtf16);
1313
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1314

1315 1316 1317
                    machine->vtbl->GetId(machine, &iid.value);
                    vboxIIDToUUID(&iid, uuid);
                    vboxIIDUnalloc(&iid);
1318 1319 1320 1321 1322 1323 1324

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

1325
                    ret = virGetDomain(conn, machineNameUtf8, uuid);
1326 1327 1328 1329 1330 1331
                    if (ret)
                        ret->id = id + 1;

                    /* Cleanup all the XPCOM allocated stuff here */
                    VBOX_UTF8_FREE(machineNameUtf8);
                    VBOX_UTF16_FREE(machineNameUtf16);
1332 1333 1334 1335 1336
                }
            }
        }
    }

1337
    vboxArrayRelease(&machines);
1338 1339

    return ret;
1340 1341
}

1342 1343 1344
static virDomainPtr
vboxDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
1345
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1346
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1347
    vboxIID iid = VBOX_IID_INITIALIZER;
1348
    char      *machineNameUtf8  = NULL;
1349
    PRUnichar *machineNameUtf16 = NULL;
1350
    unsigned char iid_as_uuid[VIR_UUID_BUFLEN];
1351 1352
    size_t i;
    int matched = 0;
1353
    nsresult rc;
1354

1355
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1356
    if (NS_FAILED(rc)) {
1357 1358
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1359 1360
        return NULL;
    }
1361

1362 1363
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1364
        PRBool isAccessible = PR_FALSE;
1365

1366 1367
        if (!machine)
            continue;
1368

1369 1370
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1371

1372 1373
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
1374
                continue;
1375 1376
            vboxIIDToUUID(&iid, iid_as_uuid);
            vboxIIDUnalloc(&iid);
1377

1378
            if (memcmp(uuid, iid_as_uuid, VIR_UUID_BUFLEN) == 0) {
1379

1380
                PRUint32 state;
1381

1382
                matched = 1;
1383

1384 1385
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1386

1387
                machine->vtbl->GetState(machine, &state);
1388

1389 1390 1391 1392 1393
                /* 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.
                 */
1394

1395
                ret = virGetDomain(conn, machineNameUtf8, iid_as_uuid);
1396 1397 1398
                if (ret &&
                    (state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1399
                    ret->id = i + 1;
1400 1401
            }

1402 1403
            if (matched == 1)
                break;
1404 1405 1406
        }
    }

1407 1408 1409
    /* Do the cleanup and take care you dont leak any memory */
    VBOX_UTF8_FREE(machineNameUtf8);
    VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1410
    vboxArrayRelease(&machines);
1411 1412

    return ret;
1413 1414
}

1415 1416 1417
static virDomainPtr
vboxDomainLookupByName(virConnectPtr conn, const char *name)
{
1418
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
1419
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1420
    vboxIID iid = VBOX_IID_INITIALIZER;
1421
    char      *machineNameUtf8  = NULL;
1422
    PRUnichar *machineNameUtf16 = NULL;
1423
    unsigned char uuid[VIR_UUID_BUFLEN];
1424 1425
    size_t i;
    int matched = 0;
1426
    nsresult rc;
1427

1428
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1429
    if (NS_FAILED(rc)) {
1430 1431
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1432 1433
        return NULL;
    }
1434

1435 1436
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1437
        PRBool isAccessible = PR_FALSE;
1438

1439 1440
        if (!machine)
            continue;
1441

1442 1443
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
1444

1445 1446
            machine->vtbl->GetName(machine, &machineNameUtf16);
            VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1447

1448
            if (STREQ(name, machineNameUtf8)) {
1449

1450
                PRUint32 state;
1451

1452
                matched = 1;
1453

1454 1455 1456
                machine->vtbl->GetId(machine, &iid.value);
                vboxIIDToUUID(&iid, uuid);
                vboxIIDUnalloc(&iid);
1457

1458
                machine->vtbl->GetState(machine, &state);
1459

1460 1461 1462 1463 1464
                /* 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.
                 */
1465

1466
                ret = virGetDomain(conn, machineNameUtf8, uuid);
1467 1468 1469
                if (ret &&
                    (state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1470
                    ret->id = i + 1;
1471 1472
            }

J
John Ferlan 已提交
1473 1474
            VBOX_UTF8_FREE(machineNameUtf8);
            VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1475 1476
            if (matched == 1)
                break;
1477 1478 1479
        }
    }

1480
    vboxArrayRelease(&machines);
1481 1482

    return ret;
1483 1484
}

1485

1486 1487
static int vboxDomainIsActive(virDomainPtr dom)
{
1488
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1489
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1490
    vboxIID iid = VBOX_IID_INITIALIZER;
1491 1492
    char      *machineNameUtf8  = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1493
    unsigned char uuid[VIR_UUID_BUFLEN];
1494 1495
    size_t i;
    int matched = 0;
1496
    nsresult rc;
1497

1498
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1499
    if (NS_FAILED(rc)) {
1500 1501
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1502 1503
        return ret;
    }
1504

1505 1506
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1507 1508 1509 1510 1511 1512 1513
        PRBool isAccessible = PR_FALSE;

        if (!machine)
            continue;

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

1515 1516
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
1517
                continue;
1518 1519
            vboxIIDToUUID(&iid, uuid);
            vboxIIDUnalloc(&iid);
1520

1521
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
1522

1523
                PRUint32 state;
1524

1525
                matched = 1;
1526

1527 1528
                machine->vtbl->GetName(machine, &machineNameUtf16);
                VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineNameUtf8);
1529

1530
                machine->vtbl->GetState(machine, &state);
1531

1532 1533
                if ((state >= MachineState_FirstOnline) &&
                    (state <= MachineState_LastOnline))
1534 1535 1536
                    ret = 1;
                else
                    ret = 0;
1537 1538
            }

1539 1540
            if (matched == 1)
                break;
1541 1542 1543
        }
    }

1544 1545 1546
    /* Do the cleanup and take care you dont leak any memory */
    VBOX_UTF8_FREE(machineNameUtf8);
    VBOX_COM_UNALLOC_MEM(machineNameUtf16);
1547
    vboxArrayRelease(&machines);
1548

1549 1550 1551 1552
    return ret;
}


1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
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)) {
1565 1566
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1567 1568 1569 1570 1571 1572 1573 1574 1575
        goto cleanup;
    }

    ret = 1;

cleanup:
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1576 1577 1578
}


1579 1580
static int vboxDomainIsUpdated(virDomainPtr dom ATTRIBUTE_UNUSED)
{
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
    /* 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)) {
1591 1592
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
1593 1594 1595 1596 1597 1598 1599 1600 1601
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
1602 1603
}

1604 1605
static int vboxDomainSuspend(virDomainPtr dom)
{
1606
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1607
    IMachine *machine    = NULL;
1608
    vboxIID iid = VBOX_IID_INITIALIZER;
1609
    IConsole *console    = NULL;
1610
    PRBool isAccessible  = PR_FALSE;
1611
    PRUint32 state;
1612
    nsresult rc;
1613

1614
    vboxIIDFromUUID(&iid, dom->uuid);
1615
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1616
    if (NS_FAILED(rc)) {
1617 1618
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1619 1620
        goto cleanup;
    }
1621

1622 1623
    if (!machine)
        goto cleanup;
1624

1625 1626 1627
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1628

1629
        if (state == MachineState_Running) {
1630 1631
            /* set state pause */
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1632 1633 1634 1635 1636
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Pause(console);
                VBOX_RELEASE(console);
                ret = 0;
1637
            } else {
1638 1639
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("error while suspending the domain"));
1640 1641
                goto cleanup;
            }
1642
            VBOX_SESSION_CLOSE();
1643
        } else {
1644 1645
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not in running state to suspend it"));
1646
            goto cleanup;
1647 1648 1649 1650
        }
    }

cleanup:
1651
    VBOX_RELEASE(machine);
1652
    vboxIIDUnalloc(&iid);
1653 1654 1655
    return ret;
}

1656 1657
static int vboxDomainResume(virDomainPtr dom)
{
1658
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1659
    IMachine *machine    = NULL;
1660
    vboxIID iid = VBOX_IID_INITIALIZER;
1661 1662
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1663
    nsresult rc;
1664

1665
    PRBool isAccessible = PR_FALSE;
1666

1667
    vboxIIDFromUUID(&iid, dom->uuid);
1668
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1669
    if (NS_FAILED(rc)) {
1670 1671
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1672 1673
        goto cleanup;
    }
1674

1675 1676
    if (!machine)
        goto cleanup;
1677

1678 1679 1680 1681 1682
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);

        if (state == MachineState_Paused) {
1683 1684
            /* resume the machine here */
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1685 1686 1687 1688 1689
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Resume(console);
                VBOX_RELEASE(console);
                ret = 0;
1690
            } else {
1691 1692
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("error while resuming the domain"));
1693 1694
                goto cleanup;
            }
1695
            VBOX_SESSION_CLOSE();
1696
        } else {
1697 1698
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not paused, so can't resume it"));
1699
            goto cleanup;
1700 1701 1702 1703
        }
    }

cleanup:
1704
    VBOX_RELEASE(machine);
1705
    vboxIIDUnalloc(&iid);
1706 1707 1708
    return ret;
}

1709
static int vboxDomainShutdownFlags(virDomainPtr dom,
1710 1711
                                   unsigned int flags)
{
1712
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1713
    IMachine *machine    = NULL;
1714
    vboxIID iid = VBOX_IID_INITIALIZER;
1715 1716
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1717 1718
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1719

1720 1721
    virCheckFlags(0, -1);

1722
    vboxIIDFromUUID(&iid, dom->uuid);
1723
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1724
    if (NS_FAILED(rc)) {
1725 1726
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1727 1728
        goto cleanup;
    }
1729

1730 1731
    if (!machine)
        goto cleanup;
1732

1733 1734 1735
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1736

1737
        if (state == MachineState_Paused) {
1738 1739
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine paused, so can't power it down"));
1740 1741
            goto cleanup;
        } else if (state == MachineState_PoweredOff) {
1742 1743
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1744 1745
            goto cleanup;
        }
1746

1747
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1748 1749 1750 1751 1752
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
            console->vtbl->PowerButton(console);
            VBOX_RELEASE(console);
            ret = 0;
1753
        }
1754
        VBOX_SESSION_CLOSE();
1755 1756 1757
    }

cleanup:
1758
    VBOX_RELEASE(machine);
1759
    vboxIIDUnalloc(&iid);
1760 1761 1762
    return ret;
}

1763 1764
static int vboxDomainShutdown(virDomainPtr dom)
{
1765 1766 1767 1768
    return vboxDomainShutdownFlags(dom, 0);
}


E
Eric Blake 已提交
1769 1770
static int vboxDomainReboot(virDomainPtr dom, unsigned int flags)
{
1771
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1772
    IMachine *machine    = NULL;
1773
    vboxIID iid = VBOX_IID_INITIALIZER;
1774 1775
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1776 1777
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1778

E
Eric Blake 已提交
1779 1780
    virCheckFlags(0, -1);

1781
    vboxIIDFromUUID(&iid, dom->uuid);
1782
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1783
    if (NS_FAILED(rc)) {
1784 1785
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1786 1787
        goto cleanup;
    }
1788

1789 1790
    if (!machine)
        goto cleanup;
1791

1792 1793 1794
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1795

1796
        if (state == MachineState_Running) {
1797
            VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1798 1799 1800 1801 1802
            data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
            if (console) {
                console->vtbl->Reset(console);
                VBOX_RELEASE(console);
                ret = 0;
1803
            }
1804
            VBOX_SESSION_CLOSE();
1805
        } else {
1806 1807
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine not running, so can't reboot it"));
1808
            goto cleanup;
1809 1810 1811 1812
        }
    }

cleanup:
1813
    VBOX_RELEASE(machine);
1814
    vboxIIDUnalloc(&iid);
1815 1816 1817
    return ret;
}

1818 1819 1820 1821
static int
vboxDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
1822
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1823
    IMachine *machine    = NULL;
1824
    vboxIID iid = VBOX_IID_INITIALIZER;
1825 1826
    IConsole *console    = NULL;
    PRUint32 state       = MachineState_Null;
1827 1828
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1829

1830 1831
    virCheckFlags(0, -1);

1832
    vboxIIDFromUUID(&iid, dom->uuid);
1833
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1834
    if (NS_FAILED(rc)) {
1835 1836
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1837 1838
        goto cleanup;
    }
1839

1840 1841
    if (!machine)
        goto cleanup;
1842

1843 1844 1845
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1846

1847
        if (state == MachineState_PoweredOff) {
1848 1849
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("machine already powered down"));
1850 1851
            goto cleanup;
        }
1852

1853
        VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
1854 1855
        data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (console) {
1856

1857
#if VBOX_API_VERSION == 2002000
1858
            console->vtbl->PowerDown(console);
1859
#else
1860
            IProgress *progress = NULL;
1861 1862 1863 1864
            console->vtbl->PowerDown(console, &progress);
            if (progress) {
                progress->vtbl->WaitForCompletion(progress, -1);
                VBOX_RELEASE(progress);
1865
            }
1866 1867
#endif
            VBOX_RELEASE(console);
1868
            dom->id = -1;
1869
            ret = 0;
1870
        }
1871
        VBOX_SESSION_CLOSE();
1872 1873 1874
    }

cleanup:
1875
    VBOX_RELEASE(machine);
1876
    vboxIIDUnalloc(&iid);
1877 1878 1879
    return ret;
}

1880 1881 1882 1883 1884 1885
static int
vboxDomainDestroy(virDomainPtr dom)
{
    return vboxDomainDestroyFlags(dom, 0);
}

1886
static char *vboxDomainGetOSType(virDomainPtr dom ATTRIBUTE_UNUSED) {
1887 1888 1889 1890 1891
    /* 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 ;)
     */
1892
    char *osType;
1893

1894
    ignore_value(VIR_STRDUP(osType, "hvm"));
1895
    return osType;
1896 1897
}

1898 1899
static int vboxDomainSetMemory(virDomainPtr dom, unsigned long memory)
{
1900
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1901
    IMachine *machine    = NULL;
1902
    vboxIID iid = VBOX_IID_INITIALIZER;
1903
    PRUint32 state       = MachineState_Null;
1904 1905
    PRBool isAccessible  = PR_FALSE;
    nsresult rc;
1906

1907
    vboxIIDFromUUID(&iid, dom->uuid);
1908
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
1909
    if (NS_FAILED(rc)) {
1910 1911
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), dom->id);
1912 1913
        goto cleanup;
    }
1914

1915 1916
    if (!machine)
        goto cleanup;
1917

1918 1919 1920
    machine->vtbl->GetAccessible(machine, &isAccessible);
    if (isAccessible) {
        machine->vtbl->GetState(machine, &state);
1921

1922
        if (state != MachineState_PoweredOff) {
1923 1924
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("memory size can't be changed unless domain is powered down"));
1925 1926
            goto cleanup;
        }
1927

1928
        rc = VBOX_SESSION_OPEN(iid.value, machine);
1929 1930 1931
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
1932

1933 1934
                rc = machine->vtbl->SetMemorySize(machine,
                                                  VIR_DIV_UP(memory, 1024));
1935 1936 1937 1938
                if (NS_SUCCEEDED(rc)) {
                    machine->vtbl->SaveSettings(machine);
                    ret = 0;
                } else {
1939 1940 1941 1942
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("could not set the memory size of the "
                                     "domain to: %lu Kb, rc=%08x"),
                                   memory, (unsigned)rc);
1943 1944
                }
            }
1945
            VBOX_SESSION_CLOSE();
1946 1947 1948 1949
        }
    }

cleanup:
1950
    VBOX_RELEASE(machine);
1951
    vboxIIDUnalloc(&iid);
1952 1953 1954
    return ret;
}

1955 1956
static virDomainState vboxConvertState(enum MachineState state)
{
1957 1958 1959 1960 1961 1962 1963 1964 1965 1966
    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 已提交
1967
        case MachineState_Saved:
1968 1969 1970 1971 1972 1973 1974 1975 1976
            return VIR_DOMAIN_SHUTOFF;
        case MachineState_Aborted:
            return VIR_DOMAIN_CRASHED;
        case MachineState_Null:
        default:
            return VIR_DOMAIN_NOSTATE;
    }
}

1977 1978
static int vboxDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
1979
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
1980
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
1981 1982
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
1983
    nsresult rc;
1984
    size_t i = 0;
1985

1986
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
1987
    if (NS_FAILED(rc)) {
1988 1989
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
1990 1991
        goto cleanup;
    }
1992

1993
    info->nrVirtCpu = 0;
1994 1995
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
1996
        PRBool isAccessible = PR_FALSE;
1997

1998 1999
        if (!machine)
            continue;
2000

2001 2002
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
2003

2004 2005 2006 2007 2008 2009
            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
2010
                * for time being set max_balloon and cur_balloon to same
2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027
                * 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;
                }
2028 2029


2030 2031 2032 2033 2034 2035
                machine->vtbl->GetCPUCount(machine, &CPUCount);
                machine->vtbl->GetMemorySize(machine, &memorySize);
                machine->vtbl->GetState(machine, &state);

                info->cpuTime = 0;
                info->nrVirtCpu = CPUCount;
2036 2037
                info->memory = memorySize * 1024;
                info->maxMem = maxMemorySize * 1024;
2038
                info->state = vboxConvertState(state);
2039

2040
                ret = 0;
2041 2042
            }

J
John Ferlan 已提交
2043 2044
            VBOX_UTF8_FREE(machineName);
            VBOX_COM_UNALLOC_MEM(machineNameUtf16);
2045 2046
            if (info->nrVirtCpu)
                break;
2047 2048 2049 2050
        }

    }

2051
    vboxArrayRelease(&machines);
2052 2053 2054 2055 2056

cleanup:
    return ret;
}

2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073
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)) {
2074 2075
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
2076 2077 2078 2079 2080
        goto cleanup;
    }

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

2081
    *state = vboxConvertState(mstate);
2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092

    if (reason)
        *reason = 0;

    ret = 0;

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

2093 2094
static int vboxDomainSave(virDomainPtr dom, const char *path ATTRIBUTE_UNUSED)
{
2095
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
2096
    IConsole *console    = NULL;
2097
    vboxIID iid = VBOX_IID_INITIALIZER;
2098
    IMachine *machine = NULL;
2099
    nsresult rc;
2100 2101 2102 2103 2104 2105 2106 2107

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

2108
    /* Open a Session for the machine */
2109
    vboxIIDFromUUID(&iid, dom->uuid);
2110
#if VBOX_API_VERSION >= 4000000
2111 2112 2113
    /* Get machine for the call to VBOX_SESSION_OPEN_EXISTING */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
2114 2115
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
2116 2117 2118 2119 2120
        return -1;
    }
#endif

    rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
2121 2122 2123 2124
    if (NS_SUCCEEDED(rc)) {
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
        if (NS_SUCCEEDED(rc) && console) {
            IProgress *progress = NULL;
2125

2126
            console->vtbl->SaveState(console, &progress);
2127

2128
            if (progress) {
2129
#if VBOX_API_VERSION == 2002000
2130
                nsresult resultCode;
2131
#else
2132
                PRInt32 resultCode;
2133
#endif
2134

2135 2136 2137 2138
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
                if (NS_SUCCEEDED(resultCode)) {
                    ret = 0;
2139
                }
2140
                VBOX_RELEASE(progress);
2141
            }
2142
            VBOX_RELEASE(console);
2143
        }
2144
        VBOX_SESSION_CLOSE();
2145 2146
    }

2147
    DEBUGIID("UUID of machine being saved:", iid.value);
2148

2149
    VBOX_RELEASE(machine);
2150
    vboxIIDUnalloc(&iid);
2151 2152 2153
    return ret;
}

2154 2155 2156 2157
static int
vboxDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
{
2158
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
2159
    IMachine *machine    = NULL;
2160
    vboxIID iid = VBOX_IID_INITIALIZER;
2161
    PRUint32  CPUCount   = nvcpus;
2162
    nsresult rc;
2163

2164
    if (flags != VIR_DOMAIN_AFFECT_LIVE) {
2165
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2166 2167 2168
        return -1;
    }

2169
    vboxIIDFromUUID(&iid, dom->uuid);
2170
#if VBOX_API_VERSION >= 4000000
2171 2172 2173
    /* Get machine for the call to VBOX_SESSION_OPEN */
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
2174 2175
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
2176 2177 2178 2179 2180
        return -1;
    }
#endif

    rc = VBOX_SESSION_OPEN(iid.value, machine);
2181 2182 2183 2184 2185 2186 2187
    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;
2188
            } else {
2189 2190 2191 2192
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("could not set the number of cpus of the domain "
                                 "to: %u, rc=%08x"),
                               CPUCount, (unsigned)rc);
2193
            }
2194
            VBOX_RELEASE(machine);
2195
        } else {
2196 2197
            virReportError(VIR_ERR_NO_DOMAIN,
                           _("no domain with matching id %d"), dom->id);
2198
        }
2199
    } else {
2200 2201
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("can't open session to the domain with id %d"), dom->id);
2202
    }
2203
    VBOX_SESSION_CLOSE();
2204

2205
    vboxIIDUnalloc(&iid);
2206 2207 2208
    return ret;
}

2209 2210 2211
static int
vboxDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
2212
    return vboxDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
2213 2214 2215 2216 2217
}

static int
vboxDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
2218 2219
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
    ISystemProperties *systemProperties = NULL;
2220 2221
    PRUint32 maxCPUCount = 0;

2222
    if (flags != (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_VCPU_MAXIMUM)) {
2223
        virReportError(VIR_ERR_INVALID_ARG, _("unsupported flags: (0x%x)"), flags);
2224 2225 2226
        return -1;
    }

2227 2228 2229 2230 2231
    /* Currently every domain supports the same number of max cpus
     * as that supported by vbox and thus take it directly from
     * the systemproperties.
     */

2232 2233 2234 2235
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxGuestCPUCount(systemProperties, &maxCPUCount);
        VBOX_RELEASE(systemProperties);
2236 2237 2238 2239 2240 2241 2242 2243
    }

    if (maxCPUCount > 0)
        ret = maxCPUCount;

    return ret;
}

2244 2245 2246
static int
vboxDomainGetMaxVcpus(virDomainPtr dom)
{
2247
    return vboxDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
2248 2249 2250
                                         VIR_DOMAIN_VCPU_MAXIMUM));
}

2251 2252
static void vboxHostDeviceGetXMLDesc(vboxGlobalData *data, virDomainDefPtr def, IMachine *machine)
{
2253
#if VBOX_API_VERSION < 4003000
2254 2255
    IUSBController *USBController = NULL;
    PRBool enabled = PR_FALSE;
R
Ryota Ozaki 已提交
2256 2257 2258
#else
    IUSBDeviceFilters *USBDeviceFilters = NULL;
#endif
2259 2260 2261 2262 2263
    vboxArray deviceFilters = VBOX_ARRAY_INITIALIZER;
    size_t i;
    PRUint32 USBFilterCount = 0;

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

2265
#if VBOX_API_VERSION < 4003000
2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277
    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 已提交
2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
#else
    machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);

    if (!USBDeviceFilters)
        return;

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

2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311
    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;

2312 2313 2314 2315 2316 2317
    for (i = 0; i < def->nhostdevs; i++) {
        def->hostdevs[i] = virDomainHostdevDefAlloc();
        if (!def->hostdevs[i])
            goto release_hostdevs;
    }

2318
    for (i = 0; i < deviceFilters.count; i++) {
2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360
        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);
2361
#if VBOX_API_VERSION < 4003000
2362 2363
release_controller:
    VBOX_RELEASE(USBController);
R
Ryota Ozaki 已提交
2364 2365 2366
#else
    VBOX_RELEASE(USBDeviceFilters);
#endif
2367 2368 2369 2370 2371 2372 2373 2374 2375

    return;

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

    goto release_filters;
2376 2377
}

2378
static char *vboxDomainGetXMLDesc(virDomainPtr dom, unsigned int flags) {
2379
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
2380 2381
    virDomainDefPtr def  = NULL;
    IMachine *machine    = NULL;
2382
    vboxIID iid = VBOX_IID_INITIALIZER;
2383
    int gotAllABoutDef   = -1;
2384
    nsresult rc;
2385

2386 2387
    /* Flags checked by virDomainDefFormat */

2388
    if (VIR_ALLOC(def) < 0)
2389 2390
        goto cleanup;

2391
    vboxIIDFromUUID(&iid, dom->uuid);
2392
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
2393
    if (NS_SUCCEEDED(rc)) {
2394
        PRBool accessible = PR_FALSE;
2395

2396 2397
        machine->vtbl->GetAccessible(machine, &accessible);
        if (accessible) {
2398
            size_t i = 0;
2399 2400 2401
            PRBool PAEEnabled                   = PR_FALSE;
            PRBool ACPIEnabled                  = PR_FALSE;
            PRBool IOAPICEnabled                = PR_FALSE;
2402
            PRBool VRDxEnabled                  = PR_FALSE;
2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413
            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;
2414
#if VBOX_API_VERSION < 3001000
2415 2416 2417 2418 2419 2420 2421 2422
            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;
2423
#else  /* VBOX_API_VERSION >= 3001000 */
2424
            vboxArray mediumAttachments         = VBOX_ARRAY_INITIALIZER;
2425 2426
#endif /* VBOX_API_VERSION >= 3001000 */
#if VBOX_API_VERSION < 4000000
2427
            IVRDPServer *VRDxServer             = NULL;
2428
#else  /* VBOX_API_VERSION >= 4000000 */
2429
            IVRDEServer *VRDxServer             = NULL;
2430
#endif /* VBOX_API_VERSION >= 4000000 */
2431
            IAudioAdapter *audioAdapter         = NULL;
2432
#if VBOX_API_VERSION >= 4001000
2433
            PRUint32 chipsetType                = ChipsetType_Null;
2434
#endif /* VBOX_API_VERSION >= 4001000 */
2435
            ISystemProperties *systemProperties = NULL;
2436 2437


2438 2439 2440
            def->virtType = VIR_DOMAIN_VIRT_VBOX;
            def->id = dom->id;
            memcpy(def->uuid, dom->uuid, VIR_UUID_BUFLEN);
2441 2442
            if (VIR_STRDUP(def->name, dom->name) < 0)
                goto cleanup;
2443

2444
            machine->vtbl->GetMemorySize(machine, &memorySize);
2445
            def->mem.cur_balloon = memorySize * 1024;
2446

2447
#if VBOX_API_VERSION >= 4001000
2448
            machine->vtbl->GetChipsetType(machine, &chipsetType);
2449
#endif /* VBOX_API_VERSION >= 4001000 */
2450

2451 2452 2453 2454
            data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
            if (systemProperties) {
                systemProperties->vtbl->GetMaxGuestRAM(systemProperties, &maxMemorySize);
                systemProperties->vtbl->GetMaxBootPosition(systemProperties, &maxBootPosition);
2455
#if VBOX_API_VERSION < 4001000
2456
                systemProperties->vtbl->GetNetworkAdapterCount(systemProperties, &netAdpCnt);
2457
#else  /* VBOX_API_VERSION >= 4000000 */
2458
                systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType, &netAdpCnt);
2459
#endif /* VBOX_API_VERSION >= 4000000 */
2460 2461 2462 2463 2464 2465 2466 2467 2468
                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
             */
2469 2470
            /* def->mem.max_balloon = maxMemorySize * 1024; */
            def->mem.max_balloon = memorySize * 1024;
2471 2472

            machine->vtbl->GetCPUCount(machine, &CPUCount);
E
Eric Blake 已提交
2473
            def->maxvcpus = def->vcpus = CPUCount;
2474 2475 2476

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

2477 2478
            if (VIR_STRDUP(def->os.type, "hvm") < 0)
                goto cleanup;
2479

2480
            def->os.arch = virArchFromHost();
2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503

            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 已提交
2504
                    /* Can VirtualBox really boot from a shared folder? */
2505
                }
2506
            }
2507

2508
#if VBOX_API_VERSION < 3001000
2509
            machine->vtbl->GetPAEEnabled(machine, &PAEEnabled);
2510
#elif VBOX_API_VERSION == 3001000
2511
            machine->vtbl->GetCpuProperty(machine, CpuPropertyType_PAE, &PAEEnabled);
2512
#elif VBOX_API_VERSION >= 3002000
2513 2514
            machine->vtbl->GetCPUProperty(machine, CPUPropertyType_PAE, &PAEEnabled);
#endif
2515 2516
            if (PAEEnabled)
                def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_DOMAIN_FEATURE_STATE_ON;
2517

2518 2519 2520
            machine->vtbl->GetBIOSSettings(machine, &bios);
            if (bios) {
                bios->vtbl->GetACPIEnabled(bios, &ACPIEnabled);
2521 2522
                if (ACPIEnabled)
                    def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_DOMAIN_FEATURE_STATE_ON;
2523

2524
                bios->vtbl->GetIOAPICEnabled(bios, &IOAPICEnabled);
2525 2526
                if (IOAPICEnabled)
                    def->features[VIR_DOMAIN_FEATURE_APIC] = VIR_DOMAIN_FEATURE_STATE_ON;
2527

2528 2529 2530 2531 2532
                VBOX_RELEASE(bios);
            }

            /* Currently VirtualBox always uses locatime
             * so locatime is always true here */
2533
            def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
2534 2535 2536 2537 2538 2539 2540 2541

            /* 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 */
2542
                        PRUint32 VRAMSize          = 8;
2543 2544 2545 2546 2547 2548 2549
                        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);
2550
#if VBOX_API_VERSION >= 3001000
2551
                        machine->vtbl->GetAccelerate2DVideoEnabled(machine, &accelerate2DEnabled);
2552
#endif /* VBOX_API_VERSION >= 3001000 */
2553 2554

                        def->videos[0]->type            = VIR_DOMAIN_VIDEO_TYPE_VBOX;
2555
                        def->videos[0]->vram            = VRAMSize * 1024;
2556 2557 2558 2559
                        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;
2560 2561 2562
                        }
                    }
                }
2563
            }
2564

2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575
            /* 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;
2576

2577
                def->ngraphics = 0;
2578

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

2583 2584 2585
                if (valueTypeUtf16) {
                    VBOX_UTF16_TO_UTF8(valueTypeUtf16, &valueTypeUtf8);
                    VBOX_UTF16_FREE(valueTypeUtf16);
2586

2587
                    if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
2588 2589 2590
                        PRUnichar *keyDislpayUtf16   = NULL;
                        PRUnichar *valueDisplayUtf16 = NULL;
                        char      *valueDisplayUtf8  = NULL;
2591

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

2596 2597 2598
                        if (valueDisplayUtf16) {
                            VBOX_UTF16_TO_UTF8(valueDisplayUtf16, &valueDisplayUtf8);
                            VBOX_UTF16_FREE(valueDisplayUtf16);
2599

J
John Ferlan 已提交
2600
                            if (strlen(valueDisplayUtf8) <= 0)
2601
                                VBOX_UTF8_FREE(valueDisplayUtf8);
2602
                        }
2603

2604 2605
                        if (STREQ(valueTypeUtf8, "sdl")) {
                            sdlPresent = 1;
2606
                            if (VIR_STRDUP(sdlDisplay, valueDisplayUtf8) < 0) {
2607 2608 2609 2610 2611 2612
                                /* 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++;
2613
                        }
2614

2615 2616
                        if (STREQ(valueTypeUtf8, "gui")) {
                            guiPresent = 1;
2617
                            if (VIR_STRDUP(guiDisplay, valueDisplayUtf8) < 0) {
2618
                                /* just don't go to cleanup yet as it is ok to have
2619 2620
                                 * guiDisplay as NULL and we check it below if it
                                 * exist and then only use it there
2621
                                 */
2622
                            }
2623 2624
                            totalPresent++;
                        }
J
John Ferlan 已提交
2625
                        VBOX_UTF8_FREE(valueDisplayUtf8);
2626 2627
                    }

2628 2629
                    if (STREQ(valueTypeUtf8, "vrdp"))
                        vrdpPresent = 1;
2630

2631 2632
                    VBOX_UTF8_FREE(valueTypeUtf8);
                }
2633

2634 2635 2636 2637 2638 2639 2640
                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++;
                    }
2641

2642 2643 2644 2645 2646 2647 2648 2649
                    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) {
2650
                        const char *tmp;
2651
                        def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP;
2652
                        tmp = virGetEnvBlockSUID("DISPLAY");
2653 2654 2655 2656
                        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
                             */
2657 2658 2659 2660 2661
                        }
                        totalPresent++;
                        def->ngraphics++;
                    }
                }
2662

2663
#if VBOX_API_VERSION < 4000000
2664
                machine->vtbl->GetVRDPServer(machine, &VRDxServer);
2665
#else  /* VBOX_API_VERSION >= 4000000 */
2666
                machine->vtbl->GetVRDEServer(machine, &VRDxServer);
2667
#endif /* VBOX_API_VERSION >= 4000000 */
2668 2669 2670
                if (VRDxServer) {
                    VRDxServer->vtbl->GetEnabled(VRDxServer, &VRDxEnabled);
                    if (VRDxEnabled) {
2671 2672 2673 2674 2675 2676 2677 2678 2679

                        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;
2680
#if VBOX_API_VERSION < 3001000
2681
                            PRUint32 VRDPport = 0;
2682
                            VRDxServer->vtbl->GetPort(VRDxServer, &VRDPport);
2683 2684
                            if (VRDPport) {
                                def->graphics[def->ngraphics]->data.rdp.port = VRDPport;
2685 2686 2687
                            } else {
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
                            }
2688
#elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */
2689
                            PRUnichar *VRDPport = NULL;
2690
                            VRDxServer->vtbl->GetPorts(VRDxServer, &VRDPport);
2691 2692 2693 2694
                            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);
2695 2696 2697
                            } else {
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
                            }
2698
#else /* VBOX_API_VERSION >= 4000000 */
2699 2700 2701 2702 2703 2704 2705 2706 2707
                            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);
2708
                            } else {
2709
                                def->graphics[def->ngraphics]->data.rdp.autoport = true;
2710
                            }
2711
#endif /* VBOX_API_VERSION >= 4000000 */
2712

2713
                            def->graphics[def->ngraphics]->type = VIR_DOMAIN_GRAPHICS_TYPE_RDP;
2714

2715
#if VBOX_API_VERSION >= 4000000
2716 2717 2718 2719
                            PRUnichar *VRDENetAddressKey = NULL;
                            VBOX_UTF8_TO_UTF16("TCP/Address", &VRDENetAddressKey);
                            VRDxServer->vtbl->GetVRDEProperty(VRDxServer, VRDENetAddressKey, &netAddressUtf16);
                            VBOX_UTF16_FREE(VRDENetAddressKey);
2720
#else /* VBOX_API_VERSION < 4000000 */
2721
                            VRDxServer->vtbl->GetNetAddress(VRDxServer, &netAddressUtf16);
2722
#endif /* VBOX_API_VERSION < 4000000 */
2723 2724 2725
                            if (netAddressUtf16) {
                                VBOX_UTF16_TO_UTF8(netAddressUtf16, &netAddressUtf8);
                                if (STRNEQ(netAddressUtf8, ""))
2726 2727
                                    virDomainGraphicsListenSetAddress(def->graphics[def->ngraphics], 0,
                                                                      netAddressUtf8, -1, true);
2728 2729 2730
                                VBOX_UTF16_FREE(netAddressUtf16);
                                VBOX_UTF8_FREE(netAddressUtf8);
                            }
2731

2732
                            VRDxServer->vtbl->GetAllowMultiConnection(VRDxServer, &allowMultiConnection);
2733
                            if (allowMultiConnection) {
2734
                                def->graphics[def->ngraphics]->data.rdp.multiUser = true;
2735
                            }
2736

2737
                            VRDxServer->vtbl->GetReuseSingleConnection(VRDxServer, &reuseSingleConnection);
2738
                            if (reuseSingleConnection) {
2739
                                def->graphics[def->ngraphics]->data.rdp.replaceUser = true;
2740
                            }
2741

2742
                            def->ngraphics++;
2743
                        } else
2744
                            virReportOOMError();
2745
                    }
2746
                    VBOX_RELEASE(VRDxServer);
2747
                }
2748
            }
2749

2750
#if VBOX_API_VERSION < 3001000
2751 2752
            /* dump IDE hdds if present */
            VBOX_UTF8_TO_UTF16(hddBus, &hddBusUtf16);
2753

2754 2755 2756 2757
            def->ndisks = 0;
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 0,  &hardDiskPM);
            if (hardDiskPM)
                def->ndisks++;
2758

2759 2760 2761
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 0, 1,  &hardDiskPS);
            if (hardDiskPS)
                def->ndisks++;
2762

2763 2764 2765
            machine->vtbl->GetHardDisk(machine, hddBusUtf16, 1, 1,  &hardDiskSS);
            if (hardDiskSS)
                def->ndisks++;
2766

2767 2768 2769 2770 2771 2772 2773
            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;
2774 2775
                        virDomainDiskSetType(def->disks[i],
                                             VIR_DOMAIN_DISK_TYPE_FILE);
2776
                    }
2777
                }
2778
            }
2779

2780 2781 2782 2783
            if (hardDiskPM) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2784

2785 2786
                hardDiskPM->vtbl->imedium.GetLocation((IMedium *)hardDiskPM, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2787

2788
                hardDiskPM->vtbl->GetType(hardDiskPM, &hddType);
2789

2790
                if (hddType == HardDiskType_Immutable)
2791
                    def->disks[hddNum]->readonly = true;
2792 2793
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
2794
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hda"));
2795
                hddNum++;
2796

2797 2798 2799 2800
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPM);
            }
2801

2802 2803 2804 2805
            if (hardDiskPS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2806

2807 2808
                hardDiskPS->vtbl->imedium.GetLocation((IMedium *)hardDiskPS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2809

2810
                hardDiskPS->vtbl->GetType(hardDiskPS, &hddType);
2811

2812
                if (hddType == HardDiskType_Immutable)
2813
                    def->disks[hddNum]->readonly = true;
2814 2815
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
2816
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdb"));
2817
                hddNum++;
2818

2819 2820 2821 2822
                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskPS);
            }
2823

2824 2825 2826 2827
            if (hardDiskSS) {
                PRUnichar *hddlocationUtf16 = NULL;
                char *hddlocation           = NULL;
                PRUint32 hddType            = HardDiskType_Normal;
2828

2829 2830
                hardDiskSS->vtbl->imedium.GetLocation((IMedium *)hardDiskSS, &hddlocationUtf16);
                VBOX_UTF16_TO_UTF8(hddlocationUtf16, &hddlocation);
2831

2832
                hardDiskSS->vtbl->GetType(hardDiskSS, &hddType);
2833

2834
                if (hddType == HardDiskType_Immutable)
2835
                    def->disks[hddNum]->readonly = true;
2836 2837
                ignore_value(virDomainDiskSetSource(def->disks[hddNum],
                                                    hddlocation));
J
Ján Tomko 已提交
2838 2839
                ignore_value(VIR_STRDUP(def->disks[hddNum]->dst, "hdd"));
                hddNum++;
2840 2841 2842 2843 2844

                VBOX_UTF8_FREE(hddlocation);
                VBOX_UTF16_FREE(hddlocationUtf16);
                VBOX_MEDIUM_RELEASE(hardDiskSS);
            }
2845
#else  /* VBOX_API_VERSION >= 3001000 */
2846 2847 2848 2849 2850 2851 2852
            /* dump IDE hdds if present */

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

            /* get the number of attachments */
2856 2857
            for (i = 0; i < mediumAttachments.count; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2858 2859 2860 2861 2862 2863 2864
                if (imediumattach) {
                    IMedium *medium = NULL;

                    imediumattach->vtbl->GetMedium(imediumattach, &medium);
                    if (medium) {
                        def->ndisks++;
                        VBOX_RELEASE(medium);
2865 2866
                    }
                }
2867
            }
2868

2869 2870 2871 2872 2873 2874
            /* 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;
2875 2876
                    }
                }
2877 2878 2879 2880 2881 2882 2883 2884
            } else {
                error = true;
            }

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

            /* get the attachment details here */
2885 2886
            for (i = 0; i < mediumAttachments.count && diskCount < def->ndisks && !error; i++) {
                IMediumAttachment *imediumattach = mediumAttachments.items[i];
2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919
                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;
                }
2920

2921 2922 2923
                medium->vtbl->GetLocation(medium, &mediumLocUtf16);
                VBOX_UTF16_TO_UTF8(mediumLocUtf16, &mediumLocUtf8);
                VBOX_UTF16_FREE(mediumLocUtf16);
2924 2925
                ignore_value(virDomainDiskSetSource(def->disks[diskCount],
                                                    mediumLocUtf8));
2926 2927
                VBOX_UTF8_FREE(mediumLocUtf8);

2928
                if (!virDomainDiskGetSource(def->disks[diskCount])) {
2929 2930 2931 2932 2933
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2934

2935 2936 2937 2938 2939 2940 2941 2942 2943 2944
                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;
                }
2945

2946 2947 2948 2949 2950 2951 2952 2953 2954 2955
                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);
2956
                def->disks[diskCount]->dst = vboxGenerateMediumName(storageBus,
2957 2958 2959 2960 2961 2962
                                                                    deviceInst,
                                                                    devicePort,
                                                                    deviceSlot,
                                                                    maxPortPerInst,
                                                                    maxSlotPerPort);
                if (!def->disks[diskCount]->dst) {
2963 2964 2965 2966
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Could not generate medium name for the disk "
                                     "at: controller instance:%u, port:%d, slot:%d"),
                                   deviceInst, devicePort, deviceSlot);
2967 2968 2969 2970 2971
                    VBOX_RELEASE(medium);
                    VBOX_RELEASE(storageController);
                    error = true;
                    break;
                }
2972

2973 2974
                medium->vtbl->GetReadOnly(medium, &readOnly);
                if (readOnly == PR_TRUE)
2975
                    def->disks[diskCount]->readonly = true;
2976

2977 2978
                virDomainDiskSetType(def->disks[diskCount],
                                     VIR_DOMAIN_DISK_TYPE_FILE);
2979

2980 2981 2982 2983
                VBOX_RELEASE(medium);
                VBOX_RELEASE(storageController);
                diskCount++;
            }
2984

2985
            vboxArrayRelease(&mediumAttachments);
2986

2987 2988 2989 2990 2991 2992 2993 2994
            /* cleanup on error */
            if (error) {
                for (i = 0; i < def->ndisks; i++) {
                    VIR_FREE(def->disks[i]);
                }
                VIR_FREE(def->disks);
                def->ndisks = 0;
            }
2995

2996
#endif /* VBOX_API_VERSION >= 3001000 */
2997

M
Matthias Bolte 已提交
2998 2999 3000 3001 3002 3003 3004 3005 3006
            /* shared folders */
            vboxArray sharedFolders = VBOX_ARRAY_INITIALIZER;

            def->nfss = 0;

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

            if (sharedFolders.count > 0) {
3007
                if (VIR_ALLOC_N(def->fss, sharedFolders.count) < 0)
M
Matthias Bolte 已提交
3008 3009 3010 3011 3012 3013 3014 3015 3016 3017
                    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;

3018
                    if (VIR_ALLOC(def->fss[i]) < 0)
M
Matthias Bolte 已提交
3019 3020 3021 3022 3023 3024
                        goto sharedFoldersCleanup;

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

                    sharedFolder->vtbl->GetHostPath(sharedFolder, &hostPathUtf16);
                    VBOX_UTF16_TO_UTF8(hostPathUtf16, &hostPath);
3025 3026 3027
                    if (VIR_STRDUP(def->fss[i]->src, hostPath) < 0) {
                        VBOX_UTF8_FREE(hostPath);
                        VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
3028 3029
                        goto sharedFoldersCleanup;
                    }
3030 3031
                    VBOX_UTF8_FREE(hostPath);
                    VBOX_UTF16_FREE(hostPathUtf16);
M
Matthias Bolte 已提交
3032 3033 3034

                    sharedFolder->vtbl->GetName(sharedFolder, &nameUtf16);
                    VBOX_UTF16_TO_UTF8(nameUtf16, &name);
3035 3036 3037
                    if (VIR_STRDUP(def->fss[i]->dst, name) < 0) {
                        VBOX_UTF8_FREE(name);
                        VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
3038 3039
                        goto sharedFoldersCleanup;
                    }
3040 3041
                    VBOX_UTF8_FREE(name);
                    VBOX_UTF16_FREE(nameUtf16);
M
Matthias Bolte 已提交
3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052

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

                    ++def->nfss;
                }
            }

sharedFoldersCleanup:
            vboxArrayRelease(&sharedFolders);

3053 3054 3055 3056 3057
            /* dump network cards if present */
            def->nnets = 0;
            /* Get which network cards are enabled */
            for (i = 0; i < netAdpCnt; i++) {
                INetworkAdapter *adapter = NULL;
3058

3059 3060 3061
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
3062

3063 3064 3065 3066
                    adapter->vtbl->GetEnabled(adapter, &enabled);
                    if (enabled) {
                        def->nnets++;
                    }
3067

3068 3069 3070
                    VBOX_RELEASE(adapter);
                }
            }
3071

3072 3073 3074
            /* 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++) {
3075
                    ignore_value(VIR_ALLOC(def->nets[i]));
3076 3077
                }
            }
3078

3079
            /* Now get the details about the network cards here */
3080
            for (i = 0; netAdpIncCnt < def->nnets && i < netAdpCnt; i++) {
3081
                INetworkAdapter *adapter = NULL;
3082

3083 3084 3085
                machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
                if (adapter) {
                    PRBool enabled = PR_FALSE;
3086

3087 3088 3089 3090 3091 3092 3093
                    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};
3094

3095 3096
                        adapter->vtbl->GetAttachmentType(adapter, &attachmentType);
                        if (attachmentType == NetworkAttachmentType_NAT) {
3097

3098
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_USER;
3099

3100 3101 3102
                        } else if (attachmentType == NetworkAttachmentType_Bridged) {
                            PRUnichar *hostIntUtf16 = NULL;
                            char *hostInt           = NULL;
3103

3104
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_BRIDGE;
3105

3106
#if VBOX_API_VERSION < 4001000
3107
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
3108
#else /* VBOX_API_VERSION >= 4001000 */
3109
                            adapter->vtbl->GetBridgedInterface(adapter, &hostIntUtf16);
3110
#endif /* VBOX_API_VERSION >= 4001000 */
3111

3112
                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
3113
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.bridge.brname, hostInt));
3114

3115 3116
                            VBOX_UTF8_FREE(hostInt);
                            VBOX_UTF16_FREE(hostIntUtf16);
3117

3118 3119 3120
                        } else if (attachmentType == NetworkAttachmentType_Internal) {
                            PRUnichar *intNetUtf16 = NULL;
                            char *intNet           = NULL;
3121

3122 3123 3124 3125 3126
                            def->nets[netAdpIncCnt]->type = VIR_DOMAIN_NET_TYPE_INTERNAL;

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

                            VBOX_UTF16_TO_UTF8(intNetUtf16, &intNet);
3127
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.internal.name, intNet));
3128 3129 3130 3131 3132 3133 3134 3135 3136 3137

                            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;

3138
#if VBOX_API_VERSION < 4001000
3139
                            adapter->vtbl->GetHostInterface(adapter, &hostIntUtf16);
3140
#else /* VBOX_API_VERSION >= 4001000 */
3141
                            adapter->vtbl->GetHostOnlyInterface(adapter, &hostIntUtf16);
3142
#endif /* VBOX_API_VERSION >= 4001000 */
3143 3144

                            VBOX_UTF16_TO_UTF8(hostIntUtf16, &hostInt);
3145
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->data.network.name, hostInt));
3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158

                            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) {
3159
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C970A"));
3160
                        } else if (adapterType == NetworkAdapterType_Am79C973) {
3161
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "Am79C973"));
3162
                        } else if (adapterType == NetworkAdapterType_I82540EM) {
3163
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82540EM"));
3164
                        } else if (adapterType == NetworkAdapterType_I82545EM) {
3165
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82545EM"));
3166
                        } else if (adapterType == NetworkAdapterType_I82543GC) {
3167
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "82543GC"));
3168
#if VBOX_API_VERSION >= 3001000
3169
                        } else if (adapterType == NetworkAdapterType_Virtio) {
3170
                            ignore_value(VIR_STRDUP(def->nets[netAdpIncCnt]->model, "virtio"));
3171
#endif /* VBOX_API_VERSION >= 3001000 */
3172 3173
                        }

3174 3175 3176 3177 3178 3179 3180 3181 3182
                        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 ... */
3183
                        if (virMacAddrParse(macaddr, &def->nets[netAdpIncCnt]->mac) < 0)
3184 3185 3186 3187 3188 3189
                        {}

                        netAdpIncCnt++;

                        VBOX_UTF16_FREE(MACAddressUtf16);
                        VBOX_UTF8_FREE(MACAddress);
3190
                    }
3191 3192

                    VBOX_RELEASE(adapter);
3193
                }
3194
            }
3195

3196
            /* dump sound card if active */
3197

3198 3199 3200
            /* Set def->nsounds to one as VirtualBox currently supports
             * only one sound card
             */
3201

3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228
            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);
            }
3229

3230
#if VBOX_API_VERSION < 3001000
3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252
            /* 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;
3253 3254
                                virDomainDiskSetType(def->disks[def->ndisks - 1],
                                                     VIR_DOMAIN_DISK_TYPE_FILE);
3255
                                def->disks[def->ndisks - 1]->readonly = true;
3256
                                ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location));
3257 3258
                                ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "hdc"));
                                def->ndisks--;
3259
                            } else {
3260
                                def->ndisks--;
3261 3262
                            }
                        } else {
3263
                            def->ndisks--;
3264
                        }
3265 3266 3267 3268

                        VBOX_UTF8_FREE(location);
                        VBOX_UTF16_FREE(locationUtf16);
                        VBOX_MEDIUM_RELEASE(dvdImage);
3269 3270
                    }
                }
3271 3272
                VBOX_RELEASE(dvdDrive);
            }
3273

3274 3275 3276 3277 3278 3279 3280
            /* 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) {
3281 3282
                    PRUint32 state = DriveState_Null;

3283
                    floppyDrive->vtbl->GetState(floppyDrive, &state);
3284
                    if (state == DriveState_ImageMounted) {
3285
                        IFloppyImage *floppyImage = NULL;
3286

3287 3288
                        floppyDrive->vtbl->GetImage(floppyDrive, &floppyImage);
                        if (floppyImage) {
3289 3290 3291
                            PRUnichar *locationUtf16 = NULL;
                            char *location           = NULL;

3292 3293
                            floppyImage->vtbl->imedium.GetLocation((IMedium *)floppyImage, &locationUtf16);
                            VBOX_UTF16_TO_UTF8(locationUtf16, &location);
3294 3295 3296 3297

                            def->ndisks++;
                            if (VIR_REALLOC_N(def->disks, def->ndisks) >= 0) {
                                if (VIR_ALLOC(def->disks[def->ndisks - 1]) >= 0) {
3298 3299
                                    def->disks[def->ndisks - 1]->device = VIR_DOMAIN_DISK_DEVICE_FLOPPY;
                                    def->disks[def->ndisks - 1]->bus = VIR_DOMAIN_DISK_BUS_FDC;
3300 3301
                                    virDomainDiskSetType(def->disks[def->ndisks - 1],
                                                         VIR_DOMAIN_DISK_TYPE_FILE);
3302
                                    def->disks[def->ndisks - 1]->readonly = false;
3303
                                    ignore_value(virDomainDiskSetSource(def->disks[def->ndisks - 1], location));
3304 3305
                                    ignore_value(VIR_STRDUP(def->disks[def->ndisks - 1]->dst, "fda"));
                                    def->ndisks--;
3306 3307 3308 3309 3310 3311 3312
                                } else {
                                    def->ndisks--;
                                }
                            } else {
                                def->ndisks--;
                            }

3313 3314 3315
                            VBOX_UTF8_FREE(location);
                            VBOX_UTF16_FREE(locationUtf16);
                            VBOX_MEDIUM_RELEASE(floppyImage);
3316 3317 3318 3319
                        }
                    }
                }

3320 3321
                VBOX_RELEASE(floppyDrive);
            }
3322 3323
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
3324 3325 3326 3327 3328 3329 3330 3331 3332

            /* 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) {
3333 3334
                    PRBool enabled = PR_FALSE;

3335
                    serialPort->vtbl->GetEnabled(serialPort, &enabled);
3336
                    if (enabled) {
3337
                        def->nserials++;
3338 3339
                    }

3340
                    VBOX_RELEASE(serialPort);
3341
                }
3342
            }
3343

3344 3345 3346
            /* 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++) {
3347
                    ignore_value(VIR_ALLOC(def->serials[i]));
3348 3349
                }
            }
3350

3351
            /* Now get the details about the serial ports here */
3352 3353 3354
            for (i = 0;
                 serialPortIncCount < def->nserials && i < serialPortCount;
                 i++) {
3355
                ISerialPort *serialPort = NULL;
3356

3357 3358 3359
                machine->vtbl->GetSerialPort(machine, i, &serialPort);
                if (serialPort) {
                    PRBool enabled = PR_FALSE;
3360

3361 3362 3363 3364 3365 3366 3367 3368 3369 3370
                    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) {
3371
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_PIPE;
3372
                        } else if (hostMode == PortMode_HostDevice) {
3373
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_DEV;
3374
#if VBOX_API_VERSION >= 3000000
3375
                        } else if (hostMode == PortMode_RawFile) {
3376
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3377
#endif /* VBOX_API_VERSION >= 3000000 */
3378
                        } else {
3379
                            def->serials[serialPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_NULL;
3380
                        }
3381

3382
                        def->serials[serialPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL;
3383

3384 3385 3386 3387 3388 3389 3390
                        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;
                        }
3391

3392
                        serialPort->vtbl->GetPath(serialPort, &pathUtf16);
3393

3394 3395
                        if (pathUtf16) {
                            VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3396
                            ignore_value(VIR_STRDUP(def->serials[serialPortIncCount]->source.data.file.path, path));
3397 3398
                        }

3399 3400 3401 3402
                        serialPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
3403 3404
                    }

3405 3406 3407
                    VBOX_RELEASE(serialPort);
                }
            }
3408

3409 3410 3411 3412 3413
            /* dump parallel ports if active */
            def->nparallels = 0;
            /* Get which parallel ports are enabled/active */
            for (i = 0; i < parallelPortCount; i++) {
                IParallelPort *parallelPort = NULL;
3414

3415 3416 3417
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
3418

3419 3420 3421
                    parallelPort->vtbl->GetEnabled(parallelPort, &enabled);
                    if (enabled) {
                        def->nparallels++;
3422
                    }
3423 3424

                    VBOX_RELEASE(parallelPort);
3425
                }
3426
            }
3427

3428 3429 3430
            /* 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++) {
3431
                    ignore_value(VIR_ALLOC(def->parallels[i]));
3432
                }
3433
            }
3434

3435
            /* Now get the details about the parallel ports here */
3436 3437 3438 3439
            for (i = 0;
                 parallelPortIncCount < def->nparallels &&
                     i < parallelPortCount;
                 i++) {
3440
                IParallelPort *parallelPort = NULL;
3441

3442 3443 3444
                machine->vtbl->GetParallelPort(machine, i, &parallelPort);
                if (parallelPort) {
                    PRBool enabled = PR_FALSE;
3445

3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459
                    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;
                        }
3460

3461
                        def->parallels[parallelPortIncCount]->source.type = VIR_DOMAIN_CHR_TYPE_FILE;
3462
                        def->parallels[parallelPortIncCount]->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_PARALLEL;
3463

3464
                        parallelPort->vtbl->GetPath(parallelPort, &pathUtf16);
3465

3466
                        VBOX_UTF16_TO_UTF8(pathUtf16, &path);
3467
                        ignore_value(VIR_STRDUP(def->parallels[parallelPortIncCount]->source.data.file.path, path));
3468

3469 3470 3471 3472
                        parallelPortIncCount++;

                        VBOX_UTF16_FREE(pathUtf16);
                        VBOX_UTF8_FREE(path);
3473
                    }
3474 3475

                    VBOX_RELEASE(parallelPort);
3476
                }
3477
            }
3478

3479
            /* dump USB devices/filters if active */
3480
            vboxHostDeviceGetXMLDesc(data, def, machine);
3481 3482 3483 3484 3485

            /* all done so set gotAllABoutDef and pass def to virDomainDefFormat
             * to generate XML for it
             */
            gotAllABoutDef = 0;
3486
        }
3487 3488
        VBOX_RELEASE(machine);
        machine = NULL;
3489 3490 3491
    }

    if (gotAllABoutDef == 0)
3492
        ret = virDomainDefFormat(def, flags);
3493 3494

cleanup:
3495
    vboxIIDUnalloc(&iid);
3496 3497 3498 3499
    virDomainDefFree(def);
    return ret;
}

3500
static int vboxConnectListDefinedDomains(virConnectPtr conn, char ** const names, int maxnames) {
3501
    VBOX_OBJECT_CHECK(conn, int, -1);
3502
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3503 3504 3505
    char *machineName    = NULL;
    PRUnichar *machineNameUtf16 = NULL;
    PRUint32 state;
3506
    nsresult rc;
3507
    size_t i, j;
3508

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

3517 3518
    memset(names, 0, sizeof(names[i]) * maxnames);

3519 3520 3521
    ret = 0;
    for (i = 0, j = 0; (i < machines.count) && (j < maxnames); i++) {
        IMachine *machine = machines.items[i];
3522 3523 3524 3525 3526 3527

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3528 3529
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3530 3531
                    machine->vtbl->GetName(machine, &machineNameUtf16);
                    VBOX_UTF16_TO_UTF8(machineNameUtf16, &machineName);
3532 3533 3534
                    if (VIR_STRDUP(names[j], machineName) < 0) {
                        VBOX_UTF16_FREE(machineNameUtf16);
                        VBOX_UTF8_FREE(machineName);
3535
                        for (j = 0; j < maxnames; j++)
3536 3537 3538
                            VIR_FREE(names[j]);
                        ret = -1;
                        goto cleanup;
3539
                    }
3540 3541
                    VBOX_UTF16_FREE(machineNameUtf16);
                    VBOX_UTF8_FREE(machineName);
3542
                    j++;
3543
                    ret++;
3544 3545 3546 3547 3548 3549
                }
            }
        }
    }

cleanup:
3550
    vboxArrayRelease(&machines);
3551 3552 3553
    return ret;
}

3554 3555
static int vboxConnectNumOfDefinedDomains(virConnectPtr conn)
{
3556
    VBOX_OBJECT_CHECK(conn, int, -1);
3557
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3558
    PRUint32 state       = MachineState_Null;
3559
    nsresult rc;
3560
    size_t i;
3561

3562
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3563
    if (NS_FAILED(rc)) {
3564 3565 3566
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get number of Defined Domains, rc=%08x"),
                       (unsigned)rc);
3567 3568
        goto cleanup;
    }
3569

3570 3571 3572
    ret = 0;
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3573 3574 3575 3576 3577 3578

        if (machine) {
            PRBool isAccessible = PR_FALSE;
            machine->vtbl->GetAccessible(machine, &isAccessible);
            if (isAccessible) {
                machine->vtbl->GetState(machine, &state);
3579 3580
                if ((state < MachineState_FirstOnline) ||
                    (state > MachineState_LastOnline)) {
3581
                    ret++;
3582 3583 3584 3585 3586 3587
                }
            }
        }
    }

cleanup:
3588
    vboxArrayRelease(&machines);
3589 3590 3591
    return ret;
}

E
Eric Blake 已提交
3592 3593

static int
3594
vboxStartMachine(virDomainPtr dom, int maxDomID, IMachine *machine,
3595
                 vboxIID *iid ATTRIBUTE_UNUSED /* >= 4.0 */)
E
Eric Blake 已提交
3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621
{
    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);

3622
        if (STREQ(valueTypeUtf8, "sdl") || STREQ(valueTypeUtf8, "gui")) {
E
Eric Blake 已提交
3623 3624 3625 3626 3627 3628 3629 3630 3631 3632

            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 已提交
3633
                if (strlen(valueDisplayUtf8) <= 0)
E
Eric Blake 已提交
3634 3635 3636 3637 3638
                    VBOX_UTF8_FREE(valueDisplayUtf8);
            }

            if (STREQ(valueTypeUtf8, "sdl")) {
                sdlPresent = 1;
3639 3640 3641 3642 3643
                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 已提交
3644 3645 3646 3647 3648
                }
            }

            if (STREQ(valueTypeUtf8, "gui")) {
                guiPresent = 1;
3649 3650 3651 3652 3653
                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 已提交
3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673
                }
            }
        }

        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 已提交
3674
    VBOX_UTF8_FREE(valueDisplayUtf8);
E
Eric Blake 已提交
3675 3676 3677

    if (guiPresent) {
        if (guiDisplay) {
E
Eric Blake 已提交
3678
            char *displayutf8;
3679
            if (virAsprintf(&displayutf8, "DISPLAY=%s", guiDisplay) >= 0) {
E
Eric Blake 已提交
3680 3681 3682
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3683 3684 3685 3686 3687 3688 3689 3690
            VIR_FREE(guiDisplay);
        }

        VBOX_UTF8_TO_UTF16("gui", &sessionType);
    }

    if (sdlPresent) {
        if (sdlDisplay) {
E
Eric Blake 已提交
3691
            char *displayutf8;
3692
            if (virAsprintf(&displayutf8, "DISPLAY=%s", sdlDisplay) >= 0) {
E
Eric Blake 已提交
3693 3694 3695
                VBOX_UTF8_TO_UTF16(displayutf8, &env);
                VIR_FREE(displayutf8);
            }
E
Eric Blake 已提交
3696 3697 3698 3699 3700 3701 3702 3703 3704 3705
            VIR_FREE(sdlDisplay);
        }

        VBOX_UTF8_TO_UTF16("sdl", &sessionType);
    }

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

3706
#if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
3707 3708
    rc = data->vboxObj->vtbl->OpenRemoteSession(data->vboxObj,
                                                data->vboxSession,
3709
                                                iid->value,
E
Eric Blake 已提交
3710 3711
                                                sessionType,
                                                env,
3712
                                                &progress);
3713
#else /* VBOX_API_VERSION >= 4000000 */
3714 3715
    rc = machine->vtbl->LaunchVMProcess(machine, data->vboxSession,
                                        sessionType, env, &progress);
3716
#endif /* VBOX_API_VERSION >= 4000000 */
3717

E
Eric Blake 已提交
3718
    if (NS_FAILED(rc)) {
3719 3720
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("OpenRemoteSession/LaunchVMProcess failed, domain can't be started"));
E
Eric Blake 已提交
3721 3722 3723
        ret = -1;
    } else {
        PRBool completed = 0;
3724
#if VBOX_API_VERSION == 2002000
E
Eric Blake 已提交
3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740
        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 */
3741
            dom->id = maxDomID + 1;
E
Eric Blake 已提交
3742 3743 3744 3745 3746 3747
            ret = 0;
        }
    }

    VBOX_RELEASE(progress);

3748
    VBOX_SESSION_CLOSE();
E
Eric Blake 已提交
3749 3750 3751 3752 3753 3754 3755

    VBOX_UTF16_FREE(env);
    VBOX_UTF16_FREE(sessionType);

    return ret;
}

3756 3757
static int vboxDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
{
3758
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
3759
    vboxArray machines = VBOX_ARRAY_INITIALIZER;
3760
    unsigned char uuid[VIR_UUID_BUFLEN] = {0};
3761
    nsresult rc;
3762
    size_t i = 0;
3763

3764 3765
    virCheckFlags(0, -1);

3766
    if (!dom->name) {
3767 3768
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Error while reading the domain name"));
3769 3770 3771
        goto cleanup;
    }

3772
    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
3773
    if (NS_FAILED(rc)) {
3774 3775
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of machines, rc=%08x"), (unsigned)rc);
3776 3777
        goto cleanup;
    }
3778

3779 3780
    for (i = 0; i < machines.count; ++i) {
        IMachine *machine = machines.items[i];
3781
        PRBool isAccessible = PR_FALSE;
3782

3783 3784
        if (!machine)
            continue;
3785

3786 3787
        machine->vtbl->GetAccessible(machine, &isAccessible);
        if (isAccessible) {
3788
            vboxIID iid = VBOX_IID_INITIALIZER;
3789

3790 3791
            rc = machine->vtbl->GetId(machine, &iid.value);
            if (NS_FAILED(rc))
3792
                continue;
3793
            vboxIIDToUUID(&iid, uuid);
3794

3795
            if (memcmp(dom->uuid, uuid, VIR_UUID_BUFLEN) == 0) {
3796 3797 3798
                PRUint32 state = MachineState_Null;
                machine->vtbl->GetState(machine, &state);

3799 3800 3801
                if ((state == MachineState_PoweredOff) ||
                    (state == MachineState_Saved) ||
                    (state == MachineState_Aborted)) {
3802
                    ret = vboxStartMachine(dom, i, machine, &iid);
3803
                } else {
3804
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
3805 3806 3807
                                   _("machine is not in "
                                     "poweroff|saved|aborted state, so "
                                     "couldn't start it"));
3808
                    ret = -1;
3809 3810
                }
            }
3811
            vboxIIDUnalloc(&iid);
3812 3813
            if (ret != -1)
                break;
3814 3815 3816
        }
    }

3817
    /* Do the cleanup and take care you dont leak any memory */
3818
    vboxArrayRelease(&machines);
3819

3820 3821 3822 3823
cleanup:
    return ret;
}

3824 3825
static int vboxDomainCreate(virDomainPtr dom)
{
3826 3827 3828
    return vboxDomainCreateWithFlags(dom, 0);
}

E
Eric Blake 已提交
3829 3830 3831 3832 3833 3834
static void
vboxSetBootDeviceOrder(virDomainDefPtr def, vboxGlobalData *data,
                       IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 maxBootPosition            = 0;
3835
    size_t i = 0;
3836

3837
    VIR_DEBUG("def->os.type             %s", def->os.type);
3838
    VIR_DEBUG("def->os.arch             %s", virArchToString(def->os.arch));
3839
    VIR_DEBUG("def->os.machine          %s", def->os.machine);
3840
    VIR_DEBUG("def->os.nBootDevs        %zu", def->os.nBootDevs);
3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852
    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);
3853

E
Eric Blake 已提交
3854 3855 3856 3857 3858 3859
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetMaxBootPosition(systemProperties,
                                                   &maxBootPosition);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
3860
    }
3861

E
Eric Blake 已提交
3862 3863 3864
    /* Clear the defaults first */
    for (i = 0; i < maxBootPosition; i++) {
        machine->vtbl->SetBootOrder(machine, i+1, DeviceType_Null);
3865
    }
3866

E
Eric Blake 已提交
3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877
    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;
3878
        }
E
Eric Blake 已提交
3879
        machine->vtbl->SetBootOrder(machine, i+1, device);
3880
    }
E
Eric Blake 已提交
3881
}
3882

E
Eric Blake 已提交
3883 3884 3885
static void
vboxAttachDrives(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
3886
    size_t i;
E
Eric Blake 已提交
3887
    nsresult rc;
3888

3889
#if VBOX_API_VERSION < 3001000
E
Eric Blake 已提交
3890 3891 3892 3893
    if (def->ndisks == 0)
        return;

    for (i = 0; i < def->ndisks; i++) {
3894 3895 3896 3897 3898
        const char *src = virDomainDiskGetSource(def->disks[i]);
        int type = virDomainDiskGetType(def->disks[i]);
        int format = virDomainDiskGetFormat(def->disks[i]);

        VIR_DEBUG("disk(%zu) type:       %d", i, type);
3899 3900
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
3901
        VIR_DEBUG("disk(%zu) src:        %s", i, src);
3902
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
3903 3904
        VIR_DEBUG("disk(%zu) driverName: %s", i,
                  virDomainDiskGetDriver(def->disks[i]));
3905
        VIR_DEBUG("disk(%zu) driverType: %s", i,
3906
                  virStorageFileFormatTypeToString(format));
3907 3908
        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 已提交
3909
                                             ? "True" : "False"));
3910
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->shared
E
Eric Blake 已提交
3911 3912 3913
                                             ? "True" : "False"));

        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
3914
            if (type == VIR_DOMAIN_DISK_TYPE_FILE && src) {
E
Eric Blake 已提交
3915 3916 3917 3918 3919 3920 3921
                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
                 */
3922

E
Eric Blake 已提交
3923 3924 3925 3926
                machine->vtbl->GetDVDDrive(machine, &dvdDrive);
                if (dvdDrive) {
                    IDVDImage *dvdImage          = NULL;
                    PRUnichar *dvdfileUtf16      = NULL;
3927 3928
                    vboxIID dvduuid = VBOX_IID_INITIALIZER;
                    vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
3929

3930
                    VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
3931

E
Eric Blake 已提交
3932 3933 3934 3935 3936
                    data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                      dvdfileUtf16, &dvdImage);
                    if (!dvdImage) {
                        data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                          dvdfileUtf16,
3937
                                                          dvdemptyuuid.value,
E
Eric Blake 已提交
3938 3939 3940 3941
                                                          &dvdImage);
                    }
                    if (dvdImage) {
                        rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage,
3942
                                                           &dvduuid.value);
E
Eric Blake 已提交
3943
                        if (NS_FAILED(rc)) {
3944 3945 3946
                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                           _("can't get the uuid of the file to "
                                             "be attached to cdrom: %s, rc=%08x"),
3947
                                           src, (unsigned)rc);
E
Eric Blake 已提交
3948
                        } else {
3949
                            rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
E
Eric Blake 已提交
3950
                            if (NS_FAILED(rc)) {
3951 3952
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("could not attach the file to cdrom: %s, rc=%08x"),
3953
                                               src, (unsigned)rc);
E
Eric Blake 已提交
3954
                            } else {
3955
                                DEBUGIID("CD/DVDImage UUID:", dvduuid.value);
3956
                            }
3957
                        }
E
Eric Blake 已提交
3958 3959

                        VBOX_MEDIUM_RELEASE(dvdImage);
3960
                    }
3961
                    vboxIIDUnalloc(&dvduuid);
E
Eric Blake 已提交
3962 3963 3964
                    VBOX_UTF16_FREE(dvdfileUtf16);
                    VBOX_RELEASE(dvdDrive);
                }
3965
            } else if (type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
E
Eric Blake 已提交
3966 3967
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
3968
            if (type == VIR_DOMAIN_DISK_TYPE_FILE && src) {
E
Eric Blake 已提交
3969 3970
                IHardDisk *hardDisk     = NULL;
                PRUnichar *hddfileUtf16 = NULL;
3971
                vboxIID hdduuid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
3972 3973 3974 3975 3976 3977
                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
                 */
3978

3979
                VBOX_UTF8_TO_UTF16(src, &hddfileUtf16);
E
Eric Blake 已提交
3980
                VBOX_UTF8_TO_UTF16("", &hddEmpty);
3981

E
Eric Blake 已提交
3982 3983
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddfileUtf16,
                                                  &hardDisk);
3984

E
Eric Blake 已提交
3985
                if (!hardDisk) {
3986
# if VBOX_API_VERSION == 2002000
E
Eric Blake 已提交
3987 3988 3989 3990
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      &hardDisk);
3991
# else
E
Eric Blake 已提交
3992 3993 3994 3995 3996 3997 3998 3999
                    data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                      hddfileUtf16,
                                                      AccessMode_ReadWrite,
                                                      0,
                                                      hddEmpty,
                                                      0,
                                                      hddEmpty,
                                                      &hardDisk);
4000
# endif
E
Eric Blake 已提交
4001
                }
4002

E
Eric Blake 已提交
4003 4004
                if (hardDisk) {
                    rc = hardDisk->vtbl->imedium.GetId((IMedium *)hardDisk,
4005
                                                       &hdduuid.value);
E
Eric Blake 已提交
4006
                    if (NS_FAILED(rc)) {
4007 4008 4009
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("can't get the uuid of the file to be "
                                         "attached as harddisk: %s, rc=%08x"),
4010
                                       src, (unsigned)rc);
E
Eric Blake 已提交
4011 4012 4013 4014
                    } else {
                        if (def->disks[i]->readonly) {
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Immutable);
4015
                            VIR_DEBUG("setting harddisk to readonly");
E
Eric Blake 已提交
4016 4017 4018
                        } else if (!def->disks[i]->readonly) {
                            hardDisk->vtbl->SetType(hardDisk,
                                                    HardDiskType_Normal);
4019
                            VIR_DEBUG("setting harddisk type to normal");
E
Eric Blake 已提交
4020 4021 4022
                        }
                        if (def->disks[i]->bus == VIR_DOMAIN_DISK_BUS_IDE) {
                            if (STREQ(def->disks[i]->dst, "hdc")) {
4023
                                VIR_DEBUG("Not connecting harddisk to hdc as hdc"
E
Eric Blake 已提交
4024
                                       " is taken by CD/DVD Drive");
4025
                            } else {
E
Eric Blake 已提交
4026 4027 4028 4029
                                PRInt32 channel          = 0;
                                PRInt32 device           = 0;
                                PRUnichar *hddcnameUtf16 = NULL;

4030 4031
                                char *hddcname;
                                ignore_value(VIR_STRDUP(hddcname, "IDE"));
E
Eric Blake 已提交
4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043
                                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;
4044
                                }
E
Eric Blake 已提交
4045 4046

                                rc = machine->vtbl->AttachHardDisk(machine,
4047
                                                                   hdduuid.value,
E
Eric Blake 已提交
4048 4049 4050 4051 4052 4053
                                                                   hddcnameUtf16,
                                                                   channel,
                                                                   device);
                                VBOX_UTF16_FREE(hddcnameUtf16);

                                if (NS_FAILED(rc)) {
4054 4055 4056
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file as "
                                                     "harddisk: %s, rc=%08x"),
4057
                                                   src, (unsigned)rc);
E
Eric Blake 已提交
4058
                                } else {
4059
                                    DEBUGIID("Attached HDD with UUID", hdduuid.value);
4060 4061 4062
                                }
                            }
                        }
4063
                    }
E
Eric Blake 已提交
4064 4065
                    VBOX_MEDIUM_RELEASE(hardDisk);
                }
4066
                vboxIIDUnalloc(&hdduuid);
E
Eric Blake 已提交
4067 4068
                VBOX_UTF16_FREE(hddEmpty);
                VBOX_UTF16_FREE(hddfileUtf16);
4069
            } else if (type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
E
Eric Blake 已提交
4070 4071
            }
        } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
4072
            if (type == VIR_DOMAIN_DISK_TYPE_FILE && src) {
E
Eric Blake 已提交
4073 4074 4075 4076 4077 4078 4079
                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;
4080 4081
                        vboxIID fduuid = VBOX_IID_INITIALIZER;
                        vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
4082

4083
                        VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
E
Eric Blake 已提交
4084 4085 4086
                        rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                  fdfileUtf16,
                                                                  &floppyImage);
4087

E
Eric Blake 已提交
4088 4089 4090
                        if (!floppyImage) {
                            data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                 fdfileUtf16,
4091
                                                                 fdemptyuuid.value,
E
Eric Blake 已提交
4092 4093
                                                                 &floppyImage);
                        }
4094

E
Eric Blake 已提交
4095 4096
                        if (floppyImage) {
                            rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage,
4097
                                                                  &fduuid.value);
E
Eric Blake 已提交
4098
                            if (NS_FAILED(rc)) {
4099 4100 4101
                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                               _("can't get the uuid of the file to "
                                                 "be attached to floppy drive: %s, rc=%08x"),
4102
                                               src, (unsigned)rc);
E
Eric Blake 已提交
4103 4104
                            } else {
                                rc = floppyDrive->vtbl->MountImage(floppyDrive,
4105
                                                                   fduuid.value);
E
Eric Blake 已提交
4106
                                if (NS_FAILED(rc)) {
4107 4108 4109
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not attach the file to "
                                                     "floppy drive: %s, rc=%08x"),
4110
                                                   src, (unsigned)rc);
E
Eric Blake 已提交
4111
                                } else {
4112
                                    DEBUGIID("floppyImage UUID", fduuid.value);
4113 4114
                                }
                            }
E
Eric Blake 已提交
4115
                            VBOX_MEDIUM_RELEASE(floppyImage);
4116
                        }
4117
                        vboxIIDUnalloc(&fduuid);
E
Eric Blake 已提交
4118
                        VBOX_UTF16_FREE(fdfileUtf16);
4119
                    }
E
Eric Blake 已提交
4120
                    VBOX_RELEASE(floppyDrive);
4121
                }
4122
            } else if (type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
4123
            }
4124
        }
E
Eric Blake 已提交
4125
    }
4126
#else  /* VBOX_API_VERSION >= 3001000 */
E
Eric Blake 已提交
4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138
    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 */
4139
    {
E
Eric Blake 已提交
4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174
        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);
    }
4175

E
Eric Blake 已提交
4176
    for (i = 0; i < def->ndisks && !error; i++) {
4177 4178 4179 4180 4181
        const char *src = virDomainDiskGetSource(def->disks[i]);
        int type = virDomainDiskGetType(def->disks[i]);
        int format = virDomainDiskGetFormat(def->disks[i]);

        VIR_DEBUG("disk(%zu) type:       %d", i, type);
4182 4183
        VIR_DEBUG("disk(%zu) device:     %d", i, def->disks[i]->device);
        VIR_DEBUG("disk(%zu) bus:        %d", i, def->disks[i]->bus);
4184
        VIR_DEBUG("disk(%zu) src:        %s", i, src);
4185
        VIR_DEBUG("disk(%zu) dst:        %s", i, def->disks[i]->dst);
4186 4187
        VIR_DEBUG("disk(%zu) driverName: %s", i,
                  virDomainDiskGetDriver(def->disks[i]));
4188
        VIR_DEBUG("disk(%zu) driverType: %s", i,
4189
                  virStorageFileFormatTypeToString(format));
4190 4191
        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 已提交
4192
                                             ? "True" : "False"));
4193
        VIR_DEBUG("disk(%zu) shared:     %s", i, (def->disks[i]->shared
E
Eric Blake 已提交
4194 4195
                                             ? "True" : "False"));

4196
        if (type == VIR_DOMAIN_DISK_TYPE_FILE && src) {
E
Eric Blake 已提交
4197 4198 4199 4200 4201
            IMedium   *medium          = NULL;
            PRUnichar *mediumUUID      = NULL;
            PRUnichar *mediumFileUtf16 = NULL;
            PRUint32   storageBus      = StorageBus_Null;
            PRUint32   deviceType      = DeviceType_Null;
4202
# if VBOX_API_VERSION >= 4000000
4203
            PRUint32   accessMode      = AccessMode_ReadOnly;
4204
# endif
E
Eric Blake 已提交
4205 4206 4207 4208
            PRInt32    deviceInst      = 0;
            PRInt32    devicePort      = 0;
            PRInt32    deviceSlot      = 0;

4209
            VBOX_UTF8_TO_UTF16(src, &mediumFileUtf16);
E
Eric Blake 已提交
4210 4211 4212

            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                deviceType = DeviceType_HardDisk;
4213
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
4214 4215
                data->vboxObj->vtbl->FindHardDisk(data->vboxObj,
                                                  mediumFileUtf16, &medium);
4216 4217
# else
                accessMode = AccessMode_ReadWrite;
4218
# endif
E
Eric Blake 已提交
4219 4220
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
                deviceType = DeviceType_DVD;
4221
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
4222 4223
                data->vboxObj->vtbl->FindDVDImage(data->vboxObj,
                                                  mediumFileUtf16, &medium);
4224 4225
# else
                accessMode = AccessMode_ReadOnly;
4226
# endif
E
Eric Blake 已提交
4227 4228
            } else if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
                deviceType = DeviceType_Floppy;
4229
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
4230 4231
                data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                     mediumFileUtf16, &medium);
4232 4233
# else
                accessMode = AccessMode_ReadWrite;
4234
# endif
E
Eric Blake 已提交
4235 4236 4237 4238
            } else {
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4239

4240
# if VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
4241 4242
            data->vboxObj->vtbl->FindMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, &medium);
4243
# elif VBOX_API_VERSION >= 4002000
4244 4245
            data->vboxObj->vtbl->OpenMedium(data->vboxObj, mediumFileUtf16,
                                            deviceType, accessMode, PR_FALSE, &medium);
4246 4247
# endif

E
Eric Blake 已提交
4248 4249
            if (!medium) {
                PRUnichar *mediumEmpty = NULL;
4250

E
Eric Blake 已提交
4251
                VBOX_UTF8_TO_UTF16("", &mediumEmpty);
4252

4253
# if VBOX_API_VERSION < 4000000
4254
                if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
4255 4256 4257 4258 4259 4260 4261 4262
                    rc = data->vboxObj->vtbl->OpenHardDisk(data->vboxObj,
                                                           mediumFileUtf16,
                                                           AccessMode_ReadWrite,
                                                           false,
                                                           mediumEmpty,
                                                           false,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
4263 4264
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_CDROM) {
4265 4266 4267 4268
                    rc = data->vboxObj->vtbl->OpenDVDImage(data->vboxObj,
                                                           mediumFileUtf16,
                                                           mediumEmpty,
                                                           &medium);
E
Eric Blake 已提交
4269 4270
                } else if (def->disks[i]->device ==
                           VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
4271 4272 4273 4274 4275 4276
                    rc = data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                              mediumFileUtf16,
                                                              mediumEmpty,
                                                              &medium);
                } else {
                    rc = 0;
4277
                }
4278
# elif VBOX_API_VERSION == 4000000
4279 4280 4281 4282
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     &medium);
4283
# elif VBOX_API_VERSION >= 4001000
4284 4285 4286 4287 4288
                rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj,
                                                     mediumFileUtf16,
                                                     deviceType, accessMode,
                                                     false,
                                                     &medium);
4289
# endif /* VBOX_API_VERSION >= 4001000 */
4290

E
Eric Blake 已提交
4291 4292
                VBOX_UTF16_FREE(mediumEmpty);
            }
4293

E
Eric Blake 已提交
4294
            if (!medium) {
4295 4296 4297
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to attach the following disk/dvd/floppy "
                                 "to the machine: %s, rc=%08x"),
4298
                               src, (unsigned)rc);
E
Eric Blake 已提交
4299 4300 4301
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4302

E
Eric Blake 已提交
4303 4304
            rc = medium->vtbl->GetId(medium, &mediumUUID);
            if (NS_FAILED(rc)) {
4305 4306 4307
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("can't get the uuid of the file to be attached "
                                 "as harddisk/dvd/floppy: %s, rc=%08x"),
4308
                               src, (unsigned)rc);
E
Eric Blake 已提交
4309 4310 4311 4312
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumFileUtf16);
                continue;
            }
4313

E
Eric Blake 已提交
4314 4315 4316
            if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
                if (def->disks[i]->readonly) {
                    medium->vtbl->SetType(medium, MediumType_Immutable);
4317
                    VIR_DEBUG("setting harddisk to immutable");
E
Eric Blake 已提交
4318 4319
                } else if (!def->disks[i]->readonly) {
                    medium->vtbl->SetType(medium, MediumType_Normal);
4320
                    VIR_DEBUG("setting harddisk type to normal");
4321
                }
E
Eric Blake 已提交
4322
            }
4323

E
Eric Blake 已提交
4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336
            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;
            }
4337

E
Eric Blake 已提交
4338 4339 4340 4341 4342 4343 4344 4345
            /* get the device details i.e instance, port and slot */
            if (!vboxGetDeviceDetails(def->disks[i]->dst,
                                      maxPortPerInst,
                                      maxSlotPerPort,
                                      storageBus,
                                      &deviceInst,
                                      &devicePort,
                                      &deviceSlot)) {
4346
                virReportError(VIR_ERR_INTERNAL_ERROR,
4347 4348 4349
                               _("can't get the port/slot number of "
                                 "harddisk/dvd/floppy to be attached: "
                                 "%s, rc=%08x"),
4350
                               src, (unsigned)rc);
4351 4352 4353
                VBOX_RELEASE(medium);
                VBOX_UTF16_FREE(mediumUUID);
                VBOX_UTF16_FREE(mediumFileUtf16);
E
Eric Blake 已提交
4354 4355 4356 4357 4358 4359 4360 4361 4362
                continue;
            }

            /* attach the harddisk/dvd/Floppy to the storage controller */
            rc = machine->vtbl->AttachDevice(machine,
                                             storageCtlName,
                                             devicePort,
                                             deviceSlot,
                                             deviceType,
4363
# if VBOX_API_VERSION < 4000000
E
Eric Blake 已提交
4364
                                             mediumUUID);
4365
# else /* VBOX_API_VERSION >= 4000000 */
4366
                                             medium);
4367
# endif /* VBOX_API_VERSION >= 4000000 */
E
Eric Blake 已提交
4368 4369

            if (NS_FAILED(rc)) {
4370
                virReportError(VIR_ERR_INTERNAL_ERROR,
4371 4372
                               _("could not attach the file as "
                                 "harddisk/dvd/floppy: %s, rc=%08x"),
4373
                               src, (unsigned)rc);
E
Eric Blake 已提交
4374 4375
            } else {
                DEBUGIID("Attached HDD/DVD/Floppy with UUID", mediumUUID);
4376
            }
E
Eric Blake 已提交
4377 4378 4379 4380 4381

            VBOX_RELEASE(medium);
            VBOX_UTF16_FREE(mediumUUID);
            VBOX_UTF16_FREE(mediumFileUtf16);
            VBOX_UTF16_FREE(storageCtlName);
4382 4383
        }
    }
4384
#endif /* VBOX_API_VERSION >= 3001000 */
E
Eric Blake 已提交
4385
}
4386

E
Eric Blake 已提交
4387 4388 4389 4390
static void
vboxAttachSound(virDomainDefPtr def, IMachine *machine)
{
    nsresult rc;
4391

E
Eric Blake 已提交
4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407
    /* 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);
4408
                }
4409
            }
E
Eric Blake 已提交
4410
            VBOX_RELEASE(audioAdapter);
4411
        }
E
Eric Blake 已提交
4412 4413 4414 4415 4416 4417 4418
    }
}

static void
vboxAttachNetwork(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
4419
#if VBOX_API_VERSION >= 4001000
4420
    PRUint32 chipsetType                = ChipsetType_Null;
4421
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4422
    PRUint32 networkAdapterCount        = 0;
4423
    size_t i = 0;
E
Eric Blake 已提交
4424

4425
#if VBOX_API_VERSION >= 4001000
4426
    machine->vtbl->GetChipsetType(machine, &chipsetType);
4427
#endif /* VBOX_API_VERSION >= 4001000 */
4428

E
Eric Blake 已提交
4429 4430
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
4431
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4432 4433
        systemProperties->vtbl->GetNetworkAdapterCount(systemProperties,
                                                       &networkAdapterCount);
4434
#else  /* VBOX_API_VERSION >= 4000000 */
4435 4436
        systemProperties->vtbl->GetMaxNetworkAdapters(systemProperties, chipsetType,
                                                      &networkAdapterCount);
4437
#endif /* VBOX_API_VERSION >= 4000000 */
E
Eric Blake 已提交
4438 4439 4440 4441
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }

4442
    VIR_DEBUG("Number of Network Cards to be connected: %zu", def->nnets);
4443
    VIR_DEBUG("Number of Network Cards available: %d", networkAdapterCount);
E
Eric Blake 已提交
4444 4445 4446 4447 4448 4449 4450

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

4451
        virMacAddrFormat(&def->nets[i]->mac, macaddr);
E
Eric Blake 已提交
4452 4453
        snprintf(macaddrvbox, VIR_MAC_STRING_BUFLEN - 5,
                 "%02X%02X%02X%02X%02X%02X",
4454 4455 4456 4457 4458 4459
                 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 已提交
4460 4461
        macaddrvbox[VIR_MAC_STRING_BUFLEN - 6] = '\0';

4462 4463 4464 4465
        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 已提交
4466
        if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
4467
            VIR_DEBUG("NIC(%zu): name:    %s", i, def->nets[i]->data.network.name);
E
Eric Blake 已提交
4468
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
4469
            VIR_DEBUG("NIC(%zu): name:   %s", i, def->nets[i]->data.internal.name);
E
Eric Blake 已提交
4470
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
4471
            VIR_DEBUG("NIC(%zu): NAT.", i);
E
Eric Blake 已提交
4472
        } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
4473 4474 4475
            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);
4476 4477
        }

E
Eric Blake 已提交
4478 4479 4480 4481 4482
        machine->vtbl->GetNetworkAdapter(machine, i, &adapter);
        if (adapter) {
            PRUnichar *MACAddress = NULL;

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

E
Eric Blake 已提交
4484
            if (def->nets[i]->model) {
E
Eric Blake 已提交
4485
                if (STRCASEEQ(def->nets[i]->model, "Am79C970A")) {
E
Eric Blake 已提交
4486
                    adapterType = NetworkAdapterType_Am79C970A;
E
Eric Blake 已提交
4487
                } else if (STRCASEEQ(def->nets[i]->model, "Am79C973")) {
E
Eric Blake 已提交
4488
                    adapterType = NetworkAdapterType_Am79C973;
E
Eric Blake 已提交
4489
                } else if (STRCASEEQ(def->nets[i]->model, "82540EM")) {
E
Eric Blake 已提交
4490
                    adapterType = NetworkAdapterType_I82540EM;
E
Eric Blake 已提交
4491
                } else if (STRCASEEQ(def->nets[i]->model, "82545EM")) {
E
Eric Blake 已提交
4492
                    adapterType = NetworkAdapterType_I82545EM;
E
Eric Blake 已提交
4493
                } else if (STRCASEEQ(def->nets[i]->model, "82543GC")) {
E
Eric Blake 已提交
4494
                    adapterType = NetworkAdapterType_I82543GC;
4495
#if VBOX_API_VERSION >= 3001000
E
Eric Blake 已提交
4496
                } else if (STRCASEEQ(def->nets[i]->model, "virtio")) {
E
Eric Blake 已提交
4497
                    adapterType = NetworkAdapterType_Virtio;
4498
#endif /* VBOX_API_VERSION >= 3001000 */
4499
                }
E
Eric Blake 已提交
4500 4501 4502
            } else {
                adapterType = NetworkAdapterType_Am79C973;
            }
4503

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

E
Eric Blake 已提交
4506 4507 4508
            if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
                PRUnichar *hostInterface = NULL;
                /* Bridged Network */
4509

4510
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4511
                adapter->vtbl->AttachToBridgedInterface(adapter);
4512
#else /* VBOX_API_VERSION >= 4001000 */
4513
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Bridged);
4514
#endif /* VBOX_API_VERSION >= 4001000 */
4515

E
Eric Blake 已提交
4516 4517 4518
                if (def->nets[i]->data.bridge.brname) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.bridge.brname,
                                       &hostInterface);
4519
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4520
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4521
#else /* VBOX_API_VERSION >= 4001000 */
4522
                    adapter->vtbl->SetBridgedInterface(adapter, hostInterface);
4523
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4524 4525 4526 4527 4528
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_INTERNAL) {
                PRUnichar *internalNetwork = NULL;
                /* Internal Network */
4529

4530
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4531
                adapter->vtbl->AttachToInternalNetwork(adapter);
4532
#else /* VBOX_API_VERSION >= 4001000 */
4533
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_Internal);
4534
#endif /* VBOX_API_VERSION >= 4001000 */
4535

E
Eric Blake 已提交
4536 4537 4538 4539 4540
                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);
4541
                }
E
Eric Blake 已提交
4542 4543 4544 4545 4546 4547
            } 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)
                 */
4548
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4549
                adapter->vtbl->AttachToHostOnlyInterface(adapter);
4550
#else /* VBOX_API_VERSION >= 4001000 */
4551
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_HostOnly);
4552
#endif /* VBOX_API_VERSION >= 4001000 */
4553

E
Eric Blake 已提交
4554 4555 4556
                if (def->nets[i]->data.network.name) {
                    VBOX_UTF8_TO_UTF16(def->nets[i]->data.network.name,
                                       &hostInterface);
4557
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4558
                    adapter->vtbl->SetHostInterface(adapter, hostInterface);
4559
#else /* VBOX_API_VERSION >= 4001000 */
4560
                    adapter->vtbl->SetHostOnlyInterface(adapter, hostInterface);
4561
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4562 4563 4564 4565
                    VBOX_UTF16_FREE(hostInterface);
                }
            } else if (def->nets[i]->type == VIR_DOMAIN_NET_TYPE_USER) {
                /* NAT */
4566
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4567
                adapter->vtbl->AttachToNAT(adapter);
4568
#else /* VBOX_API_VERSION >= 4001000 */
4569
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
4570
#endif /* VBOX_API_VERSION >= 4001000 */
E
Eric Blake 已提交
4571 4572 4573 4574
            } else {
                /* else always default to NAT if we don't understand
                 * what option is been passed to us
                 */
4575
#if VBOX_API_VERSION < 4001000
E
Eric Blake 已提交
4576
                adapter->vtbl->AttachToNAT(adapter);
4577
#else /* VBOX_API_VERSION >= 4001000 */
4578
                adapter->vtbl->SetAttachmentType(adapter, NetworkAttachmentType_NAT);
4579
#endif /* VBOX_API_VERSION >= 4001000 */
4580
            }
E
Eric Blake 已提交
4581 4582 4583 4584

            VBOX_UTF8_TO_UTF16(macaddrvbox, &MACAddress);
            adapter->vtbl->SetMACAddress(adapter, MACAddress);
            VBOX_UTF16_FREE(MACAddress);
4585
        }
E
Eric Blake 已提交
4586 4587 4588 4589 4590 4591 4592 4593
    }
}

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

E
Eric Blake 已提交
4596 4597 4598 4599 4600 4601 4602
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetSerialPortCount(systemProperties,
                                                   &serialPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4603

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

4609 4610
        VIR_DEBUG("SerialPort(%zu): Type: %d", i, def->serials[i]->source.type);
        VIR_DEBUG("SerialPort(%zu): target.port: %d", i,
E
Eric Blake 已提交
4611
              def->serials[i]->target.port);
4612

E
Eric Blake 已提交
4613 4614 4615
        machine->vtbl->GetSerialPort(machine, i, &serialPort);
        if (serialPort) {
            PRUnichar *pathUtf16 = NULL;
4616

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

4619 4620 4621
            if (def->serials[i]->source.data.file.path) {
                VBOX_UTF8_TO_UTF16(def->serials[i]->source.data.file.path,
                                   &pathUtf16);
E
Eric Blake 已提交
4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636
                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);
4637
                VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4638
                      i, 4, 1016, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4639 4640 4641
            } else if (def->serials[i]->target.port == 1) {
                serialPort->vtbl->SetIRQ(serialPort, 3);
                serialPort->vtbl->SetIOBase(serialPort, 760);
4642
                VIR_DEBUG(" serialPort-%zu irq: %d, iobase 0x%x, path: %s",
4643
                      i, 3, 760, def->serials[i]->source.data.file.path);
E
Eric Blake 已提交
4644
            }
4645

4646
            if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_DEV) {
E
Eric Blake 已提交
4647
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostDevice);
4648
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_PIPE) {
E
Eric Blake 已提交
4649
                serialPort->vtbl->SetHostMode(serialPort, PortMode_HostPipe);
4650
#if VBOX_API_VERSION >= 3000000
4651
            } else if (def->serials[i]->source.type == VIR_DOMAIN_CHR_TYPE_FILE) {
E
Eric Blake 已提交
4652
                serialPort->vtbl->SetHostMode(serialPort, PortMode_RawFile);
4653
#endif /* VBOX_API_VERSION >= 3000000 */
E
Eric Blake 已提交
4654 4655 4656 4657
            } else {
                serialPort->vtbl->SetHostMode(serialPort,
                                              PortMode_Disconnected);
            }
4658

E
Eric Blake 已提交
4659
            VBOX_RELEASE(serialPort);
J
John Ferlan 已提交
4660
            VBOX_UTF16_FREE(pathUtf16);
4661
        }
E
Eric Blake 已提交
4662 4663
    }
}
4664

E
Eric Blake 已提交
4665 4666 4667 4668 4669
static void
vboxAttachParallel(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    ISystemProperties *systemProperties = NULL;
    PRUint32 parallelPortCount          = 0;
4670
    size_t i = 0;
4671

E
Eric Blake 已提交
4672 4673 4674 4675 4676 4677 4678
    data->vboxObj->vtbl->GetSystemProperties(data->vboxObj, &systemProperties);
    if (systemProperties) {
        systemProperties->vtbl->GetParallelPortCount(systemProperties,
                                                     &parallelPortCount);
        VBOX_RELEASE(systemProperties);
        systemProperties = NULL;
    }
4679

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

4685 4686
        VIR_DEBUG("ParallelPort(%zu): Type: %d", i, def->parallels[i]->source.type);
        VIR_DEBUG("ParallelPort(%zu): target.port: %d", i,
E
Eric Blake 已提交
4687
              def->parallels[i]->target.port);
4688

E
Eric Blake 已提交
4689 4690 4691
        machine->vtbl->GetParallelPort(machine, i, &parallelPort);
        if (parallelPort) {
            PRUnichar *pathUtf16 = NULL;
4692

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

E
Eric Blake 已提交
4695 4696 4697 4698 4699
            /* 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
             */
4700 4701 4702 4703
            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 已提交
4704 4705 4706 4707
                parallelPort->vtbl->SetPath(parallelPort, pathUtf16);
                if (i == 0) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 7);
                    parallelPort->vtbl->SetIOBase(parallelPort, 888);
4708
                    VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4709
                          i, 7, 888, def->parallels[i]->source.data.file.path);
E
Eric Blake 已提交
4710 4711 4712
                } else if (i == 1) {
                    parallelPort->vtbl->SetIRQ(parallelPort, 5);
                    parallelPort->vtbl->SetIOBase(parallelPort, 632);
4713
                    VIR_DEBUG(" parallePort-%zu irq: %d, iobase 0x%x, path: %s",
4714
                          i, 5, 632, def->parallels[i]->source.data.file.path);
4715 4716
                }
            }
E
Eric Blake 已提交
4717 4718 4719 4720 4721 4722 4723

            /* 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 已提交
4724
            VBOX_UTF16_FREE(pathUtf16);
4725
        }
E
Eric Blake 已提交
4726 4727 4728 4729 4730 4731 4732 4733
    }
}

static void
vboxAttachVideo(virDomainDefPtr def, IMachine *machine)
{
    if ((def->nvideos == 1) &&
        (def->videos[0]->type == VIR_DOMAIN_VIDEO_TYPE_VBOX)) {
4734 4735
        machine->vtbl->SetVRAMSize(machine,
                                   VIR_DIV_UP(def->videos[0]->vram, 1024));
E
Eric Blake 已提交
4736 4737 4738 4739
        machine->vtbl->SetMonitorCount(machine, def->videos[0]->heads);
        if (def->videos[0]->accel) {
            machine->vtbl->SetAccelerate3DEnabled(machine,
                                                  def->videos[0]->accel->support3d);
4740
#if VBOX_API_VERSION >= 3001000
E
Eric Blake 已提交
4741 4742
            machine->vtbl->SetAccelerate2DVideoEnabled(machine,
                                                       def->videos[0]->accel->support2d);
4743
#endif /* VBOX_API_VERSION >= 3001000 */
E
Eric Blake 已提交
4744 4745
        } else {
            machine->vtbl->SetAccelerate3DEnabled(machine, 0);
4746
#if VBOX_API_VERSION >= 3001000
E
Eric Blake 已提交
4747
            machine->vtbl->SetAccelerate2DVideoEnabled(machine, 0);
4748
#endif /* VBOX_API_VERSION >= 3001000 */
4749
        }
E
Eric Blake 已提交
4750 4751
    }
}
4752

E
Eric Blake 已提交
4753 4754 4755 4756 4757 4758 4759 4760
static void
vboxAttachDisplay(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
    int vrdpPresent  = 0;
    int sdlPresent   = 0;
    int guiPresent   = 0;
    char *guiDisplay = NULL;
    char *sdlDisplay = NULL;
4761
    size_t i = 0;
4762

E
Eric Blake 已提交
4763
    for (i = 0; i < def->ngraphics; i++) {
4764
#if VBOX_API_VERSION < 4000000
4765
        IVRDPServer *VRDxServer = NULL;
4766
#else /* VBOX_API_VERSION >= 4000000 */
4767
        IVRDEServer *VRDxServer = NULL;
4768
#endif /* VBOX_API_VERSION >= 4000000 */
4769

E
Eric Blake 已提交
4770 4771
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_RDP) &&
            (vrdpPresent == 0)) {
4772

E
Eric Blake 已提交
4773
            vrdpPresent = 1;
4774
#if VBOX_API_VERSION < 4000000
4775
            machine->vtbl->GetVRDPServer(machine, &VRDxServer);
4776
#else /* VBOX_API_VERSION >= 4000000 */
4777
            machine->vtbl->GetVRDEServer(machine, &VRDxServer);
4778
#endif /* VBOX_API_VERSION >= 4000000 */
4779
            if (VRDxServer) {
4780 4781 4782
                const char *listenAddr
                    = virDomainGraphicsListenGetAddress(def->graphics[i], 0);

4783
                VRDxServer->vtbl->SetEnabled(VRDxServer, PR_TRUE);
4784
                VIR_DEBUG("VRDP Support turned ON.");
4785

4786
#if VBOX_API_VERSION < 3001000
E
Eric Blake 已提交
4787
                if (def->graphics[i]->data.rdp.port) {
4788
                    VRDxServer->vtbl->SetPort(VRDxServer,
E
Eric Blake 已提交
4789
                                              def->graphics[i]->data.rdp.port);
4790
                    VIR_DEBUG("VRDP Port changed to: %d",
E
Eric Blake 已提交
4791 4792 4793 4794 4795
                          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
                     */
4796
                    VRDxServer->vtbl->SetPort(VRDxServer, 0);
4797
                    VIR_DEBUG("VRDP Port changed to default, which is 3389 currently");
E
Eric Blake 已提交
4798
                }
4799
#elif VBOX_API_VERSION < 4000000 /* 3001000 <= VBOX_API_VERSION < 4000000 */
E
Eric Blake 已提交
4800 4801
                PRUnichar *portUtf16 = NULL;
                portUtf16 = PRUnicharFromInt(def->graphics[i]->data.rdp.port);
4802
                VRDxServer->vtbl->SetPorts(VRDxServer, portUtf16);
E
Eric Blake 已提交
4803
                VBOX_UTF16_FREE(portUtf16);
4804
#else /* VBOX_API_VERSION >= 4000000 */
4805 4806 4807 4808 4809 4810 4811 4812
                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);
4813
#endif /* VBOX_API_VERSION >= 4000000 */
4814

E
Eric Blake 已提交
4815
                if (def->graphics[i]->data.rdp.replaceUser) {
4816
                    VRDxServer->vtbl->SetReuseSingleConnection(VRDxServer,
E
Eric Blake 已提交
4817
                                                               PR_TRUE);
4818
                    VIR_DEBUG("VRDP set to reuse single connection");
E
Eric Blake 已提交
4819
                }
4820

E
Eric Blake 已提交
4821
                if (def->graphics[i]->data.rdp.multiUser) {
4822
                    VRDxServer->vtbl->SetAllowMultiConnection(VRDxServer,
E
Eric Blake 已提交
4823
                                                              PR_TRUE);
4824
                    VIR_DEBUG("VRDP set to allow multiple connection");
E
Eric Blake 已提交
4825
                }
4826

4827
                if (listenAddr) {
4828
#if VBOX_API_VERSION >= 4000000
4829 4830
                    PRUnichar *netAddressKey = NULL;
#endif
E
Eric Blake 已提交
4831
                    PRUnichar *netAddressUtf16 = NULL;
4832

4833
                    VBOX_UTF8_TO_UTF16(listenAddr, &netAddressUtf16);
4834
#if VBOX_API_VERSION < 4000000
4835
                    VRDxServer->vtbl->SetNetAddress(VRDxServer,
E
Eric Blake 已提交
4836
                                                    netAddressUtf16);
4837
#else /* VBOX_API_VERSION >= 4000000 */
4838 4839 4840 4841
                    VBOX_UTF8_TO_UTF16("TCP/Address", &netAddressKey);
                    VRDxServer->vtbl->SetVRDEProperty(VRDxServer, netAddressKey,
                                                      netAddressUtf16);
                    VBOX_UTF16_FREE(netAddressKey);
4842
#endif /* VBOX_API_VERSION >= 4000000 */
4843
                    VIR_DEBUG("VRDP listen address is set to: %s",
4844
                              listenAddr);
4845

E
Eric Blake 已提交
4846
                    VBOX_UTF16_FREE(netAddressUtf16);
4847
                }
E
Eric Blake 已提交
4848

4849
                VBOX_RELEASE(VRDxServer);
4850
            }
E
Eric Blake 已提交
4851
        }
4852

E
Eric Blake 已提交
4853 4854 4855
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_DESKTOP) &&
            (guiPresent == 0)) {
            guiPresent = 1;
4856 4857 4858 4859 4860
            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
                 */
4861
            }
E
Eric Blake 已提交
4862
        }
4863

E
Eric Blake 已提交
4864 4865 4866
        if ((def->graphics[i]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) &&
            (sdlPresent == 0)) {
            sdlPresent = 1;
4867 4868 4869 4870 4871
            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
                 */
4872
            }
4873
        }
E
Eric Blake 已提交
4874
    }
4875

E
Eric Blake 已提交
4876 4877 4878 4879
    if ((vrdpPresent == 1) && (guiPresent == 0) && (sdlPresent == 0)) {
        /* store extradata key that frontend is set to vrdp */
        PRUnichar *keyTypeUtf16   = NULL;
        PRUnichar *valueTypeUtf16 = NULL;
4880

E
Eric Blake 已提交
4881 4882
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("vrdp", &valueTypeUtf16);
4883

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

E
Eric Blake 已提交
4886 4887
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4888

E
Eric Blake 已提交
4889 4890 4891 4892 4893 4894
    } 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;
4895

E
Eric Blake 已提交
4896 4897
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("sdl", &valueTypeUtf16);
4898

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

E
Eric Blake 已提交
4901 4902
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4903

E
Eric Blake 已提交
4904 4905 4906
        if (sdlDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(sdlDisplay, &valueDisplayUtf16);
4907

E
Eric Blake 已提交
4908 4909
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4910

E
Eric Blake 已提交
4911 4912 4913
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
        }
4914

E
Eric Blake 已提交
4915 4916 4917 4918 4919 4920
    } 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;
4921

E
Eric Blake 已提交
4922 4923
        VBOX_UTF8_TO_UTF16("FRONTEND/Type", &keyTypeUtf16);
        VBOX_UTF8_TO_UTF16("gui", &valueTypeUtf16);
4924

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

E
Eric Blake 已提交
4927 4928
        VBOX_UTF16_FREE(keyTypeUtf16);
        VBOX_UTF16_FREE(valueTypeUtf16);
4929

E
Eric Blake 已提交
4930 4931 4932
        if (guiDisplay) {
            VBOX_UTF8_TO_UTF16("FRONTEND/Display", &keyDislpayUtf16);
            VBOX_UTF8_TO_UTF16(guiDisplay, &valueDisplayUtf16);
4933

E
Eric Blake 已提交
4934 4935
            machine->vtbl->SetExtraData(machine, keyDislpayUtf16,
                                        valueDisplayUtf16);
4936

E
Eric Blake 已提交
4937 4938
            VBOX_UTF16_FREE(keyDislpayUtf16);
            VBOX_UTF16_FREE(valueDisplayUtf16);
4939
        }
E
Eric Blake 已提交
4940
    }
4941

E
Eric Blake 已提交
4942 4943 4944
    VIR_FREE(guiDisplay);
    VIR_FREE(sdlDisplay);
}
4945

E
Eric Blake 已提交
4946 4947 4948
static void
vboxAttachUSB(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
4949
#if VBOX_API_VERSION < 4003000
E
Eric Blake 已提交
4950
    IUSBController *USBController = NULL;
R
Ryota Ozaki 已提交
4951 4952 4953
#else
    IUSBDeviceFilters *USBDeviceFilters = NULL;
#endif
4954
    size_t i = 0;
E
Eric Blake 已提交
4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965
    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 已提交
4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981
        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 已提交
4982 4983
    }

R
Ryota Ozaki 已提交
4984 4985 4986
    if (!isUSB)
        return;

4987
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
4988 4989 4990 4991 4992 4993 4994 4995 4996
    /* 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);
4997
# if VBOX_API_VERSION < 4002000
R
Ryota Ozaki 已提交
4998
    USBController->vtbl->SetEnabledEhci(USBController, 1);
R
Ryota Ozaki 已提交
4999
# else
R
Ryota Ozaki 已提交
5000
    USBController->vtbl->SetEnabledEHCI(USBController, 1);
R
Ryota Ozaki 已提交
5001 5002 5003 5004 5005 5006
# endif
#else
    machine->vtbl->GetUSBDeviceFilters(machine, &USBDeviceFilters);

    if (!USBDeviceFilters)
        return;
5007
#endif
5008

R
Ryota Ozaki 已提交
5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019
    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;
5020

R
Ryota Ozaki 已提交
5021 5022 5023
        if (def->hostdevs[i]->source.subsys.type !=
            VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            continue;
5024

R
Ryota Ozaki 已提交
5025 5026 5027 5028 5029 5030
        /* 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);
5031
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
5032 5033 5034
            USBController->vtbl->CreateDeviceFilter(USBController,
                                                    filternameUtf16,
                                                    &filter);
R
Ryota Ozaki 已提交
5035 5036 5037 5038 5039
#else
            USBDeviceFilters->vtbl->CreateDeviceFilter(USBDeviceFilters,
                                                       filternameUtf16,
                                                       &filter);
#endif
R
Ryota Ozaki 已提交
5040 5041
        }
        VBOX_UTF16_FREE(filternameUtf16);
E
Eric Blake 已提交
5042

R
Ryota Ozaki 已提交
5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063
        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 已提交
5064
        }
R
Ryota Ozaki 已提交
5065
        filter->vtbl->SetActive(filter, 1);
5066
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
5067 5068 5069
        USBController->vtbl->InsertDeviceFilter(USBController,
                                                i,
                                                filter);
R
Ryota Ozaki 已提交
5070 5071 5072 5073 5074
#else
        USBDeviceFilters->vtbl->InsertDeviceFilter(USBDeviceFilters,
                                                   i,
                                                   filter);
#endif
R
Ryota Ozaki 已提交
5075
        VBOX_RELEASE(filter);
E
Eric Blake 已提交
5076
    }
R
Ryota Ozaki 已提交
5077

5078
#if VBOX_API_VERSION < 4003000
R
Ryota Ozaki 已提交
5079
    VBOX_RELEASE(USBController);
R
Ryota Ozaki 已提交
5080 5081 5082
#else
    VBOX_RELEASE(USBDeviceFilters);
#endif
E
Eric Blake 已提交
5083 5084
}

M
Matthias Bolte 已提交
5085 5086 5087
static void
vboxAttachSharedFolder(virDomainDefPtr def, vboxGlobalData *data, IMachine *machine)
{
5088
    size_t i;
M
Matthias Bolte 已提交
5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103
    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;

5104
#if VBOX_API_VERSION < 4000000
M
Matthias Bolte 已提交
5105 5106
        machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                          writable);
5107
#else /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
5108 5109
        machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                          writable, PR_FALSE);
5110
#endif /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
5111 5112 5113 5114 5115 5116

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

5117 5118
static virDomainPtr vboxDomainDefineXML(virConnectPtr conn, const char *xml)
{
E
Eric Blake 已提交
5119 5120 5121
    VBOX_OBJECT_CHECK(conn, virDomainPtr, NULL);
    IMachine       *machine     = NULL;
    IBIOSSettings  *bios        = NULL;
5122 5123
    vboxIID iid = VBOX_IID_INITIALIZER;
    vboxIID mchiid = VBOX_IID_INITIALIZER;
E
Eric Blake 已提交
5124 5125
    virDomainDefPtr def         = NULL;
    PRUnichar *machineNameUtf16 = NULL;
5126
#if VBOX_API_VERSION >= 3002000 && VBOX_API_VERSION < 4002000
E
Eric Blake 已提交
5127 5128 5129
    PRBool override             = PR_FALSE;
#endif
    nsresult rc;
5130
    char uuidstr[VIR_UUID_STRING_BUFLEN];
5131
#if VBOX_API_VERSION >= 4002000
5132 5133 5134 5135 5136 5137
    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 已提交
5138

5139 5140
    if (!(def = virDomainDefParseString(xml, data->caps, data->xmlopt,
                                        1 << VIR_DOMAIN_VIRT_VBOX,
E
Eric Blake 已提交
5141 5142 5143 5144 5145
                                        VIR_DOMAIN_XML_INACTIVE))) {
        goto cleanup;
    }

    VBOX_UTF8_TO_UTF16(def->name, &machineNameUtf16);
5146
    vboxIIDFromUUID(&iid, def->uuid);
5147 5148
    virUUIDFormat(def->uuid, uuidstr);

5149
#if VBOX_API_VERSION < 3002000
E
Eric Blake 已提交
5150 5151 5152 5153
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
5154
                                            iid.value,
E
Eric Blake 已提交
5155
                                            &machine);
5156
#elif VBOX_API_VERSION < 4000000 /* 3002000 <= VBOX_API_VERSION < 4000000 */
E
Eric Blake 已提交
5157 5158 5159 5160
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            machineNameUtf16,
                                            NULL,
                                            NULL,
5161
                                            iid.value,
E
Eric Blake 已提交
5162 5163
                                            override,
                                            &machine);
5164
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
5165 5166 5167 5168 5169 5170 5171
    rc = data->vboxObj->vtbl->CreateMachine(data->vboxObj,
                                            NULL,
                                            machineNameUtf16,
                                            NULL,
                                            iid.value,
                                            override,
                                            &machine);
5172
#else /* VBOX_API_VERSION >= 4002000 */
5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187
    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);
5188
#endif /* VBOX_API_VERSION >= 4002000 */
E
Eric Blake 已提交
5189 5190 5191
    VBOX_UTF16_FREE(machineNameUtf16);

    if (NS_FAILED(rc)) {
5192 5193
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
5194 5195 5196
        goto cleanup;
    }

5197 5198
    rc = machine->vtbl->SetMemorySize(machine,
                                      VIR_DIV_UP(def->mem.cur_balloon, 1024));
E
Eric Blake 已提交
5199
    if (NS_FAILED(rc)) {
5200 5201 5202 5203
        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 已提交
5204 5205
    }

E
Eric Blake 已提交
5206
    if (def->vcpus != def->maxvcpus) {
5207 5208
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("current vcpu count must equal maximum"));
E
Eric Blake 已提交
5209 5210
    }
    rc = machine->vtbl->SetCPUCount(machine, def->maxvcpus);
E
Eric Blake 已提交
5211
    if (NS_FAILED(rc)) {
5212 5213 5214
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not set the number of virtual CPUs to: %u, rc=%08x"),
                       def->maxvcpus, (unsigned)rc);
E
Eric Blake 已提交
5215 5216
    }

5217
#if VBOX_API_VERSION < 3001000
5218 5219 5220
    rc = machine->vtbl->SetPAEEnabled(machine,
                                      def->features[VIR_DOMAIN_FEATURE_PAE] ==
                                      VIR_DOMAIN_FEATURE_STATE_ON);
5221
#elif VBOX_API_VERSION == 3001000
E
Eric Blake 已提交
5222
    rc = machine->vtbl->SetCpuProperty(machine, CpuPropertyType_PAE,
5223 5224
                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
                                       VIR_DOMAIN_FEATURE_STATE_ON);
5225
#elif VBOX_API_VERSION >= 3002000
E
Eric Blake 已提交
5226
    rc = machine->vtbl->SetCPUProperty(machine, CPUPropertyType_PAE,
5227 5228
                                       def->features[VIR_DOMAIN_FEATURE_PAE] ==
                                       VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5229 5230
#endif
    if (NS_FAILED(rc)) {
5231 5232
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not change PAE status to: %s, rc=%08x"),
5233
                       (def->features[VIR_DOMAIN_FEATURE_PAE] == VIR_DOMAIN_FEATURE_STATE_ON)
5234
                       ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
5235 5236 5237 5238
    }

    machine->vtbl->GetBIOSSettings(machine, &bios);
    if (bios) {
5239 5240 5241
        rc = bios->vtbl->SetACPIEnabled(bios,
                                        def->features[VIR_DOMAIN_FEATURE_ACPI] ==
                                        VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5242
        if (NS_FAILED(rc)) {
5243 5244
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change ACPI status to: %s, rc=%08x"),
5245
                           (def->features[VIR_DOMAIN_FEATURE_ACPI] == VIR_DOMAIN_FEATURE_STATE_ON)
5246
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
E
Eric Blake 已提交
5247
        }
5248 5249 5250
        rc = bios->vtbl->SetIOAPICEnabled(bios,
                                          def->features[VIR_DOMAIN_FEATURE_APIC] ==
                                          VIR_DOMAIN_FEATURE_STATE_ON);
E
Eric Blake 已提交
5251
        if (NS_FAILED(rc)) {
5252 5253
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not change APIC status to: %s, rc=%08x"),
5254
                           (def->features[VIR_DOMAIN_FEATURE_APIC] == VIR_DOMAIN_FEATURE_STATE_ON)
5255
                           ? _("Enabled") : _("Disabled"), (unsigned)rc);
5256
        }
E
Eric Blake 已提交
5257 5258 5259 5260 5261 5262
        VBOX_RELEASE(bios);
    }

    /* Register the machine before attaching other devices to it */
    rc = data->vboxObj->vtbl->RegisterMachine(data->vboxObj, machine);
    if (NS_FAILED(rc)) {
5263 5264
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not define a domain, rc=%08x"), (unsigned)rc);
E
Eric Blake 已提交
5265 5266 5267 5268 5269 5270 5271
        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
     */
5272
    machine->vtbl->GetId(machine, &mchiid.value);
5273
    VBOX_SESSION_OPEN(mchiid.value, machine);
E
Eric Blake 已提交
5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284
    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 已提交
5285
    vboxAttachSharedFolder(def, data, machine);
5286

5287 5288 5289 5290
    /* Save the machine settings made till now and close the
     * session. also free up the mchiid variable used.
     */
    rc = machine->vtbl->SaveSettings(machine);
5291
    VBOX_SESSION_CLOSE();
5292
    vboxIIDUnalloc(&mchiid);
5293

5294 5295
    ret = virGetDomain(conn, def->name, def->uuid);
    VBOX_RELEASE(machine);
5296

5297
    vboxIIDUnalloc(&iid);
5298 5299
    virDomainDefFree(def);

5300
    return ret;
5301 5302

cleanup:
5303
    VBOX_RELEASE(machine);
5304
    vboxIIDUnalloc(&iid);
5305 5306 5307 5308
    virDomainDefFree(def);
    return NULL;
}

5309
static int
5310
vboxDomainUndefineFlags(virDomainPtr dom, unsigned int flags)
5311
{
5312
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5313
    IMachine *machine    = NULL;
5314
    vboxIID iid = VBOX_IID_INITIALIZER;
5315
    nsresult rc;
5316
#if VBOX_API_VERSION >= 4000000
5317 5318
    vboxArray media = VBOX_ARRAY_INITIALIZER;
#endif
5319 5320 5321 5322
    /* 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);
5323

5324
    vboxIIDFromUUID(&iid, dom->uuid);
5325

5326
#if VBOX_API_VERSION < 4000000
5327 5328 5329
    /* 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
5330 5331 5332 5333
     * 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.
5334 5335 5336
     */
    {
        PRUnichar *hddcnameUtf16 = NULL;
5337

5338 5339
        char *hddcname;
        ignore_value(VIR_STRDUP(hddcname, "IDE"));
5340 5341
        VBOX_UTF8_TO_UTF16(hddcname, &hddcnameUtf16);
        VIR_FREE(hddcname);
5342

5343
        /* Open a Session for the machine */
5344
        rc = VBOX_SESSION_OPEN(iid.value, machine);
5345 5346 5347 5348
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {

5349
# if VBOX_API_VERSION < 3001000
5350 5351 5352 5353
                /* 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);
5354
# else  /* VBOX_API_VERSION >= 3001000 */
5355 5356 5357
                /* get all the controller first, then the attachments and
                 * remove them all so that the machine can be undefined
                 */
5358
                vboxArray storageControllers = VBOX_ARRAY_INITIALIZER;
5359
                size_t i = 0, j = 0;
5360

5361 5362
                vboxArrayGet(&storageControllers, machine,
                             machine->vtbl->GetStorageControllers);
5363

5364 5365
                for (i = 0; i < storageControllers.count; i++) {
                    IStorageController *strCtl = storageControllers.items[i];
5366
                    PRUnichar *strCtlName = NULL;
5367
                    vboxArray mediumAttachments = VBOX_ARRAY_INITIALIZER;
5368 5369 5370 5371 5372

                    if (!strCtl)
                        continue;

                    strCtl->vtbl->GetName(strCtl, &strCtlName);
5373 5374 5375
                    vboxArrayGetWithPtrArg(&mediumAttachments, machine,
                                           machine->vtbl->GetMediumAttachmentsOfController,
                                           strCtlName);
5376

5377 5378
                    for (j = 0; j < mediumAttachments.count; j++) {
                        IMediumAttachment *medAtt = mediumAttachments.items[j];
5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394
                        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);
                        }
                    }
5395

5396 5397
                    vboxArrayRelease(&storageControllers);

5398 5399
                    machine->vtbl->RemoveStorageController(machine, strCtlName);
                    VBOX_UTF16_FREE(strCtlName);
5400
                }
5401 5402

                vboxArrayRelease(&storageControllers);
5403
# endif /* VBOX_API_VERSION >= 3001000 */
5404 5405

                machine->vtbl->SaveSettings(machine);
5406
            }
5407
            VBOX_SESSION_CLOSE();
5408
        }
5409 5410
        VBOX_UTF16_FREE(hddcnameUtf16);
    }
5411
#endif
5412

5413
#if VBOX_API_VERSION < 4000000
5414
    rc = data->vboxObj->vtbl->UnregisterMachine(data->vboxObj, iid.value, &machine);
5415
#else /* VBOX_API_VERSION >= 4000000 */
5416 5417
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
5418 5419
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5420 5421 5422 5423 5424 5425 5426 5427 5428
        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);
5429
#endif /* VBOX_API_VERSION >= 4000000 */
5430
    DEBUGIID("UUID of machine being undefined", iid.value);
5431

5432
    if (NS_SUCCEEDED(rc)) {
5433
#if VBOX_API_VERSION < 4000000
5434
        machine->vtbl->DeleteSettings(machine);
5435
#else /* VBOX_API_VERSION >= 4000000 */
5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448
        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);

5449
#  if VBOX_API_VERSION < 4003000
5450
        ((IMachine_Delete)machine->vtbl->Delete)(machine, &safeArray, &progress);
R
Ryota Ozaki 已提交
5451 5452 5453
#  else
        ((IMachine_Delete)machine->vtbl->DeleteConfig)(machine, &safeArray, &progress);
#  endif
5454
# else
5455 5456 5457
        /* 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 };
5458
#  if VBOX_API_VERSION < 4003000
5459
        machine->vtbl->Delete(machine, 0, array, &progress);
R
Ryota Ozaki 已提交
5460 5461 5462
#  else
        machine->vtbl->DeleteConfig(machine, 0, array, &progress);
#  endif
5463 5464 5465 5466 5467
# endif
        if (progress != NULL) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
5468
#endif /* VBOX_API_VERSION >= 4000000 */
5469 5470
        ret = 0;
    } else {
5471 5472
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not delete the domain, rc=%08x"), (unsigned)rc);
5473 5474
    }

5475
#if VBOX_API_VERSION >= 4000000
5476 5477
    vboxArrayUnalloc(&media);
#endif
5478
    vboxIIDUnalloc(&iid);
5479
    VBOX_RELEASE(machine);
5480 5481 5482 5483

    return ret;
}

5484 5485 5486 5487 5488 5489
static int
vboxDomainUndefine(virDomainPtr dom)
{
    return vboxDomainUndefineFlags(dom, 0);
}

5490 5491
static int vboxDomainAttachDeviceImpl(virDomainPtr dom,
                                      const char *xml,
5492 5493
                                      int mediaChangeOnly ATTRIBUTE_UNUSED)
{
5494
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5495
    IMachine *machine    = NULL;
5496
    vboxIID iid = VBOX_IID_INITIALIZER;
5497 5498 5499
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5500
    nsresult rc;
5501

5502
    if (VIR_ALLOC(def) < 0)
5503 5504
        return ret;

5505
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
5506 5507
        goto cleanup;

5508 5509
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5510
    if (dev == NULL)
5511 5512
        goto cleanup;

5513
    vboxIIDFromUUID(&iid, dom->uuid);
5514
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5515
    if (NS_FAILED(rc)) {
5516 5517
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5518 5519
        goto cleanup;
    }
5520

5521 5522
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5523

5524 5525
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5526
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5527
        } else {
5528
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5529 5530 5531 5532 5533
        }
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5534
#if VBOX_API_VERSION < 3001000
5535 5536 5537
                    const char *src = virDomainDiskGetSource(dev->data.disk);
                    int type = virDomainDiskGetType(dev->data.disk);

5538
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
5539
                        if (type == VIR_DOMAIN_DISK_TYPE_FILE && src) {
5540 5541 5542 5543 5544 5545 5546 5547 5548
                            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;
5549 5550
                                vboxIID dvduuid = VBOX_IID_INITIALIZER;
                                vboxIID dvdemptyuuid = VBOX_IID_INITIALIZER;
5551

5552
                                VBOX_UTF8_TO_UTF16(src, &dvdfileUtf16);
5553

5554 5555
                                data->vboxObj->vtbl->FindDVDImage(data->vboxObj, dvdfileUtf16, &dvdImage);
                                if (!dvdImage) {
5556
                                    data->vboxObj->vtbl->OpenDVDImage(data->vboxObj, dvdfileUtf16, dvdemptyuuid.value, &dvdImage);
5557 5558
                                }
                                if (dvdImage) {
5559
                                    rc = dvdImage->vtbl->imedium.GetId((IMedium *)dvdImage, &dvduuid.value);
5560
                                    if (NS_FAILED(rc)) {
5561 5562 5563
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("can't get the uuid of the file to "
                                                         "be attached to cdrom: %s, rc=%08x"),
5564
                                                       src, (unsigned)rc);
5565 5566 5567
                                    } else {
                                        /* unmount the previous mounted image */
                                        dvdDrive->vtbl->Unmount(dvdDrive);
5568
                                        rc = dvdDrive->vtbl->MountImage(dvdDrive, dvduuid.value);
5569
                                        if (NS_FAILED(rc)) {
5570 5571
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("could not attach the file to cdrom: %s, rc=%08x"),
5572
                                                           src, (unsigned)rc);
5573
                                        } else {
5574
                                            ret = 0;
5575
                                            DEBUGIID("CD/DVD Image UUID:", dvduuid.value);
5576 5577
                                        }
                                    }
5578 5579

                                    VBOX_MEDIUM_RELEASE(dvdImage);
5580
                                }
5581
                                vboxIIDUnalloc(&dvduuid);
5582 5583
                                VBOX_UTF16_FREE(dvdfileUtf16);
                                VBOX_RELEASE(dvdDrive);
5584
                            }
5585
                        } else if (type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5586 5587
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
5588
                        if (type == VIR_DOMAIN_DISK_TYPE_FILE && src) {
5589 5590 5591 5592 5593 5594 5595
                            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;
5596 5597
                                    vboxIID fduuid = VBOX_IID_INITIALIZER;
                                    vboxIID fdemptyuuid = VBOX_IID_INITIALIZER;
5598
                                    VBOX_UTF8_TO_UTF16(src, &fdfileUtf16);
5599 5600 5601 5602 5603 5604 5605
                                    rc = data->vboxObj->vtbl->FindFloppyImage(data->vboxObj,
                                                                              fdfileUtf16,
                                                                              &floppyImage);

                                    if (!floppyImage) {
                                        data->vboxObj->vtbl->OpenFloppyImage(data->vboxObj,
                                                                             fdfileUtf16,
5606
                                                                             fdemptyuuid.value,
5607 5608
                                                                             &floppyImage);
                                    }
5609

5610
                                    if (floppyImage) {
5611
                                        rc = floppyImage->vtbl->imedium.GetId((IMedium *)floppyImage, &fduuid.value);
5612
                                        if (NS_FAILED(rc)) {
5613 5614 5615
                                            virReportError(VIR_ERR_INTERNAL_ERROR,
                                                           _("can't get the uuid of the file to be "
                                                             "attached to floppy drive: %s, rc=%08x"),
5616
                                                           src, (unsigned)rc);
5617
                                        } else {
5618
                                            rc = floppyDrive->vtbl->MountImage(floppyDrive, fduuid.value);
5619
                                            if (NS_FAILED(rc)) {
5620 5621
                                                virReportError(VIR_ERR_INTERNAL_ERROR,
                                                               _("could not attach the file to floppy drive: %s, rc=%08x"),
5622
                                                               src, (unsigned)rc);
5623
                                            } else {
5624
                                                ret = 0;
5625
                                                DEBUGIID("attached floppy, UUID:", fduuid.value);
5626 5627
                                            }
                                        }
5628
                                        VBOX_MEDIUM_RELEASE(floppyImage);
5629
                                    }
5630
                                    vboxIIDUnalloc(&fduuid);
5631
                                    VBOX_UTF16_FREE(fdfileUtf16);
5632
                                }
5633
                                VBOX_RELEASE(floppyDrive);
5634
                            }
5635
                        } else if (type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5636
                        }
5637
                    }
5638 5639
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
5640 5641 5642 5643
                } 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) {
5644 5645
                        }
                    }
M
Matthias Bolte 已提交
5646 5647 5648 5649 5650 5651 5652 5653 5654 5655
                } 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;

5656
#if VBOX_API_VERSION < 4000000
M
Matthias Bolte 已提交
5657 5658
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable);
5659
#else /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
5660 5661
                    rc = machine->vtbl->CreateSharedFolder(machine, nameUtf16, hostPathUtf16,
                                                           writable, PR_FALSE);
5662
#endif /* VBOX_API_VERSION >= 4000000 */
M
Matthias Bolte 已提交
5663 5664

                    if (NS_FAILED(rc)) {
5665 5666 5667
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not attach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5668 5669 5670 5671 5672 5673
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
                    VBOX_UTF16_FREE(hostPathUtf16);
5674
                }
5675 5676
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5677
            }
5678
            VBOX_SESSION_CLOSE();
5679 5680 5681 5682
        }
    }

cleanup:
5683
    vboxIIDUnalloc(&iid);
5684 5685 5686 5687 5688
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5689 5690
static int vboxDomainAttachDevice(virDomainPtr dom, const char *xml)
{
5691 5692 5693
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

5694 5695 5696 5697 5698 5699
static int
vboxDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5700
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5701 5702
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5703 5704 5705
        return -1;
    }

5706 5707 5708 5709
    return vboxDomainAttachDeviceImpl(dom, xml, 0);
}

static int vboxDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
5710 5711
                                       unsigned int flags)
{
5712 5713 5714
    virCheckFlags(VIR_DOMAIN_AFFECT_CURRENT |
                  VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
5715

5716
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5717 5718
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5719 5720 5721 5722
        return -1;
    }

    return vboxDomainAttachDeviceImpl(dom, xml, 1);
5723 5724
}

5725 5726
static int vboxDomainDetachDevice(virDomainPtr dom, const char *xml)
{
5727
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
5728
    IMachine *machine    = NULL;
5729
    vboxIID iid = VBOX_IID_INITIALIZER;
5730 5731 5732
    PRUint32 state       = MachineState_Null;
    virDomainDefPtr def  = NULL;
    virDomainDeviceDefPtr dev  = NULL;
5733
    nsresult rc;
5734

5735
    if (VIR_ALLOC(def) < 0)
5736 5737
        return ret;

5738
    if (VIR_STRDUP(def->os.type, "hvm") < 0)
5739 5740
        goto cleanup;

5741 5742
    dev = virDomainDeviceDefParse(xml, def, data->caps, data->xmlopt,
                                  VIR_DOMAIN_XML_INACTIVE);
5743
    if (dev == NULL)
5744 5745
        goto cleanup;

5746
    vboxIIDFromUUID(&iid, dom->uuid);
5747
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
5748
    if (NS_FAILED(rc)) {
5749 5750
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
5751 5752
        goto cleanup;
    }
5753

5754 5755
    if (machine) {
        machine->vtbl->GetState(machine, &state);
5756

5757 5758
        if ((state == MachineState_Running) ||
            (state == MachineState_Paused)) {
5759
            rc = VBOX_SESSION_OPEN_EXISTING(iid.value, machine);
5760
        } else {
5761
            rc = VBOX_SESSION_OPEN(iid.value, machine);
5762
        }
5763

5764 5765 5766 5767
        if (NS_SUCCEEDED(rc)) {
            rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
            if (NS_SUCCEEDED(rc) && machine) {
                if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
5768
#if VBOX_API_VERSION < 3001000
5769 5770
                    int type = virDomainDiskGetType(dev->data.disk);

5771
                    if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
5772
                        if (type == VIR_DOMAIN_DISK_TYPE_FILE) {
5773 5774 5775 5776 5777 5778 5779 5780 5781
                            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)) {
5782 5783 5784
                                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                                   _("could not de-attach the mounted ISO, rc=%08x"),
                                                   (unsigned)rc);
5785 5786 5787 5788 5789
                                } else {
                                    ret = 0;
                                }
                                VBOX_RELEASE(dvdDrive);
                            }
5790
                        } else if (type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5791 5792
                        }
                    } else if (dev->data.disk->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY) {
5793
                        if (type == VIR_DOMAIN_DISK_TYPE_FILE) {
5794 5795 5796 5797 5798 5799 5800 5801
                            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);
5802
                                    if (NS_FAILED(rc)) {
5803 5804 5805 5806
                                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                                       _("could not attach the file "
                                                         "to floppy drive, rc=%08x"),
                                                       (unsigned)rc);
5807 5808 5809
                                    } else {
                                        ret = 0;
                                    }
5810 5811 5812 5813 5814
                                } 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;
5815
                                }
5816
                                VBOX_RELEASE(floppyDrive);
5817
                            }
5818
                        } else if (type == VIR_DOMAIN_DISK_TYPE_BLOCK) {
5819
                        }
5820
                    }
5821 5822
#else  /* VBOX_API_VERSION >= 3001000 */
#endif /* VBOX_API_VERSION >= 3001000 */
5823 5824 5825 5826
                } 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) {
5827 5828
                        }
                    }
M
Matthias Bolte 已提交
5829 5830 5831 5832 5833 5834 5835 5836 5837
                } 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)) {
5838 5839 5840
                        virReportError(VIR_ERR_INTERNAL_ERROR,
                                       _("could not detach shared folder '%s', rc=%08x"),
                                       dev->data.fs->dst, (unsigned)rc);
M
Matthias Bolte 已提交
5841 5842 5843 5844 5845
                    } else {
                        ret = 0;
                    }

                    VBOX_UTF16_FREE(nameUtf16);
5846
                }
5847 5848
                machine->vtbl->SaveSettings(machine);
                VBOX_RELEASE(machine);
5849
            }
5850
            VBOX_SESSION_CLOSE();
5851 5852 5853 5854
        }
    }

cleanup:
5855
    vboxIIDUnalloc(&iid);
5856 5857 5858 5859 5860
    virDomainDefFree(def);
    virDomainDeviceDefFree(dev);
    return ret;
}

5861 5862 5863 5864 5865 5866
static int
vboxDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags)
{
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG, -1);

5867
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
5868 5869
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot modify the persistent configuration of a domain"));
5870 5871 5872 5873 5874 5875
        return -1;
    }

    return vboxDomainDetachDevice(dom, xml);
}

J
Jiri Denemark 已提交
5876 5877 5878 5879 5880
static int
vboxDomainSnapshotGetAll(virDomainPtr dom,
                         IMachine *machine,
                         ISnapshot ***snapshots)
{
5881
    vboxIID empty = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
5882 5883 5884 5885 5886 5887 5888 5889
    ISnapshot **list = NULL;
    PRUint32 count;
    nsresult rc;
    unsigned int next;
    unsigned int top;

    rc = machine->vtbl->GetSnapshotCount(machine, &count);
    if (NS_FAILED(rc)) {
5890 5891 5892
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5893 5894 5895 5896 5897 5898
        goto error;
    }

    if (count == 0)
        goto out;

5899
    if (VIR_ALLOC_N(list, count) < 0)
J
Jiri Denemark 已提交
5900 5901
        goto error;

5902
#if VBOX_API_VERSION < 4000000
5903
    rc = machine->vtbl->GetSnapshot(machine, empty.value, list);
5904
#else /* VBOX_API_VERSION >= 4000000 */
5905
    rc = machine->vtbl->FindSnapshot(machine, empty.value, list);
5906
#endif /* VBOX_API_VERSION >= 4000000 */
J
Jiri Denemark 已提交
5907
    if (NS_FAILED(rc) || !list[0]) {
5908 5909 5910
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get root snapshot for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
5911 5912 5913 5914 5915 5916
        goto error;
    }

    /* BFS walk through snapshot tree */
    top = 1;
    for (next = 0; next < count; next++) {
5917
        vboxArray children = VBOX_ARRAY_INITIALIZER;
5918
        size_t i;
J
Jiri Denemark 已提交
5919 5920

        if (!list[next]) {
5921 5922
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected number of snapshots < %u"), count);
J
Jiri Denemark 已提交
5923 5924 5925
            goto error;
        }

5926 5927
        rc = vboxArrayGet(&children, list[next],
                               list[next]->vtbl->GetChildren);
J
Jiri Denemark 已提交
5928
        if (NS_FAILED(rc)) {
5929 5930
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get children snapshots"));
J
Jiri Denemark 已提交
5931 5932
            goto error;
        }
5933 5934 5935
        for (i = 0; i < children.count; i++) {
            ISnapshot *child = children.items[i];
            if (!child)
J
Jiri Denemark 已提交
5936 5937
                continue;
            if (top == count) {
5938 5939
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected number of snapshots > %u"), count);
5940
                vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5941 5942
                goto error;
            }
5943 5944
            VBOX_ADDREF(child);
            list[top++] = child;
J
Jiri Denemark 已提交
5945
        }
5946
        vboxArrayRelease(&children);
J
Jiri Denemark 已提交
5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972
    }

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;
5973
    size_t i;
J
Jiri Denemark 已提交
5974 5975 5976 5977 5978 5979 5980 5981 5982 5983

    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) {
5984 5985
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998
            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) {
5999 6000 6001
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s has no snapshots with name %s"),
                       dom->name, name);
J
Jiri Denemark 已提交
6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018
        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,
6019
                            unsigned int flags)
J
Jiri Denemark 已提交
6020 6021 6022
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
    virDomainSnapshotDefPtr def = NULL;
6023
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6024 6025 6026 6027 6028 6029 6030 6031
    IMachine *machine = NULL;
    IConsole *console = NULL;
    IProgress *progress = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *name = NULL;
    PRUnichar *description = NULL;
    PRUint32 state;
    nsresult rc;
6032
#if VBOX_API_VERSION == 2002000
J
Jiri Denemark 已提交
6033 6034 6035 6036 6037
    nsresult result;
#else
    PRInt32 result;
#endif

6038 6039
    /* VBox has no snapshot metadata, so this flag is trivial.  */
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA, NULL);
6040

6041
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, data->caps,
6042
                                                data->xmlopt, 0, 0)))
J
Jiri Denemark 已提交
6043 6044
        goto cleanup;

6045
    if (def->ndisks) {
6046 6047
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk snapshots not supported yet"));
6048 6049 6050
        goto cleanup;
    }

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

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6061 6062
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6063 6064 6065 6066 6067
        goto cleanup;
    }

    if ((state >= MachineState_FirstOnline)
        && (state <= MachineState_LastOnline)) {
6068
        rc = VBOX_SESSION_OPEN_EXISTING(domiid.value, machine);
J
Jiri Denemark 已提交
6069
    } else {
6070
        rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6071
    }
6072

J
Jiri Denemark 已提交
6073 6074 6075
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6076 6077 6078
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097
        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) {
6098 6099
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6100 6101 6102 6103 6104 6105
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6106 6107
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not take snapshot of domain %s"), dom->name);
J
Jiri Denemark 已提交
6108 6109 6110 6111 6112
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6113 6114
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
J
Jiri Denemark 已提交
6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125
                  dom->name);
        goto cleanup;
    }

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

cleanup:
    VBOX_RELEASE(progress);
    VBOX_UTF16_FREE(description);
    VBOX_UTF16_FREE(name);
    VBOX_RELEASE(console);
6126
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
6127
    VBOX_RELEASE(machine);
6128
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6129 6130 6131 6132 6133
    virDomainSnapshotDefFree(def);
    return ret;
}

static char *
6134 6135
vboxDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                             unsigned int flags)
J
Jiri Denemark 已提交
6136 6137 6138
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, char *, NULL);
6139
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150
    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];

6151 6152
    virCheckFlags(0, NULL);

6153
    vboxIIDFromUUID(&domiid, dom->uuid);
6154
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6155
    if (NS_FAILED(rc)) {
6156 6157
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6158 6159 6160 6161 6162 6163
        goto cleanup;
    }

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

6164
    if (VIR_ALLOC(def) < 0)
6165
        goto cleanup;
6166 6167
    if (VIR_STRDUP(def->name, snapshot->name) < 0)
        goto cleanup;
J
Jiri Denemark 已提交
6168 6169 6170

    rc = snap->vtbl->GetDescription(snap, &str16);
    if (NS_FAILED(rc)) {
6171 6172 6173
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get description of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6174 6175 6176 6177 6178
        goto cleanup;
    }
    if (str16) {
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
6179 6180 6181 6182
        if (VIR_STRDUP(def->description, str8) < 0) {
            VBOX_UTF8_FREE(str8);
            goto cleanup;
        }
J
Jiri Denemark 已提交
6183 6184 6185 6186 6187
        VBOX_UTF8_FREE(str8);
    }

    rc = snap->vtbl->GetTimeStamp(snap, &timestamp);
    if (NS_FAILED(rc)) {
6188 6189 6190
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get creation time of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6191 6192 6193 6194 6195 6196 6197
        goto cleanup;
    }
    /* timestamp is in milliseconds while creationTime in seconds */
    def->creationTime = timestamp / 1000;

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
6198 6199 6200
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6201 6202 6203 6204 6205
        goto cleanup;
    }
    if (parent) {
        rc = parent->vtbl->GetName(parent, &str16);
        if (NS_FAILED(rc) || !str16) {
6206 6207 6208
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get name of parent of snapshot %s"),
                           snapshot->name);
J
Jiri Denemark 已提交
6209 6210 6211 6212
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(str16, &str8);
        VBOX_UTF16_FREE(str16);
6213 6214
        if (VIR_STRDUP(def->parent, str8) < 0) {
            VBOX_UTF8_FREE(str8);
6215
            goto cleanup;
6216 6217
        }
        VBOX_UTF8_FREE(str8);
J
Jiri Denemark 已提交
6218 6219 6220 6221
    }

    rc = snap->vtbl->GetOnline(snap, &online);
    if (NS_FAILED(rc)) {
6222 6223 6224
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6225 6226 6227 6228 6229 6230 6231 6232
        goto cleanup;
    }
    if (online)
        def->state = VIR_DOMAIN_RUNNING;
    else
        def->state = VIR_DOMAIN_SHUTOFF;

    virUUIDFormat(dom->uuid, uuidstr);
6233
    ret = virDomainSnapshotDefFormat(uuidstr, def, flags, 0);
J
Jiri Denemark 已提交
6234 6235 6236 6237 6238 6239

cleanup:
    virDomainSnapshotDefFree(def);
    VBOX_RELEASE(parent);
    VBOX_RELEASE(snap);
    VBOX_RELEASE(machine);
6240
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6241 6242 6243 6244 6245
    return ret;
}

static int
vboxDomainSnapshotNum(virDomainPtr dom,
6246
                      unsigned int flags)
J
Jiri Denemark 已提交
6247 6248
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6249
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6250 6251 6252 6253
    IMachine *machine = NULL;
    nsresult rc;
    PRUint32 snapshotCount;

6254 6255
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6256

6257
    vboxIIDFromUUID(&iid, dom->uuid);
6258
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6259
    if (NS_FAILED(rc)) {
6260 6261
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6262 6263 6264
        goto cleanup;
    }

6265 6266 6267 6268 6269 6270
    /* VBox snapshots do not require libvirt to maintain any metadata.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

J
Jiri Denemark 已提交
6271 6272
    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
    if (NS_FAILED(rc)) {
6273 6274 6275
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get snapshot count for domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6276 6277 6278
        goto cleanup;
    }

6279 6280 6281 6282 6283
    /* VBox has at most one root snapshot.  */
    if (snapshotCount && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS))
        ret = 1;
    else
        ret = snapshotCount;
J
Jiri Denemark 已提交
6284 6285 6286

cleanup:
    VBOX_RELEASE(machine);
6287
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6288 6289 6290 6291 6292 6293 6294
    return ret;
}

static int
vboxDomainSnapshotListNames(virDomainPtr dom,
                            char **names,
                            int nameslen,
6295
                            unsigned int flags)
J
Jiri Denemark 已提交
6296 6297
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6298
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6299 6300 6301 6302
    IMachine *machine = NULL;
    nsresult rc;
    ISnapshot **snapshots = NULL;
    int count = 0;
6303
    size_t i;
J
Jiri Denemark 已提交
6304

6305 6306
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_LIST_METADATA, -1);
6307

6308
    vboxIIDFromUUID(&iid, dom->uuid);
6309
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6310
    if (NS_FAILED(rc)) {
6311 6312
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6313 6314 6315
        goto cleanup;
    }

6316 6317 6318 6319 6320
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_METADATA) {
        ret = 0;
        goto cleanup;
    }

6321 6322 6323
    if (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS) {
        vboxIID empty = VBOX_IID_INITIALIZER;

6324
        if (VIR_ALLOC_N(snapshots, 1) < 0)
6325
            goto cleanup;
6326
#if VBOX_API_VERSION < 4000000
6327
        rc = machine->vtbl->GetSnapshot(machine, empty.value, snapshots);
6328
#else /* VBOX_API_VERSION >= 4000000 */
6329
        rc = machine->vtbl->FindSnapshot(machine, empty.value, snapshots);
6330
#endif /* VBOX_API_VERSION >= 4000000 */
6331
        if (NS_FAILED(rc) || !snapshots[0]) {
6332 6333 6334
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not get root snapshot for domain %s"),
                           dom->name);
6335 6336 6337 6338 6339 6340 6341
            goto cleanup;
        }
        count = 1;
    } else {
        if ((count = vboxDomainSnapshotGetAll(dom, machine, &snapshots)) < 0)
            goto cleanup;
    }
J
Jiri Denemark 已提交
6342 6343 6344 6345 6346 6347 6348 6349 6350 6351

    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) {
6352 6353
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("could not get snapshot name"));
J
Jiri Denemark 已提交
6354 6355 6356 6357
            goto cleanup;
        }
        VBOX_UTF16_TO_UTF8(nameUtf16, &name);
        VBOX_UTF16_FREE(nameUtf16);
6358 6359
        if (VIR_STRDUP(names[i], name) < 0) {
            VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
6360 6361
            goto cleanup;
        }
6362
        VBOX_UTF8_FREE(name);
J
Jiri Denemark 已提交
6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376
    }

    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);
6377
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6378 6379 6380 6381 6382 6383
    return ret;
}

static virDomainSnapshotPtr
vboxDomainSnapshotLookupByName(virDomainPtr dom,
                               const char *name,
6384
                               unsigned int flags)
J
Jiri Denemark 已提交
6385 6386
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6387
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6388 6389 6390 6391
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

6392 6393
    virCheckFlags(0, NULL);

6394
    vboxIIDFromUUID(&iid, dom->uuid);
6395
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
J
Jiri Denemark 已提交
6396
    if (NS_FAILED(rc)) {
6397 6398
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409
        goto cleanup;
    }

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

    ret = virGetDomainSnapshot(dom, name);

cleanup:
    VBOX_RELEASE(snapshot);
    VBOX_RELEASE(machine);
6410
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6411 6412 6413 6414 6415
    return ret;
}

static int
vboxDomainHasCurrentSnapshot(virDomainPtr dom,
6416
                             unsigned int flags)
J
Jiri Denemark 已提交
6417 6418
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6419
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6420 6421 6422 6423
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    nsresult rc;

6424 6425
    virCheckFlags(0, -1);

6426
    vboxIIDFromUUID(&iid, dom->uuid);
6427
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6428
    if (NS_FAILED(rc)) {
6429 6430
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6431 6432 6433 6434 6435
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6436 6437
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
6438 6439 6440 6441 6442 6443 6444 6445 6446 6447
        goto cleanup;
    }

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

cleanup:
    VBOX_RELEASE(machine);
6448
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6449 6450 6451
    return ret;
}

6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470
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)) {
6471 6472
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6473 6474 6475 6476 6477 6478 6479 6480
        goto cleanup;
    }

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

    rc = snap->vtbl->GetParent(snap, &parent);
    if (NS_FAILED(rc)) {
6481 6482 6483
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get parent of snapshot %s"),
                       snapshot->name);
6484 6485 6486
        goto cleanup;
    }
    if (!parent) {
6487 6488 6489
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snapshot->name);
6490 6491 6492 6493 6494
        goto cleanup;
    }

    rc = parent->vtbl->GetName(parent, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6495 6496 6497
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get name of parent of snapshot %s"),
                       snapshot->name);
6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517
        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 已提交
6518 6519
static virDomainSnapshotPtr
vboxDomainSnapshotCurrent(virDomainPtr dom,
6520
                          unsigned int flags)
J
Jiri Denemark 已提交
6521 6522
{
    VBOX_OBJECT_CHECK(dom->conn, virDomainSnapshotPtr, NULL);
6523
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6524 6525 6526 6527 6528 6529
    IMachine *machine = NULL;
    ISnapshot *snapshot = NULL;
    PRUnichar *nameUtf16 = NULL;
    char *name = NULL;
    nsresult rc;

6530 6531
    virCheckFlags(0, NULL);

6532
    vboxIIDFromUUID(&iid, dom->uuid);
6533
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
6534
    if (NS_FAILED(rc)) {
6535 6536
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6537 6538 6539 6540 6541
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &snapshot);
    if (NS_FAILED(rc)) {
6542 6543
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
J
Jiri Denemark 已提交
6544 6545 6546 6547
        goto cleanup;
    }

    if (!snapshot) {
6548 6549
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain has no snapshots"));
J
Jiri Denemark 已提交
6550 6551 6552 6553 6554
        goto cleanup;
    }

    rc = snapshot->vtbl->GetName(snapshot, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6555 6556
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
J
Jiri Denemark 已提交
6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572
        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);
6573
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6574 6575 6576
    return ret;
}

6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595
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)) {
6596 6597
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6598 6599 6600 6601 6602 6603 6604 6605
        goto cleanup;
    }

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

    rc = machine->vtbl->GetCurrentSnapshot(machine, &current);
    if (NS_FAILED(rc)) {
6606 6607
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot"));
6608 6609 6610 6611 6612 6613 6614 6615 6616
        goto cleanup;
    }
    if (!current) {
        ret = 0;
        goto cleanup;
    }

    rc = current->vtbl->GetName(current, &nameUtf16);
    if (NS_FAILED(rc) || !nameUtf16) {
6617 6618
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get current snapshot name"));
6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655
        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)) {
6656 6657
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673
        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;
}

6674
#if VBOX_API_VERSION < 3001000
J
Jiri Denemark 已提交
6675 6676 6677 6678 6679 6680
static int
vboxDomainSnapshotRestore(virDomainPtr dom,
                          IMachine *machine,
                          ISnapshot *snapshot)
{
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6681
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6682 6683
    nsresult rc;

6684 6685
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
6686 6687
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
6688 6689 6690
        goto cleanup;
    }

6691
    rc = machine->vtbl->SetCurrentSnapshot(machine, iid.value);
J
Jiri Denemark 已提交
6692
    if (NS_FAILED(rc)) {
6693 6694
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
6695 6696 6697 6698 6699 6700
        goto cleanup;
    }

    ret = 0;

cleanup:
6701
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715
    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;
6716
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6717

6718 6719
    rc = machine->vtbl->GetId(machine, &domiid.value);
    if (NS_FAILED(rc)) {
6720 6721
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain UUID"));
J
Jiri Denemark 已提交
6722 6723 6724 6725 6726
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6727 6728
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6729 6730 6731 6732 6733
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6734 6735
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("domain %s is already running"), dom->name);
J
Jiri Denemark 已提交
6736 6737 6738
        goto cleanup;
    }

6739
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6740 6741 6742
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6743 6744 6745
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6746 6747 6748 6749 6750 6751
        goto cleanup;
    }

    rc = console->vtbl->RestoreSnapshot(console, snapshot, &progress);
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
6752 6753
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot restore domain snapshot for running domain"));
J
Jiri Denemark 已提交
6754
        } else {
6755 6756 6757
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("could not restore snapshot for domain %s"),
                           dom->name);
J
Jiri Denemark 已提交
6758 6759 6760 6761 6762 6763 6764
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6765 6766
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not restore snapshot for domain %s"), dom->name);
J
Jiri Denemark 已提交
6767 6768 6769 6770 6771 6772 6773 6774
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(progress);
    VBOX_RELEASE(console);
6775
    VBOX_SESSION_CLOSE();
6776
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6777 6778 6779 6780 6781 6782
    return ret;
}
#endif

static int
vboxDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
6783
                           unsigned int flags)
J
Jiri Denemark 已提交
6784 6785 6786
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6787
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6788 6789 6790 6791 6792 6793 6794
    IMachine *machine = NULL;
    ISnapshot *newSnapshot = NULL;
    ISnapshot *prevSnapshot = NULL;
    PRBool online = PR_FALSE;
    PRUint32 state;
    nsresult rc;

6795 6796
    virCheckFlags(0, -1);

6797
    vboxIIDFromUUID(&domiid, dom->uuid);
6798
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6799
    if (NS_FAILED(rc)) {
6800 6801
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6802 6803 6804 6805 6806 6807 6808 6809 6810
        goto cleanup;
    }

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

    rc = newSnapshot->vtbl->GetOnline(newSnapshot, &online);
    if (NS_FAILED(rc)) {
6811 6812 6813
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get online state of snapshot %s"),
                       snapshot->name);
J
Jiri Denemark 已提交
6814 6815 6816 6817 6818
        goto cleanup;
    }

    rc = machine->vtbl->GetCurrentSnapshot(machine, &prevSnapshot);
    if (NS_FAILED(rc)) {
6819 6820 6821
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get current snapshot of domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6822 6823 6824 6825 6826
        goto cleanup;
    }

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6827 6828
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6829 6830 6831 6832 6833
        goto cleanup;
    }

    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6834 6835
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot revert snapshot of running domain"));
J
Jiri Denemark 已提交
6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851
        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);
6852
    vboxIIDUnalloc(&domiid);
J
Jiri Denemark 已提交
6853 6854 6855 6856 6857 6858 6859 6860 6861
    return ret;
}

static int
vboxDomainSnapshotDeleteSingle(vboxGlobalData *data,
                               IConsole *console,
                               ISnapshot *snapshot)
{
    IProgress *progress = NULL;
6862
    vboxIID iid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6863 6864
    int ret = -1;
    nsresult rc;
6865
#if VBOX_API_VERSION == 2002000
J
Jiri Denemark 已提交
6866 6867 6868 6869 6870
    nsresult result;
#else
    PRInt32 result;
#endif

6871 6872
    rc = snapshot->vtbl->GetId(snapshot, &iid.value);
    if (NS_FAILED(rc)) {
6873 6874
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get snapshot UUID"));
J
Jiri Denemark 已提交
6875 6876 6877
        goto cleanup;
    }

6878
#if VBOX_API_VERSION < 3001000
6879
    rc = console->vtbl->DiscardSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
6880
#else
6881
    rc = console->vtbl->DeleteSnapshot(console, iid.value, &progress);
J
Jiri Denemark 已提交
6882 6883 6884
#endif
    if (NS_FAILED(rc) || !progress) {
        if (rc == VBOX_E_INVALID_VM_STATE) {
6885 6886
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot delete domain snapshot for running domain"));
J
Jiri Denemark 已提交
6887
        } else {
6888 6889
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("could not delete snapshot"));
J
Jiri Denemark 已提交
6890 6891 6892 6893 6894 6895 6896
        }
        goto cleanup;
    }

    progress->vtbl->WaitForCompletion(progress, -1);
    progress->vtbl->GetResultCode(progress, &result);
    if (NS_FAILED(result)) {
6897 6898
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not delete snapshot"));
J
Jiri Denemark 已提交
6899 6900 6901 6902 6903 6904 6905
        goto cleanup;
    }

    ret = 0;

cleanup:
    VBOX_RELEASE(progress);
6906
    vboxIIDUnalloc(&iid);
J
Jiri Denemark 已提交
6907 6908 6909 6910 6911 6912 6913 6914
    return ret;
}

static int
vboxDomainSnapshotDeleteTree(vboxGlobalData *data,
                             IConsole *console,
                             ISnapshot *snapshot)
{
6915
    vboxArray children = VBOX_ARRAY_INITIALIZER;
J
Jiri Denemark 已提交
6916 6917
    int ret = -1;
    nsresult rc;
6918
    size_t i;
J
Jiri Denemark 已提交
6919

6920
    rc = vboxArrayGet(&children, snapshot, snapshot->vtbl->GetChildren);
J
Jiri Denemark 已提交
6921
    if (NS_FAILED(rc)) {
6922 6923
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get children snapshots"));
J
Jiri Denemark 已提交
6924 6925 6926
        goto cleanup;
    }

6927 6928 6929
    for (i = 0; i < children.count; i++) {
        if (vboxDomainSnapshotDeleteTree(data, console, children.items[i]))
            goto cleanup;
J
Jiri Denemark 已提交
6930 6931 6932 6933 6934
    }

    ret = vboxDomainSnapshotDeleteSingle(data, console, snapshot);

cleanup:
6935
    vboxArrayRelease(&children);
J
Jiri Denemark 已提交
6936 6937 6938 6939 6940 6941 6942 6943 6944
    return ret;
}

static int
vboxDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                         unsigned int flags)
{
    virDomainPtr dom = snapshot->domain;
    VBOX_OBJECT_CHECK(dom->conn, int, -1);
6945
    vboxIID domiid = VBOX_IID_INITIALIZER;
J
Jiri Denemark 已提交
6946 6947 6948 6949 6950 6951
    IMachine *machine = NULL;
    ISnapshot *snap = NULL;
    IConsole *console = NULL;
    PRUint32 state;
    nsresult rc;

6952 6953
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY, -1);
6954

6955
    vboxIIDFromUUID(&domiid, dom->uuid);
6956
    rc = VBOX_OBJECT_GET_MACHINE(domiid.value, &machine);
J
Jiri Denemark 已提交
6957
    if (NS_FAILED(rc)) {
6958 6959
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching UUID"));
J
Jiri Denemark 已提交
6960 6961 6962 6963 6964 6965 6966 6967 6968
        goto cleanup;
    }

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

    rc = machine->vtbl->GetState(machine, &state);
    if (NS_FAILED(rc)) {
6969 6970
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not get domain state"));
J
Jiri Denemark 已提交
6971 6972 6973
        goto cleanup;
    }

6974 6975 6976 6977 6978 6979 6980
    /* 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 已提交
6981 6982
    if (state >= MachineState_FirstOnline
        && state <= MachineState_LastOnline) {
6983 6984
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot delete snapshots of running domain"));
J
Jiri Denemark 已提交
6985 6986 6987
        goto cleanup;
    }

6988
    rc = VBOX_SESSION_OPEN(domiid.value, machine);
J
Jiri Denemark 已提交
6989 6990 6991
    if (NS_SUCCEEDED(rc))
        rc = data->vboxSession->vtbl->GetConsole(data->vboxSession, &console);
    if (NS_FAILED(rc)) {
6992 6993 6994
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not open VirtualBox session with domain %s"),
                       dom->name);
J
Jiri Denemark 已提交
6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005
        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);
7006
    vboxIIDUnalloc(&domiid);
7007
    VBOX_SESSION_CLOSE();
J
Jiri Denemark 已提交
7008 7009 7010
    return ret;
}

7011
#if VBOX_API_VERSION <= 2002000 || VBOX_API_VERSION >= 4000000
7012
    /* No Callback support for VirtualBox 2.2.* series */
7013
    /* No Callback support for VirtualBox 4.* series */
7014
#else /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
7015 7016

/* Functions needed for Callbacks */
7017
static nsresult PR_COM_METHOD
7018
vboxCallbackOnMachineStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7019 7020
                                 PRUnichar *machineId, PRUint32 state)
{
7021 7022 7023 7024 7025 7026
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

7027
    VIR_DEBUG("IVirtualBoxCallback: %p, State: %d", pThis, state);
7028 7029 7030 7031 7032 7033 7034
    DEBUGPRUnichar("machineId", machineId);

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

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
7035
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
7036 7037 7038

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
7039
            virObjectEventPtr ev;
7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069

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

7070
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
7071

7072
            if (ev)
7073
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
7074 7075 7076 7077 7078 7079 7080 7081
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

7082
static nsresult PR_COM_METHOD
7083
vboxCallbackOnMachineDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7084 7085
                                PRUnichar *machineId)
{
7086
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7087 7088 7089 7090 7091
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

7092
static nsresult PR_COM_METHOD
7093
vboxCallbackOnExtraDataCanChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7094 7095 7096
                                 PRUnichar *machineId, PRUnichar *key,
                                 PRUnichar *value,
                                 PRUnichar **error ATTRIBUTE_UNUSED,
7097
                                 PRBool *allowChange ATTRIBUTE_UNUSED)
7098
{
7099
    VIR_DEBUG("IVirtualBoxCallback: %p, allowChange: %s", pThis, *allowChange ? "true" : "false");
7100 7101 7102 7103 7104 7105 7106
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

7107
static nsresult PR_COM_METHOD
7108 7109
vboxCallbackOnExtraDataChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *machineId,
7110 7111
                              PRUnichar *key, PRUnichar *value)
{
7112
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7113 7114 7115 7116 7117 7118 7119
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("key", key);
    DEBUGPRUnichar("value", value);

    return NS_OK;
}

7120
# if VBOX_API_VERSION < 3001000
7121
static nsresult PR_COM_METHOD
7122 7123 7124 7125
vboxCallbackOnMediaRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                              PRUnichar *mediaId,
                              PRUint32 mediaType ATTRIBUTE_UNUSED,
                              PRBool registered ATTRIBUTE_UNUSED)
7126
{
7127 7128
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
    VIR_DEBUG("mediaType: %d", mediaType);
7129 7130 7131 7132
    DEBUGPRUnichar("mediaId", mediaId);

    return NS_OK;
}
7133 7134
# else  /* VBOX_API_VERSION >= 3001000 */
# endif /* VBOX_API_VERSION >= 3001000 */
7135

7136
static nsresult PR_COM_METHOD
7137
vboxCallbackOnMachineRegistered(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7138 7139
                                PRUnichar *machineId, PRBool registered)
{
7140 7141 7142 7143 7144 7145
    virDomainPtr dom = NULL;
    int event        = 0;
    int detail       = 0;

    vboxDriverLock(g_pVBoxGlobalData);

7146
    VIR_DEBUG("IVirtualBoxCallback: %p, registered: %s", pThis, registered ? "true" : "false");
7147 7148 7149 7150 7151 7152 7153
    DEBUGPRUnichar("machineId", machineId);

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

        g_pVBoxGlobalData->pFuncs->pfnUtf16ToUtf8(machineId, &machineIdUtf8);
7154
        ignore_value(virUUIDParse(machineIdUtf8, uuid));
7155 7156 7157

        dom = vboxDomainLookupByUUID(g_pVBoxGlobalData->conn, uuid);
        if (dom) {
7158
            virObjectEventPtr ev;
7159 7160

            /* CURRENT LIMITATION: we never get the VIR_DOMAIN_EVENT_UNDEFINED
J
Ján Tomko 已提交
7161
             * event because the when the machine is de-registered the call
7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173
             * 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;
            }

7174
            ev = virDomainEventLifecycleNewFromDom(dom, event, detail);
7175

7176
            if (ev)
7177
                virObjectEventStateQueue(g_pVBoxGlobalData->domainEvents, ev);
7178 7179 7180 7181 7182 7183 7184 7185
        }
    }

    vboxDriverUnlock(g_pVBoxGlobalData);

    return NS_OK;
}

7186
static nsresult PR_COM_METHOD
7187 7188 7189
vboxCallbackOnSessionStateChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                 PRUnichar *machineId,
                                 PRUint32 state ATTRIBUTE_UNUSED)
7190
{
7191
    VIR_DEBUG("IVirtualBoxCallback: %p, state: %d", pThis, state);
7192 7193 7194 7195 7196
    DEBUGPRUnichar("machineId", machineId);

    return NS_OK;
}

7197
static nsresult PR_COM_METHOD
7198 7199
vboxCallbackOnSnapshotTaken(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                            PRUnichar *machineId,
7200 7201
                            PRUnichar *snapshotId)
{
7202
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7203 7204 7205 7206 7207 7208
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

7209
static nsresult PR_COM_METHOD
7210 7211
vboxCallbackOnSnapshotDiscarded(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                                PRUnichar *machineId,
7212 7213
                                PRUnichar *snapshotId)
{
7214
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7215 7216 7217 7218 7219 7220
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

7221
static nsresult PR_COM_METHOD
7222 7223
vboxCallbackOnSnapshotChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
                             PRUnichar *machineId,
7224 7225
                             PRUnichar *snapshotId)
{
7226
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7227 7228 7229 7230 7231 7232
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("snapshotId", snapshotId);

    return NS_OK;
}

7233
static nsresult PR_COM_METHOD
7234
vboxCallbackOnGuestPropertyChange(IVirtualBoxCallback *pThis ATTRIBUTE_UNUSED,
7235 7236 7237
                                  PRUnichar *machineId, PRUnichar *name,
                                  PRUnichar *value, PRUnichar *flags)
{
7238
    VIR_DEBUG("IVirtualBoxCallback: %p", pThis);
7239 7240 7241 7242 7243 7244 7245 7246
    DEBUGPRUnichar("machineId", machineId);
    DEBUGPRUnichar("name", name);
    DEBUGPRUnichar("value", value);
    DEBUGPRUnichar("flags", flags);

    return NS_OK;
}

7247
static nsresult PR_COM_METHOD
7248
vboxCallbackAddRef(nsISupports *pThis ATTRIBUTE_UNUSED)
7249
{
7250 7251 7252 7253
    nsresult c;

    c = ++g_pVBoxGlobalData->vboxCallBackRefCount;

7254
    VIR_DEBUG("pThis: %p, vboxCallback AddRef: %d", pThis, c);
7255 7256 7257 7258

    return c;
}

7259 7260 7261
static nsresult PR_COM_METHOD
vboxCallbackRelease(nsISupports *pThis)
{
7262 7263 7264 7265 7266 7267 7268 7269 7270
    nsresult c;

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

7271
    VIR_DEBUG("pThis: %p, vboxCallback Release: %d", pThis, c);
7272 7273 7274 7275

    return c;
}

7276 7277 7278
static nsresult PR_COM_METHOD
vboxCallbackQueryInterface(nsISupports *pThis, const nsID *iid, void **resultp)
{
7279 7280 7281 7282 7283
    IVirtualBoxCallback *that = (IVirtualBoxCallback *)pThis;
    static const nsID ivirtualboxCallbackUUID = IVIRTUALBOXCALLBACK_IID;
    static const nsID isupportIID = NS_ISUPPORTS_IID;

    /* Match UUID for IVirtualBoxCallback class */
7284 7285
    if (memcmp(iid, &ivirtualboxCallbackUUID, sizeof(nsID)) == 0 ||
        memcmp(iid, &isupportIID, sizeof(nsID)) == 0) {
7286 7287 7288
        g_pVBoxGlobalData->vboxCallBackRefCount++;
        *resultp = that;

7289
        VIR_DEBUG("pThis: %p, vboxCallback QueryInterface: %d", pThis, g_pVBoxGlobalData->vboxCallBackRefCount);
7290 7291 7292 7293 7294

        return NS_OK;
    }


7295
    VIR_DEBUG("pThis: %p, vboxCallback QueryInterface didn't find a matching interface", pThis);
7296 7297 7298 7299 7300 7301
    DEBUGUUID("The UUID Callback Interface expects", iid);
    DEBUGUUID("The UUID Callback Interface got", &ivirtualboxCallbackUUID);
    return NS_NOINTERFACE;
}


7302
static IVirtualBoxCallback *vboxAllocCallbackObj(void) {
7303 7304
    IVirtualBoxCallback *vboxCallback = NULL;

7305
    /* Allocate, Initialize and return a valid
7306 7307 7308
     * IVirtualBoxCallback object here
     */
    if ((VIR_ALLOC(vboxCallback) < 0) || (VIR_ALLOC(vboxCallback->vtbl) < 0)) {
7309
        VIR_FREE(vboxCallback);
7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320
        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;
7321
# if VBOX_API_VERSION < 3001000
7322
        vboxCallback->vtbl->OnMediaRegistered           = &vboxCallbackOnMediaRegistered;
7323 7324
# else  /* VBOX_API_VERSION >= 3001000 */
# endif /* VBOX_API_VERSION >= 3001000 */
7325 7326 7327
        vboxCallback->vtbl->OnMachineRegistered         = &vboxCallbackOnMachineRegistered;
        vboxCallback->vtbl->OnSessionStateChange        = &vboxCallbackOnSessionStateChange;
        vboxCallback->vtbl->OnSnapshotTaken             = &vboxCallbackOnSnapshotTaken;
7328
# if VBOX_API_VERSION < 3002000
7329
        vboxCallback->vtbl->OnSnapshotDiscarded         = &vboxCallbackOnSnapshotDiscarded;
7330
# else /* VBOX_API_VERSION >= 3002000 */
7331
        vboxCallback->vtbl->OnSnapshotDeleted           = &vboxCallbackOnSnapshotDiscarded;
7332
# endif /* VBOX_API_VERSION >= 3002000 */
7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344
        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,
7345 7346
                             void *opaque ATTRIBUTE_UNUSED)
{
7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358
    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);
    }
}

7359 7360 7361 7362 7363 7364
static int
vboxConnectDomainEventRegister(virConnectPtr conn,
                               virConnectDomainEventCallback callback,
                               void *opaque,
                               virFreeCallback freecb)
{
7365
    VBOX_OBJECT_CHECK(conn, int, -1);
7366
    int vboxRet          = -1;
7367
    nsresult rc;
7368 7369 7370 7371 7372 7373

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

7374
    if (data->vboxCallback == NULL) {
7375
        data->vboxCallback = vboxAllocCallbackObj();
7376 7377 7378 7379
        if (data->vboxCallback != NULL) {
            rc = data->vboxObj->vtbl->RegisterCallback(data->vboxObj, data->vboxCallback);
            if (NS_SUCCEEDED(rc)) {
                vboxRet = 0;
7380 7381
            }
        }
7382 7383 7384
    } else {
        vboxRet = 0;
    }
7385

7386 7387 7388 7389 7390 7391 7392
    /* 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);
7393

7394 7395
            data->fdWatch = virEventAddHandle(vboxFileHandle, VIR_EVENT_HANDLE_READABLE, vboxReadCallback, NULL, NULL);
        }
7396

7397 7398 7399 7400 7401
        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
             */
7402

7403
            ret = virDomainEventStateRegister(conn, data->domainEvents,
7404
                                              callback, opaque, freecb);
7405
            VIR_DEBUG("virObjectEventStateRegister (ret = %d) (conn: %p, "
7406
                      "callback: %p, opaque: %p, "
7407
                      "freecb: %p)", ret, conn, callback,
7408
                      opaque, freecb);
7409 7410 7411 7412 7413 7414
        }
    }

    vboxDriverUnlock(data);

    if (ret >= 0) {
7415
        return 0;
7416 7417 7418 7419 7420 7421 7422 7423
    } else {
        if (data->vboxObj && data->vboxCallback) {
            data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        }
        return -1;
    }
}

7424 7425 7426 7427
static int
vboxConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback callback)
{
7428
    VBOX_OBJECT_CHECK(conn, int, -1);
7429
    int cnt;
7430 7431 7432 7433 7434 7435

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

7436 7437
    cnt = virDomainEventStateDeregister(conn, data->domainEvents,
                                        callback);
7438

7439 7440 7441
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
7442

7443 7444 7445
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
7446 7447 7448 7449
    }

    vboxDriverUnlock(data);

7450 7451 7452
    if (cnt >= 0)
        ret = 0;

7453 7454 7455
    return ret;
}

7456 7457 7458 7459 7460
static int vboxConnectDomainEventRegisterAny(virConnectPtr conn,
                                             virDomainPtr dom,
                                             int eventID,
                                             virConnectDomainEventGenericCallback callback,
                                             void *opaque,
7461 7462
                                             virFreeCallback freecb)
{
7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500
    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
             */

7501
            if (virDomainEventStateRegisterID(conn, data->domainEvents,
7502 7503
                                              dom, eventID,
                                              callback, opaque, freecb, &ret) < 0)
7504
                ret = -1;
7505
            VIR_DEBUG("virDomainEventStateRegisterID (ret = %d) (conn: %p, "
7506
                      "callback: %p, opaque: %p, "
7507
                      "freecb: %p)", ret, conn, callback,
7508
                      opaque, freecb);
7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523
        }
    }

    vboxDriverUnlock(data);

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

7524 7525 7526 7527
static int
vboxConnectDomainEventDeregisterAny(virConnectPtr conn,
                                    int callbackID)
{
7528
    VBOX_OBJECT_CHECK(conn, int, -1);
7529
    int cnt;
7530 7531 7532 7533 7534 7535

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

7536
    cnt = virObjectEventStateDeregisterID(conn, data->domainEvents,
7537
                                          callbackID);
7538

7539 7540 7541
    if (data->vboxCallback && cnt == 0) {
        data->vboxObj->vtbl->UnregisterCallback(data->vboxObj, data->vboxCallback);
        VBOX_RELEASE(data->vboxCallback);
7542

7543 7544 7545
        /* Remove the Event file handle on which we are listening as well */
        virEventRemoveHandle(data->fdWatch);
        data->fdWatch = -1;
7546 7547 7548 7549
    }

    vboxDriverUnlock(data);

7550 7551 7552
    if (cnt >= 0)
        ret = 0;

7553 7554 7555
    return ret;
}

7556
#endif /* !(VBOX_API_VERSION == 2002000 || VBOX_API_VERSION >= 4000000) */
7557

7558 7559 7560 7561 7562
/**
 * The Network Functions here on
 */
static virDrvOpenStatus vboxNetworkOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
7563 7564
                                        unsigned int flags)
{
7565 7566
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
7567 7568
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

7569 7570 7571 7572 7573 7574 7575 7576
    if (STRNEQ(conn->driver->name, "VBOX"))
        goto cleanup;

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
        goto cleanup;

7577
    VIR_DEBUG("network initialized");
7578 7579 7580 7581 7582 7583 7584
    /* conn->networkPrivateData = some network specific data */
    return VIR_DRV_OPEN_SUCCESS;

cleanup:
    return VIR_DRV_OPEN_DECLINED;
}

7585 7586
static int vboxNetworkClose(virConnectPtr conn)
{
7587
    VIR_DEBUG("network uninitialized");
7588 7589 7590 7591
    conn->networkPrivateData = NULL;
    return 0;
}

7592 7593
static int vboxConnectNumOfNetworks(virConnectPtr conn)
{
7594
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7595
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7596
    size_t i = 0;
7597

7598
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7599

7600 7601 7602 7603
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
7604
            PRUint32 interfaceType = 0;
7605

7606
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7607 7608
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7609

7610
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7611

7612 7613
                if (status == HostNetworkInterfaceStatus_Up)
                    ret++;
7614 7615 7616 7617
            }
        }
    }

7618 7619
    vboxArrayRelease(&networkInterfaces);

7620 7621
    VBOX_RELEASE(host);

7622
    VIR_DEBUG("numActive: %d", ret);
7623
    return ret;
7624 7625
}

7626
static int vboxConnectListNetworks(virConnectPtr conn, char **const names, int nnames) {
7627
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7628
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7629
    size_t i = 0;
7630

7631 7632 7633 7634
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7635

7636
        if (networkInterface) {
7637
            PRUint32 interfaceType = 0;
7638

7639
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7640

7641 7642
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7643

7644
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7645

7646 7647 7648
                if (status == HostNetworkInterfaceStatus_Up) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
7649

7650
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7651
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7652

7653
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
7654
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
7655
                        ret++;
7656

7657 7658
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
7659 7660 7661 7662 7663
                }
            }
        }
    }

7664
    vboxArrayRelease(&networkInterfaces);
7665

7666
    VBOX_RELEASE(host);
7667

7668 7669
    return ret;
}
7670

7671 7672
static int vboxConnectNumOfDefinedNetworks(virConnectPtr conn)
{
7673
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7674
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7675
    size_t i = 0;
7676

7677
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);
7678

7679 7680 7681 7682
    for (i = 0; i < networkInterfaces.count; i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];

        if (networkInterface) {
7683
            PRUint32 interfaceType = 0;
7684

7685
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7686 7687
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7688

7689
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7690

7691 7692
                if (status == HostNetworkInterfaceStatus_Down)
                    ret++;
7693 7694 7695 7696
            }
        }
    }

7697 7698
    vboxArrayRelease(&networkInterfaces);

7699 7700
    VBOX_RELEASE(host);

7701
    VIR_DEBUG("numActive: %d", ret);
7702
    return ret;
7703 7704
}

7705
static int vboxConnectListDefinedNetworks(virConnectPtr conn, char **const names, int nnames) {
7706
    VBOX_OBJECT_HOST_CHECK(conn, int, 0);
7707
    vboxArray networkInterfaces = VBOX_ARRAY_INITIALIZER;
7708
    size_t i = 0;
7709

7710 7711 7712 7713
    vboxArrayGet(&networkInterfaces, host, host->vtbl->GetNetworkInterfaces);

    for (i = 0; (ret < nnames) && (i < networkInterfaces.count); i++) {
        IHostNetworkInterface *networkInterface = networkInterfaces.items[i];
7714

7715
        if (networkInterface) {
7716
            PRUint32 interfaceType = 0;
7717

7718
            networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7719

7720 7721
            if (interfaceType == HostNetworkInterfaceType_HostOnly) {
                PRUint32 status = HostNetworkInterfaceStatus_Unknown;
7722

7723
                networkInterface->vtbl->GetStatus(networkInterface, &status);
7724

7725 7726 7727
                if (status == HostNetworkInterfaceStatus_Down) {
                    char *nameUtf8       = NULL;
                    PRUnichar *nameUtf16 = NULL;
7728

7729
                    networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
7730
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7731

7732
                    VIR_DEBUG("nnames[%d]: %s", ret, nameUtf8);
J
Ján Tomko 已提交
7733
                    if (VIR_STRDUP(names[ret], nameUtf8) >= 0)
7734
                        ret++;
7735

7736 7737
                    VBOX_UTF8_FREE(nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
7738 7739 7740 7741 7742
                }
            }
        }
    }

7743
    vboxArrayRelease(&networkInterfaces);
7744 7745 7746 7747

    VBOX_RELEASE(host);

    return ret;
7748 7749
}

7750 7751 7752
static virNetworkPtr
vboxNetworkLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
7753
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
7754
    vboxIID iid = VBOX_IID_INITIALIZER;
7755

7756
    vboxIIDFromUUID(&iid, uuid);
7757

7758 7759 7760
    /* TODO: "internal" networks are just strings and
     * thus can't do much with them
     */
7761
    IHostNetworkInterface *networkInterface = NULL;
7762

7763
    host->vtbl->FindHostNetworkInterfaceById(host, iid.value, &networkInterface);
7764 7765
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7766

7767
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7768

7769 7770 7771
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            char *nameUtf8       = NULL;
            PRUnichar *nameUtf16 = NULL;
7772

7773 7774
            networkInterface->vtbl->GetName(networkInterface, &nameUtf16);
            VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
7775

7776
            ret = virGetNetwork(conn, nameUtf8, uuid);
7777

7778
            VIR_DEBUG("Network Name: %s", nameUtf8);
7779
            DEBUGIID("Network UUID", iid.value);
7780

7781 7782
            VBOX_UTF8_FREE(nameUtf8);
            VBOX_UTF16_FREE(nameUtf16);
7783
        }
7784 7785

        VBOX_RELEASE(networkInterface);
7786 7787
    }

7788 7789
    VBOX_RELEASE(host);

7790
    vboxIIDUnalloc(&iid);
7791 7792 7793
    return ret;
}

7794 7795 7796
static virNetworkPtr
vboxNetworkLookupByName(virConnectPtr conn, const char *name)
{
7797 7798 7799
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *nameUtf16                    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7800

7801
    VBOX_UTF8_TO_UTF16(name, &nameUtf16);
7802

7803
    host->vtbl->FindHostNetworkInterfaceByName(host, nameUtf16, &networkInterface);
7804

7805 7806
    if (networkInterface) {
        PRUint32 interfaceType = 0;
7807

7808
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
7809

7810 7811
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            unsigned char uuid[VIR_UUID_BUFLEN];
7812
            vboxIID iid = VBOX_IID_INITIALIZER;
7813

7814 7815
            networkInterface->vtbl->GetId(networkInterface, &iid.value);
            vboxIIDToUUID(&iid, uuid);
7816
            ret = virGetNetwork(conn, name, uuid);
7817
            VIR_DEBUG("Network Name: %s", name);
7818

7819 7820
            DEBUGIID("Network UUID", iid.value);
            vboxIIDUnalloc(&iid);
7821
        }
7822 7823

        VBOX_RELEASE(networkInterface);
7824 7825
    }

7826 7827 7828
    VBOX_UTF16_FREE(nameUtf16);
    VBOX_RELEASE(host);

7829 7830 7831
    return ret;
}

7832 7833 7834
static virNetworkPtr
vboxNetworkDefineCreateXML(virConnectPtr conn, const char *xml, bool start)
{
7835 7836 7837 7838
    VBOX_OBJECT_HOST_CHECK(conn, virNetworkPtr, NULL);
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    char      *networkInterfaceNameUtf8     = NULL;
    IHostNetworkInterface *networkInterface = NULL;
7839
    nsresult rc;
7840

7841
    virNetworkDefPtr def = virNetworkDefParseString(xml);
7842 7843
    virNetworkIpDefPtr ipdef;
    virSocketAddr netmask;
7844

7845
    if ((!def) ||
7846
        (def->forward.type != VIR_NETWORK_FORWARD_NONE) ||
7847
        (def->nips == 0 || !def->ips))
7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858
        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)
7859
        goto cleanup;
7860

7861 7862 7863 7864 7865 7866
    /* 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.
     */
7867

7868
#if VBOX_API_VERSION == 2002000
7869
    if (STREQ(def->name, "vboxnet0")) {
7870
        PRUint32 interfaceType = 0;
7871

7872 7873
        VBOX_UTF8_TO_UTF16(def->name, &networkInterfaceNameUtf16);
        host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
7874

7875 7876 7877 7878 7879 7880
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
        if (interfaceType != HostNetworkInterfaceType_HostOnly) {
            VBOX_RELEASE(networkInterface);
            networkInterface = NULL;
        }
    }
7881
#else /* VBOX_API_VERSION != 2002000 */
7882 7883 7884 7885
    {
        IProgress *progress = NULL;
        host->vtbl->CreateHostOnlyNetworkInterface(host, &networkInterface,
                                                   &progress);
7886

7887 7888 7889 7890
        if (progress) {
            progress->vtbl->WaitForCompletion(progress, -1);
            VBOX_RELEASE(progress);
        }
7891
    }
7892
#endif /* VBOX_API_VERSION != 2002000 */
7893

7894 7895 7896 7897
    if (networkInterface) {
        unsigned char uuid[VIR_UUID_BUFLEN];
        char      *networkNameUtf8  = NULL;
        PRUnichar *networkNameUtf16 = NULL;
7898
        vboxIID vboxnetiid = VBOX_IID_INITIALIZER;
7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909

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

E
Eric Blake 已提交
7911
        VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
7912

7913 7914 7915
        /* Currently support only one dhcp server per network
         * with contigious address space from start to end
         */
7916
        if ((ipdef->nranges >= 1) &&
7917 7918
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].start) &&
            VIR_SOCKET_ADDR_VALID(&ipdef->ranges[0].end)) {
7919 7920 7921 7922 7923 7924 7925 7926 7927 7928
            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);
7929
                VIR_DEBUG("couldn't find dhcp server so creating one");
7930 7931 7932 7933 7934 7935 7936 7937
            }
            if (dhcpServer) {
                PRUnichar *ipAddressUtf16     = NULL;
                PRUnichar *networkMaskUtf16   = NULL;
                PRUnichar *fromIPAddressUtf16 = NULL;
                PRUnichar *toIPAddressUtf16   = NULL;
                PRUnichar *trunkTypeUtf16     = NULL;

7938 7939 7940 7941
                ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->address);
                networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
                fromIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].start);
                toIPAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->ranges[0].end);
7942 7943 7944 7945 7946 7947 7948 7949 7950 7951

                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;
                }
7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976

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

7978
        if ((ipdef->nhosts >= 1) &&
7979
            VIR_SOCKET_ADDR_VALID(&ipdef->hosts[0].ip)) {
7980 7981
            PRUnichar *ipAddressUtf16   = NULL;
            PRUnichar *networkMaskUtf16 = NULL;
7982

7983 7984
            ipAddressUtf16 = vboxSocketFormatAddrUtf16(data, &ipdef->hosts[0].ip);
            networkMaskUtf16 = vboxSocketFormatAddrUtf16(data, &netmask);
7985 7986 7987 7988 7989 7990

            if (ipAddressUtf16 == NULL || networkMaskUtf16 == NULL) {
                VBOX_UTF16_FREE(ipAddressUtf16);
                VBOX_UTF16_FREE(networkMaskUtf16);
                goto cleanup;
            }
7991

7992 7993 7994 7995
            /* 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
             */
7996
#if VBOX_API_VERSION < 4002000
7997 7998 7999
            networkInterface->vtbl->EnableStaticIpConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
8000 8001 8002 8003 8004
#else
            networkInterface->vtbl->EnableStaticIPConfig(networkInterface,
                                                         ipAddressUtf16,
                                                         networkMaskUtf16);
#endif
8005

8006 8007 8008
            VBOX_UTF16_FREE(ipAddressUtf16);
            VBOX_UTF16_FREE(networkMaskUtf16);
        } else {
8009
#if VBOX_API_VERSION < 4002000
8010 8011
            networkInterface->vtbl->EnableDynamicIpConfig(networkInterface);
            networkInterface->vtbl->DhcpRediscover(networkInterface);
8012 8013 8014 8015
#else
            networkInterface->vtbl->EnableDynamicIPConfig(networkInterface);
            networkInterface->vtbl->DHCPRediscover(networkInterface);
#endif
8016
        }
8017

8018 8019 8020 8021 8022
        rc = networkInterface->vtbl->GetId(networkInterface, &vboxnetiid.value);
        if (NS_SUCCEEDED(rc)) {
            vboxIIDToUUID(&vboxnetiid, uuid);
            DEBUGIID("Real Network UUID", vboxnetiid.value);
            vboxIIDUnalloc(&vboxnetiid);
8023
            ret = virGetNetwork(conn, networkInterfaceNameUtf8, uuid);
8024
        }
8025 8026 8027 8028

        VIR_FREE(networkNameUtf8);
        VBOX_UTF16_FREE(networkNameUtf16);
        VBOX_RELEASE(networkInterface);
8029 8030
    }

8031 8032 8033 8034
    VBOX_UTF8_FREE(networkInterfaceNameUtf8);
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8035 8036 8037 8038 8039
cleanup:
    virNetworkDefFree(def);
    return ret;
}

8040 8041
static virNetworkPtr vboxNetworkCreateXML(virConnectPtr conn, const char *xml)
{
8042 8043 8044
    return vboxNetworkDefineCreateXML(conn, xml, true);
}

8045 8046
static virNetworkPtr vboxNetworkDefineXML(virConnectPtr conn, const char *xml)
{
8047 8048 8049
    return vboxNetworkDefineCreateXML(conn, xml, false);
}

8050 8051 8052
static int
vboxNetworkUndefineDestroy(virNetworkPtr network, bool removeinterface)
{
8053
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
8054
    char *networkNameUtf8 = NULL;
8055 8056
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
8057 8058 8059 8060 8061 8062 8063 8064 8065

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

8066
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
8067 8068
        goto cleanup;

8069
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8070

8071
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8072

8073 8074
    if (networkInterface) {
        PRUint32 interfaceType = 0;
8075

8076
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8077

8078 8079 8080
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
8081

8082
#if VBOX_API_VERSION != 2002000
8083 8084 8085
            if (removeinterface) {
                PRUnichar *iidUtf16 = NULL;
                IProgress *progress = NULL;
8086

8087
                networkInterface->vtbl->GetId(networkInterface, &iidUtf16);
8088

8089
                if (iidUtf16) {
8090
# if VBOX_API_VERSION == 3000000
8091 8092 8093
                    IHostNetworkInterface *netInt = NULL;
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &netInt, &progress);
                    VBOX_RELEASE(netInt);
8094
# else  /* VBOX_API_VERSION > 3000000 */
8095
                    host->vtbl->RemoveHostOnlyNetworkInterface(host, iidUtf16, &progress);
8096
# endif /* VBOX_API_VERSION > 3000000 */
8097 8098
                    VBOX_UTF16_FREE(iidUtf16);
                }
8099

8100 8101 8102 8103 8104
                if (progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
                }
            }
8105
#endif /* VBOX_API_VERSION != 2002000 */
8106

E
Eric Blake 已提交
8107
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8108 8109 8110 8111 8112 8113 8114 8115 8116 8117

            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);
8118 8119
            }

8120 8121
            VBOX_UTF16_FREE(networkNameUtf16);

8122
        }
8123
        VBOX_RELEASE(networkInterface);
8124 8125
    }

8126 8127 8128
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8129 8130 8131 8132 8133 8134 8135
    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

8136 8137
static int vboxNetworkUndefine(virNetworkPtr network)
{
8138 8139 8140
    return vboxNetworkUndefineDestroy(network, true);
}

8141 8142
static int vboxNetworkCreate(virNetworkPtr network)
{
8143
    VBOX_OBJECT_HOST_CHECK(network->conn, int, -1);
8144
    char *networkNameUtf8 = NULL;
8145 8146
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
8147 8148 8149 8150 8151 8152 8153 8154

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

8155
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
8156 8157
        goto cleanup;

8158
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8159

8160
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8161

8162 8163
    if (networkInterface) {
        PRUint32 interfaceType = 0;
8164

8165
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8166

8167 8168 8169
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
            PRUnichar *networkNameUtf16 = NULL;
            IDHCPServer *dhcpServer     = NULL;
8170 8171


E
Eric Blake 已提交
8172
            VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8173

8174 8175 8176 8177 8178
            data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                             networkNameUtf16,
                                                             &dhcpServer);
            if (dhcpServer) {
                PRUnichar *trunkTypeUtf16 = NULL;
8179

8180
                dhcpServer->vtbl->SetEnabled(dhcpServer, PR_TRUE);
8181

8182
                VBOX_UTF8_TO_UTF16("netflt", &trunkTypeUtf16);
8183

8184 8185 8186 8187
                dhcpServer->vtbl->Start(dhcpServer,
                                        networkNameUtf16,
                                        networkInterfaceNameUtf16,
                                        trunkTypeUtf16);
8188

8189 8190
                VBOX_UTF16_FREE(trunkTypeUtf16);
                VBOX_RELEASE(dhcpServer);
8191 8192
            }

8193
            VBOX_UTF16_FREE(networkNameUtf16);
8194
        }
8195 8196

        VBOX_RELEASE(networkInterface);
8197 8198
    }

8199 8200 8201
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8202 8203 8204 8205 8206 8207 8208
    ret = 0;

cleanup:
    VIR_FREE(networkNameUtf8);
    return ret;
}

8209 8210
static int vboxNetworkDestroy(virNetworkPtr network)
{
8211
    return vboxNetworkUndefineDestroy(network, false);
8212 8213
}

8214
static char *vboxNetworkGetXMLDesc(virNetworkPtr network,
E
Eric Blake 已提交
8215 8216
                                   unsigned int flags)
{
8217
    VBOX_OBJECT_HOST_CHECK(network->conn, char *, NULL);
8218
    virNetworkDefPtr def  = NULL;
8219
    virNetworkIpDefPtr ipdef = NULL;
8220
    char *networkNameUtf8 = NULL;
8221 8222
    PRUnichar *networkInterfaceNameUtf16    = NULL;
    IHostNetworkInterface *networkInterface = NULL;
8223

E
Eric Blake 已提交
8224 8225
    virCheckFlags(0, NULL);

8226
    if (VIR_ALLOC(def) < 0)
8227
        goto cleanup;
8228
    if (VIR_ALLOC(ipdef) < 0)
8229 8230 8231
        goto cleanup;
    def->ips = ipdef;
    def->nips = 1;
8232

8233
    if (virAsprintf(&networkNameUtf8, "HostInterfaceNetworking-%s", network->name) < 0)
8234 8235
        goto cleanup;

8236
    VBOX_UTF8_TO_UTF16(network->name, &networkInterfaceNameUtf16);
8237

8238
    host->vtbl->FindHostNetworkInterfaceByName(host, networkInterfaceNameUtf16, &networkInterface);
8239

8240 8241
    if (networkInterface) {
        PRUint32 interfaceType = 0;
8242

8243
        networkInterface->vtbl->GetInterfaceType(networkInterface, &interfaceType);
8244

8245
        if (interfaceType == HostNetworkInterfaceType_HostOnly) {
J
Ján Tomko 已提交
8246
            if (VIR_STRDUP(def->name, network->name) >= 0) {
8247 8248
                PRUnichar *networkNameUtf16 = NULL;
                IDHCPServer *dhcpServer     = NULL;
8249
                vboxIID vboxnet0IID = VBOX_IID_INITIALIZER;
8250

8251 8252
                networkInterface->vtbl->GetId(networkInterface, &vboxnet0IID.value);
                vboxIIDToUUID(&vboxnet0IID, def->uuid);
8253

E
Eric Blake 已提交
8254
                VBOX_UTF8_TO_UTF16(networkNameUtf8, &networkNameUtf16);
8255

8256
                def->forward.type = VIR_NETWORK_FORWARD_NONE;
8257

8258 8259 8260 8261
                data->vboxObj->vtbl->FindDHCPServerByNetworkName(data->vboxObj,
                                                                 networkNameUtf16,
                                                                 &dhcpServer);
                if (dhcpServer) {
8262
                    ipdef->nranges = 1;
8263
                    if (VIR_ALLOC_N(ipdef->ranges, ipdef->nranges) >=0) {
8264 8265 8266 8267
                        PRUnichar *ipAddressUtf16     = NULL;
                        PRUnichar *networkMaskUtf16   = NULL;
                        PRUnichar *fromIPAddressUtf16 = NULL;
                        PRUnichar *toIPAddressUtf16   = NULL;
8268
                        bool errorOccurred = false;
8269

8270 8271 8272 8273 8274 8275 8276
                        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
                         */
8277
                        if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8278
                                                     &ipdef->address) < 0 ||
8279
                            vboxSocketParseAddrUtf16(data, networkMaskUtf16,
8280
                                                     &ipdef->netmask) < 0 ||
8281
                            vboxSocketParseAddrUtf16(data, fromIPAddressUtf16,
8282
                                                     &ipdef->ranges[0].start) < 0 ||
8283
                            vboxSocketParseAddrUtf16(data, toIPAddressUtf16,
8284
                                                     &ipdef->ranges[0].end) < 0) {
8285 8286
                            errorOccurred = true;
                        }
8287 8288 8289 8290 8291

                        VBOX_UTF16_FREE(ipAddressUtf16);
                        VBOX_UTF16_FREE(networkMaskUtf16);
                        VBOX_UTF16_FREE(fromIPAddressUtf16);
                        VBOX_UTF16_FREE(toIPAddressUtf16);
8292 8293 8294 8295

                        if (errorOccurred) {
                            goto cleanup;
                        }
8296
                    } else {
8297
                        ipdef->nranges = 0;
8298
                    }
8299

8300
                    ipdef->nhosts = 1;
8301
                    if (VIR_ALLOC_N(ipdef->hosts, ipdef->nhosts) >=0) {
8302
                        if (VIR_STRDUP(ipdef->hosts[0].name, network->name) < 0) {
8303 8304
                            VIR_FREE(ipdef->hosts);
                            ipdef->nhosts = 0;
8305
                        } else {
8306 8307
                            PRUnichar *macAddressUtf16 = NULL;
                            PRUnichar *ipAddressUtf16  = NULL;
8308
                            bool errorOccurred = false;
8309

8310
                            networkInterface->vtbl->GetHardwareAddress(networkInterface, &macAddressUtf16);
8311 8312
                            networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

8313
                            VBOX_UTF16_TO_UTF8(macAddressUtf16, &ipdef->hosts[0].mac);
8314 8315

                            if (vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8316
                                                         &ipdef->hosts[0].ip) < 0) {
8317 8318
                                errorOccurred = true;
                            }
8319

8320 8321
                            VBOX_UTF16_FREE(macAddressUtf16);
                            VBOX_UTF16_FREE(ipAddressUtf16);
8322 8323 8324 8325

                            if (errorOccurred) {
                                goto cleanup;
                            }
8326 8327
                        }
                    } else {
8328
                        ipdef->nhosts = 0;
8329
                    }
8330 8331 8332 8333 8334

                    VBOX_RELEASE(dhcpServer);
                } else {
                    PRUnichar *networkMaskUtf16 = NULL;
                    PRUnichar *ipAddressUtf16   = NULL;
8335
                    bool errorOccurred = false;
8336 8337 8338 8339

                    networkInterface->vtbl->GetNetworkMask(networkInterface, &networkMaskUtf16);
                    networkInterface->vtbl->GetIPAddress(networkInterface, &ipAddressUtf16);

8340
                    if (vboxSocketParseAddrUtf16(data, networkMaskUtf16,
8341
                                                 &ipdef->netmask) < 0 ||
8342
                        vboxSocketParseAddrUtf16(data, ipAddressUtf16,
8343
                                                 &ipdef->address) < 0) {
8344 8345
                        errorOccurred = true;
                    }
8346 8347 8348

                    VBOX_UTF16_FREE(networkMaskUtf16);
                    VBOX_UTF16_FREE(ipAddressUtf16);
8349 8350 8351 8352

                    if (errorOccurred) {
                        goto cleanup;
                    }
8353 8354
                }

8355 8356
                DEBUGIID("Network UUID", vboxnet0IID.value);
                vboxIIDUnalloc(&vboxnet0IID);
8357
                VBOX_UTF16_FREE(networkNameUtf16);
8358 8359
            }
        }
8360 8361

        VBOX_RELEASE(networkInterface);
8362 8363
    }

8364 8365 8366
    VBOX_UTF16_FREE(networkInterfaceNameUtf16);
    VBOX_RELEASE(host);

8367
    ret = virNetworkDefFormat(def, 0);
8368 8369

cleanup:
8370
    virNetworkDefFree(def);
8371 8372 8373 8374
    VIR_FREE(networkNameUtf8);
    return ret;
}

8375 8376 8377 8378
/**
 * The Storage Functions here on
 */

8379 8380 8381
static virDrvOpenStatus vboxStorageOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
E
Eric Blake 已提交
8382
{
8383 8384
    vboxGlobalData *data = conn->privateData;

E
Eric Blake 已提交
8385 8386
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

8387
    if (STRNEQ(conn->driver->name, "VBOX"))
8388
        return VIR_DRV_OPEN_DECLINED;
8389 8390 8391 8392

    if ((data->pFuncs      == NULL) ||
        (data->vboxObj     == NULL) ||
        (data->vboxSession == NULL))
8393
        return VIR_DRV_OPEN_ERROR;
8394

8395
    VIR_DEBUG("vbox storage initialized");
8396 8397 8398 8399
    /* conn->storagePrivateData = some storage specific data */
    return VIR_DRV_OPEN_SUCCESS;
}

8400 8401
static int vboxStorageClose(virConnectPtr conn)
{
8402
    VIR_DEBUG("vbox storage uninitialized");
8403 8404 8405 8406
    conn->storagePrivateData = NULL;
    return 0;
}

8407 8408
static int vboxConnectNumOfStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED)
{
8409 8410 8411 8412 8413 8414 8415 8416

    /** Currently only one pool supported, the default one
     * given by ISystemProperties::defaultHardDiskFolder()
     */

    return 1;
}

8417 8418
static int vboxConnectListStoragePools(virConnectPtr conn ATTRIBUTE_UNUSED,
                                       char **const names, int nnames) {
8419 8420
    int numActive = 0;

8421 8422 8423
    if (nnames == 1 &&
        VIR_STRDUP(names[numActive], "default-pool") > 0)
        numActive++;
8424 8425 8426
    return numActive;
}

8427 8428 8429
static virStoragePoolPtr
vboxStoragePoolLookupByName(virConnectPtr conn, const char *name)
{
8430 8431 8432 8433 8434 8435 8436 8437 8438 8439
    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";

8440
        ignore_value(virUUIDParse(uuidstr, uuid));
8441

8442
        ret = virGetStoragePool(conn, name, uuid, NULL, NULL);
8443 8444 8445 8446 8447
    }

    return ret;
}

8448 8449
static int vboxStoragePoolNumOfVolumes(virStoragePoolPtr pool)
{
8450
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
8451
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8452 8453
    PRUint32 hardDiskAccessible = 0;
    nsresult rc;
8454
    size_t i;
8455

8456
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8457
    if (NS_SUCCEEDED(rc)) {
8458 8459
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8460 8461
            if (hardDisk) {
                PRUint32 hddstate;
8462

8463 8464 8465
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible)
                    hardDiskAccessible++;
8466 8467
            }
        }
8468 8469 8470 8471

        vboxArrayRelease(&hardDisks);

        ret = hardDiskAccessible;
8472
    } else {
8473
        ret = -1;
8474 8475 8476
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get number of volumes in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
8477 8478
    }

8479
    return ret;
8480 8481 8482
}

static int vboxStoragePoolListVolumes(virStoragePoolPtr pool, char **const names, int nnames) {
8483
    VBOX_OBJECT_CHECK(pool->conn, int, -1);
8484
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8485 8486
    PRUint32 numActive     = 0;
    nsresult rc;
8487
    size_t i;
8488

8489
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8490
    if (NS_SUCCEEDED(rc)) {
8491 8492
        for (i = 0; i < hardDisks.count && numActive < nnames; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8493

8494 8495 8496 8497
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
8498

8499 8500 8501
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8502

8503 8504
                    VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                    VBOX_UTF16_FREE(nameUtf16);
8505

8506
                    if (nameUtf8) {
8507
                        VIR_DEBUG("nnames[%d]: %s", numActive, nameUtf8);
8508
                        if (VIR_STRDUP(names[numActive], nameUtf8) > 0)
8509 8510 8511
                            numActive++;

                        VBOX_UTF8_FREE(nameUtf8);
8512 8513 8514 8515
                    }
                }
            }
        }
8516 8517 8518 8519

        vboxArrayRelease(&hardDisks);

        ret = numActive;
8520
    } else {
8521
        ret = -1;
8522 8523 8524
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("could not get the volume list in the pool: %s, rc=%08x"),
                       pool->name, (unsigned)rc);
8525 8526
    }

8527
    return ret;
8528 8529
}

8530 8531 8532
static virStorageVolPtr
vboxStorageVolLookupByName(virStoragePoolPtr pool, const char *name)
{
8533
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8534
    vboxArray hardDisks = VBOX_ARRAY_INITIALIZER;
8535
    nsresult rc;
8536
    size_t i;
8537

8538
    if (!name)
8539
        return ret;
8540

8541
    rc = vboxArrayGet(&hardDisks, data->vboxObj, data->vboxObj->vtbl->GetHardDisks);
8542
    if (NS_SUCCEEDED(rc)) {
8543 8544
        for (i = 0; i < hardDisks.count; ++i) {
            IHardDisk *hardDisk = hardDisks.items[i];
8545

8546 8547 8548 8549
            if (hardDisk) {
                PRUint32 hddstate;
                char      *nameUtf8  = NULL;
                PRUnichar *nameUtf16 = NULL;
8550

8551 8552 8553
                VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
                if (hddstate != MediaState_Inaccessible) {
                    VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &nameUtf16);
8554

8555 8556 8557 8558
                    if (nameUtf16) {
                        VBOX_UTF16_TO_UTF8(nameUtf16, &nameUtf8);
                        VBOX_UTF16_FREE(nameUtf16);
                    }
8559

8560
                    if (nameUtf8 && STREQ(nameUtf8, name)) {
8561 8562 8563
                        vboxIID hddIID = VBOX_IID_INITIALIZER;
                        unsigned char uuid[VIR_UUID_BUFLEN];
                        char key[VIR_UUID_STRING_BUFLEN] = "";
8564

8565 8566 8567 8568
                        rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                        if (NS_SUCCEEDED(rc)) {
                            vboxIIDToUUID(&hddIID, uuid);
                            virUUIDFormat(uuid, key);
8569

8570 8571
                            ret = virGetStorageVol(pool->conn, pool->name, name, key,
                                                   NULL, NULL);
8572

8573 8574 8575 8576
                            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);
8577 8578
                        }

8579
                        vboxIIDUnalloc(&hddIID);
8580 8581
                        VBOX_UTF8_FREE(nameUtf8);
                        break;
8582
                    }
8583

J
John Ferlan 已提交
8584
                    VBOX_UTF8_FREE(nameUtf8);
8585 8586 8587
                }
            }
        }
8588

8589
        vboxArrayRelease(&hardDisks);
8590 8591 8592 8593 8594
    }

    return ret;
}

8595 8596 8597
static virStorageVolPtr
vboxStorageVolLookupByKey(virConnectPtr conn, const char *key)
{
8598
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
8599 8600
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
8601 8602 8603
    IHardDisk *hardDisk  = NULL;
    nsresult rc;

8604 8605 8606
    if (!key)
        return ret;

8607
    if (virUUIDParse(key, uuid) < 0) {
8608 8609
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), key);
8610
        return NULL;
8611 8612
    }

8613
    vboxIIDFromUUID(&hddIID, uuid);
8614
#if VBOX_API_VERSION < 4000000
8615
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8616
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
8617 8618
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8619 8620 8621 8622
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8623
#endif /* VBOX_API_VERSION >= 4000000 */
8624 8625
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8626

8627 8628 8629 8630
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
8631

8632 8633
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
            VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
8634

8635
            if (hddNameUtf8) {
8636
                if (vboxConnectNumOfStoragePools(conn) == 1) {
8637 8638
                    ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                           NULL, NULL);
8639
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
8640 8641 8642 8643
                } else {
                    /* TODO: currently only one default pool and thus
                     * nothing here, change it when pools are supported
                     */
8644 8645
                }

8646 8647
                VIR_DEBUG("Storage Volume Name: %s", key);
                VIR_DEBUG("Storage Volume key : %s", hddNameUtf8);
8648 8649 8650

                VBOX_UTF8_FREE(hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
8651 8652
            }
        }
8653 8654

        VBOX_MEDIUM_RELEASE(hardDisk);
8655 8656
    }

8657
    vboxIIDUnalloc(&hddIID);
8658 8659 8660
    return ret;
}

8661 8662 8663
static virStorageVolPtr
vboxStorageVolLookupByPath(virConnectPtr conn, const char *path)
{
8664
    VBOX_OBJECT_CHECK(conn, virStorageVolPtr, NULL);
8665 8666 8667 8668
    PRUnichar *hddPathUtf16 = NULL;
    IHardDisk *hardDisk     = NULL;
    nsresult rc;

8669 8670
    if (!path)
        return ret;
8671

8672
    VBOX_UTF8_TO_UTF16(path, &hddPathUtf16);
8673

8674 8675
    if (!hddPathUtf16)
        return ret;
8676

8677
#if VBOX_API_VERSION < 4000000
8678
    rc = data->vboxObj->vtbl->FindHardDisk(data->vboxObj, hddPathUtf16, &hardDisk);
8679
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
8680 8681
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, &hardDisk);
8682 8683 8684 8685
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddPathUtf16,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8686
#endif /* VBOX_API_VERSION >= 4000000 */
8687 8688
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8689

8690 8691 8692 8693
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddNameUtf16 = NULL;
            char      *hddNameUtf8  = NULL;
8694

8695
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetName, &hddNameUtf16);
8696

8697 8698 8699 8700
            if (hddNameUtf16) {
                VBOX_UTF16_TO_UTF8(hddNameUtf16, &hddNameUtf8);
                VBOX_UTF16_FREE(hddNameUtf16);
            }
8701

8702 8703 8704 8705
            if (hddNameUtf8) {
                vboxIID hddIID = VBOX_IID_INITIALIZER;
                unsigned char uuid[VIR_UUID_BUFLEN];
                char key[VIR_UUID_STRING_BUFLEN] = "";
8706

8707 8708 8709 8710
                rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
                if (NS_SUCCEEDED(rc)) {
                    vboxIIDToUUID(&hddIID, uuid);
                    virUUIDFormat(uuid, key);
8711

8712 8713 8714
                    /* TODO: currently only one default pool and thus
                     * the check below, change it when pools are supported
                     */
8715
                    if (vboxConnectNumOfStoragePools(conn) == 1)
8716 8717
                        ret = virGetStorageVol(conn, "default-pool", hddNameUtf8, key,
                                               NULL, NULL);
8718

8719 8720 8721
                    VIR_DEBUG("Storage Volume Pool: %s", "default-pool");
                    VIR_DEBUG("Storage Volume Name: %s", hddNameUtf8);
                    VIR_DEBUG("Storage Volume key : %s", key);
8722
                }
8723

8724
                vboxIIDUnalloc(&hddIID);
8725 8726
            }

J
John Ferlan 已提交
8727
            VBOX_UTF8_FREE(hddNameUtf8);
8728
        }
8729 8730

        VBOX_MEDIUM_RELEASE(hardDisk);
8731 8732
    }

8733 8734
    VBOX_UTF16_FREE(hddPathUtf16);

8735 8736 8737 8738 8739
    return ret;
}

static virStorageVolPtr vboxStorageVolCreateXML(virStoragePoolPtr pool,
                                                const char *xml,
E
Eric Blake 已提交
8740 8741
                                                unsigned int flags)
{
8742
    VBOX_OBJECT_CHECK(pool->conn, virStorageVolPtr, NULL);
8743
    virStorageVolDefPtr  def  = NULL;
8744 8745
    PRUnichar *hddFormatUtf16 = NULL;
    PRUnichar *hddNameUtf16   = NULL;
8746 8747 8748
    virStoragePoolDef poolDef;
    nsresult rc;

E
Eric Blake 已提交
8749 8750
    virCheckFlags(0, NULL);

8751 8752 8753 8754 8755 8756 8757 8758
    /* 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;

8759
    if ((def = virStorageVolDefParseString(&poolDef, xml)) == NULL)
8760 8761
        goto cleanup;

8762 8763
    if (!def->name ||
        (def->type != VIR_STORAGE_VOL_FILE))
8764
        goto cleanup;
8765

8766 8767 8768 8769 8770 8771
    /* 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
     */
8772

8773 8774 8775 8776 8777 8778 8779
    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);
    }
8780

8781
    VBOX_UTF8_TO_UTF16(def->name, &hddNameUtf16);
8782

8783 8784
    if (hddFormatUtf16 && hddNameUtf16) {
        IHardDisk *hardDisk = NULL;
8785

8786 8787 8788
        rc = data->vboxObj->vtbl->CreateHardDisk(data->vboxObj, hddFormatUtf16, hddNameUtf16, &hardDisk);
        if (NS_SUCCEEDED(rc)) {
            IProgress *progress    = NULL;
8789
            PRUint64   logicalSize = VIR_DIV_UP(def->capacity, 1024 * 1024);
8790
            PRUint32   variant     = HardDiskVariant_Standard;
8791

8792 8793
            if (def->capacity == def->allocation)
                variant = HardDiskVariant_Fixed;
8794

8795
#if VBOX_API_VERSION < 4003000
8796
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, variant, &progress);
R
Ryota Ozaki 已提交
8797 8798 8799
#else
            rc = hardDisk->vtbl->CreateBaseStorage(hardDisk, logicalSize, 1, &variant, &progress);
#endif
8800
            if (NS_SUCCEEDED(rc) && progress) {
8801
#if VBOX_API_VERSION == 2002000
8802
                nsresult resultCode;
8803
#else
8804
                PRInt32  resultCode;
8805 8806
#endif

8807 8808
                progress->vtbl->WaitForCompletion(progress, -1);
                progress->vtbl->GetResultCode(progress, &resultCode);
8809

8810
                if (NS_SUCCEEDED(resultCode)) {
8811 8812 8813
                    vboxIID hddIID = VBOX_IID_INITIALIZER;
                    unsigned char uuid[VIR_UUID_BUFLEN];
                    char key[VIR_UUID_STRING_BUFLEN] = "";
8814

8815
                    rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetId, &hddIID.value);
8816
                    if (NS_SUCCEEDED(rc)) {
8817 8818
                        vboxIIDToUUID(&hddIID, uuid);
                        virUUIDFormat(uuid, key);
8819

8820 8821
                        ret = virGetStorageVol(pool->conn, pool->name, def->name, key,
                                               NULL, NULL);
8822
                    }
8823 8824

                    vboxIIDUnalloc(&hddIID);
8825 8826
                }

8827
                VBOX_RELEASE(progress);
8828
            }
8829
        }
8830 8831
    }

8832 8833 8834
    VBOX_UTF16_FREE(hddFormatUtf16);
    VBOX_UTF16_FREE(hddNameUtf16);

8835 8836 8837 8838 8839 8840
cleanup:
    virStorageVolDefFree(def);
    return ret;
}

static int vboxStorageVolDelete(virStorageVolPtr vol,
E
Eric Blake 已提交
8841 8842
                                unsigned int flags)
{
8843
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
8844 8845
    vboxIID hddIID = VBOX_IID_INITIALIZER;
    unsigned char uuid[VIR_UUID_BUFLEN];
8846 8847 8848
    IHardDisk *hardDisk  = NULL;
    int deregister = 0;
    nsresult rc;
8849 8850
    size_t i = 0;
    size_t j = 0;
8851

E
Eric Blake 已提交
8852 8853
    virCheckFlags(0, -1);

8854
    if (virUUIDParse(vol->key, uuid) < 0) {
8855 8856
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
8857 8858
        return -1;
    }
8859

8860
    vboxIIDFromUUID(&hddIID, uuid);
8861
#if VBOX_API_VERSION < 4000000
8862
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
8863
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
8864 8865
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
8866 8867 8868 8869
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
8870
#endif /* VBOX_API_VERSION >= 4000000 */
8871 8872
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
8873

8874 8875 8876
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUint32  machineIdsSize = 0;
8877 8878
            vboxArray machineIds = VBOX_ARRAY_INITIALIZER;

8879
#if VBOX_API_VERSION < 3001000
8880
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->imedium.GetMachineIds);
8881
#else  /* VBOX_API_VERSION >= 3001000 */
8882
            vboxArrayGet(&machineIds, hardDisk, hardDisk->vtbl->GetMachineIds);
8883
#endif /* VBOX_API_VERSION >= 3001000 */
8884

8885
#if VBOX_API_VERSION == 2002000 && defined WIN32
8886 8887 8888 8889 8890 8891
            /* 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 已提交
8892
             * we divide the size of the SafeArray by two, to compensate for
8893 8894
             * this workaround in VirtualBox */
            machineIds.count /= 2;
8895
#endif /* VBOX_API_VERSION >= 2002000 */
8896

8897
            machineIdsSize = machineIds.count;
8898

8899
            for (i = 0; i < machineIds.count; i++) {
8900
                IMachine *machine = NULL;
8901 8902 8903
                vboxIID machineId = VBOX_IID_INITIALIZER;

                vboxIIDFromArrayItem(&machineId, &machineIds, i);
8904

8905
#if VBOX_API_VERSION >= 4000000
8906 8907
                rc = VBOX_OBJECT_GET_MACHINE(machineId.value, &machine);
                if (NS_FAILED(rc)) {
8908 8909
                    virReportError(VIR_ERR_NO_DOMAIN, "%s",
                                   _("no domain with matching uuid"));
8910 8911 8912 8913 8914 8915
                    break;
                }
#endif

                rc = VBOX_SESSION_OPEN(machineId.value, machine);

8916
                if (NS_SUCCEEDED(rc)) {
8917

8918 8919
                    rc = data->vboxSession->vtbl->GetMachine(data->vboxSession, &machine);
                    if (NS_SUCCEEDED(rc)) {
8920
                        vboxArray hddAttachments = VBOX_ARRAY_INITIALIZER;
8921

8922
#if VBOX_API_VERSION < 3001000
8923 8924
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetHardDiskAttachments);
8925
#else  /* VBOX_API_VERSION >= 3001000 */
8926 8927
                        vboxArrayGet(&hddAttachments, machine,
                                     machine->vtbl->GetMediumAttachments);
8928
#endif /* VBOX_API_VERSION >= 3001000 */
8929 8930
                        for (j = 0; j < hddAttachments.count; j++) {
                            IHardDiskAttachment *hddAttachment = hddAttachments.items[j];
8931 8932 8933 8934

                            if (hddAttachment) {
                                IHardDisk *hdd = NULL;

8935
#if VBOX_API_VERSION < 3001000
8936
                                rc = hddAttachment->vtbl->GetHardDisk(hddAttachment, &hdd);
8937
#else  /* VBOX_API_VERSION >= 3001000 */
8938
                                rc = hddAttachment->vtbl->GetMedium(hddAttachment, &hdd);
8939
#endif /* VBOX_API_VERSION >= 3001000 */
8940
                                if (NS_SUCCEEDED(rc) && hdd) {
8941
                                    vboxIID iid = VBOX_IID_INITIALIZER;
8942

8943 8944
                                    rc = VBOX_MEDIUM_FUNC_ARG1(hdd, GetId, &iid.value);
                                    if (NS_SUCCEEDED(rc)) {
8945

8946 8947
                                            DEBUGIID("HardDisk (to delete) UUID", hddIID.value);
                                            DEBUGIID("HardDisk (currently processing) UUID", iid.value);
8948

8949
                                        if (vboxIIDIsEqual(&hddIID, &iid)) {
8950 8951 8952 8953
                                            PRUnichar *controller = NULL;
                                            PRInt32    port       = 0;
                                            PRInt32    device     = 0;

8954
                                            DEBUGIID("Found HardDisk to delete, UUID", hddIID.value);
8955 8956 8957 8958 8959

                                            hddAttachment->vtbl->GetController(hddAttachment, &controller);
                                            hddAttachment->vtbl->GetPort(hddAttachment, &port);
                                            hddAttachment->vtbl->GetDevice(hddAttachment, &device);

8960
#if VBOX_API_VERSION < 3001000
8961
                                            rc = machine->vtbl->DetachHardDisk(machine, controller, port, device);
8962
#else  /* VBOX_API_VERSION >= 3001000 */
8963
                                            rc = machine->vtbl->DetachDevice(machine, controller, port, device);
8964
#endif /* VBOX_API_VERSION >= 3001000 */
8965 8966
                                            if (NS_SUCCEEDED(rc)) {
                                                rc = machine->vtbl->SaveSettings(machine);
8967
                                                VIR_DEBUG("saving machine settings");
8968
                                            }
8969

8970 8971
                                            if (NS_SUCCEEDED(rc)) {
                                                deregister++;
8972
                                                VIR_DEBUG("deregistering hdd:%d", deregister);
8973
                                            }
8974

J
John Ferlan 已提交
8975
                                            VBOX_UTF16_FREE(controller);
8976
                                        }
8977
                                        vboxIIDUnalloc(&iid);
8978
                                    }
8979
                                    VBOX_MEDIUM_RELEASE(hdd);
8980 8981 8982
                                }
                            }
                        }
8983
                        vboxArrayRelease(&hddAttachments);
8984
                        VBOX_RELEASE(machine);
8985
                    }
8986
                    VBOX_SESSION_CLOSE();
8987
                }
8988 8989

                vboxIIDUnalloc(&machineId);
8990
            }
8991

8992
            vboxArrayUnalloc(&machineIds);
8993

8994 8995
            if (machineIdsSize == 0 || machineIdsSize == deregister) {
                IProgress *progress = NULL;
8996

8997
                rc = hardDisk->vtbl->DeleteStorage(hardDisk, &progress);
8998

8999 9000 9001
                if (NS_SUCCEEDED(rc) && progress) {
                    progress->vtbl->WaitForCompletion(progress, -1);
                    VBOX_RELEASE(progress);
9002
                    DEBUGIID("HardDisk deleted, UUID", hddIID.value);
9003
                    ret = 0;
9004 9005 9006
                }
            }
        }
9007 9008

        VBOX_MEDIUM_RELEASE(hardDisk);
9009 9010
    }

9011
    vboxIIDUnalloc(&hddIID);
9012

9013 9014 9015
    return ret;
}

9016 9017 9018
static int
vboxStorageVolGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info)
{
9019
    VBOX_OBJECT_CHECK(vol->conn, int, -1);
9020
    IHardDisk *hardDisk  = NULL;
9021 9022
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
9023 9024
    nsresult rc;

9025
    if (!info)
9026
        return ret;
9027

9028
    if (virUUIDParse(vol->key, uuid) < 0) {
9029 9030
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
9031
        return ret;
9032
    }
9033

9034
    vboxIIDFromUUID(&hddIID, uuid);
9035
#if VBOX_API_VERSION < 4000000
9036
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9037
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
9038 9039
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
9040 9041 9042 9043
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
9044
#endif /* VBOX_API_VERSION >= 4000000 */
9045 9046
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
9047

9048 9049
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
9050
#if VBOX_API_VERSION < 4000000
9051 9052
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
9053
#else /* VBOX_API_VERSION >= 4000000 */
9054 9055
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
9056
#endif /* VBOX_API_VERSION >= 4000000 */
9057

9058
            info->type = VIR_STORAGE_VOL_FILE;
9059

9060
            hardDisk->vtbl->GetLogicalSize(hardDisk, &hddLogicalSize);
9061
#if VBOX_API_VERSION < 4000000
9062
            info->capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
9063
#else /* VBOX_API_VERSION >= 4000000 */
9064
            info->capacity = hddLogicalSize;
9065
#endif /* VBOX_API_VERSION >= 4000000 */
9066

9067 9068
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            info->allocation = hddActualSize;
9069

9070
            ret = 0;
9071

9072 9073 9074 9075
            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);
9076
        }
9077 9078

        VBOX_MEDIUM_RELEASE(hardDisk);
9079 9080
    }

9081
    vboxIIDUnalloc(&hddIID);
9082

9083 9084 9085
    return ret;
}

E
Eric Blake 已提交
9086 9087
static char *vboxStorageVolGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
{
9088
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
9089
    IHardDisk *hardDisk  = NULL;
9090 9091
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
9092 9093 9094 9095 9096
    virStoragePoolDef pool;
    virStorageVolDef def;
    int defOk = 0;
    nsresult rc;

E
Eric Blake 已提交
9097 9098
    virCheckFlags(0, NULL);

9099 9100 9101
    memset(&pool, 0, sizeof(pool));
    memset(&def, 0, sizeof(def));

9102
    if (virUUIDParse(vol->key, uuid) < 0) {
9103 9104
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
9105
        return ret;
9106
    }
9107

9108
    vboxIIDFromUUID(&hddIID, uuid);
9109
#if VBOX_API_VERSION < 4000000
9110
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9111
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
9112 9113
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
9114 9115 9116 9117
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
9118
#endif /* VBOX_API_VERSION >= 4000000 */
9119 9120 9121 9122 9123 9124
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;

        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (NS_SUCCEEDED(rc) && hddstate != MediaState_Inaccessible) {
            PRUnichar *hddFormatUtf16 = NULL;
9125
#if VBOX_API_VERSION < 4000000
9126 9127
            PRUint64 hddLogicalSize;
            PRUint64 hddActualSize;
9128
#else /* VBOX_API_VERSION >= 4000000 */
9129 9130
            PRInt64 hddLogicalSize;
            PRInt64 hddActualSize;
9131
#endif /* VBOX_API_VERSION >= 4000000 */
9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142

            /* 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);
9143
            if (NS_SUCCEEDED(rc) && defOk) {
9144
#if VBOX_API_VERSION < 4000000
9145
                def.capacity = hddLogicalSize * 1024 * 1024; /* MB => Bytes */
9146
#else /* VBOX_API_VERSION >= 4000000 */
9147
                def.capacity = hddLogicalSize;
9148
#endif /* VBOX_API_VERSION >= 4000000 */
9149
            } else
9150 9151 9152 9153 9154 9155 9156 9157
                defOk = 0;

            rc = VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetSize, &hddActualSize);
            if (NS_SUCCEEDED(rc) && defOk)
                def.allocation = hddActualSize;
            else
                defOk = 0;

9158
            if (VIR_STRDUP(def.name, vol->name) < 0)
9159 9160
                defOk = 0;

9161
            if (VIR_STRDUP(def.key, vol->key) < 0)
9162 9163 9164 9165 9166 9167 9168 9169 9170
                defOk = 0;

            rc = hardDisk->vtbl->GetFormat(hardDisk, &hddFormatUtf16);
            if (NS_SUCCEEDED(rc) && defOk) {
                char *hddFormatUtf8 = NULL;

                VBOX_UTF16_TO_UTF8(hddFormatUtf16, &hddFormatUtf8);
                if (hddFormatUtf8) {

9171
                    VIR_DEBUG("Storage Volume Format: %s", hddFormatUtf8);
9172 9173 9174 9175 9176

                    if (STRCASEEQ("vmdk", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VMDK;
                    else if (STRCASEEQ("vhd", hddFormatUtf8))
                        def.target.format = VIR_STORAGE_FILE_VPC;
9177
                    else
9178
                        def.target.format = VIR_STORAGE_FILE_RAW;
9179

9180 9181 9182
                    /* TODO: need to add vdi to enum virStorageFileFormat {}
                     * and then add it here
                     */
9183

9184
                    VBOX_UTF8_FREE(hddFormatUtf8);
9185 9186
                }

9187 9188 9189
                VBOX_UTF16_FREE(hddFormatUtf16);
            } else {
                defOk = 0;
9190 9191
            }
        }
9192 9193

        VBOX_MEDIUM_RELEASE(hardDisk);
9194 9195
    }

9196
    vboxIIDUnalloc(&hddIID);
9197

9198
    if (defOk)
9199
        ret = virStorageVolDefFormat(&pool, &def);
9200 9201 9202 9203 9204

    return ret;
}

static char *vboxStorageVolGetPath(virStorageVolPtr vol) {
9205
    VBOX_OBJECT_CHECK(vol->conn, char *, NULL);
9206
    IHardDisk *hardDisk  = NULL;
9207 9208
    unsigned char uuid[VIR_UUID_BUFLEN];
    vboxIID hddIID = VBOX_IID_INITIALIZER;
9209 9210
    nsresult rc;

9211
    if (virUUIDParse(vol->key, uuid) < 0) {
9212 9213
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Could not parse UUID from '%s'"), vol->key);
9214
        return ret;
9215
    }
9216

9217
    vboxIIDFromUUID(&hddIID, uuid);
9218
#if VBOX_API_VERSION < 4000000
9219
    rc = data->vboxObj->vtbl->GetHardDisk(data->vboxObj, hddIID.value, &hardDisk);
9220
#elif VBOX_API_VERSION >= 4000000 && VBOX_API_VERSION < 4002000
9221 9222
    rc = data->vboxObj->vtbl->FindMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, &hardDisk);
9223 9224 9225 9226
#else
    rc = data->vboxObj->vtbl->OpenMedium(data->vboxObj, hddIID.value,
                                         DeviceType_HardDisk, AccessMode_ReadWrite,
                                         PR_FALSE, &hardDisk);
9227
#endif /* VBOX_API_VERSION >= 4000000 */
9228 9229
    if (NS_SUCCEEDED(rc)) {
        PRUint32 hddstate;
9230

9231 9232 9233 9234
        VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetState, &hddstate);
        if (hddstate != MediaState_Inaccessible) {
            PRUnichar *hddLocationUtf16 = NULL;
            char      *hddLocationUtf8  = NULL;
9235

9236
            VBOX_MEDIUM_FUNC_ARG1(hardDisk, GetLocation, &hddLocationUtf16);
9237

9238 9239
            VBOX_UTF16_TO_UTF8(hddLocationUtf16, &hddLocationUtf8);
            if (hddLocationUtf8) {
9240

9241
                ignore_value(VIR_STRDUP(ret, hddLocationUtf8));
9242

9243 9244 9245
                VIR_DEBUG("Storage Volume Name: %s", vol->name);
                VIR_DEBUG("Storage Volume Path: %s", hddLocationUtf8);
                VIR_DEBUG("Storage Volume Pool: %s", vol->pool);
9246

9247
                VBOX_UTF8_FREE(hddLocationUtf8);
9248 9249
            }

9250
            VBOX_UTF16_FREE(hddLocationUtf16);
9251
        }
9252 9253

        VBOX_MEDIUM_RELEASE(hardDisk);
9254 9255
    }

9256
    vboxIIDUnalloc(&hddIID);
9257

9258 9259
    return ret;
}
9260

9261
#if VBOX_API_VERSION >= 4000000
9262 9263 9264 9265
static char *
vboxDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
9266
                     unsigned int flags)
9267 9268 9269 9270 9271 9272 9273 9274 9275 9276
{
    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 已提交
9277 9278
    virCheckFlags(0, NULL);

9279 9280 9281
    vboxIIDFromUUID(&iid, dom->uuid);
    rc = VBOX_OBJECT_GET_MACHINE(iid.value, &machine);
    if (NS_FAILED(rc)) {
9282 9283
        virReportError(VIR_ERR_NO_DOMAIN, "%s",
                       _("no domain with matching uuid"));
9284 9285 9286 9287 9288
        return NULL;
    }

    rc = machine->vtbl->GetMonitorCount(machine, &max_screen);
    if (NS_FAILED(rc)) {
9289 9290
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to get monitor count"));
9291 9292 9293 9294 9295
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (screen >= max_screen) {
9296 9297 9298
        virReportError(VIR_ERR_INVALID_ARG,
                       _("screen ID higher than monitor "
                         "count (%d)"), max_screen);
9299 9300 9301 9302 9303 9304 9305 9306 9307
        VBOX_RELEASE(machine);
        return NULL;
    }

    if (virAsprintf(&tmp, "%s/cache/libvirt/vbox.screendump.XXXXXX", LOCALSTATEDIR) < 0) {
        VBOX_RELEASE(machine);
        return NULL;
    }

9308 9309
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327
        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;
9328
# if VBOX_API_VERSION >= 4003000
R
Ryota Ozaki 已提交
9329 9330
                PRInt32 xOrigin, yOrigin;
# endif
9331 9332 9333

                rc = display->vtbl->GetScreenResolution(display, screen,
                                                        &width, &height,
9334
# if VBOX_API_VERSION < 4003000
9335
                                                        &bitsPerPixel);
R
Ryota Ozaki 已提交
9336 9337 9338 9339
# else
                                                        &bitsPerPixel,
                                                        &xOrigin, &yOrigin);
# endif
9340 9341

                if (NS_FAILED(rc) || !width || !height) {
9342 9343
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to get screen resolution"));
9344 9345 9346 9347 9348 9349 9350 9351
                    goto endjob;
                }

                rc = display->vtbl->TakeScreenShotPNGToArray(display, screen,
                                                             width, height,
                                                             &screenDataSize,
                                                             &screenData);
                if (NS_FAILED(rc)) {
9352 9353
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("failed to take screenshot"));
9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368
                    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;
                }

9369 9370 9371
                if (VIR_STRDUP(ret, "image/png") < 0)
                    goto endjob;

E
Eric Blake 已提交
9372
                if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
9373 9374
                    virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                                   _("unable to open stream"));
9375
                    VIR_FREE(ret);
9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386
                }
endjob:
                VIR_FREE(screenData);
                VBOX_RELEASE(display);
            }
            VBOX_RELEASE(console);
        }
        VBOX_SESSION_CLOSE();
    }

    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
9387
    unlink(tmp);
9388 9389 9390 9391 9392
    VIR_FREE(tmp);
    VBOX_RELEASE(machine);
    vboxIIDUnalloc(&iid);
    return ret;
}
9393
#endif /* VBOX_API_VERSION >= 4000000 */
9394

9395 9396 9397

#define MATCH(FLAG) (flags & (FLAG))
static int
9398 9399 9400
vboxConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
9401 9402 9403 9404 9405 9406 9407 9408 9409
{
    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;
9410
    size_t i;
9411 9412 9413 9414 9415 9416
    virDomainPtr dom;
    virDomainPtr *doms = NULL;
    int count = 0;
    bool active;
    PRUint32 snapshotCount;

O
Osier Yang 已提交
9417
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431

    /* 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)
9432
            goto cleanup;
9433 9434 9435 9436 9437 9438 9439

        ret = 0;
        goto cleanup;
    }

    rc = vboxArrayGet(&machines, data->vboxObj, data->vboxObj->vtbl->GetMachines);
    if (NS_FAILED(rc)) {
9440 9441
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Could not get list of domains, rc=%08x"), (unsigned)rc);
9442 9443 9444 9445 9446
        goto cleanup;
    }

    if (domains &&
        VIR_ALLOC_N(doms, machines.count + 1) < 0)
9447
        goto cleanup;
9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464

    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 已提交
9465
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_ACTIVE) &&
9466 9467 9468 9469 9470
                    !((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
                      (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
                    continue;

                /* filter by snapshot existence */
O
Osier Yang 已提交
9471
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_SNAPSHOT)) {
9472 9473
                    rc = machine->vtbl->GetSnapshotCount(machine, &snapshotCount);
                    if (NS_FAILED(rc)) {
9474
                        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
9475
                                       _("could not get snapshot count for listed domains"));
9476 9477 9478 9479 9480 9481 9482 9483 9484 9485
                        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 已提交
9486
                if (MATCH(VIR_CONNECT_LIST_DOMAINS_FILTERS_STATE) &&
9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551
                    !((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


9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575
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();
}

9576

9577 9578 9579 9580
/**
 * Function Tables
 */

9581
virDriver NAME(Driver) = {
9582 9583
    .no = VIR_DRV_VBOX,
    .name = "VBOX",
9584 9585 9586
    .connectOpen = vboxConnectOpen, /* 0.6.3 */
    .connectClose = vboxConnectClose, /* 0.6.3 */
    .connectGetVersion = vboxConnectGetVersion, /* 0.6.3 */
9587
    .connectGetHostname = vboxConnectGetHostname, /* 0.6.3 */
9588
    .connectGetMaxVcpus = vboxConnectGetMaxVcpus, /* 0.6.3 */
9589
    .nodeGetInfo = vboxNodeGetInfo, /* 0.6.3 */
9590 9591 9592 9593
    .connectGetCapabilities = vboxConnectGetCapabilities, /* 0.6.3 */
    .connectListDomains = vboxConnectListDomains, /* 0.6.3 */
    .connectNumOfDomains = vboxConnectNumOfDomains, /* 0.6.3 */
    .connectListAllDomains = vboxConnectListAllDomains, /* 0.9.13 */
9594 9595 9596 9597 9598 9599 9600
    .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 */
9601
    .domainShutdownFlags = vboxDomainShutdownFlags, /* 0.9.10 */
9602 9603
    .domainReboot = vboxDomainReboot, /* 0.6.3 */
    .domainDestroy = vboxDomainDestroy, /* 0.6.3 */
9604
    .domainDestroyFlags = vboxDomainDestroyFlags, /* 0.9.4 */
9605 9606 9607 9608 9609 9610 9611 9612 9613 9614
    .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 */
9615 9616
    .connectListDefinedDomains = vboxConnectListDefinedDomains, /* 0.6.3 */
    .connectNumOfDefinedDomains = vboxConnectNumOfDefinedDomains, /* 0.6.3 */
9617 9618 9619 9620
    .domainCreate = vboxDomainCreate, /* 0.6.3 */
    .domainCreateWithFlags = vboxDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = vboxDomainDefineXML, /* 0.6.3 */
    .domainUndefine = vboxDomainUndefine, /* 0.6.3 */
9621
    .domainUndefineFlags = vboxDomainUndefineFlags, /* 0.9.5 */
9622 9623 9624 9625 9626
    .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 */
9627 9628
    .nodeGetCellsFreeMemory = vboxNodeGetCellsFreeMemory, /* 0.6.5 */
    .nodeGetFreeMemory = vboxNodeGetFreeMemory, /* 0.6.5 */
9629
#if VBOX_API_VERSION >= 4000000
9630
    .domainScreenshot = vboxDomainScreenshot, /* 0.9.2 */
9631
#endif
9632
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
9633 9634
    .connectDomainEventRegister = vboxConnectDomainEventRegister, /* 0.7.0 */
    .connectDomainEventDeregister = vboxConnectDomainEventDeregister, /* 0.7.0 */
9635
#endif
9636 9637
    .connectIsEncrypted = vboxConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = vboxConnectIsSecure, /* 0.7.3 */
9638 9639 9640
    .domainIsActive = vboxDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = vboxDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = vboxDomainIsUpdated, /* 0.8.6 */
9641
#if VBOX_API_VERSION > 2002000 && VBOX_API_VERSION < 4000000
9642 9643
    .connectDomainEventRegisterAny = vboxConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = vboxConnectDomainEventDeregisterAny, /* 0.8.0 */
9644
#endif
9645 9646 9647 9648 9649 9650
    .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 */
9651
    .domainSnapshotGetParent = vboxDomainSnapshotGetParent, /* 0.9.7 */
9652
    .domainSnapshotCurrent = vboxDomainSnapshotCurrent, /* 0.8.0 */
9653 9654
    .domainSnapshotIsCurrent = vboxDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = vboxDomainSnapshotHasMetadata, /* 0.9.13 */
9655 9656
    .domainRevertToSnapshot = vboxDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = vboxDomainSnapshotDelete, /* 0.8.0 */
9657
    .connectIsAlive = vboxConnectIsAlive, /* 0.9.8 */
9658
};
9659 9660 9661

virNetworkDriver NAME(NetworkDriver) = {
    "VBOX",
9662 9663
    .networkOpen = vboxNetworkOpen, /* 0.6.4 */
    .networkClose = vboxNetworkClose, /* 0.6.4 */
9664 9665 9666 9667
    .connectNumOfNetworks = vboxConnectNumOfNetworks, /* 0.6.4 */
    .connectListNetworks = vboxConnectListNetworks, /* 0.6.4 */
    .connectNumOfDefinedNetworks = vboxConnectNumOfDefinedNetworks, /* 0.6.4 */
    .connectListDefinedNetworks = vboxConnectListDefinedNetworks, /* 0.6.4 */
9668 9669 9670 9671 9672 9673 9674 9675
    .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 */
9676
};
9677 9678 9679

virStorageDriver NAME(StorageDriver) = {
    .name               = "VBOX",
9680 9681
    .storageOpen = vboxStorageOpen, /* 0.7.1 */
    .storageClose = vboxStorageClose, /* 0.7.1 */
9682 9683
    .connectNumOfStoragePools = vboxConnectNumOfStoragePools, /* 0.7.1 */
    .connectListStoragePools = vboxConnectListStoragePools, /* 0.7.1 */
9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695
    .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 */
9696
};